Fri Jun 21 20:21:00 2019 UTC ()
Revert GHashTable improvements
https://gitlab.gnome.org/GNOME/glib/merge_requests/208

to fix PR pkg/54310

For the record, the patch was created with:
git checkout -f 2.60.4
git revert --no-edit 86c6f7e2b..3bed8a13b
git revert --no-edit 75f8ec1df9b48b0c3a13a9125f2c7d7c5adf5159
git revert --no-edit 603fb5958..d3074a748
git revert --no-edit 0b45ddc55..0600dd322
git diff 2.60.4


(prlw1)
diff -r1.253 -r1.254 pkgsrc/devel/glib2/Makefile
diff -r1.247 -r1.248 pkgsrc/devel/glib2/distinfo
diff -r0 -r1.1 pkgsrc/devel/glib2/patches/patch-gio_tests_gdbus-export.c
diff -r0 -r1.1 pkgsrc/devel/glib2/patches/patch-glib_ghash.c
diff -r0 -r1.1 pkgsrc/devel/glib2/patches/patch-glib_tests_hash.c

cvs diff -r1.253 -r1.254 pkgsrc/devel/glib2/Makefile (expand / switch to unified diff)

--- pkgsrc/devel/glib2/Makefile 2019/06/16 15:28:11 1.253
+++ pkgsrc/devel/glib2/Makefile 2019/06/21 20:20:59 1.254
@@ -1,18 +1,18 @@ @@ -1,18 +1,18 @@
1# $NetBSD: Makefile,v 1.253 2019/06/16 15:28:11 leot Exp $ 1# $NetBSD: Makefile,v 1.254 2019/06/21 20:20:59 prlw1 Exp $
2 2
3.include "Makefile.common" 3.include "Makefile.common"
4 4
5PKGREVISION= 1 5PKGREVISION= 2
6CATEGORIES= devel gnome 6CATEGORIES= devel gnome
7COMMENT= Some useful routines for C programming (glib2) 7COMMENT= Some useful routines for C programming (glib2)
8 8
9.include "options.mk" 9.include "options.mk"
10 10
11MESON_ARGS+= -Dinstalled_tests=false 11MESON_ARGS+= -Dinstalled_tests=false
12# Avoid linux dependency on libmount-dev 12# Avoid linux dependency on libmount-dev
13MESON_ARGS+= -Dlibmount=false 13MESON_ARGS+= -Dlibmount=false
14 14
15LDFLAGS.SunOS+= -lintl -lnsl 15LDFLAGS.SunOS+= -lintl -lnsl
16 16
17REPLACE_PYTHON+= gio/gio-querymodules-wrapper.py 17REPLACE_PYTHON+= gio/gio-querymodules-wrapper.py
18REPLACE_PYTHON+= gio/tests/gengiotypefuncs.py 18REPLACE_PYTHON+= gio/tests/gengiotypefuncs.py

cvs diff -r1.247 -r1.248 pkgsrc/devel/glib2/distinfo (expand / switch to unified diff)

--- pkgsrc/devel/glib2/distinfo 2019/06/18 13:05:14 1.247
+++ pkgsrc/devel/glib2/distinfo 2019/06/21 20:20:59 1.248
@@ -1,24 +1,27 @@ @@ -1,24 +1,27 @@
1$NetBSD: distinfo,v 1.247 2019/06/18 13:05:14 jperkin Exp $ 1$NetBSD: distinfo,v 1.248 2019/06/21 20:20:59 prlw1 Exp $
2 2
3SHA1 (glib-2.60.4.tar.xz) = f76ef7339fef5784d79520478110caa4c5054806 3SHA1 (glib-2.60.4.tar.xz) = f76ef7339fef5784d79520478110caa4c5054806
4RMD160 (glib-2.60.4.tar.xz) = e8520dd0da7c37e6bb18b24a3b3ec308a6fa6aa0 4RMD160 (glib-2.60.4.tar.xz) = e8520dd0da7c37e6bb18b24a3b3ec308a6fa6aa0
5SHA512 (glib-2.60.4.tar.xz) = 614d25652ec9e8387f7865777e128b7f6fd68ff4a1a000868117cbcf5210b5f6aa476eb2b795a6dde56b997906aeb2157c83308f1421a27c4e379522d0ed0afc 5SHA512 (glib-2.60.4.tar.xz) = 614d25652ec9e8387f7865777e128b7f6fd68ff4a1a000868117cbcf5210b5f6aa476eb2b795a6dde56b997906aeb2157c83308f1421a27c4e379522d0ed0afc
6Size (glib-2.60.4.tar.xz) = 4589384 bytes 6Size (glib-2.60.4.tar.xz) = 4589384 bytes
7SHA1 (patch-gio_gcredentialsprivate.h) = dab92e07f8357a7dc1a569e37f65f9b199aee281 7SHA1 (patch-gio_gcredentialsprivate.h) = dab92e07f8357a7dc1a569e37f65f9b199aee281
8SHA1 (patch-gio_gdbus-2.0_codegen_meson.build) = 21c806f1a9884000b6a1683bc2fd1276b3c3544f 8SHA1 (patch-gio_gdbus-2.0_codegen_meson.build) = 21c806f1a9884000b6a1683bc2fd1276b3c3544f
9SHA1 (patch-gio_giomodule.c) = 0715e77fa97f90631c77e9a2cfd54b74698522e2 9SHA1 (patch-gio_giomodule.c) = 0715e77fa97f90631c77e9a2cfd54b74698522e2
10SHA1 (patch-gio_gresource-tool.c) = ad0e59f48f5f98ea66be568dbe2e5a5d1ac602fc 10SHA1 (patch-gio_gresource-tool.c) = ad0e59f48f5f98ea66be568dbe2e5a5d1ac602fc
11SHA1 (patch-gio_gunixcredentialsmessage.c) = c13119ddd6262db7c03e53857e987f0c495d3312 11SHA1 (patch-gio_gunixcredentialsmessage.c) = c13119ddd6262db7c03e53857e987f0c495d3312
12SHA1 (patch-gio_gunixmounts.c) = 13af07fffe898457edd0d8db4296a60fccba913d 12SHA1 (patch-gio_gunixmounts.c) = 13af07fffe898457edd0d8db4296a60fccba913d
13SHA1 (patch-gio_inotify_inotify-kernel.c) = 24deec33a1ad5e3c1a4f2d1397440d26b0f23b84 13SHA1 (patch-gio_inotify_inotify-kernel.c) = 24deec33a1ad5e3c1a4f2d1397440d26b0f23b84
14SHA1 (patch-gio_meson.build) = a0dcda4e9d05ed83b7fb11102945821eea27b81d 14SHA1 (patch-gio_meson.build) = a0dcda4e9d05ed83b7fb11102945821eea27b81d
 15SHA1 (patch-gio_tests_gdbus-export.c) = 59d85ca079d02b52e33153c7d2ac1cc48c26707a
 16SHA1 (patch-glib_ghash.c) = 938135c3a71199e61d1cd1dffa6e1d63864150d6
