[glib] Add iter_replace API to GHashTableIter



commit f6ed3571017e7ace55c78491ef4e79bfc914c07b
Author: Philip Van Hoof <philip codeminded be>
Date:   Sat Jun 18 19:40:34 2011 +0200

    Add iter_replace API to GHashTableIter
    
    https://bugzilla.gnome.org/show_bug.cgi?id=652822

 docs/reference/glib/glib-sections.txt |    1 +
 glib/ghash.c                          |  152 +++++++++++++++++++++++----------
 glib/ghash.h                          |    2 +
 glib/glib.symbols                     |    1 +
 glib/tests/hash.c                     |   23 +++++
 5 files changed, 135 insertions(+), 44 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index cc7fe6b..cc28d68 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -2263,6 +2263,7 @@ GHashTableIter
 g_hash_table_iter_init
 g_hash_table_iter_next
 g_hash_table_iter_get_hash_table
+g_hash_table_iter_replace
 g_hash_table_iter_remove
 g_hash_table_iter_steal
 
diff --git a/glib/ghash.c b/glib/ghash.c
index f381eaa..00a2a6b 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -805,6 +805,112 @@ g_hash_table_iter_remove (GHashTableIter *iter)
   iter_remove_or_steal ((RealIter *) iter, TRUE);
 }
 
+/*
+ * g_hash_table_insert_node:
+ * @hash_table: our #GHashTable
+ * @node_index: pointer to node to insert/replace
+ * @key_hash: key hash
+ * @key: key to replace with
+ * @value: value to replace with
+ *
+ * Inserts a value at @node_index in the hash table and updates it.
+ */
+static void
+g_hash_table_insert_node (GHashTable *hash_table,
+                          guint       node_index,
+                          guint       key_hash,
+                          gpointer    key,
+                          gpointer    value,
+                          gboolean    keep_new_key)
+{
+  guint old_hash;
+  gpointer old_key;
+  gpointer old_value;
+
+  if (G_UNLIKELY (hash_table->keys == hash_table->values && key != value))
+    hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size);
+
+  old_hash = hash_table->hashes[node_index];
+  old_key = hash_table->keys[node_index];
+  old_value = hash_table->values[node_index];
+
+  if (HASH_IS_REAL (old_hash))
+    {
+      if (keep_new_key)
+        hash_table->keys[node_index] = key;
+      hash_table->values[node_index] = value;
+    }
+  else
+    {
+      hash_table->keys[node_index] = key;
+      hash_table->values[node_index] = value;
+      hash_table->hashes[node_index] = key_hash;
+
+      hash_table->nnodes++;
+
+      if (HASH_IS_UNUSED (old_hash))
+        {
+          /* We replaced an empty node, and not a tombstone */
+          hash_table->noccupied++;
+          g_hash_table_maybe_resize (hash_table);
+        }
+
+#ifndef G_DISABLE_ASSERT
+      hash_table->version++;
+#endif
+    }
+
+  if (HASH_IS_REAL (old_hash))
+    {
+      if (hash_table->key_destroy_func)
+        hash_table->key_destroy_func (keep_new_key ? old_key : key);
+      if (hash_table->value_destroy_func)
+        hash_table->value_destroy_func (old_value);
+    }
+}
+
+/**
+ * g_hash_table_iter_replace:
+ * @iter: an initialized #GHashTableIter.
+ * @value: the value to replace with
+ *
+ * Replaces the value currently pointed to by the iterator
+ * from its associated #GHashTable. Can only be called after
+ * g_hash_table_iter_next() returned %TRUE.
+ *
+ * If you supplied a @value_destroy_func when creating the #GHashTable,
+ * the old value is freed using that function.
+ *
+ * Since: 2.29.9
+ **/
+void
+g_hash_table_iter_replace (GHashTableIter *iter,
+                           gpointer        value)
+{
+  RealIter *ri;
+  guint node_hash;
+  gpointer key;
+
+  ri = (RealIter *) iter;
+
+  g_return_if_fail (ri != NULL);
+#ifndef G_DISABLE_ASSERT
+  g_return_if_fail (ri->version == ri->hash_table->version);
+#endif
+  g_return_if_fail (ri->position >= 0);
+  g_return_if_fail (ri->position < ri->hash_table->size);
+
+  node_hash = ri->hash_table->hashes[ri->position];
+  key = ri->hash_table->keys[ri->position];
+
+  g_hash_table_insert_node (ri->hash_table, ri->position, node_hash, key, value, TRUE);
+
+#ifndef G_DISABLE_ASSERT
+  ri->version++;
+  ri->hash_table->version++;
+#endif
+}
+
 /**
  * g_hash_table_iter_steal:
  * @iter: an initialized #GHashTableIter.
@@ -985,56 +1091,14 @@ g_hash_table_insert_internal (GHashTable *hash_table,
                               gpointer    value,
                               gboolean    keep_new_key)
 {
-  guint node_index;
   guint key_hash;
-  guint old_hash;
-  gpointer old_key;
-  gpointer old_value;
+  guint node_index;
 
   g_return_if_fail (hash_table != NULL);
 
-  if (G_UNLIKELY (hash_table->keys == hash_table->values && key != value))
-    hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size);
-
   node_index = g_hash_table_lookup_node (hash_table, key, &key_hash);
 
-  old_hash = hash_table->hashes[node_index];
-  old_key = hash_table->keys[node_index];
-  old_value = hash_table->values[node_index];
-
-  if (HASH_IS_REAL (old_hash))
-    {
-      if (keep_new_key)
-        hash_table->keys[node_index] = key;
-      hash_table->values[node_index] = value;
-    }
-  else
-    {
-      hash_table->keys[node_index] = key;
-      hash_table->values[node_index] = value;
-      hash_table->hashes[node_index] = key_hash;
-
-      hash_table->nnodes++;
-
-      if (HASH_IS_UNUSED (old_hash))
-        {
-          /* We replaced an empty node, and not a tombstone */
-          hash_table->noccupied++;
-          g_hash_table_maybe_resize (hash_table);
-        }
-
-#ifndef G_DISABLE_ASSERT
-      hash_table->version++;
-#endif
-    }
-
-  if (HASH_IS_REAL (old_hash))
-    {
-      if (hash_table->key_destroy_func)
-        hash_table->key_destroy_func (keep_new_key ? old_key : key);
-      if (hash_table->value_destroy_func)
-        hash_table->value_destroy_func (old_value);
-    }
+  g_hash_table_insert_node (hash_table, node_index, key_hash, key, value, keep_new_key);
 }
 
 /**
diff --git a/glib/ghash.h b/glib/ghash.h
index 9128721..3bc8226 100644
--- a/glib/ghash.h
+++ b/glib/ghash.h
@@ -105,6 +105,8 @@ gboolean    g_hash_table_iter_next         (GHashTableIter *iter,
 					    gpointer       *value);
 GHashTable* g_hash_table_iter_get_hash_table (GHashTableIter *iter);
 void        g_hash_table_iter_remove       (GHashTableIter *iter);
+void        g_hash_table_iter_replace      (GHashTableIter *iter,
+					    gpointer	    value);
 void        g_hash_table_iter_steal        (GHashTableIter *iter);
 
 /* keeping hash tables alive */
