Coverage Report

Created: 2023-06-07 07:15

/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_