From 12490574554f6f302efdcdb91f67bd26e538e731 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Tue, 19 Jul 2022 20:32:09 -0400 Subject: [PATCH] Fix issue #158 - imperfect hash for tuple of small integers --- CMakeLists.txt | 1 + parallel_hashmap/phmap_utils.h | 74 ++++++++++++++++++++++++++++------ 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 860ad94..9c1bf03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,6 +145,7 @@ if (PHMAP_BUILD_EXAMPLES) target_include_directories(ex_serialize PUBLIC $) add_executable(ex_hash_std examples/hash_std.cc phmap.natvis) add_executable(ex_hash_value examples/hash_value.cc phmap.natvis) + add_executable(ex_hash examples/hash.cc phmap.natvis) add_executable(ex_two_files examples/f1.cc examples/f2.cc phmap.natvis) add_executable(ex_insert_bench examples/insert_bench.cc phmap.natvis) add_executable(ex_knucleotide examples/knucleotide.cc phmap.natvis) diff --git a/parallel_hashmap/phmap_utils.h b/parallel_hashmap/phmap_utils.h index 1d0c472..4adef4e 100644 --- a/parallel_hashmap/phmap_utils.h +++ b/parallel_hashmap/phmap_utils.h @@ -286,6 +286,13 @@ struct Hash : public phmap_unary_function #endif +#if defined(_MSC_VER) +# define PHMAP_HASH_ROTL32(x, r) _rotl(x,r) +#else +# define PHMAP_HASH_ROTL32(x, r) (x << r) | (x >> (32 - r)) +#endif + + template struct Combiner { H operator()(H seed, size_t value); @@ -293,17 +300,57 @@ template struct Combiner template struct Combiner { - H operator()(H seed, size_t value) + H operator()(H h1, size_t k1) { - return seed ^ (value + 0x9e3779b9 + (seed << 6) + (seed >> 2)); +#if 1 + // Copyright 2005-2014 Daniel James. + // Distributed under the Boost Software License, Version 1.0. (See accompanying + // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; + + k1 *= c1; + k1 = PHMAP_HASH_ROTL32(k1,15); + k1 *= c2; + + h1 ^= k1; + h1 = PHMAP_HASH_ROTL32(h1,13); + h1 = h1*5+0xe6546b64; + + return h1; +#else + return h1 ^ (k1 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2)); +#endif } }; template struct Combiner { - H operator()(H seed, size_t value) + H operator()(H h, size_t k) { - return seed ^ (value + size_t(0xc6a4a7935bd1e995) + (seed << 6) + (seed >> 2)); +#if 1 + // Copyright 2005-2014 Daniel James. + // Distributed under the Boost Software License, Version 1.0. (See accompanying + // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + const uint64_t m = (uint64_t(0xc6a4a793) << 32) + 0x5bd1e995; + const int r = 47; + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + + // Completely arbitrary number, to prevent 0's + // from hashing to 0. + h += 0xe6546b64; + + return h; +#else + return h ^ (k + size_t(0xc6a4a7935bd1e995) + (h << 6) + (h >> 2)); +#endif } }; @@ -347,21 +394,22 @@ struct Hash> { template struct Hash> { size_t operator()(std::tuple const& t) const noexcept { - return _hash_helper(t); + size_t seed = 0; + return _hash_helper(seed, t); } private: - template - typename std::enable_if::type - _hash_helper(const std::tuple &) const noexcept { return 0; } + template + typename std::enable_if::value, size_t>::type + _hash_helper(size_t seed, const TUP &) const noexcept { return seed; } - template - typename std::enable_if::type - _hash_helper(const std::tuple &t) const noexcept { + template + typename std::enable_if::value, size_t>::type + _hash_helper(size_t seed, const TUP &t) const noexcept { const auto &el = std::get(t); using el_type = typename std::remove_cv::type>::type; - return Combiner()( - phmap::Hash()(el), _hash_helper(t)); + seed = Combiner()(seed, phmap::Hash()(el)); + return _hash_helper(seed, t); } };