15SHA1 (patch-glib_gmain.c) = 2ab4b59e438d9f764bee62e0c1fa8bbd231b6e8d 17SHA1 (patch-glib_gmain.c) = 2ab4b59e438d9f764bee62e0c1fa8bbd231b6e8d
16SHA1 (patch-glib_meson.build) = 119e48efd8aaabf06b62c6e1897261b470cf7355 18SHA1 (patch-glib_meson.build) = 119e48efd8aaabf06b62c6e1897261b470cf7355
 19SHA1 (patch-glib_tests_hash.c) = e928b22926ad917a7a201882a5105b25533554ae
17SHA1 (patch-gmodule_gmodule-ar.c) = e382a0ada232e083d51cbede7f689a50ebeff4d8 20SHA1 (patch-gmodule_gmodule-ar.c) = e382a0ada232e083d51cbede7f689a50ebeff4d8
18SHA1 (patch-gmodule_gmodule-dl.c) = b678a04debbc79ebb67d91db7716990658e76da4 21SHA1 (patch-gmodule_gmodule-dl.c) = b678a04debbc79ebb67d91db7716990658e76da4
19SHA1 (patch-gmodule_gmodule-dyld.c) = 5adf62970d9cff22d451307aaa0b00d975dab138 22SHA1 (patch-gmodule_gmodule-dyld.c) = 5adf62970d9cff22d451307aaa0b00d975dab138
20SHA1 (patch-gmodule_gmodule-win32.c) = 477a861f8590a62c3dbc0aa4ad728cc86ebb34dd 23SHA1 (patch-gmodule_gmodule-win32.c) = 477a861f8590a62c3dbc0aa4ad728cc86ebb34dd
21SHA1 (patch-gmodule_gmodule.c) = 55c5f9d16e3517f3fdc04d40922f50d9c66b0b9a 24SHA1 (patch-gmodule_gmodule.c) = 55c5f9d16e3517f3fdc04d40922f50d9c66b0b9a
22SHA1 (patch-gobject_glib-mkenums.in) = c177cf9b1ea81542665240678f47f68351a3760d 25SHA1 (patch-gobject_glib-mkenums.in) = c177cf9b1ea81542665240678f47f68351a3760d
23SHA1 (patch-gobject_meson.build) = 58ee162e44047bf20c66067fd3edbe98cc13af50 26SHA1 (patch-gobject_meson.build) = 58ee162e44047bf20c66067fd3edbe98cc13af50
24SHA1 (patch-meson.build) = ce24f19714f6d78d1be9ecd6802f6c25a086c8e8 27SHA1 (patch-meson.build) = ce24f19714f6d78d1be9ecd6802f6c25a086c8e8

File Added: pkgsrc/devel/glib2/patches/Attic/patch-gio_tests_gdbus-export.c
$NetBSD: patch-gio_tests_gdbus-export.c,v 1.1 2019/06/21 20:21:00 prlw1 Exp $

Revert GHashTable improvements
https://gitlab.gnome.org/GNOME/glib/merge_requests/208

to fix PR pkg/54310

--- gio/tests/gdbus-export.c.orig	2019-06-10 17:47:20.000000000 +0000
+++ gio/tests/gdbus-export.c
@@ -337,22 +337,6 @@ introspect_callback (GDBusProxy   *proxy
   g_main_loop_quit (loop);
 }
 
-static gint
-compare_strings (gconstpointer a,
-                 gconstpointer b)
-{
-  const gchar *sa = *(const gchar **) a;
-  const gchar *sb = *(const gchar **) b;
-
-  /* Array terminator must sort last */
-  if (sa == NULL)
-    return 1;
-  if (sb == NULL)
-    return -1;
-
-  return strcmp (sa, sb);
-}
-
 static gchar **
 get_nodes_at (GDBusConnection  *c,
               const gchar      *object_path)
@@ -406,9 +390,6 @@ get_nodes_at (GDBusConnection  *c,
   g_free (xml_data);
   g_dbus_node_info_unref (node_info);
 
-  /* Nodes are semantically unordered; sort array so tests can rely on order */
-  g_ptr_array_sort (p, compare_strings);
-
   return (gchar **) g_ptr_array_free (p, FALSE);
 }
 
@@ -1259,9 +1240,9 @@ test_object_registration (void)
   nodes = get_nodes_at (c, "/foo/dyna");
   g_assert (nodes != NULL);
   g_assert_cmpint (g_strv_length (nodes), ==, 3);
-  g_assert_cmpstr (nodes[0], ==, "cat");
-  g_assert_cmpstr (nodes[1], ==, "cheezburger");
-  g_assert_cmpstr (nodes[2], ==, "lol");
+  g_assert_cmpstr (nodes[0], ==, "lol");
+  g_assert_cmpstr (nodes[1], ==, "cat");
+  g_assert_cmpstr (nodes[2], ==, "cheezburger");
   g_strfreev (nodes);
   g_assert_cmpint (count_interfaces (c, "/foo/dyna/lol"), ==, 4);
   g_assert_cmpint (count_interfaces (c, "/foo/dyna/cat"), ==, 4);
@@ -1272,10 +1253,10 @@ test_object_registration (void)
   nodes = get_nodes_at (c, "/foo/dyna");
   g_assert (nodes != NULL);
   g_assert_cmpint (g_strv_length (nodes), ==, 4);
