diff --git a/src/test/chashtable.cpp b/src/test/chashtable.cpp index 9675ee312a..d954fcc7c1 100644 --- a/src/test/chashtable.cpp +++ b/src/test/chashtable.cpp @@ -20,6 +20,7 @@ Revision History: #include "util/hashtable.h" #include "util/hash.h" #include "util/util.h" +#include #include typedef chashtable > int_table; @@ -172,6 +173,22 @@ static void tst6() { }); } +static void tst_combine_hash_low_bits() { + constexpr unsigned num_buckets = 1 << 12; + constexpr unsigned mask = num_buckets - 1; + std::array seen{}; + unsigned num_seen = 0; + for (unsigned i = 0; i < (1u << 16); ++i) { + unsigned h = combine_hash(i << 12, 0x12345678u); + unsigned b = h & mask; + if (!seen[b]) { + seen[b] = true; + ++num_seen; + } + } + ENSURE(num_seen > 3000); +} + void tst_chashtable() { tst1(); tst2(); @@ -180,5 +197,6 @@ void tst_chashtable() { tst4(1000,10); tst4(10000,10); tst4(50000,1000); + tst_combine_hash_low_bits(); tst5(); } diff --git a/src/util/hash.h b/src/util/hash.h index ac6896bf19..40ea7bfb89 100644 --- a/src/util/hash.h +++ b/src/util/hash.h @@ -57,10 +57,8 @@ static inline unsigned hash_ull(unsigned long long a) { } static inline unsigned combine_hash(unsigned h1, unsigned h2) { - h2 -= h1; h2 ^= (h1 << 8); - h1 -= h2; h2 ^= (h1 << 16); - h2 -= h1; h2 ^= (h1 << 10); - return h2; + h1 ^= h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2); + return hash_u(h1); } static inline unsigned hash_u_u(unsigned a, unsigned b) { @@ -256,4 +254,3 @@ static inline unsigned mk_mix(unsigned a, unsigned b, unsigned c) { return c; } -