/src/parallel-hashmap/parallel_hashmap/phmap_utils.h
Line | Count | Source (jump to first uncovered line) |
1 | | #if !defined(phmap_utils_h_guard_) |
2 | | #define phmap_utils_h_guard_ |
3 | | |
4 | | // --------------------------------------------------------------------------- |
5 | | // Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com |
6 | | // |
7 | | // minimal header providing phmap::HashState |
8 | | // |
9 | | // use as: phmap::HashState().combine(0, _first_name, _last_name, _age); |
10 | | // |
11 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
12 | | // you may not use this file except in compliance with the License. |
13 | | // You may obtain a copy of the License at |
14 | | // |
15 | | // https://www.apache.org/licenses/LICENSE-2.0 |
16 | | // |
17 | | // Unless required by applicable law or agreed to in writing, software |
18 | | // distributed under the License is distributed on an "AS IS" BASIS, |
19 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
20 | | // See the License for the specific language governing permissions and |
21 | | // limitations under the License. |
22 | | // --------------------------------------------------------------------------- |
23 | | |
24 | | #ifdef _MSC_VER |
25 | | #pragma warning(push) |
26 | | #pragma warning(disable : 4514) // unreferenced inline function has been removed |
27 | | #pragma warning(disable : 4710) // function not inlined |
28 | | #pragma warning(disable : 4711) // selected for automatic inline expansion |
29 | | #endif |
30 | | |
31 | | #include <cstdint> |
32 | | #include <functional> |
33 | | #include <tuple> |
34 | | #include "phmap_bits.h" |
35 | | |
36 | | // --------------------------------------------------------------- |
37 | | // Absl forward declaration requires global scope. |
38 | | // --------------------------------------------------------------- |
39 | | #if defined(PHMAP_USE_ABSL_HASH) && !defined(phmap_fwd_decl_h_guard_) && !defined(ABSL_HASH_HASH_H_) |
40 | | namespace absl { template <class T> struct Hash; }; |
41 | | #endif |
42 | | |
43 | | namespace phmap |
44 | | { |
45 | | |
46 | | // --------------------------------------------------------------- |
47 | | // --------------------------------------------------------------- |
48 | | template<int n> |
49 | | struct phmap_mix |
50 | | { |
51 | | inline size_t operator()(size_t) const; |
52 | | }; |
53 | | |
54 | | template<> |
55 | | struct phmap_mix<4> |
56 | | { |
57 | | inline size_t operator()(size_t a) const |
58 | 0 | { |
59 | 0 | static constexpr uint64_t kmul = 0xcc9e2d51UL; |
60 | 0 | uint64_t l = a * kmul; |
61 | 0 | return static_cast<size_t>(l ^ (l >> 32)); |
62 | 0 | } |
63 | | }; |
64 | | |
65 | | #if defined(PHMAP_HAS_UMUL128) |
66 | | template<> |
67 | | struct phmap_mix<8> |
68 | | { |
69 | | // Very fast mixing (similar to Abseil) |
70 | | inline size_t operator()(size_t a) const |
71 | 10.3M | { |
72 | 10.3M | static constexpr uint64_t k = 0xde5fb9d2630458e9ULL; |
73 | 10.3M | uint64_t h; |
74 | 10.3M | uint64_t l = umul128(a, k, &h); |
75 | 10.3M | return static_cast<size_t>(h + l); |
76 | 10.3M | } |
77 | | }; |
78 | | #else |
79 | | template<> |
80 | | struct phmap_mix<8> |
81 | | { |
82 | | inline size_t operator()(size_t a) const |
83 | | { |
84 | | a = (~a) + (a << 21); // a = (a << 21) - a - 1; |
85 | | a = a ^ (a >> 24); |
86 | | a = (a + (a << 3)) + (a << 8); // a * 265 |
87 | | a = a ^ (a >> 14); |
88 | | a = (a + (a << 2)) + (a << 4); // a * 21 |
89 | | a = a ^ (a >> 28); |
90 | | a = a + (a << 31); |
91 | | return static_cast<size_t>(a); |
92 | | } |
93 | | }; |
94 | | #endif |
95 | | |
96 | | // -------------------------------------------- |
97 | | template<int n> |
98 | | struct fold_if_needed |
99 | | { |
100 | | inline size_t operator()(uint64_t) const; |
101 | | }; |
102 | | |
103 | | template<> |
104 | | struct fold_if_needed<4> |
105 | | { |
106 | | inline size_t operator()(uint64_t a) const |
107 | 0 | { |
108 | 0 | return static_cast<size_t>(a ^ (a >> 32)); |
109 | 0 | } |
110 | | }; |
111 | | |
112 | | template<> |
113 | | struct fold_if_needed<8> |
114 | | { |
115 | | inline size_t operator()(uint64_t a) const |
116 | 0 | { |
117 | 0 | return static_cast<size_t>(a); |
118 | 0 | } |
119 | | }; |
120 | | |
121 | | // --------------------------------------------------------------- |
122 | | // see if class T has a hash_value() friend method |
123 | | // --------------------------------------------------------------- |
124 | | template<typename T> |
125 | | struct has_hash_value |
126 | | { |
127 | | private: |
128 | | typedef std::true_type yes; |
129 | | typedef std::false_type no; |
130 | | |
131 | | template<typename U> static auto test(int) -> decltype(hash_value(std::declval<const U&>()) == 1, yes()); |
132 | | |
133 | | template<typename> static no test(...); |
134 | | |
135 | | public: |
136 | | static constexpr bool value = std::is_same<decltype(test<T>(0)), yes>::value; |
137 | | }; |
138 | | |
139 | | #if defined(PHMAP_USE_ABSL_HASH) && !defined(phmap_fwd_decl_h_guard_) |
140 | | template <class T> using Hash = ::absl::Hash<T>; |
141 | | #elif !defined(PHMAP_USE_ABSL_HASH) |
142 | | // --------------------------------------------------------------- |
143 | | // phmap::Hash |
144 | | // --------------------------------------------------------------- |
145 | | template <class T> |
146 | | struct Hash |
147 | | { |
148 | | template <class U, typename std::enable_if<has_hash_value<U>::value, int>::type = 0> |
149 | | size_t _hash(const T& val) const |
150 | | { |
151 | | return hash_value(val); |
152 | | } |
153 | | |
154 | | template <class U, typename std::enable_if<!has_hash_value<U>::value, int>::type = 0> |
155 | | size_t _hash(const T& val) const |
156 | | { |
157 | | return std::hash<T>()(val); |
158 | | } |
159 | | |
160 | | inline size_t operator()(const T& val) const |
161 | | { |
162 | | return _hash<T>(val); |
163 | | } |
164 | | }; |
165 | | |
166 | | template<class ArgumentType, class ResultType> |
167 | | struct phmap_unary_function |
168 | | { |
169 | | typedef ArgumentType argument_type; |
170 | | typedef ResultType result_type; |
171 | | }; |
172 | | |
173 | | template <> |
174 | | struct Hash<bool> : public phmap_unary_function<bool, size_t> |
175 | | { |
176 | | inline size_t operator()(bool val) const noexcept |
177 | 0 | { return static_cast<size_t>(val); } |
178 | | }; |
179 | | |
180 | | template <> |
181 | | struct Hash<char> : public phmap_unary_function<char, size_t> |
182 | | { |
183 | | inline size_t operator()(char val) const noexcept |
184 | 0 | { return static_cast<size_t>(val); } |
185 | | }; |
186 | | |
187 | | template <> |
188 | | struct Hash<signed char> : public phmap_unary_function<signed char, size_t> |
189 | | { |
190 | | inline size_t operator()(signed char val) const noexcept |
191 | 0 | { return static_cast<size_t>(val); } |
192 | | }; |
193 | | |
194 | | template <> |
195 | | struct Hash<unsigned char> : public phmap_unary_function<unsigned char, size_t> |
196 | | { |
197 | | inline size_t operator()(unsigned char val) const noexcept |
198 | 0 | { return static_cast<size_t>(val); } |
199 | | }; |
200 | | |
201 | | #ifdef PHMAP_HAS_NATIVE_WCHAR_T |
202 | | template <> |
203 | | struct Hash<wchar_t> : public phmap_unary_function<wchar_t, size_t> |
204 | | { |
205 | | inline size_t operator()(wchar_t val) const noexcept |
206 | 0 | { return static_cast<size_t>(val); } |
207 | | }; |
208 | | #endif |
209 | | |
210 | | template <> |
211 | | struct Hash<int16_t> : public phmap_unary_function<int16_t, size_t> |
212 | | { |
213 | | inline size_t operator()(int16_t val) const noexcept |
214 | 0 | { return static_cast<size_t>(val); } |
215 | | }; |
216 | | |
217 | | template <> |
218 | | struct Hash<uint16_t> : public phmap_unary_function<uint16_t, size_t> |
219 | | { |
220 | | inline size_t operator()(uint16_t val) const noexcept |
221 | 0 | { return static_cast<size_t>(val); } |
222 | | }; |
223 | | |
224 | | template <> |
225 | | struct Hash<int32_t> : public phmap_unary_function<int32_t, size_t> |
226 | | { |
227 | | inline size_t operator()(int32_t val) const noexcept |
228 | 0 | { return static_cast<size_t>(val); } |
229 | | }; |
230 | | |
231 | | template <> |
232 | | struct Hash<uint32_t> : public phmap_unary_function<uint32_t, size_t> |
233 | | { |
234 | | inline size_t operator()(uint32_t val) const noexcept |
235 | 10.3M | { return static_cast<size_t>(val); } |
236 | | }; |
237 | | |
238 | | template <> |
239 | | struct Hash<int64_t> : public phmap_unary_function<int64_t, size_t> |
240 | | { |
241 | | inline size_t operator()(int64_t val) const noexcept |
242 | 0 | { return fold_if_needed<sizeof(size_t)>()(static_cast<uint64_t>(val)); } |
243 | | }; |
244 | | |
245 | | template <> |
246 | | struct Hash<uint64_t> : public phmap_unary_function<uint64_t, size_t> |
247 | | { |
248 | | inline size_t operator()(uint64_t val) const noexcept |
249 | 0 | { return fold_if_needed<sizeof(size_t)>()(val); } |
250 | | }; |
251 | | |
252 | | template <> |
253 | | struct Hash<float> : public phmap_unary_function<float, size_t> |
254 | | { |
255 | | inline size_t operator()(float val) const noexcept |
256 | 0 | { |
257 | 0 | // -0.0 and 0.0 should return same hash |
258 | 0 | uint32_t *as_int = reinterpret_cast<uint32_t *>(&val); |
259 | 0 | return (val == 0) ? static_cast<size_t>(0) : |
260 | 0 | static_cast<size_t>(*as_int); |
261 | 0 | } |
262 | | }; |
263 | | |
264 | | template <> |
265 | | struct Hash<double> : public phmap_unary_function<double, size_t> |
266 | | { |
267 | | inline size_t operator()(double val) const noexcept |
268 | 0 | { |
269 | 0 | // -0.0 and 0.0 should return same hash |
270 | 0 | uint64_t *as_int = reinterpret_cast<uint64_t *>(&val); |
271 | 0 | return (val == 0) ? static_cast<size_t>(0) : |
272 | 0 | fold_if_needed<sizeof(size_t)>()(*as_int); |
273 | 0 | } |
274 | | }; |
275 | | |
276 | | #endif |
277 | | |
278 | | #if defined(_MSC_VER) |
279 | | # define PHMAP_HASH_ROTL32(x, r) _rotl(x,r) |
280 | | #else |
281 | | # define PHMAP_HASH_ROTL32(x, r) (x << r) | (x >> (32 - r)) |
282 | | #endif |
283 | | |
284 | | |
285 | | template <class H, int sz> struct Combiner |
286 | | { |
287 | | H operator()(H seed, size_t value); |
288 | | }; |
289 | | |
290 | | template <class H> struct Combiner<H, 4> |
291 | | { |
292 | | H operator()(H h1, size_t k1) |
293 | | { |
294 | | // Copyright 2005-2014 Daniel James. |
295 | | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
296 | | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
297 | | |
298 | | const uint32_t c1 = 0xcc9e2d51; |
299 | | const uint32_t c2 = 0x1b873593; |
300 | | |
301 | | k1 *= c1; |
302 | | k1 = PHMAP_HASH_ROTL32(k1,15); |
303 | | k1 *= c2; |
304 | | |
305 | | h1 ^= k1; |
306 | | h1 = PHMAP_HASH_ROTL32(h1,13); |
307 | | h1 = h1*5+0xe6546b64; |
308 | | |
309 | | return h1; |
310 | | } |
311 | | }; |
312 | | |
313 | | template <class H> struct Combiner<H, 8> |
314 | | { |
315 | | H operator()(H h, size_t k) |
316 | | { |
317 | | // Copyright 2005-2014 Daniel James. |
318 | | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
319 | | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
320 | | const uint64_t m = (uint64_t(0xc6a4a793) << 32) + 0x5bd1e995; |
321 | | const int r = 47; |
322 | | |
323 | | k *= m; |
324 | | k ^= k >> r; |
325 | | k *= m; |
326 | | |
327 | | h ^= k; |
328 | | h *= m; |
329 | | |
330 | | // Completely arbitrary number, to prevent 0's |
331 | | // from hashing to 0. |
332 | | h += 0xe6546b64; |
333 | | |
334 | | return h; |
335 | | } |
336 | | }; |
337 | | |
338 | | // define HashState to combine member hashes... see example below |
339 | | // ----------------------------------------------------------------------------- |
340 | | template <typename H> |
341 | | class HashStateBase { |
342 | | public: |
343 | | template <typename T, typename... Ts> |
344 | | static H combine(H state, const T& value, const Ts&... values); |
345 | | |
346 | | static H combine(H state) { return state; } |
347 | | }; |
348 | | |
349 | | template <typename H> |
350 | | template <typename T, typename... Ts> |
351 | | H HashStateBase<H>::combine(H seed, const T& v, const Ts&... vs) |
352 | | { |
353 | | return HashStateBase<H>::combine(Combiner<H, sizeof(H)>()( |
354 | | seed, phmap::Hash<T>()(v)), |
355 | | vs...); |
356 | | } |
357 | | |
358 | | using HashState = HashStateBase<size_t>; |
359 | | |
360 | | // ----------------------------------------------------------------------------- |
361 | | |
362 | | #if !defined(PHMAP_USE_ABSL_HASH) |
363 | | |
364 | | // define Hash for std::pair |
365 | | // ------------------------- |
366 | | template<class T1, class T2> |
367 | | struct Hash<std::pair<T1, T2>> { |
368 | | size_t operator()(std::pair<T1, T2> const& p) const noexcept { |
369 | | return phmap::HashState().combine(phmap::Hash<T1>()(p.first), p.second); |
370 | | } |
371 | | }; |
372 | | |
373 | | // define Hash for std::tuple |
374 | | // -------------------------- |
375 | | template<class... T> |
376 | | struct Hash<std::tuple<T...>> { |
377 | | size_t operator()(std::tuple<T...> const& t) const noexcept { |
378 | | size_t seed = 0; |
379 | | return _hash_helper(seed, t); |
380 | | } |
381 | | |
382 | | private: |
383 | | template<size_t I = 0, class TUP> |
384 | | typename std::enable_if<I == std::tuple_size<TUP>::value, size_t>::type |
385 | | _hash_helper(size_t seed, const TUP &) const noexcept { return seed; } |
386 | | |
387 | | template<size_t I = 0, class TUP> |
388 | | typename std::enable_if<I < std::tuple_size<TUP>::value, size_t>::type |
389 | | _hash_helper(size_t seed, const TUP &t) const noexcept { |
390 | | const auto &el = std::get<I>(t); |
391 | | using el_type = typename std::remove_cv<typename std::remove_reference<decltype(el)>::type>::type; |
392 | | seed = Combiner<size_t, sizeof(size_t)>()(seed, phmap::Hash<el_type>()(el)); |
393 | | return _hash_helper<I + 1>(seed, t); |
394 | | } |
395 | | }; |
396 | | |
397 | | |
398 | | #endif |
399 | | |
400 | | |
401 | | } // namespace phmap |
402 | | |
403 | | #ifdef _MSC_VER |
404 | | #pragma warning(pop) |
405 | | #endif |
406 | | |
407 | | #endif // phmap_utils_h_guard_ |