-  g_assert_cmpstr (nodes[0], ==, "cat");
-  g_assert_cmpstr (nodes[1], ==, "cheezburger");
-  g_assert_cmpstr (nodes[2], ==, "dynamicallycreated");
-  g_assert_cmpstr (nodes[3], ==, "lol");
+  g_assert_cmpstr (nodes[0], ==, "lol");
+  g_assert_cmpstr (nodes[1], ==, "cat");
+  g_assert_cmpstr (nodes[2], ==, "cheezburger");
+  g_assert_cmpstr (nodes[3], ==, "dynamicallycreated");
   g_strfreev (nodes);
   g_assert_cmpint (count_interfaces (c, "/foo/dyna/dynamicallycreated"), ==, 4);
 

File Added: pkgsrc/devel/glib2/patches/Attic/patch-glib_ghash.c
$NetBSD: patch-glib_ghash.c,v 1.1 2019/06/21 20:21:00 prlw1 Exp $

Revert GHashTable improvements
https://gitlab.gnome.org/GNOME/glib/merge_requests/208

to fix PR pkg/54310

--- glib/ghash.c.orig	2019-06-10 17:47:20.000000000 +0000
+++ glib/ghash.c
@@ -38,26 +38,6 @@
 #include "gtestutils.h"
 #include "gslice.h"
 #include "grefcount.h"
