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