OSSIA
Open Scenario System for Interactive Application
hash.hpp
1 #pragma once
2 #include <ossia/detail/config.hpp>
3 #include <ossia/detail/math.hpp>
4 
5 #include <ankerl/unordered_dense.h>
6 
7 #include <cinttypes>
8 #include <cstdint>
9 #include <memory>
10 #include <string>
11 #include <string_view>
12 
13 namespace ossia
14 {
15 
16 struct string_hash
17 {
18  using is_transparent = std::true_type;
19  using is_avalanching = std::true_type;
20  std::size_t operator()(const std::string& s) const noexcept
21  {
22  return ankerl::unordered_dense::hash<std::string>{}(s);
23  }
24 
25  std::size_t operator()(std::string_view s) const noexcept
26  {
27  return ankerl::unordered_dense::hash<std::string_view>{}(s);
28  }
29 
30  template <std::size_t N>
31  std::size_t operator()(const char (&s)[N]) const noexcept
32  {
33  return ankerl::unordered_dense::hash<std::string_view>{}(std::string_view{s, N - 1});
34  }
35 };
36 
37 // https://stackoverflow.com/q/20953390/1495627
38 struct egur_hash
39 {
40  using is_transparent = std::true_type;
41 
42  template <typename T>
43  OSSIA_INLINE
44  std::size_t operator()(const T* val) const noexcept
45  {
46  static const constexpr std::size_t shift = constexpr_log2(1 + sizeof(T));
47  return (size_t)(val) >> shift;
48  }
49 
50  template <typename T>
51  OSSIA_INLINE
52  std::size_t operator()(const std::shared_ptr<T>& val) const noexcept
53  {
54  static const constexpr std::size_t shift = constexpr_log2(1 + sizeof(T));
55  return (size_t)(val.get()) >> shift;
56  }
57 };
58 
59 template<typename T> struct is_shared_ptr : std::false_type {};
60 template<typename T> struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
61 
62 
63 template <typename T>
64 struct hash : ankerl::unordered_dense::hash<T> { };
65 
66 template <typename T>
67 requires std::is_pointer_v<T>
68 struct hash<T> : egur_hash { };
69 
70 template <typename T>
71 requires is_shared_ptr<T>::value
72 struct hash<T> : egur_hash { };
73 
74 template <>
75 struct hash<std::string> : string_hash { };
76 template <>
77 struct hash<std::string_view> : string_hash { };
78 
79 // Invalid overloads
80 template <>
81 struct hash<const char*>;
82 template <>
83 struct hash<char*>;
84 
85 
86 
87 struct string_equal
88 {
89  using is_transparent = std::true_type;
90  bool operator()(const std::string& s, const std::string& s2) const noexcept
91  {
92  return s == s2;
93  }
94  bool operator()(std::string_view s, const std::string& s2) const noexcept
95  {
96  return s == s2;
97  }
98  bool operator()(const std::string& s, std::string_view s2) const noexcept
99  {
100  return s == s2;
101  }
102  bool operator()(std::string_view s, std::string_view s2) const noexcept
103  {
104  return s == s2;
105  }
106 
107  template <std::size_t N>
108  bool operator()(const std::string& s, const char (&s2)[N]) const noexcept
109  {
110  return operator()(s, std::string_view{s2, N-1});
111  }
112 
113  template <std::size_t N>
114  bool operator()(std::string_view s, const char (&s2)[N]) const noexcept
115  {
116  return operator()(s, std::string_view{s2, N-1});
117  }
118 
119  template <std::size_t N>
120  bool operator()(const char (&s)[N], const std::string& s2) const noexcept
121  {
122  return operator()(std::string_view{s, N-1}, s2);
123  }
124 
125  template <std::size_t N>
126  bool operator()(const char (&s)[N], std::string_view s2) const noexcept
127  {
128  return operator()(std::string_view{s, N-1}, s2);
129  }
130 };
131 
132 
133 struct pointer_equal
134 {
135  using is_transparent = std::true_type;
136  template<typename U, typename V>
137  OSSIA_INLINE
138  bool operator()(const U* lhs, const V* rhs) const noexcept { return lhs == rhs; }
139 
140  template<typename U, typename V>
141  OSSIA_INLINE
142  bool operator()(const std::shared_ptr<U>& lhs, const V* rhs) const noexcept
143  {
144  return lhs.get() == rhs;
145  }
146 
147  template<typename U, typename V>
148  OSSIA_INLINE
149  bool operator()(const U* lhs, const std::shared_ptr<V>& rhs) const noexcept
150  {
151  return lhs == rhs.get();
152  }
153 
154  template<typename U, typename V>
155  OSSIA_INLINE
156  bool
157  operator()(const std::shared_ptr<U>& lhs, const std::shared_ptr<V>& rhs) const noexcept
158  {
159  return lhs == rhs;
160  }
161 };
162 
163 template <typename T>
164 struct equal_to : std::equal_to<T> { };
165 
166 template <>
167 struct equal_to<std::string> : string_equal { };
168 template <>
169 struct equal_to<std::string_view> : string_equal { };
170 
171 template <typename T>
172 requires std::is_pointer_v<T>
173 struct equal_to<T> : pointer_equal { };
174 
175 template <typename T>
176 requires is_shared_ptr<T>::value
177 struct equal_to<T> : pointer_equal { };
178 
179 // hash_combine_impl taken from boost
180 template <typename T>
181 constexpr inline void hash_combine(std::size_t& seed, const T& k) noexcept
182 {
183  using namespace std;
184  seed ^= hash<T>{}(k) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
185 }
186 
187 template <typename T>
188 constexpr inline void hash_combine(std::size_t& seed, const T* k) noexcept
189 {
190  using namespace std;
191  seed ^= egur_hash{}(k) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
192 }
193 
194 constexpr inline void hash_combine(uint64_t& seed, uint8_t k) noexcept
195 {
196  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
197 }
198 constexpr inline void hash_combine(uint64_t& seed, int8_t k) noexcept
199 {
200  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
201 }
202 constexpr inline void hash_combine(uint64_t& seed, uint16_t k) noexcept
203 {
204  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
205 }
206 constexpr inline void hash_combine(uint64_t& seed, int16_t k) noexcept
207 {
208  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
209 }
210 constexpr inline void hash_combine(uint64_t& seed, uint32_t k) noexcept
211 {
212  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
213 }
214 constexpr inline void hash_combine(uint64_t& seed, int32_t k) noexcept
215 {
216  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
217 }
218 constexpr inline void hash_combine(uint64_t& seed, int64_t k) noexcept
219 {
220  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
221 }
222 
223 constexpr inline void hash_combine(uint32_t& seed, uint8_t k) noexcept
224 {
225  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
226 }
227 constexpr inline void hash_combine(uint32_t& seed, int8_t k) noexcept
228 {
229  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
230 }
231 constexpr inline void hash_combine(uint32_t& seed, uint16_t k) noexcept
232 {
233  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
234 }
235 constexpr inline void hash_combine(uint32_t& seed, int16_t k) noexcept
236 {
237  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
238 }
239 constexpr inline void hash_combine(uint32_t& seed, int32_t k) noexcept
240 {
241  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
242 }
243 constexpr inline void hash_combine(uint32_t& seed, uint64_t k) noexcept
244 {
245  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
246 }
247 constexpr inline void hash_combine(uint32_t& seed, int64_t k) noexcept
248 {
249  seed ^= k + 0x9e3779b9 + (seed << 6) + (seed >> 2);
250 }
251 
252 constexpr inline void hash_combine(uint32_t& h1, uint32_t k1) noexcept
253 {
254  constexpr auto rotl32
255  = [](uint32_t x, int8_t r) noexcept { return (x << r) | (x >> (32 - r)); };
256 
257  constexpr uint32_t c1 = 0xcc9e2d51;
258  constexpr uint32_t c2 = 0x1b873593;
259 
260  k1 *= c1;
261  k1 = rotl32(k1, 15);
262  k1 *= c2;
263 
264  h1 ^= k1;
265  h1 = rotl32(h1, 13);
266  h1 = h1 * 5 + 0xe6546b64;
267 }
268 
269 constexpr inline void hash_combine(uint64_t& h, uint64_t k) noexcept
270 {
271  constexpr auto m = UINT64_C(0xc6a4a7935bd1e995);
272  constexpr int r = 47;
273 
274  k *= m;
275  k ^= k >> r;
276  k *= m;
277 
278  h ^= k;
279  h *= m;
280 
281  // Completely arbitrary number, to prevent 0's
282  // from hashing to 0.
283  h += 0xe6546b64;
284 }
285 }
Definition: git_info.h:7