-#include "gvalgrind.h"
-
-/* The following #pragma is here so we can do this...
- *
- *   #ifndef USE_SMALL_ARRAYS
- *     is_big = TRUE;
- *   #endif
- *     return is_big ? *(((gpointer *) a) + index) : GUINT_TO_POINTER (*(((guint *) a) + index));
- *
- * ...instead of this...
- *
- *   #ifndef USE_SMALL_ARRAYS
- *     return *(((gpointer *) a) + index);
- *   #else
- *     return is_big ? *(((gpointer *) a) + index) : GUINT_TO_POINTER (*(((guint *) a) + index));
- *   #endif
- *
- * ...and still compile successfully when -Werror=duplicated-branches is passed. */
-
-#pragma GCC diagnostic ignored "-Wduplicated-branches"
 
 /**
  * SECTION:hash_tables
@@ -233,18 +213,6 @@
 #define HASH_IS_TOMBSTONE(h_) ((h_) == TOMBSTONE_HASH_VALUE)
 #define HASH_IS_REAL(h_) ((h_) >= 2)
 
-/* If int is smaller than void * on our arch, we start out with
- * int-sized keys and values and resize to pointer-sized entries as
- * needed. This saves a good amount of memory when the HT is being
- * used with e.g. GUINT_TO_POINTER(). */
-
-#define BIG_ENTRY_SIZE (SIZEOF_VOID_P)
-#define SMALL_ENTRY_SIZE (SIZEOF_INT)
-
-#if SMALL_ENTRY_SIZE < BIG_ENTRY_SIZE
-# define USE_SMALL_ARRAYS
-#endif
-
 struct _GHashTable
 {
   gint             size;
@@ -253,12 +221,9 @@ struct _GHashTable
   gint             nnodes;
   gint             noccupied;  /* nnodes + tombstones */
 
-  guint            have_big_keys : 1;
-  guint            have_big_values : 1;
-
-  gpointer         keys;
+  gpointer        *keys;
   guint           *hashes;
-  gpointer         values;
+  gpointer        *values;
 
   GHashFunc        hash_func;
   GEqualFunc       key_equal_func;
@@ -332,15 +297,19 @@ static const gint prime_mod [] =
 static void
 g_hash_table_set_shift (GHashTable *hash_table, gint shift)
 {
+  gint i;
+  guint mask = 0;
+
   hash_table->size = 1 << shift;
   hash_table->mod  = prime_mod [shift];
 
-  /* hash_table->size is always a power of two, so we can calculate the mask
-   * by simply subtracting 1 from it. The leading assertion ensures that
-   * we're really dealing with a power of two. */
+  for (i = 0; i < shift; i++)
+    {
+      mask <<= 1;
+      mask |= 1;
+    }
 
-  g_assert ((hash_table->size & (hash_table->size - 1)) == 0);
-  hash_table->mask = hash_table->size - 1;
+  hash_table->mask = mask;
 }
 
 static gint
@@ -365,67 +334,6 @@ g_hash_table_set_shift_from_size (GHashT
   g_hash_table_set_shift (hash_table, shift);
 }
 
-static inline gpointer
-g_hash_table_realloc_key_or_value_array (gpointer a, guint size, G_GNUC_UNUSED gboolean is_big)
-{
-#ifdef USE_SMALL_ARRAYS
-  return g_realloc (a, size * (is_big ? BIG_ENTRY_SIZE : SMALL_ENTRY_SIZE));
-#else
-  return g_renew (gpointer, a, size);
-#endif
-}
-
-static inline gpointer
-g_hash_table_fetch_key_or_value (gpointer a, guint index, gboolean is_big)
-{
-#ifndef USE_SMALL_ARRAYS
-  is_big = TRUE;
-#endif
-  return is_big ? *(((gpointer *) a) + index) : GUINT_TO_POINTER (*(((guint *) a) + index));
-}
-
-static inline void
-g_hash_table_assign_key_or_value (gpointer a, guint index, gboolean is_big, gpointer v)
-{
-#ifndef USE_SMALL_ARRAYS
-  is_big = TRUE;
-#endif
-  if (is_big)
-    *(((gpointer *) a) + index) = v;
-  else
-    *(((guint *) a) + index) = GPOINTER_TO_UINT (v);
-}
-
-static inline gpointer
-g_hash_table_evict_key_or_value (gpointer a, guint index, gboolean is_big, gpointer v)
-{
-#ifndef USE_SMALL_ARRAYS
-  is_big = TRUE;
-#endif
-  if (is_big)
-    {
-      gpointer r = *(((gpointer *) a) + index);
-      *(((gpointer *) a) + index) = v;
-      return r;
-    }
-  else
-    {
-      gpointer r = GUINT_TO_POINTER (*(((guint *) a) + index));
-      *(((guint *) a) + index) = GPOINTER_TO_UINT (v);
-      return r;
-    }
-}
-
-static inline guint
-g_hash_table_hash_to_index (GHashTable *hash_table, guint hash)
-{
-  /* Multiply the hash by a small prime before applying the modulo. This
-   * prevents the table from becoming densely packed, even with a poor hash
-   * function. A densely packed table would have poor performance on
-   * workloads with many failed lookups or a high degree of churn. */
-  return (hash * 11) % hash_table->mod;
-}
-
 /*
  * g_hash_table_lookup_node:
  * @hash_table: our #GHashTable
@@ -474,7 +382,7 @@ g_hash_table_lookup_node (GHashTable    
 
   *hash_return = hash_value;
 
-  node_index = g_hash_table_hash_to_index (hash_table, hash_value);
+  node_index = hash_value % hash_table->mod;
   node_hash = hash_table->hashes[node_index];
 
   while (!HASH_IS_UNUSED (node_hash))
@@ -485,7 +393,7 @@ g_hash_table_lookup_node (GHashTable    
        */
       if (node_hash == hash_value)
         {
-          gpointer node_key = g_hash_table_fetch_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys);
+          gpointer node_key = hash_table->keys[node_index];
 
           if (hash_table->key_equal_func)
             {
@@ -535,15 +443,15 @@ g_hash_table_remove_node (GHashTable   *
   gpointer key;
   gpointer value;
 
-  key = g_hash_table_fetch_key_or_value (hash_table->keys, i, hash_table->have_big_keys);
-  value = g_hash_table_fetch_key_or_value (hash_table->values, i, hash_table->have_big_values);
+  key = hash_table->keys[i];
+  value = hash_table->values[i];
 
   /* Erect tombstone */
   hash_table->hashes[i] = TOMBSTONE_HASH_VALUE;
 
   /* Be GC friendly */
-  g_hash_table_assign_key_or_value (hash_table->keys, i, hash_table->have_big_keys, NULL);
-  g_hash_table_assign_key_or_value (hash_table->values, i, hash_table->have_big_values, NULL);
+  hash_table->keys[i] = NULL;
+  hash_table->values[i] = NULL;
 
   hash_table->nnodes--;
 
@@ -556,58 +464,15 @@ g_hash_table_remove_node (GHashTable   *
 }
 
 /*
- * g_hash_table_setup_storage:
- * @hash_table: our #GHashTable
- *
- * Initialise the hash table size, mask, mod, and arrays.
- */
-static void
-g_hash_table_setup_storage (GHashTable *hash_table)
-{
-  gboolean small;
-
-  /* We want to use small arrays only if:
-   *   - we are running on a system where that makes sense (64 bit); and
-   *   - we are not running under valgrind.
-   */
-  small = FALSE;
-
-#ifdef USE_SMALL_ARRAYS
-  small = TRUE;
-
-# ifdef ENABLE_VALGRIND
-  if (RUNNING_ON_VALGRIND)
-    small = FALSE;
-# endif
-#endif
-
-  g_hash_table_set_shift (hash_table, HASH_TABLE_MIN_SHIFT);
-
-  hash_table->have_big_keys = !small;
-  hash_table->have_big_values = !small;
-
-  hash_table->keys   = g_hash_table_realloc_key_or_value_array (NULL, hash_table->size, hash_table->have_big_keys);
-  hash_table->values = hash_table->keys;
-  hash_table->hashes = g_new0 (guint, hash_table->size);
-}
-
-/*
  * g_hash_table_remove_all_nodes:
  * @hash_table: our #GHashTable
  * @notify: %TRUE if the destroy notify handlers are to be called
  *
- * Removes all nodes from the table.
+ * Removes all nodes from the table.  Since this may be a precursor to
+ * freeing the table entirely, no resize is performed.
  *
  * If @notify is %TRUE then the destroy notify functions are called
  * for the key and value of the hash node.
- *
- * Since this may be a precursor to freeing the table entirely, we'd
- * ideally perform no resize, and we can indeed avoid that in some
- * cases.  However: in the case that we'll be making callbacks to user
- * code (via destroy notifies) we need to consider that the user code
- * might call back into the table again.  In this case, we setup a new
- * set of arrays so that any callers will see an empty (but valid)
- * table.
  */
 static void
 g_hash_table_remove_all_nodes (GHashTable *hash_table,
@@ -621,8 +486,6 @@ g_hash_table_remove_all_nodes (GHashTabl
   gpointer *old_keys;
   gpointer *old_values;
   guint    *old_hashes;
-  gboolean  old_have_big_keys;
-  gboolean  old_have_big_values;
 
   /* If the hash table is already empty, there is nothing to be done. */
   if (hash_table->nnodes == 0)
@@ -631,7 +494,6 @@ g_hash_table_remove_all_nodes (GHashTabl
   hash_table->nnodes = 0;
   hash_table->noccupied = 0;
 
-  /* Easy case: no callbacks, so we just zero out the arrays */
   if (!notify ||
       (hash_table->key_destroy_func == NULL &&
        hash_table->value_destroy_func == NULL))
@@ -639,65 +501,49 @@ g_hash_table_remove_all_nodes (GHashTabl
       if (!destruction)
         {
           memset (hash_table->hashes, 0, hash_table->size * sizeof (guint));
-
-#ifdef USE_SMALL_ARRAYS
-          memset (hash_table->keys, 0, hash_table->size * (hash_table->have_big_keys ? BIG_ENTRY_SIZE : SMALL_ENTRY_SIZE));
-          memset (hash_table->values, 0, hash_table->size * (hash_table->have_big_values ? BIG_ENTRY_SIZE : SMALL_ENTRY_SIZE));
-#else
           memset (hash_table->keys, 0, hash_table->size * sizeof (gpointer));
           memset (hash_table->values, 0, hash_table->size * sizeof (gpointer));
-#endif
         }
 
       return;
     }
 
-  /* Hard case: we need to do user callbacks.  There are two
-   * possibilities here:
-   *
-   *   1) there are no outstanding references on the table and therefore
-   *   nobody should be calling into it again (destroying == true)
-   *
-   *   2) there are outstanding references, and there may be future
-   *   calls into the table, either after we return, or from the destroy
-   *   notifies that we're about to do (destroying == false)
-   *
-   * We handle both cases by taking the current state of the table into
-   * local variables and replacing it with something else: in the "no
-   * outstanding references" cases we replace it with a bunch of
-   * null/zero values so that any access to the table will fail.  In the
-   * "may receive future calls" case, we reinitialise the struct to
-   * appear like a newly-created empty table.
-   *
-   * In both cases, we take over the references for the current state,
-   * freeing them below.
-   */
+  /* Keep the old storage space around to iterate over it. */
   old_size = hash_table->size;
-  old_have_big_keys = hash_table->have_big_keys;
-  old_have_big_values = hash_table->have_big_values;
-  old_keys   = g_steal_pointer (&hash_table->keys);
-  old_values = g_steal_pointer (&hash_table->values);
-  old_hashes = g_steal_pointer (&hash_table->hashes);
-
+  old_keys   = hash_table->keys;
+  old_values = hash_table->values;
+  old_hashes = hash_table->hashes;
+
+  /* Now create a new storage space; If the table is destroyed we can use the
+   * shortcut of not creating a new storage. This saves the allocation at the
+   * cost of not allowing any recursive access.
+   * However, the application doesn't own any reference anymore, so access
+   * is not allowed. If accesses are done, then either an assert or crash
+   * *will* happen. */
+  g_hash_table_set_shift (hash_table, HASH_TABLE_MIN_SHIFT);
   if (!destruction)
-    /* Any accesses will see an empty table */
-    g_hash_table_setup_storage (hash_table);
+    {
+      hash_table->keys   = g_new0 (gpointer, hash_table->size);
+      hash_table->values = hash_table->keys;
+      hash_table->hashes = g_new0 (guint, hash_table->size);
+    }
   else
-    /* Will cause a quick crash on any attempted access */
-    hash_table->size = hash_table->mod = hash_table->mask = 0;
+    {
+      hash_table->keys   = NULL;
+      hash_table->values = NULL;
+      hash_table->hashes = NULL;
+    }
 
-  /* Now do the actual destroy notifies */
   for (i = 0; i < old_size; i++)
     {
       if (HASH_IS_REAL (old_hashes[i]))
         {
-          key = g_hash_table_fetch_key_or_value (old_keys, i, old_have_big_keys);
-          value = g_hash_table_fetch_key_or_value (old_values, i, old_have_big_values);
+          key = old_keys[i];
+          value = old_values[i];
 
           old_hashes[i] = UNUSED_HASH_VALUE;
-
-          g_hash_table_assign_key_or_value (old_keys, i, old_have_big_keys, NULL);
-          g_hash_table_assign_key_or_value (old_values, i, old_have_big_values, NULL);
+          old_keys[i] = NULL;
+          old_values[i] = NULL;
 
           if (hash_table->key_destroy_func != NULL)
             hash_table->key_destroy_func (key);
@@ -715,125 +561,6 @@ g_hash_table_remove_all_nodes (GHashTabl
   g_free (old_hashes);
 }
 
-static void
-realloc_arrays (GHashTable *hash_table, gboolean is_a_set)
-{
-  hash_table->hashes = g_renew (guint, hash_table->hashes, hash_table->size);
-  hash_table->keys = g_hash_table_realloc_key_or_value_array (hash_table->keys, hash_table->size, hash_table->have_big_keys);
-
-  if (is_a_set)
-    hash_table->values = hash_table->keys;
-  else
-    hash_table->values = g_hash_table_realloc_key_or_value_array (hash_table->values, hash_table->size, hash_table->have_big_values);
-}
-
-/* When resizing the table in place, we use a temporary bit array to keep
- * track of which entries have been assigned a proper location in the new
- * table layout.
- *
- * Each bit corresponds to a bucket. A bit is set if an entry was assigned
- * its corresponding location during the resize and thus should not be
- * evicted. The array starts out cleared to zero. */
-
-static inline gboolean
-get_status_bit (const guint32 *bitmap, guint index)
-{
-  return (bitmap[index / 32] >> (index % 32)) & 1;
-}
-
-static inline void
-set_status_bit (guint32 *bitmap, guint index)
-{
-  bitmap[index / 32] |= 1U << (index % 32);
-}
-
-/* By calling dedicated resize functions for sets and maps, we avoid 2x
- * test-and-branch per key in the inner loop. This yields a small
- * performance improvement at the cost of a bit of macro gunk. */
-
-#define DEFINE_RESIZE_FUNC(fname) \
-static void fname (GHashTable *hash_table, guint old_size, guint32 *reallocated_buckets_bitmap) \
-{                                                                       \
-  guint i;                                                              \
-                                                                        \
-  for (i = 0; i < old_size; i++)                                        \
-    {                                                                   \
-      guint node_hash = hash_table->hashes[i];                          \
-      gpointer key, value G_GNUC_UNUSED;                                \
-                                                                        \
-      if (!HASH_IS_REAL (node_hash))                                    \
-        {                                                               \
-          /* Clear tombstones */                                        \
-          hash_table->hashes[i] = UNUSED_HASH_VALUE;                    \
-          continue;                                                     \
-        }                                                               \
-                                                                        \
-      /* Skip entries relocated through eviction */                     \
-      if (get_status_bit (reallocated_buckets_bitmap, i))               \
-        continue;                                                       \
-                                                                        \
-      hash_table->hashes[i] = UNUSED_HASH_VALUE;                        \
-      EVICT_KEYVAL (hash_table, i, NULL, NULL, key, value);             \
-                                                                        \
-      for (;;)                                                          \
-        {                                                               \
-          guint hash_val;                                               \
-          guint replaced_hash;                                          \
-          guint step = 0;                                               \
-                                                                        \
-          hash_val = g_hash_table_hash_to_index (hash_table, node_hash); \
-                                                                        \
-          while (get_status_bit (reallocated_buckets_bitmap, hash_val)) \
-            {                                                           \
-              step++;                                                   \
-              hash_val += step;                                         \
-              hash_val &= hash_table->mask;                             \
-            }                                                           \
-                                                                        \
-          set_status_bit (reallocated_buckets_bitmap, hash_val);        \
-                                                                        \
-          replaced_hash = hash_table->hashes[hash_val];                 \
-          hash_table->hashes[hash_val] = node_hash;                     \
-          if (!HASH_IS_REAL (replaced_hash))                            \
-            {                                                           \
-              ASSIGN_KEYVAL (hash_table, hash_val, key, value);         \
-              break;                                                    \
-            }                                                           \
-                                                                        \
-          node_hash = replaced_hash;                                    \
-          EVICT_KEYVAL (hash_table, hash_val, key, value, key, value);  \
-        }                                                               \
-    }                                                                   \
-}
-
-#define ASSIGN_KEYVAL(ht, index, key, value) G_STMT_START{ \
-    g_hash_table_assign_key_or_value ((ht)->keys, (index), (ht)->have_big_keys, (key)); \
-    g_hash_table_assign_key_or_value ((ht)->values, (index), (ht)->have_big_values, (value)); \
-  }G_STMT_END
-
-#define EVICT_KEYVAL(ht, index, key, value, outkey, outvalue) G_STMT_START{ \
-    (outkey) = g_hash_table_evict_key_or_value ((ht)->keys, (index), (ht)->have_big_keys, (key)); \
-    (outvalue) = g_hash_table_evict_key_or_value ((ht)->values, (index), (ht)->have_big_values, (value)); \
-  }G_STMT_END
-
-DEFINE_RESIZE_FUNC (resize_map)
-
-#undef ASSIGN_KEYVAL
-#undef EVICT_KEYVAL
-
-#define ASSIGN_KEYVAL(ht, index, key, value) G_STMT_START{ \
-    g_hash_table_assign_key_or_value ((ht)->keys, (index), (ht)->have_big_keys, (key)); \
-  }G_STMT_END
-
-#define EVICT_KEYVAL(ht, index, key, value, outkey, outvalue) G_STMT_START{ \
-    (outkey) = g_hash_table_evict_key_or_value ((ht)->keys, (index), (ht)->have_big_keys, (key)); \
-  }G_STMT_END
-
-DEFINE_RESIZE_FUNC (resize_set)
-
-#undef ASSIGN_KEYVAL
-#undef EVICT_KEYVAL
-
 /*
  * g_hash_table_resize:
  * @hash_table: our #GHashTable
@@ -850,47 +577,54 @@ DEFINE_RESIZE_FUNC (resize_set)
 static void
 g_hash_table_resize (GHashTable *hash_table)
 {
-  guint32 *reallocated_buckets_bitmap;
-  guint old_size;
-  gboolean is_a_set;
+  gpointer *new_keys;
+  gpointer *new_values;
+  guint *new_hashes;
+  gint old_size;
+  gint i;
 
   old_size = hash_table->size;
-  is_a_set = hash_table->keys == hash_table->values;
-
-  /* The outer checks in g_hash_table_maybe_resize() will only consider
-   * cleanup/resize when the load factor goes below .25 (1/4, ignoring
-   * tombstones) or above .9375 (15/16, including tombstones).
-   *
-   * Once this happens, tombstones will always be cleaned out. If our
-   * load sans tombstones is greater than .75 (1/1.333, see below), we'll
-   * take this opportunity to grow the table too.
-   *
-   * Immediately after growing, the load factor will be in the range
-   * .375 .. .469. After shrinking, it will be exactly .5. */
+  g_hash_table_set_shift_from_size (hash_table, hash_table->nnodes * 2);
 
-  g_hash_table_set_shift_from_size (hash_table, hash_table->nnodes * 1.333);
+  new_keys = g_new0 (gpointer, hash_table->size);
+  if (hash_table->keys == hash_table->values)
+    new_values = new_keys;
+  else
+    new_values = g_new0 (gpointer, hash_table->size);
+  new_hashes = g_new0 (guint, hash_table->size);
 
-  if (hash_table->size > old_size)
+  for (i = 0; i < old_size; i++)
     {
-      realloc_arrays (hash_table, is_a_set);
-      memset (&hash_table->hashes[old_size], 0, (hash_table->size - old_size) * sizeof (guint));
+      guint node_hash = hash_table->hashes[i];
+      guint hash_val;
+      guint step = 0;
 
-      reallocated_buckets_bitmap = g_new0 (guint32, (hash_table->size + 31) / 32);
-    }
-  else
-    {
-      reallocated_buckets_bitmap = g_new0 (guint32, (old_size + 31) / 32);
+      if (!HASH_IS_REAL (node_hash))
+        continue;
+
+      hash_val = node_hash % hash_table->mod;
+
+      while (!HASH_IS_UNUSED (new_hashes[hash_val]))
+        {
+          step++;
+          hash_val += step;
+          hash_val &= hash_table->mask;
+        }
+
+      new_hashes[hash_val] = hash_table->hashes[i];
+      new_keys[hash_val] = hash_table->keys[i];
+      new_values[hash_val] = hash_table->values[i];
     }
 
-  if (is_a_set)
-    resize_set (hash_table, old_size, reallocated_buckets_bitmap);
-  else
-    resize_map (hash_table, old_size, reallocated_buckets_bitmap);
+  if (hash_table->keys != hash_table->values)
+    g_free (hash_table->values);
 
-  g_free (reallocated_buckets_bitmap);
+  g_free (hash_table->keys);
+  g_free (hash_table->hashes);
 
-  if (hash_table->size < old_size)
-    realloc_arrays (hash_table, is_a_set);
+  hash_table->keys = new_keys;
+  hash_table->values = new_values;
+  hash_table->hashes = new_hashes;
 
   hash_table->noccupied = hash_table->nnodes;
 }
@@ -915,94 +649,6 @@ g_hash_table_maybe_resize (GHashTable *h
     g_hash_table_resize (hash_table);
 }
 
-#ifdef USE_SMALL_ARRAYS
-
-static inline gboolean
-entry_is_big (gpointer v)
-{
-  return (((guintptr) v) >> ((BIG_ENTRY_SIZE - SMALL_ENTRY_SIZE) * 8)) != 0;
-}
-
-static inline gboolean
-g_hash_table_maybe_make_big_keys_or_values (gpointer *a_p, gpointer v, gint ht_size)
-{
-  if (entry_is_big (v))
-    {
-      guint *a = (guint *) *a_p;
-      gpointer *a_new;
-      gint i;
-
-      a_new = g_new (gpointer, ht_size);
-
-      for (i = 0; i < ht_size; i++)
-        {
-          a_new[i] = GUINT_TO_POINTER (a[i]);
-        }
-
-      g_free (a);
-      *a_p = a_new;
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-#endif
-
-static inline void
-g_hash_table_ensure_keyval_fits (GHashTable *hash_table, gpointer key, gpointer value)
-{
-  gboolean is_a_set = (hash_table->keys == hash_table->values);
-
-#ifdef USE_SMALL_ARRAYS
-
-  /* Convert from set to map? */
-  if (is_a_set)
-    {
-      if (hash_table->have_big_keys)
-        {
-          if (key != value)
-            hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size);
-          /* Keys and values are both big now, so no need for further checks */
-          return;
-        }
-      else
-        {
-          if (key != value)
-            {
-              hash_table->values = g_memdup (hash_table->keys, sizeof (guint) * hash_table->size);
-              is_a_set = FALSE;
-            }
-        }
-    }
-
-  /* Make keys big? */
-  if (!hash_table->have_big_keys)
-    {
-      hash_table->have_big_keys = g_hash_table_maybe_make_big_keys_or_values (&hash_table->keys, key, hash_table->size);
-
-      if (is_a_set)
-        {
-          hash_table->values = hash_table->keys;
-          hash_table->have_big_values = hash_table->have_big_keys;
-        }
-    }
-
-  /* Make values big? */
-  if (!is_a_set && !hash_table->have_big_values)
-    {
-      hash_table->have_big_values = g_hash_table_maybe_make_big_keys_or_values (&hash_table->values, value, hash_table->size);
-    }
-
-#else
-
-  /* Just split if necessary */
-  if (is_a_set && key != value)
-    hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size);
-
-#endif
-}
-
 /**
  * g_hash_table_new:
  * @hash_func: a function to create a hash value from a key
@@ -1069,6 +715,7 @@ g_hash_table_new_full (GHashFunc      ha
   GHashTable *hash_table;
 
   hash_table = g_slice_new (GHashTable);
+  g_hash_table_set_shift (hash_table, HASH_TABLE_MIN_SHIFT);
   g_atomic_ref_count_init (&hash_table->ref_count);
   hash_table->nnodes             = 0;
   hash_table->noccupied          = 0;
@@ -1079,8 +726,9 @@ g_hash_table_new_full (GHashFunc      ha
 #endif
   hash_table->key_destroy_func   = key_destroy_func;
   hash_table->value_destroy_func = value_destroy_func;
-
-  g_hash_table_setup_storage (hash_table);
+  hash_table->keys               = g_new0 (gpointer, hash_table->size);
+  hash_table->values             = hash_table->keys;
+  hash_table->hashes             = g_new0 (guint, hash_table->size);
 
   return hash_table;
 }
@@ -1164,9 +812,9 @@ g_hash_table_iter_next (GHashTableIter *
   while (!HASH_IS_REAL (ri->hash_table->hashes[position]));
 
   if (key != NULL)
-    *key = g_hash_table_fetch_key_or_value (ri->hash_table->keys, position, ri->hash_table->have_big_keys);
+    *key = ri->hash_table->keys[position];
   if (value != NULL)
-    *value = g_hash_table_fetch_key_or_value (ri->hash_table->values, position, ri->hash_table->have_big_values);
+    *value = ri->hash_table->values[position];
 
   ri->position = position;
   return TRUE;
@@ -1269,7 +917,6 @@ g_hash_table_insert_node (GHashTable *ha
   gboolean already_exists;
   guint old_hash;
   gpointer key_to_free = NULL;
-  gpointer key_to_keep = NULL;
   gpointer value_to_free = NULL;
 
   old_hash = hash_table->hashes[node_index];
@@ -1299,31 +946,31 @@ g_hash_table_insert_node (GHashTable *ha
        * because we might change the value in the event that the two
        * arrays are shared.
        */
-      value_to_free = g_hash_table_fetch_key_or_value (hash_table->values, node_index, hash_table->have_big_values);
+      value_to_free = hash_table->values[node_index];
 
       if (keep_new_key)
         {
-          key_to_free = g_hash_table_fetch_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys);
-          key_to_keep = new_key;
+          key_to_free = hash_table->keys[node_index];
+          hash_table->keys[node_index] = new_key;
         }
       else
-        {
-          key_to_free = new_key;
-          key_to_keep = g_hash_table_fetch_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys);
-        }
+        key_to_free = new_key;
     }
   else
     {
       hash_table->hashes[node_index] = key_hash;
-      key_to_keep = new_key;
+      hash_table->keys[node_index] = new_key;
     }
 
