[glib] ghash: Add g_hash_table_steal_extended()



commit 6acece5074d00f54c65a018498d9913664fa52ba
Author: Philip Withnall <withnall endlessm com>
Date:   Mon Apr 16 16:02:13 2018 +0100

    ghash: Add g_hash_table_steal_extended()
    
    This is a combination of g_hash_table_lookup_extended() and
    g_hash_table_steal(), so that users can combine the two to reduce code
    and eliminate a pointless second hash table lookup by
    g_hash_table_steal().
    
    Signed-off-by: Philip Withnall <withnall endlessm com>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=795302

 docs/reference/glib/glib-sections.txt |  1 +
 glib/ghash.c                          | 61 +++++++++++++++++++++++++++++++++++
 glib/ghash.h                          |  5 +++
 glib/tests/hash.c                     | 45 ++++++++++++++++++++++++++
 4 files changed, 112 insertions(+)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 47baf5eb8..f4b8dba54 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -2453,6 +2453,7 @@ g_hash_table_find
 GHFunc
 g_hash_table_remove
 g_hash_table_steal
+g_hash_table_steal_extended
 g_hash_table_foreach_remove
 g_hash_table_foreach_steal
 g_hash_table_remove_all
diff --git a/glib/ghash.c b/glib/ghash.c
index 6bb04a50d..87218114f 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -1421,6 +1421,67 @@ g_hash_table_steal (GHashTable    *hash_table,
   return g_hash_table_remove_internal (hash_table, key, FALSE);
 }
 
+/**
+ * g_hash_table_steal_extended:
+ * @hash_table: a #GHashTable
+ * @lookup_key: the key to look up
+ * @stolen_key: (out) (optional) (transfer full): return location for the
+ *    original key
+ * @stolen_value: (out) (optional) (nullable) (transfer full): return location
+ *    for the value associated with the key
+ *
+ * Looks up a key in the #GHashTable, stealing the original key and the
+ * associated value and returning %TRUE if the key was found. If the key was
+ * not found, %FALSE is returned.
+ *
+ * If found, the stolen key and value are removed from the hash table without
+ * calling the key and value destroy functions, and ownership is transferred to
+ * the caller of this method; as with g_hash_table_steal().
+ *
+ * You can pass %NULL for @lookup_key, provided the hash and equal functions
+ * of @hash_table are %NULL-safe.
+ *
+ * Returns: %TRUE if the key was found in the #GHashTable
+ * Since: 2.58
+ */
+gboolean
+g_hash_table_steal_extended (GHashTable    *hash_table,
+                             gconstpointer  lookup_key,
+                             gpointer      *stolen_key,
+                             gpointer      *stolen_value)
+{
+  guint node_index;
+  guint node_hash;
+
+  g_return_val_if_fail (hash_table != NULL, FALSE);
+
+  node_index = g_hash_table_lookup_node (hash_table, lookup_key, &node_hash);
+
+  if (!HASH_IS_REAL (hash_table->hashes[node_index]))
+    {
+      if (stolen_key != NULL)
+        *stolen_key = NULL;
+      if (stolen_value != NULL)
+        *stolen_value = NULL;
+      return FALSE;
+    }
+
+  if (stolen_key != NULL)
+    *stolen_key = g_steal_pointer (&hash_table->keys[node_index]);
+
+  if (stolen_value != NULL)
+    *stolen_value = g_steal_pointer (&hash_table->values[node_index]);
+
+  g_hash_table_remove_node (hash_table, node_index, FALSE);
+  g_hash_table_maybe_resize (hash_table);
+
+#ifndef G_DISABLE_ASSERT
+  hash_table->version++;
+#endif
+
+  return TRUE;
+}
+
 /**
  * g_hash_table_remove_all:
  * @hash_table: a #GHashTable
diff --git a/glib/ghash.h b/glib/ghash.h
index 5c8cb9195..0256d5411 100644
--- a/glib/ghash.h
+++ b/glib/ghash.h
@@ -82,6 +82,11 @@ void        g_hash_table_remove_all        (GHashTable     *hash_table);
 GLIB_AVAILABLE_IN_ALL
 gboolean    g_hash_table_steal             (GHashTable     *hash_table,
                                             gconstpointer   key);
+GLIB_AVAILABLE_IN_2_58
+gboolean    g_hash_table_steal_extended    (GHashTable     *hash_table,
+                                            gconstpointer   lookup_key,
+                                            gpointer       *stolen_key,
+                                            gpointer       *stolen_value);
 GLIB_AVAILABLE_IN_ALL
 void        g_hash_table_steal_all         (GHashTable     *hash_table);
 GLIB_AVAILABLE_IN_ALL
diff --git a/glib/tests/hash.c b/glib/tests/hash.c
index 0513d6558..963cef894 100644
--- a/glib/tests/hash.c
+++ b/glib/tests/hash.c
@@ -1189,6 +1189,50 @@ test_foreach_steal (void)
   g_hash_table_unref (hash2);
 }
 
+/* Test g_hash_table_steal_extended() works properly with existing and
+ * non-existing keys. */
+static void
+test_steal_extended (void)
+{
+  GHashTable *hash;
+  gchar *stolen_key = NULL, *stolen_value = NULL;
+
+  hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+  g_hash_table_insert (hash, g_strdup ("a"), g_strdup ("A"));
+  g_hash_table_insert (hash, g_strdup ("b"), g_strdup ("B"));
+  g_hash_table_insert (hash, g_strdup ("c"), g_strdup ("C"));
+  g_hash_table_insert (hash, g_strdup ("d"), g_strdup ("D"));
+  g_hash_table_insert (hash, g_strdup ("e"), g_strdup ("E"));
+  g_hash_table_insert (hash, g_strdup ("f"), g_strdup ("F"));
+
+  g_assert_true (g_hash_table_steal_extended (hash, "a",
+                                              (gpointer *) &stolen_key,
+                                              (gpointer *) &stolen_value));
+  g_assert_cmpstr (stolen_key, ==, "a");
+  g_assert_cmpstr (stolen_value, ==, "A");
+  g_clear_pointer (&stolen_key, g_free);
+  g_clear_pointer (&stolen_value, g_free);
+
+  g_assert_cmpuint (g_hash_table_size (hash), ==, 5);
+
+  g_assert_false (g_hash_table_steal_extended (hash, "a",
+                                               (gpointer *) &stolen_key,
+                                               (gpointer *) &stolen_value));
+  g_assert_null (stolen_key);
+  g_assert_null (stolen_value);
+
+  g_assert_false (g_hash_table_steal_extended (hash, "never a key",
+                                               (gpointer *) &stolen_key,
+                                               (gpointer *) &stolen_value));
+  g_assert_null (stolen_key);
+  g_assert_null (stolen_value);
+
+  g_assert_cmpuint (g_hash_table_size (hash), ==, 5);
+
+  g_hash_table_unref (hash);
+}
+
 struct _GHashTable
 {
   gint             size;
@@ -1513,6 +1557,7 @@ main (int argc, char *argv[])
   g_test_add_func ("/hash/find", test_find);
   g_test_add_func ("/hash/foreach", test_foreach);
   g_test_add_func ("/hash/foreach-steal", test_foreach_steal);
+  g_test_add_func ("/hash/steal-extended", test_steal_extended);
 
   /* 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]