diff options
Diffstat (limited to 'src/common/container_hash.h')
| -rw-r--r-- | src/common/container_hash.h | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/src/common/container_hash.h b/src/common/container_hash.h new file mode 100644 index 000000000..a5e357745 --- /dev/null +++ b/src/common/container_hash.h | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2005-2014 Daniel James | ||
| 2 | // SPDX-FileCopyrightText: 2016 Austin Appleby | ||
| 3 | // SPDX-License-Identifier: BSL-1.0 | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | #include <climits> | ||
| 7 | #include <cstdint> | ||
| 8 | #include <limits> | ||
| 9 | #include <type_traits> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | namespace Common { | ||
| 13 | |||
| 14 | namespace detail { | ||
| 15 | |||
| 16 | template <typename T> | ||
| 17 | requires std::is_unsigned_v<T> | ||
| 18 | inline std::size_t HashValue(T val) { | ||
| 19 | const unsigned int size_t_bits = std::numeric_limits<std::size_t>::digits; | ||
| 20 | const unsigned int length = | ||
| 21 | (std::numeric_limits<T>::digits - 1) / static_cast<unsigned int>(size_t_bits); | ||
| 22 | |||
| 23 | std::size_t seed = 0; | ||
| 24 | |||
| 25 | for (unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits) { | ||
| 26 | seed ^= static_cast<size_t>(val >> i) + (seed << 6) + (seed >> 2); | ||
| 27 | } | ||
| 28 | |||
| 29 | seed ^= static_cast<size_t>(val) + (seed << 6) + (seed >> 2); | ||
| 30 | |||
| 31 | return seed; | ||
| 32 | } | ||
| 33 | |||
| 34 | template <size_t Bits> | ||
| 35 | struct HashCombineImpl { | ||
| 36 | template <typename T> | ||
| 37 | static inline T fn(T seed, T value) { | ||
| 38 | seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2); | ||
| 39 | return seed; | ||
| 40 | } | ||
| 41 | }; | ||
| 42 | |||
| 43 | template <> | ||
| 44 | struct HashCombineImpl<64> { | ||
| 45 | static inline std::uint64_t fn(std::uint64_t h, std::uint64_t k) { | ||
| 46 | const std::uint64_t m = (std::uint64_t(0xc6a4a793) << 32) + 0x5bd1e995; | ||
| 47 | const int r = 47; | ||
| 48 | |||
| 49 | k *= m; | ||
| 50 | k ^= k >> r; | ||
| 51 | k *= m; | ||
| 52 | |||
| 53 | h ^= k; | ||
| 54 | h *= m; | ||
| 55 | |||
| 56 | // Completely arbitrary number, to prevent 0's | ||
| 57 | // from hashing to 0. | ||
| 58 | h += 0xe6546b64; | ||
| 59 | |||
| 60 | return h; | ||
| 61 | } | ||
| 62 | }; | ||
| 63 | |||
| 64 | } // namespace detail | ||
| 65 | |||
| 66 | template <typename T> | ||
| 67 | inline void HashCombine(std::size_t& seed, const T& v) { | ||
| 68 | seed = detail::HashCombineImpl<sizeof(std::size_t) * CHAR_BIT>::fn(seed, detail::HashValue(v)); | ||
| 69 | } | ||
| 70 | |||
| 71 | template <typename It> | ||
| 72 | inline std::size_t HashRange(It first, It last) { | ||
| 73 | std::size_t seed = 0; | ||
| 74 | |||
| 75 | for (; first != last; ++first) { | ||
| 76 | HashCombine<typename std::iterator_traits<It>::value_type>(seed, *first); | ||
| 77 | } | ||
| 78 | |||
| 79 | return seed; | ||
| 80 | } | ||
| 81 | |||
| 82 | template <typename T, size_t Size> | ||
| 83 | std::size_t HashValue(const std::array<T, Size>& v) { | ||
| 84 | return HashRange(v.cbegin(), v.cend()); | ||
| 85 | } | ||
| 86 | |||
| 87 | template <typename T, typename Allocator> | ||
| 88 | std::size_t HashValue(const std::vector<T, Allocator>& v) { | ||
| 89 | return HashRange(v.cbegin(), v.cend()); | ||
| 90 | } | ||
| 91 | |||
| 92 | } // namespace Common | ||