ghash: Add g_hash_table_new_similar()

This function creates a new hash table, but inherits the functions used
for the hash, comparison, and key/value memory management functions from
another hash table.

The primary use case is to implement a behaviour where you maintain a
hash table by regenerating it, letting the values not migrated be freed.
See the following pseudo code:

```
GHashTable *ht;

init(GList *resources) {
  ht = g_hash_table_new (g_str_hash, g_str_equal, g_free, g_free);
  for (r in resources)
    g_hash_table_insert (ht, strdup (resource_get_key (r)), create_value (r));
}

update(GList *resources) {
  GHashTable *new_ht = g_hash_table_new_similar (ht);

  for (r in resources) {
    if (g_hash_table_steal_extended (ht, resource_get_key (r), &key, &value))
      g_hash_table_insert (new_ht, key, value);
    else
      g_hash_table_insert (new_ht, strdup (resource_get_key (r)), create_value (r));
  }
  g_hash_table_unref (ht);
  ht = new_ht;
}
```
This commit is contained in:
Jonas Ådahl 2021-12-23 00:58:54 +01:00
parent 41d80f5029
commit 283d9e0c15
4 changed files with 74 additions and 0 deletions

View File

@ -2851,6 +2851,7 @@ g_trash_stack_height
GHashTable
g_hash_table_new
g_hash_table_new_full
g_hash_table_new_similar
GHashFunc
GEqualFunc
g_hash_table_insert

View File

@ -1085,6 +1085,33 @@ g_hash_table_new_full (GHashFunc hash_func,
return hash_table;
}
/**
* g_hash_table_new_similar:
* @other_hash_table: (not nullable) (transfer none): Another #GHashTable
*
* Creates a new #GHashTable like g_hash_table_new_full() with a reference
* count of 1.
*
* It inherits the hash function, the key equal function, the key destroy function,
* as well as the value destroy function, from @other_hash_table.
*
* The returned hash table will be empty; it will not contain the keys
* or values from @other_hash_table.
*
* Returns: (transfer full) (not nullable): a new #GHashTable
* Since: 2.72
*/
GHashTable *
g_hash_table_new_similar (GHashTable *other_hash_table)
{
g_return_val_if_fail (other_hash_table, NULL);
return g_hash_table_new_full (other_hash_table->hash_func,
other_hash_table->key_equal_func,
other_hash_table->key_destroy_func,
other_hash_table->value_destroy_func);
}
/**
* g_hash_table_iter_init:
* @iter: an uninitialized #GHashTableIter

View File

@ -61,6 +61,8 @@ GHashTable* g_hash_table_new_full (GHashFunc hash_func,
GEqualFunc key_equal_func,
GDestroyNotify key_destroy_func,
GDestroyNotify value_destroy_func);
GLIB_AVAILABLE_IN_2_72
GHashTable *g_hash_table_new_similar (GHashTable *other_hash_table);
GLIB_AVAILABLE_IN_ALL
void g_hash_table_destroy (GHashTable *hash_table);
GLIB_AVAILABLE_IN_ALL

View File

@ -1345,6 +1345,49 @@ test_lookup_extended (void)
g_hash_table_unref (hash);
}
static void
inc_state (gpointer user_data)
{
int *state = user_data;
g_assert_cmpint (*state, ==, 0);
*state = 1;
}
static void
test_new_similar (void)
{
GHashTable *hash1;
GHashTable *hash2;
int state1;
int state2;
hash1 = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, inc_state);
state1 = 0;
g_hash_table_insert (hash1,
g_strdup ("test"),
&state1);
g_assert_true (g_hash_table_lookup (hash1, "test") == &state1);
hash2 = g_hash_table_new_similar (hash1);
g_assert_true (g_hash_table_lookup (hash1, "test") == &state1);
g_assert_null (g_hash_table_lookup (hash2, "test"));
state2 = 0;
g_hash_table_insert (hash2, g_strdup ("test"), &state2);
g_assert_true (g_hash_table_lookup (hash2, "test") == &state2);
g_hash_table_remove (hash2, "test");
g_assert_cmpint (state2, ==, 1);
g_assert_cmpint (state1, ==, 0);
g_hash_table_remove (hash1, "test");
g_assert_cmpint (state1, ==, 1);
g_hash_table_unref (hash1);
g_hash_table_unref (hash2);
}
struct _GHashTable
{
gsize size;
@ -1685,6 +1728,7 @@ main (int argc, char *argv[])
g_test_add_func ("/hash/steal-extended", test_steal_extended);
g_test_add_func ("/hash/steal-extended/optional", test_steal_extended_optional);
g_test_add_func ("/hash/lookup-extended", test_lookup_extended);
g_test_add_func ("/hash/new-similar", test_new_similar);
/* tests for individual bugs */
g_test_add_func ("/hash/lookup-null-key", test_lookup_null_key);