diff --git a/glib/glib.symbols b/glib/glib.symbols
index d8a18b9..bea2784 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -382,6 +382,7 @@ g_hash_table_iter_init
 g_hash_table_iter_next
 g_hash_table_iter_get_hash_table
 g_hash_table_iter_remove
+g_hash_table_iter_replace
 g_hash_table_iter_steal
 g_hook_alloc
 g_hook_compare_ids
diff --git a/glib/tests/hash.c b/glib/tests/hash.c
index 8ef8208..687447c 100644
--- a/glib/tests/hash.c
+++ b/glib/tests/hash.c
@@ -539,6 +539,7 @@ test_hash_misc (void)
   GHashTableIter iter;
   gpointer ikey, ivalue;
   int result_array[10000];
+  int n_array[1];
 
   hash_table = g_hash_table_new (my_hash, my_hash_equal);
   fill_hash_table_and_array (hash_table);
@@ -594,6 +595,28 @@ test_hash_misc (void)
 
   g_hash_table_foreach (hash_table, my_hash_callback_remove_test, NULL);
   g_hash_table_destroy (hash_table);
+
+  hash_table = g_hash_table_new (my_hash, my_hash_equal);
+  fill_hash_table_and_array (hash_table);
+
+  n_array[0] = 1;
+
+  g_hash_table_iter_init (&iter, hash_table);
+  for (i = 0; i < 10000; i++)
+    {
+      g_assert (g_hash_table_iter_next (&iter, &ikey, &ivalue));
+      g_hash_table_iter_replace (&iter, &n_array[0]);
+    }
+
+  g_hash_table_iter_init (&iter, hash_table);
+  for (i = 0; i < 10000; i++)
+    {
+      g_assert (g_hash_table_iter_next (&iter, &ikey, &ivalue));
+
+      g_assert (ivalue == &n_array[0]);
+    }
+
+  g_hash_table_destroy (hash_table);
 }
 
 static gint destroy_counter;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]