[glib] Enforce rules about modifying hash tables in callbacks
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] Enforce rules about modifying hash tables in callbacks
- Date: Fri, 20 May 2011 19:08:09 +0000 (UTC)
commit 120b85a31b061f17608a3b691d412ef17ca93681
Author: Matthias Clasen <mclasen redhat com>
Date: Fri May 20 15:07:08 2011 -0400
Enforce rules about modifying hash tables in callbacks
We have the infrastructure to do this, so lets do it.
Also add tests for find and foreach to the testsuite.
Bug 650688
glib/ghash.c | 44 +++++++++++++++++++++++------
glib/tests/hash.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 116 insertions(+), 9 deletions(-)
---
diff --git a/glib/ghash.c b/glib/ghash.c
index 39b5679..e9eace5 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -1228,6 +1228,9 @@ g_hash_table_foreach_remove_or_steal (GHashTable *hash_table,
{
guint deleted = 0;
gint i;
+#ifndef G_DISABLE_ASSERT
+ gint version = hash_table->version;
+#endif
for (i = 0; i < hash_table->size; i++)
{
@@ -1241,6 +1244,10 @@ g_hash_table_foreach_remove_or_steal (GHashTable *hash_table,
g_hash_table_remove_node (hash_table, i, notify);
deleted++;
}
+
+#ifndef G_DISABLE_ASSERT
+ g_return_val_if_fail (version == hash_table->version, 0);
+#endif
}
g_hash_table_maybe_resize (hash_table);
@@ -1291,7 +1298,7 @@ g_hash_table_foreach_remove (GHashTable *hash_table,
* If the function returns %TRUE, then the key/value pair is removed from the
* #GHashTable, but no key or value destroy functions are called.
*
- * See #GHashTableIter for an alternative way to loop over the
+ * See #GHashTableIter for an alternative way to loop over the
* key/value pairs in the hash table.
*
* Return value: the number of key/value pairs removed.
@@ -1329,6 +1336,9 @@ g_hash_table_foreach (GHashTable *hash_table,
gpointer user_data)
{
gint i;
+#ifndef G_DISABLE_ASSERT
+ gint version = hash_table->version;
+#endif
g_return_if_fail (hash_table != NULL);
g_return_if_fail (func != NULL);
@@ -1341,6 +1351,10 @@ g_hash_table_foreach (GHashTable *hash_table,
if (HASH_IS_REAL (node_hash))
(* func) (node_key, node_value, user_data);
+
+#ifndef G_DISABLE_ASSERT
+ g_return_if_fail (version == hash_table->version);
+#endif
}
}
@@ -1364,30 +1378,42 @@ g_hash_table_foreach (GHashTable *hash_table,
* operation issued for all n values in a hash table ends up needing O(n*n)
* operations).
*
- * Return value: The value of the first key/value pair is returned, for which
- * func evaluates to %TRUE. If no pair with the requested property is found,
- * %NULL is returned.
+ * Return value: The value of the first key/value pair is returned,
+ * for which @predicate evaluates to %TRUE. If no pair with the
+ * requested property is found, %NULL is returned.
*
* Since: 2.4
**/
gpointer
-g_hash_table_find (GHashTable *hash_table,
- GHRFunc predicate,
- gpointer user_data)
+g_hash_table_find (GHashTable *hash_table,
+ GHRFunc predicate,
+ gpointer user_data)
{
gint i;
+#ifndef G_DISABLE_ASSERT
+ gint version = hash_table->version;
+#endif
+ gboolean match;
g_return_val_if_fail (hash_table != NULL, NULL);
g_return_val_if_fail (predicate != NULL, NULL);
+ match = FALSE;
+
for (i = 0; i < hash_table->size; i++)
{
guint node_hash = hash_table->hashes[i];
gpointer node_key = hash_table->keys[i];
gpointer node_value = hash_table->values[i];
- if (HASH_IS_REAL (node_hash) &&
- predicate (node_key, node_value, user_data))
+ if (HASH_IS_REAL (node_hash))
+ match = predicate (node_key, node_value, user_data);
+
+#ifndef G_DISABLE_ASSERT
+ g_return_val_if_fail (version == hash_table->version, NULL);
+#endif
+
+ if (match)
return node_value;
}
diff --git a/glib/tests/hash.c b/glib/tests/hash.c
index 8f3d172..b82120e 100644
--- a/glib/tests/hash.c
+++ b/glib/tests/hash.c
@@ -853,6 +853,85 @@ test_destroy_modify (void)
g_hash_table_unref (h);
}
+static gboolean
+find_str (gpointer key, gpointer value, gpointer data)
+{
+ return g_str_equal (key, data);
+}
+
+static void
+test_find (void)
+{
+ GHashTable *hash;
+ const gchar *value;
+
+ hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+ g_hash_table_insert (hash, "a", "A");
+ g_hash_table_insert (hash, "b", "B");
+ g_hash_table_insert (hash, "c", "C");
+ g_hash_table_insert (hash, "d", "D");
+ g_hash_table_insert (hash, "e", "E");
+ g_hash_table_insert (hash, "f", "F");
+
+ value = g_hash_table_find (hash, find_str, "a");
+ g_assert_cmpstr (value, ==, "A");
+
+ value = g_hash_table_find (hash, find_str, "b");
+ g_assert_cmpstr (value, ==, "B");
+
+ value = g_hash_table_find (hash, find_str, "c");
+ g_assert_cmpstr (value, ==, "C");
+
+ value = g_hash_table_find (hash, find_str, "d");
+ g_assert_cmpstr (value, ==, "D");
+
+ value = g_hash_table_find (hash, find_str, "e");
+ g_assert_cmpstr (value, ==, "E");
+
+ value = g_hash_table_find (hash, find_str, "f");
+ g_assert_cmpstr (value, ==, "F");
+
+ value = g_hash_table_find (hash, find_str, "0");
+ g_assert (value == NULL);
+
+ g_hash_table_unref (hash);
+}
+
+gboolean seen_key[6];
+
+static void
+foreach_func (gpointer key, gpointer value, gpointer data)
+{
+ seen_key[((char*)key)[0] - 'a'] = TRUE;
+}
+
+static void
+test_foreach (void)
+{
+ GHashTable *hash;
+ gint i;
+
+ hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+ g_hash_table_insert (hash, "a", "A");
+ g_hash_table_insert (hash, "b", "B");
+ g_hash_table_insert (hash, "c", "C");
+ g_hash_table_insert (hash, "d", "D");
+ g_hash_table_insert (hash, "e", "E");
+ g_hash_table_insert (hash, "f", "F");
+
+ for (i = 0; i < 6; i++)
+ seen_key[i] = FALSE;
+
+ g_hash_table_foreach (hash, foreach_func, NULL);
+
+ for (i = 0; i < 6; i++)
+ g_assert (seen_key[i]);
+
+ g_hash_table_unref (hash);
+}
+
int
main (int argc, char *argv[])
{
@@ -871,6 +950,8 @@ main (int argc, char *argv[])
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);
+ g_test_add_func ("/hash/find", test_find);
+ g_test_add_func ("/hash/foreach", test_foreach);
/* tests for individual bugs */
g_test_add_func ("/hash/lookup-null-key", test_lookup_null_key);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]