From 55a77388373b7803600a5ad6fdc3f76d47b08391 Mon Sep 17 00:00:00 2001 From: Schlufi <81391208+Schlufi@users.noreply.github.com> Date: Thu, 6 Jan 2022 17:57:39 +0100 Subject: [PATCH] AK: Use a full-period xorshift PRNG for double_hash The previous implementation had some pretty short cycles and two fixed points (1711463637 and 2389024350). If two keys hashed to one of these values insertions and lookups would loop forever. This version is based on a standard xorshift PRNG with period 2**32-1. The all-zero state is usually forbidden, so we insert it into the cycle at an arbitrary location. --- AK/HashFunctions.h | 14 +++++++++----- Tests/AK/TestHashFunctions.cpp | 5 +++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/AK/HashFunctions.h b/AK/HashFunctions.h index 951619c4a7..e869b44800 100644 --- a/AK/HashFunctions.h +++ b/AK/HashFunctions.h @@ -21,11 +21,15 @@ constexpr unsigned int_hash(u32 key) constexpr unsigned double_hash(u32 key) { - key = ~key + (key >> 23); - key ^= (key << 12); - key ^= (key >> 7); - key ^= (key << 2); - key ^= (key >> 20); + const unsigned magic = 0xBA5EDB01; + if (key == magic) + return 0u; + if (key == 0u) + key = magic; + + key ^= key << 13; + key ^= key >> 17; + key ^= key << 5; return key; } diff --git a/Tests/AK/TestHashFunctions.cpp b/Tests/AK/TestHashFunctions.cpp index fa8eafae9e..6fbb0ab6f7 100644 --- a/Tests/AK/TestHashFunctions.cpp +++ b/Tests/AK/TestHashFunctions.cpp @@ -17,8 +17,9 @@ TEST_CASE(int_hash) TEST_CASE(double_hash) { - static_assert(double_hash(42) == 524450u); - static_assert(double_hash(0) == 12384u); + static_assert(double_hash(666) == 171644115u); + static_assert(double_hash(0) == 1189591134u); + static_assert(double_hash(0xBA5EDB01) == 0u); } TEST_CASE(pair_int_hash)