-  /* Resize key/value arrays and split table as necessary */
-  g_hash_table_ensure_keyval_fits (hash_table, key_to_keep, new_value);
-  g_hash_table_assign_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys, key_to_keep);
+  /* Step two: check if the value that we are about to write to the
+   * table is the same as the key in the same position.  If it's not,
+   * split the table.
+   */
+  if (G_UNLIKELY (hash_table->keys == hash_table->values && hash_table->keys[node_index] != new_value))
+    hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size);
 
   /* Step 3: Actually do the write */
-  g_hash_table_assign_key_or_value (hash_table->values, node_index, hash_table->have_big_values, new_value);
+  hash_table->values[node_index] = new_value;
 
   /* Now, the bookkeeping... */
   if (!already_exists)
@@ -1385,8 +1032,7 @@ g_hash_table_iter_replace (GHashTableIte
   g_return_if_fail (ri->position < ri->hash_table->size);
 
   node_hash = ri->hash_table->hashes[ri->position];
-
-  key = g_hash_table_fetch_key_or_value (ri->hash_table->keys, ri->position, ri->hash_table->have_big_keys);
+  key = ri->hash_table->keys[ri->position];
 
   g_hash_table_insert_node (ri->hash_table, ri->position, node_hash, key, value, TRUE, TRUE);
 
@@ -1507,7 +1153,7 @@ g_hash_table_lookup (GHashTable    *hash
   node_index = g_hash_table_lookup_node (hash_table, key, &node_hash);
 
   return HASH_IS_REAL (hash_table->hashes[node_index])
-    ? g_hash_table_fetch_key_or_value (hash_table->values, node_index, hash_table->have_big_values)
+    ? hash_table->values[node_index]
     : NULL;
 }
 
@@ -1554,10 +1200,10 @@ g_hash_table_lookup_extended (GHashTable
     }
 
   if (orig_key)
-    *orig_key = g_hash_table_fetch_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys);
+    *orig_key = hash_table->keys[node_index];
 
   if (value)
