Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/templates/hashfuncs.h
21138 views
1
/**************************************************************************/
2
/* hashfuncs.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
#include "core/math/math_defs.h"
34
#include "core/math/math_funcs.h"
35
#include "core/typedefs.h"
36
37
#ifdef _MSC_VER
38
#include <intrin.h> // Needed for `__umulh` below.
39
#endif
40
41
template <typename F, typename S>
42
struct Pair;
43
44
/**
45
* Hashing functions
46
*/
47
48
/**
49
* DJB2 Hash function
50
* @param C String
51
* @return 32-bits hashcode
52
*/
53
_FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) {
54
const unsigned char *chr = (const unsigned char *)p_cstr;
55
uint32_t hash = 5381;
56
uint32_t c = *chr++;
57
58
while (c) {
59
hash = ((hash << 5) + hash) ^ c; /* hash * 33 ^ c */
60
c = *chr++;
61
}
62
63
return hash;
64
}
65
66
_FORCE_INLINE_ uint32_t hash_djb2_buffer(const uint8_t *p_buff, int p_len, uint32_t p_prev = 5381) {
67
uint32_t hash = p_prev;
68
69
for (int i = 0; i < p_len; i++) {
70
hash = ((hash << 5) + hash) ^ p_buff[i]; /* hash * 33 + c */
71
}
72
73
return hash;
74
}
75
76
_FORCE_INLINE_ uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev = 5381) {
77
return ((p_prev << 5) + p_prev) ^ p_in;
78
}
79
80
/**
81
* Thomas Wang's 64-bit to 32-bit Hash function:
82
* https://web.archive.org/web/20071223173210/https:/www.concentric.net/~Ttwang/tech/inthash.htm
83
*
84
* @param p_int - 64-bit unsigned integer key to be hashed
85
* @return unsigned 32-bit value representing hashcode
86
*/
87
_FORCE_INLINE_ uint32_t hash_one_uint64(const uint64_t p_int) {
88
uint64_t v = p_int;
89
v = (~v) + (v << 18); // v = (v << 18) - v - 1;
90
v = v ^ (v >> 31);
91
v = v * 21; // v = (v + (v << 2)) + (v << 4);
92
v = v ^ (v >> 11);
93
v = v + (v << 6);
94
v = v ^ (v >> 22);
95
return uint32_t(v);
96
}
97
98
_FORCE_INLINE_ uint64_t hash64_murmur3_64(uint64_t key, uint64_t seed) {
99
key ^= seed;
100
key ^= key >> 33;
101
key *= 0xff51afd7ed558ccd;
102
key ^= key >> 33;
103
key *= 0xc4ceb9fe1a85ec53;
104
key ^= key >> 33;
105
return key;
106
}
107
108
#define HASH_MURMUR3_SEED 0x7F07C65
109
// Murmurhash3 32-bit version.
110
// All MurmurHash versions are public domain software, and the author disclaims all copyright to their code.
111
112
_FORCE_INLINE_ uint32_t hash_murmur3_one_32(uint32_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
113
p_in *= 0xcc9e2d51;
114
p_in = (p_in << 15) | (p_in >> 17);
115
p_in *= 0x1b873593;
116
117
p_seed ^= p_in;
118
p_seed = (p_seed << 13) | (p_seed >> 19);
119
p_seed = p_seed * 5 + 0xe6546b64;
120
121
return p_seed;
122
}
123
124
_FORCE_INLINE_ uint32_t hash_murmur3_one_64(uint64_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
125
p_seed = hash_murmur3_one_32(p_in & 0xFFFFFFFF, p_seed);
126
return hash_murmur3_one_32(p_in >> 32, p_seed);
127
}
128
129
uint32_t hash_murmur3_one_float(float p_in, uint32_t p_seed = HASH_MURMUR3_SEED);
130
uint32_t hash_murmur3_one_double(double p_in, uint32_t p_seed = HASH_MURMUR3_SEED);
131
132
_FORCE_INLINE_ uint32_t hash_murmur3_one_real(real_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
133
#ifdef REAL_T_IS_DOUBLE
134
return hash_murmur3_one_double(p_in, p_seed);
135
#else
136
return hash_murmur3_one_float(p_in, p_seed);
137
#endif
138
}
139
140
_FORCE_INLINE_ uint32_t hash_rotl32(uint32_t x, int8_t r) {
141
return (x << r) | (x >> (32 - r));
142
}
143
144
_FORCE_INLINE_ uint32_t hash_fmix32(uint32_t h) {
145
h ^= h >> 16;
146
h *= 0x85ebca6b;
147
h ^= h >> 13;
148
h *= 0xc2b2ae35;
149
h ^= h >> 16;
150
151
return h;
152
}
153
154
uint32_t hash_murmur3_buffer(const void *key, int length, uint32_t seed = HASH_MURMUR3_SEED);
155
156
uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev = 5381);
157
uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev = 5381);
158
159
_FORCE_INLINE_ uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev = 5381) {
160
return ((p_prev << 5) + p_prev) ^ p_in;
161
}
162
163
template <typename, typename = std::void_t<>>
164
struct has_hash_method : std::false_type {};
165
166
template <typename T>
167
struct has_hash_method<T, std::void_t<std::is_same<decltype(std::declval<const T>().hash()), uint32_t>>> : std::true_type {};
168
169
template <typename T>
170
constexpr bool has_hash_method_v = has_hash_method<T>::value;
171
172
template <typename T, typename = void>
173
struct HashMapHasherDefaultImpl {
174
};
175
176
struct HashMapHasherDefault {
177
template <typename T>
178
static _FORCE_INLINE_ uint32_t hash(const T &p_type) {
179
return HashMapHasherDefaultImpl<std::decay_t<T>>::hash(p_type);
180
}
181
};
182
183
template <typename T>
184
struct HashMapHasherDefaultImpl<T, std::enable_if_t<has_hash_method_v<T>>> {
185
// For self hashing types.
186
static _FORCE_INLINE_ uint32_t hash(const T &p_value) {
187
return p_value.hash();
188
}
189
};
190
191
template <typename T>
192
struct HashMapHasherDefaultImpl<T *> {
193
// For pointer types.
194
static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); }
195
};
196
197
template <typename T>
198
struct HashMapHasherDefaultImpl<T, std::enable_if_t<std::is_enum_v<T>>> {
199
// For all enums.
200
static _FORCE_INLINE_ uint32_t hash(T p_value) {
201
return HashMapHasherDefaultImpl<std::underlying_type_t<T>>::hash(static_cast<std::underlying_type_t<T>>(p_value));
202
}
203
};
204
205
template <>
206
struct HashMapHasherDefaultImpl<char *> {
207
static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); }
208
};
209
210
template <>
211
struct HashMapHasherDefaultImpl<wchar_t> {
212
static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return hash_fmix32(uint32_t(p_wchar)); }
213
};
214
215
template <>
216
struct HashMapHasherDefaultImpl<char16_t> {
217
static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(uint32_t(p_uchar)); }
218
};
219
220
template <>
221
struct HashMapHasherDefaultImpl<char32_t> {
222
static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(uint32_t(p_uchar)); }
223
};
224
225
template <>
226
struct HashMapHasherDefaultImpl<uint64_t> {
227
static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); }
228
};
229
230
template <>
231
struct HashMapHasherDefaultImpl<int64_t> {
232
static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(uint64_t(p_int)); }
233
};
234
235
template <>
236
struct HashMapHasherDefaultImpl<float> {
237
static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_murmur3_one_float(p_float); }
238
};
239
240
template <>
241
struct HashMapHasherDefaultImpl<double> {
242
static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_murmur3_one_double(p_double); }
243
};
244
245
template <>
246
struct HashMapHasherDefaultImpl<uint32_t> {
247
static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return hash_fmix32(p_int); }
248
};
249
250
template <>
251
struct HashMapHasherDefaultImpl<int32_t> {
252
static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return hash_fmix32(uint32_t(p_int)); }
253
};
254
255
template <>
256
struct HashMapHasherDefaultImpl<uint16_t> {
257
static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return hash_fmix32(uint32_t(p_int)); }
258
};
259
260
template <>
261
struct HashMapHasherDefaultImpl<int16_t> {
262
static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return hash_fmix32(uint32_t(p_int)); }
263
};
264
265
template <>
266
struct HashMapHasherDefaultImpl<uint8_t> {
267
static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return hash_fmix32(uint32_t(p_int)); }
268
};
269
270
template <>
271
struct HashMapHasherDefaultImpl<int8_t> {
272
static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return hash_fmix32(uint32_t(p_int)); }
273
};
274
275
template <typename F, typename S>
276
struct HashMapHasherDefaultImpl<Pair<F, S>> {
277
static _FORCE_INLINE_ uint32_t hash(const Pair<F, S> &p_pair) {
278
uint64_t h1 = HashMapHasherDefault::hash(p_pair.first);
279
uint64_t h2 = HashMapHasherDefault::hash(p_pair.second);
280
return hash_one_uint64((h1 << 32) | h2);
281
}
282
};
283
284
template <typename, typename = std::void_t<>>
285
struct has_is_same_method : std::false_type {};
286
287
template <typename T>
288
struct has_is_same_method<T, std::void_t<std::is_same<decltype(std::declval<const T>().is_same(std::declval<const T>())), uint32_t>>> : std::true_type {};
289
290
template <typename T>
291
constexpr bool has_is_same_method_v = has_is_same_method<T>::value;
292
293
struct HashHasher {
294
static _FORCE_INLINE_ uint32_t hash(const int32_t hash) { return hash; }
295
static _FORCE_INLINE_ uint32_t hash(const uint32_t hash) { return hash; }
296
static _FORCE_INLINE_ uint64_t hash(const int64_t hash) { return hash; }
297
static _FORCE_INLINE_ uint64_t hash(const uint64_t hash) { return hash; }
298
};
299
300
template <typename T, typename = void>
301
struct HashMapComparatorDefault {
302
static bool compare(const T &p_lhs, const T &p_rhs) {
303
return p_lhs == p_rhs;
304
}
305
};
306
307
template <>
308
struct HashMapComparatorDefault<float> {
309
static bool compare(const float &p_lhs, const float &p_rhs) {
310
return Math::is_same(p_lhs, p_rhs);
311
}
312
};
313
314
template <>
315
struct HashMapComparatorDefault<double> {
316
static bool compare(const double &p_lhs, const double &p_rhs) {
317
return Math::is_same(p_lhs, p_rhs);
318
}
319
};
320
321
template <typename T>
322
struct HashMapComparatorDefault<T, std::enable_if_t<has_is_same_method_v<T>>> {
323
// For self comparing types.
324
static bool compare(const T &p_lhs, const T &p_rhs) {
325
return p_lhs.is_same(p_rhs);
326
}
327
};
328
329
constexpr uint32_t HASH_TABLE_SIZE_MAX = 29;
330
331
inline constexpr uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = {
332
5,
333
13,
334
23,
335
47,
336
97,
337
193,
338
389,
339
769,
340
1543,
341
3079,
342
6151,
343
12289,
344
24593,
345
49157,
346
98317,
347
196613,
348
393241,
349
786433,
350
1572869,
351
3145739,
352
6291469,
353
12582917,
354
25165843,
355
50331653,
356
100663319,
357
201326611,
358
402653189,
359
805306457,
360
1610612741,
361
};
362
363
// Computed with elem_i = UINT64_C (0 x FFFFFFFF FFFFFFFF ) / d_i + 1, where d_i is the i-th element of the above array.
364
inline constexpr uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = {
365
3689348814741910324,
366
1418980313362273202,
367
802032351030850071,
368
392483916461905354,
369
190172619316593316,
370
95578984837873325,
371
47420935922132524,
372
23987963684927896,
373
11955116055547344,
374
5991147799191151,
375
2998982941588287,
376
1501077717772769,
377
750081082979285,
378
375261795343686,
379
187625172388393,
380
93822606204624,
381
46909513691883,
382
23456218233098,
383
11728086747027,
384
5864041509391,
385
2932024948977,
386
1466014921160,
387
733007198436,
388
366503839517,
389
183251896093,
390
91625960335,
391
45812983922,
392
22906489714,
393
11453246088
394
};
395
396
/**
397
* Fastmod computes ( n mod d ) given the precomputed c much faster than n % d.
398
* The implementation of fastmod is based on the following paper by Daniel Lemire et al.
399
* Faster Remainder by Direct Computation: Applications to Compilers and Software Libraries
400
* https://arxiv.org/abs/1902.01961
401
*/
402
static _FORCE_INLINE_ uint32_t fastmod(const uint32_t n, const uint64_t c, const uint32_t d) {
403
#if defined(_MSC_VER)
404
// Returns the upper 64 bits of the product of two 64-bit unsigned integers.
405
// This intrinsic function is required since MSVC does not support unsigned 128-bit integers.
406
#if defined(_M_X64) || defined(_M_ARM64)
407
return __umulh(c * n, d);
408
#else
409
// Fallback to the slower method for 32-bit platforms.
410
return n % d;
411
#endif // _M_X64 || _M_ARM64
412
#else
413
#ifdef __SIZEOF_INT128__
414
// Prevent compiler warning, because we know what we are doing.
415
uint64_t lowbits = c * n;
416
__extension__ typedef unsigned __int128 uint128;
417
return static_cast<uint64_t>(((uint128)lowbits * d) >> 64);
418
#else
419
// Fallback to the slower method if no 128-bit unsigned integer type is available.
420
return n % d;
421
#endif // __SIZEOF_INT128__
422
#endif // _MSC_VER
423
}
424
425