[glib] GHash: make sets with refcounted keys work correctly
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] GHash: make sets with refcounted keys work correctly
- Date: Sun, 1 May 2011 14:56:19 +0000 (UTC)
commit d09df426ba3788174b5bcc974831651208a13ea2
Author: Matthias Clasen <mclasen redhat com>
Date: Sun May 1 10:55:24 2011 -0400
GHash: make sets with refcounted keys work correctly
When keys == values, we have to be careful about the order in
which we replace their elements.
glib/ghash.c | 6 ++--
glib/tests/hash.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 96 insertions(+), 3 deletions(-)
---
diff --git a/glib/ghash.c b/glib/ghash.c
index 006f2e5..8b31a59 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -982,6 +982,9 @@ g_hash_table_insert_internal (GHashTable *hash_table,
if (HASH_IS_REAL (old_hash))
{
+ if (hash_table->value_destroy_func)
+ hash_table->value_destroy_func (hash_table->values[node_index]);
+
if (keep_new_key)
{
if (hash_table->key_destroy_func)
@@ -994,9 +997,6 @@ g_hash_table_insert_internal (GHashTable *hash_table,
hash_table->key_destroy_func (key);
}
- if (hash_table->value_destroy_func)
- hash_table->value_destroy_func (hash_table->values[node_index]);
-
hash_table->values[node_index] = value;
}
else
diff --git a/glib/tests/hash.c b/glib/tests/hash.c
index 5d47894..2aedece 100644
--- a/glib/tests/hash.c
+++ b/glib/tests/hash.c
@@ -733,6 +733,98 @@ test_remove_all (void)
g_hash_table_unref (h);
}
+typedef struct {
+ gint ref_count;
+ const gchar *key;
+} RefCountedKey;
+
+static guint
+hash_func (gconstpointer key)
+{
+ const RefCountedKey *rkey = key;
+
+ return g_str_hash (rkey->key);
+}
+
+static gboolean
+eq_func (gconstpointer a, gconstpointer b)
+{
+ const RefCountedKey *aa = a;
+ const RefCountedKey *bb = b;
+
+ return g_strcmp0 (aa->key, bb->key) == 0;
+}
+
+static void
+key_unref (gpointer data)
+{
+ RefCountedKey *key = data;
+
+ g_assert (key->ref_count > 0);
+
+ key->ref_count -= 1;
+
+ if (key->ref_count == 0)
+ g_free (key);
+}
+
+static RefCountedKey *
+key_ref (RefCountedKey *key)
+{
+ key->ref_count += 1;
+
+ return key;
+}
+
+static RefCountedKey *
+key_new (const gchar *key)
+{
+ RefCountedKey *rkey;
+
+ rkey = g_new (RefCountedKey, 1);
+
+ rkey->ref_count = 1;
+ rkey->key = key;
+
+ return rkey;
+}
+
+static void
+set_ref_hash_test (void)
+{
+ GHashTable *h;
+ RefCountedKey *key1;
+ RefCountedKey *key2;
+
+ h = g_hash_table_new_full (hash_func, eq_func, key_unref, key_unref);
+
+ key1 = key_new ("a");
+ key2 = key_new ("a");
+
+ g_assert_cmpint (key1->ref_count, ==, 1);
+ g_assert_cmpint (key2->ref_count, ==, 1);
+
+ g_hash_table_insert (h, key_ref (key1), key_ref (key1));
+
+ g_assert_cmpint (key1->ref_count, ==, 3);
+ g_assert_cmpint (key2->ref_count, ==, 1);
+
+ g_hash_table_replace (h, key_ref (key2), key_ref (key2));
+
+ g_assert_cmpint (key1->ref_count, ==, 1);
+ g_assert_cmpint (key2->ref_count, ==, 3);
+
+ g_hash_table_remove (h, key1);
+
+ g_assert_cmpint (key1->ref_count, ==, 1);
+ g_assert_cmpint (key2->ref_count, ==, 1);
+
+ g_hash_table_unref (h);
+
+ key_unref (key1);
+ key_unref (key2);
+}
+
int
main (int argc, char *argv[])
{
@@ -748,6 +840,7 @@ main (int argc, char *argv[])
g_test_add_func ("/hash/double", double_hash_test);
g_test_add_func ("/hash/string", string_hash_test);
g_test_add_func ("/hash/set", set_hash_test);
+ g_test_add_func ("/hash/set-ref", set_ref_hash_test);
g_test_add_func ("/hash/ref", test_hash_ref);
g_test_add_func ("/hash/remove-all", test_remove_all);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]