summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Trevisan <mail@3v1n0.net>2022-10-11 11:26:41 +0000
committerMarco Trevisan <mail@3v1n0.net>2022-10-11 11:26:41 +0000
commit4231426abe903d3c7c4f252d64c3d9041abf9141 (patch)
treee3e392262a8bac64287380e46b4528e11dd3c51f
parentdb259b592539a84acd1ee78a088ad8ff629a27a6 (diff)
parente02db8ea22d545749ecaf3be9d342cc565bc143a (diff)
downloadglib-4231426abe903d3c7c4f252d64c3d9041abf9141.tar.gz
Merge branch 'optimize_g_double_hash' into 'main'
Optimize the implementation of `g_double_hash` See merge request GNOME/glib!2924
-rw-r--r--glib/ghash.c4
-rw-r--r--glib/tests/hash.c36
2 files changed, 38 insertions, 2 deletions
diff --git a/glib/ghash.c b/glib/ghash.c
index 5fb722c04..6c9514207 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -2490,7 +2490,7 @@ g_int64_equal (gconstpointer v1,
guint
g_int64_hash (gconstpointer v)
{
- return (guint) *(const gint64*) v;
+ return (guint) ((const guint) (*(guint64 *) v >> 32)) ^ (*(const guint *) v);
}
/**
@@ -2531,5 +2531,5 @@ g_double_equal (gconstpointer v1,
guint
g_double_hash (gconstpointer v)
{
- return (guint) *(const gdouble*) v;
+ return (guint) ((const guint) (*(guint64 *) v >> 32)) ^ (*(const guint *) v);
}
diff --git a/glib/tests/hash.c b/glib/tests/hash.c
index 32d357979..604dcc049 100644
--- a/glib/tests/hash.c
+++ b/glib/tests/hash.c
@@ -460,6 +460,19 @@ int64_hash_test (void)
}
static void
+int64_hash_collision_test (void)
+{
+ gint64 m;
+ gint64 n;
+
+ g_test_summary ("Check int64 Hash collisions caused by ignoring high word");
+
+ m = 722;
+ n = ((gint64) 2003 << 32) + 722;
+ g_assert_cmpuint (g_int64_hash (&m), !=, g_int64_hash (&n));
+}
+
+static void
double_hash_test (void)
{
gint i, rc;
@@ -489,6 +502,27 @@ double_hash_test (void)
}
static void
+double_hash_collision_test (void)
+{
+ gdouble m;
+ gdouble n;
+
+ g_test_summary ("Check double Hash collisions caused by int conversion " \
+ "and by numbers larger than 2^64-1 (G_MAXUINT64)");
+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2771");
+
+ /* Equal when directly converted to integers */
+ m = 0.1;
+ n = 0.2;
+ g_assert_cmpuint (g_double_hash (&m), !=, g_double_hash (&n));
+
+ /* Numbers larger than 2^64-1 (G_MAXUINT64) */
+ m = 1e100;
+ n = 1e200;
+ g_assert_cmpuint (g_double_hash (&m), !=, g_double_hash (&n));
+}
+
+static void
string_free (gpointer data)
{
GString *s = data;
@@ -1715,7 +1749,9 @@ main (int argc, char *argv[])
g_test_add_func ("/hash/direct2", direct_hash_test2);
g_test_add_func ("/hash/int", int_hash_test);
g_test_add_func ("/hash/int64", int64_hash_test);
+ g_test_add_func ("/hash/int64/collisions", int64_hash_collision_test);
g_test_add_func ("/hash/double", double_hash_test);
+ g_test_add_func ("/hash/double/collisions", double_hash_collision_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);