-    *value = g_hash_table_fetch_key_or_value (hash_table->values, node_index, hash_table->have_big_values);
+    *value = hash_table->values[node_index];
 
   return TRUE;
 }
@@ -1828,16 +1474,10 @@ g_hash_table_steal_extended (GHashTable 
     }
 
   if (stolen_key != NULL)
-  {
-    *stolen_key = g_hash_table_fetch_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys);
-    g_hash_table_assign_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys, NULL);
-  }
+    *stolen_key = g_steal_pointer (&hash_table->keys[node_index]);
 
   if (stolen_value != NULL)
-  {
-    *stolen_value = g_hash_table_fetch_key_or_value (hash_table->values, node_index, hash_table->have_big_values);
-    g_hash_table_assign_key_or_value (hash_table->values, node_index, hash_table->have_big_values, 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);
@@ -1931,8 +1571,8 @@ g_hash_table_foreach_remove_or_steal (GH
   for (i = 0; i < hash_table->size; i++)
     {
       guint node_hash = hash_table->hashes[i];
-      gpointer node_key = g_hash_table_fetch_key_or_value (hash_table->keys, i, hash_table->have_big_keys);
-      gpointer node_value = g_hash_table_fetch_key_or_value (hash_table->values, i, hash_table->have_big_values);
+      gpointer node_key = hash_table->keys[i];
+      gpointer node_value = hash_table->values[i];
 
       if (HASH_IS_REAL (node_hash) &&
           (* func) (node_key, node_value, user_data))
@@ -2047,8 +1687,8 @@ g_hash_table_foreach (GHashTable *hash_t
   for (i = 0; i < hash_table->size; i++)
     {
       guint node_hash = hash_table->hashes[i];
-      gpointer node_key = g_hash_table_fetch_key_or_value (hash_table->keys, i, hash_table->have_big_keys);
-      gpointer node_value = g_hash_table_fetch_key_or_value (hash_table->values, i, hash_table->have_big_values);
+      gpointer node_key = hash_table->keys[i];
+      gpointer node_value = hash_table->values[i];
 
       if (HASH_IS_REAL (node_hash))
         (* func) (node_key, node_value, user_data);
@@ -2108,8 +1748,8 @@ g_hash_table_find (GHashTable *hash_tabl
   for (i = 0; i < hash_table->size; i++)
     {
       guint node_hash = hash_table->hashes[i];
-      gpointer node_key = g_hash_table_fetch_key_or_value (hash_table->keys, i, hash_table->have_big_keys);
-      gpointer node_value = g_hash_table_fetch_key_or_value (hash_table->values, i, hash_table->have_big_values);
+      gpointer node_key = hash_table->keys[i];
+      gpointer node_value = hash_table->values[i];
 
       if (HASH_IS_REAL (node_hash))
         match = predicate (node_key, node_value, user_data);
@@ -2171,7 +1811,7 @@ g_hash_table_get_keys (GHashTable *hash_
   for (i = 0; i < hash_table->size; i++)
     {
       if (HASH_IS_REAL (hash_table->hashes[i]))
-        retval = g_list_prepend (retval, g_hash_table_fetch_key_or_value (hash_table->keys, i, hash_table->have_big_keys));
+        retval = g_list_prepend (retval, hash_table->keys[i]);
     }
 
   return retval;
@@ -2216,7 +1856,7 @@ g_hash_table_get_keys_as_array (GHashTab
   for (i = 0; i < hash_table->size; i++)
     {
       if (HASH_IS_REAL (hash_table->hashes[i]))
-        result[j++] = g_hash_table_fetch_key_or_value (hash_table->keys, i, hash_table->have_big_keys);
+        result[j++] = hash_table->keys[i];
     }
   g_assert_cmpint (j, ==, hash_table->nnodes);
   result[j] = NULL;
@@ -2257,7 +1897,7 @@ g_hash_table_get_values (GHashTable *has
   for (i = 0; i < hash_table->size; i++)
     {
       if (HASH_IS_REAL (hash_table->hashes[i]))
-        retval = g_list_prepend (retval, g_hash_table_fetch_key_or_value (hash_table->values, i, hash_table->have_big_values));
+        retval = g_list_prepend (retval, hash_table->values[i]);
     }
 
   return retval;

File Added: pkgsrc/devel/glib2/patches/patch-glib_tests_hash.c
$NetBSD: patch-glib_tests_hash.c,v 1.1 2019/06/21 20:21:00 prlw1 Exp $

Revert GHashTable improvements
https://gitlab.gnome.org/GNOME/glib/merge_requests/208

to fix PR pkg/54310

--- glib/tests/hash.c.orig	2019-06-10 17:47:20.000000000 +0000
+++ glib/tests/hash.c
@@ -1353,9 +1353,6 @@ struct _GHashTable
   gint             nnodes;
   gint             noccupied;  /* nnodes + tombstones */
 
-  guint            have_big_keys : 1;
-  guint            have_big_values : 1;
-
   gpointer        *keys;
   guint           *hashes;
   gpointer        *values;
@@ -1390,23 +1387,6 @@ count_keys (GHashTable *h, gint *unused,
     }
 }
 
-#define BIG_ENTRY_SIZE (SIZEOF_VOID_P)
-#define SMALL_ENTRY_SIZE (SIZEOF_INT)
-
-#if SMALL_ENTRY_SIZE < BIG_ENTRY_SIZE
-# define USE_SMALL_ARRAYS
-#endif
-
-static gpointer
-fetch_key_or_value (gpointer a, guint index, gboolean is_big)
-{
-#ifdef USE_SMALL_ARRAYS
-  return is_big ? *(((gpointer *) a) + index) : GUINT_TO_POINTER (*(((guint *) a) + index));
-#else
-  return *(((gpointer *) a) + index);
-#endif
-}
-
 static void
 check_data (GHashTable *h)
 {
@@ -1414,9 +1394,14 @@ check_data (GHashTable *h)
 
   for (i = 0; i < h->size; i++)
     {
-      if (h->hashes[i] >= 2)
+      if (h->hashes[i] < 2)
+        {
+          g_assert (h->keys[i] == NULL);
+          g_assert (h->values[i] == NULL);
+        }
+      else
         {
-          g_assert_cmpint (h->hashes[i], ==, h->hash_func (fetch_key_or_value (h->keys, i, h->have_big_keys)));
+          g_assert_cmpint (h->hashes[i], ==, h->hash_func (h->keys[i]));
         }
     }
 }