Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/templates/hashfuncs.h
9973 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/aabb.h"
34
#include "core/math/basis.h"
35
#include "core/math/color.h"
36
#include "core/math/math_defs.h"
37
#include "core/math/math_funcs.h"
38
#include "core/math/plane.h"
39
#include "core/math/projection.h"
40
#include "core/math/quaternion.h"
41
#include "core/math/rect2.h"
42
#include "core/math/rect2i.h"
43
#include "core/math/transform_2d.h"
44
#include "core/math/transform_3d.h"
45
#include "core/math/vector2.h"
46
#include "core/math/vector2i.h"
47
#include "core/math/vector3.h"
48
#include "core/math/vector3i.h"
49
#include "core/math/vector4.h"
50
#include "core/math/vector4i.h"
51
#include "core/object/object_id.h"
52
#include "core/string/node_path.h"
53
#include "core/string/string_name.h"
54
#include "core/string/ustring.h"
55
#include "core/templates/pair.h"
56
#include "core/templates/rid.h"
57
#include "core/typedefs.h"
58
#include "core/variant/callable.h"
59
60
#ifdef _MSC_VER
61
#include <intrin.h> // Needed for `__umulh` below.
62
#endif
63
64
/**
65
* Hashing functions
66
*/
67
68
/**
69
* DJB2 Hash function
70
* @param C String
71
* @return 32-bits hashcode
72
*/
73
static _FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) {
74
const unsigned char *chr = (const unsigned char *)p_cstr;
75
uint32_t hash = 5381;
76
uint32_t c = *chr++;
77
78
while (c) {
79
hash = ((hash << 5) + hash) ^ c; /* hash * 33 ^ c */
80
c = *chr++;
81
}
82
83
return hash;
84
}
85
86
static _FORCE_INLINE_ uint32_t hash_djb2_buffer(const uint8_t *p_buff, int p_len, uint32_t p_prev = 5381) {
87
uint32_t hash = p_prev;
88
89
for (int i = 0; i < p_len; i++) {
90
hash = ((hash << 5) + hash) ^ p_buff[i]; /* hash * 33 + c */
91
}
92
93
return hash;
94
}
95
96
static _FORCE_INLINE_ uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev = 5381) {
97
return ((p_prev << 5) + p_prev) ^ p_in;
98
}
99
100
/**
101
* Thomas Wang's 64-bit to 32-bit Hash function:
102
* https://web.archive.org/web/20071223173210/https:/www.concentric.net/~Ttwang/tech/inthash.htm
103
*
104
* @param p_int - 64-bit unsigned integer key to be hashed
105
* @return unsigned 32-bit value representing hashcode
106
*/
107
static _FORCE_INLINE_ uint32_t hash_one_uint64(const uint64_t p_int) {
108
uint64_t v = p_int;
109
v = (~v) + (v << 18); // v = (v << 18) - v - 1;
110
v = v ^ (v >> 31);
111
v = v * 21; // v = (v + (v << 2)) + (v << 4);
112
v = v ^ (v >> 11);
113
v = v + (v << 6);
114
v = v ^ (v >> 22);
115
return uint32_t(v);
116
}
117
118
static _FORCE_INLINE_ uint64_t hash64_murmur3_64(uint64_t key, uint64_t seed) {
119
key ^= seed;
120
key ^= key >> 33;
121
key *= 0xff51afd7ed558ccd;
122
key ^= key >> 33;
123
key *= 0xc4ceb9fe1a85ec53;
124
key ^= key >> 33;
125
return key;
126
}
127
128
#define HASH_MURMUR3_SEED 0x7F07C65
129
// Murmurhash3 32-bit version.
130
// All MurmurHash versions are public domain software, and the author disclaims all copyright to their code.
131
132
static _FORCE_INLINE_ uint32_t hash_murmur3_one_32(uint32_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
133
p_in *= 0xcc9e2d51;
134
p_in = (p_in << 15) | (p_in >> 17);
135
p_in *= 0x1b873593;
136
137
p_seed ^= p_in;
138
p_seed = (p_seed << 13) | (p_seed >> 19);
139
p_seed = p_seed * 5 + 0xe6546b64;
140
141
return p_seed;
142
}
143
144
static _FORCE_INLINE_ uint32_t hash_murmur3_one_float(float p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
145
union {
146
float f;
147
uint32_t i;
148
} u;
149
150
// Normalize +/- 0.0 and NaN values so they hash the same.
151
if (p_in == 0.0f) {
152
u.f = 0.0;
153
} else if (Math::is_nan(p_in)) {
154
u.f = Math::NaN;
155
} else {
156
u.f = p_in;
157
}
158
159
return hash_murmur3_one_32(u.i, p_seed);
160
}
161
162
static _FORCE_INLINE_ uint32_t hash_murmur3_one_64(uint64_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
163
p_seed = hash_murmur3_one_32(p_in & 0xFFFFFFFF, p_seed);
164
return hash_murmur3_one_32(p_in >> 32, p_seed);
165
}
166
167
static _FORCE_INLINE_ uint32_t hash_murmur3_one_double(double p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
168
union {
169
double d;
170
uint64_t i;
171
} u;
172
173
// Normalize +/- 0.0 and NaN values so they hash the same.
174
if (p_in == 0.0f) {
175
u.d = 0.0;
176
} else if (Math::is_nan(p_in)) {
177
u.d = Math::NaN;
178
} else {
179
u.d = p_in;
180
}
181
182
return hash_murmur3_one_64(u.i, p_seed);
183
}
184
185
static _FORCE_INLINE_ uint32_t hash_murmur3_one_real(real_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
186
#ifdef REAL_T_IS_DOUBLE
187
return hash_murmur3_one_double(p_in, p_seed);
188
#else
189
return hash_murmur3_one_float(p_in, p_seed);
190
#endif
191
}
192
193
static _FORCE_INLINE_ uint32_t hash_rotl32(uint32_t x, int8_t r) {
194
return (x << r) | (x >> (32 - r));
195
}
196
197
static _FORCE_INLINE_ uint32_t hash_fmix32(uint32_t h) {
198
h ^= h >> 16;
199
h *= 0x85ebca6b;
200
h ^= h >> 13;
201
h *= 0xc2b2ae35;
202
h ^= h >> 16;
203
204
return h;
205
}
206
207
static _FORCE_INLINE_ uint32_t hash_murmur3_buffer(const void *key, int length, const uint32_t seed = HASH_MURMUR3_SEED) {
208
// Although not required, this is a random prime number.
209
const uint8_t *data = (const uint8_t *)key;
210
const int nblocks = length / 4;
211
212
uint32_t h1 = seed;
213
214
const uint32_t c1 = 0xcc9e2d51;
215
const uint32_t c2 = 0x1b873593;
216
217
const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
218
219
for (int i = -nblocks; i; i++) {
220
uint32_t k1 = blocks[i];
221
222
k1 *= c1;
223
k1 = hash_rotl32(k1, 15);
224
k1 *= c2;
225
226
h1 ^= k1;
227
h1 = hash_rotl32(h1, 13);
228
h1 = h1 * 5 + 0xe6546b64;
229
}
230
231
const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
232
233
uint32_t k1 = 0;
234
235
switch (length & 3) {
236
case 3:
237
k1 ^= tail[2] << 16;
238
[[fallthrough]];
239
case 2:
240
k1 ^= tail[1] << 8;
241
[[fallthrough]];
242
case 1:
243
k1 ^= tail[0];
244
k1 *= c1;
245
k1 = hash_rotl32(k1, 15);
246
k1 *= c2;
247
h1 ^= k1;
248
};
249
250
// Finalize with additional bit mixing.
251
h1 ^= length;
252
return hash_fmix32(h1);
253
}
254
255
static _FORCE_INLINE_ uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev = 5381) {
256
union {
257
double d;
258
uint64_t i;
259
} u;
260
261
// Normalize +/- 0.0 and NaN values so they hash the same.
262
if (p_in == 0.0f) {
263
u.d = 0.0;
264
} else if (Math::is_nan(p_in)) {
265
u.d = Math::NaN;
266
} else {
267
u.d = p_in;
268
}
269
270
return ((p_prev << 5) + p_prev) + hash_one_uint64(u.i);
271
}
272
273
template <typename T>
274
static _FORCE_INLINE_ uint32_t hash_make_uint32_t(T p_in) {
275
union {
276
T t;
277
uint32_t _u32;
278
} _u;
279
_u._u32 = 0;
280
_u.t = p_in;
281
return _u._u32;
282
}
283
284
static _FORCE_INLINE_ uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev = 5381) {
285
union {
286
double d;
287
uint64_t i;
288
} u;
289
290
// Normalize +/- 0.0 and NaN values so they hash the same.
291
if (p_in == 0.0f) {
292
u.d = 0.0;
293
} else if (Math::is_nan(p_in)) {
294
u.d = Math::NaN;
295
} else {
296
u.d = p_in;
297
}
298
299
return ((p_prev << 5) + p_prev) + u.i;
300
}
301
302
static _FORCE_INLINE_ uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev = 5381) {
303
return ((p_prev << 5) + p_prev) ^ p_in;
304
}
305
306
template <typename T>
307
static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) {
308
union {
309
T t;
310
uint64_t _u64;
311
} _u;
312
_u._u64 = 0; // in case p_in is smaller
313
314
_u.t = p_in;
315
return _u._u64;
316
}
317
318
template <typename T>
319
class Ref;
320
321
struct HashMapHasherDefault {
322
// Generic hash function for any type.
323
template <typename T>
324
static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); }
325
326
template <typename T>
327
static _FORCE_INLINE_ uint32_t hash(const Ref<T> &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); }
328
329
template <typename F, typename S>
330
static _FORCE_INLINE_ uint32_t hash(const Pair<F, S> &p_pair) {
331
uint64_t h1 = hash(p_pair.first);
332
uint64_t h2 = hash(p_pair.second);
333
return hash_one_uint64((h1 << 32) | h2);
334
}
335
336
static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }
337
static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); }
338
static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return hash_fmix32(uint32_t(p_wchar)); }
339
static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(uint32_t(p_uchar)); }
340
static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(uint32_t(p_uchar)); }
341
static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); }
342
static _FORCE_INLINE_ uint32_t hash(const CharString &p_char_string) { return hash_djb2(p_char_string.get_data()); }
343
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
344
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
345
static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
346
static _FORCE_INLINE_ uint32_t hash(const Callable &p_callable) { return p_callable.hash(); }
347
348
static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); }
349
static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(uint64_t(p_int)); }
350
static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_murmur3_one_float(p_float); }
351
static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_murmur3_one_double(p_double); }
352
static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return hash_fmix32(p_int); }
353
static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return hash_fmix32(uint32_t(p_int)); }
354
static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return hash_fmix32(uint32_t(p_int)); }
355
static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return hash_fmix32(uint32_t(p_int)); }
356
static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return hash_fmix32(uint32_t(p_int)); }
357
static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return hash_fmix32(uint32_t(p_int)); }
358
static _FORCE_INLINE_ uint32_t hash(const Vector2i &p_vec) {
359
uint32_t h = hash_murmur3_one_32(uint32_t(p_vec.x));
360
h = hash_murmur3_one_32(uint32_t(p_vec.y), h);
361
return hash_fmix32(h);
362
}
363
static _FORCE_INLINE_ uint32_t hash(const Vector3i &p_vec) {
364
uint32_t h = hash_murmur3_one_32(uint32_t(p_vec.x));
365
h = hash_murmur3_one_32(uint32_t(p_vec.y), h);
366
h = hash_murmur3_one_32(uint32_t(p_vec.z), h);
367
return hash_fmix32(h);
368
}
369
static _FORCE_INLINE_ uint32_t hash(const Vector4i &p_vec) {
370
uint32_t h = hash_murmur3_one_32(uint32_t(p_vec.x));
371
h = hash_murmur3_one_32(uint32_t(p_vec.y), h);
372
h = hash_murmur3_one_32(uint32_t(p_vec.z), h);
373
h = hash_murmur3_one_32(uint32_t(p_vec.w), h);
374
return hash_fmix32(h);
375
}
376
static _FORCE_INLINE_ uint32_t hash(const Vector2 &p_vec) {
377
uint32_t h = hash_murmur3_one_real(p_vec.x);
378
h = hash_murmur3_one_real(p_vec.y, h);
379
return hash_fmix32(h);
380
}
381
static _FORCE_INLINE_ uint32_t hash(const Vector3 &p_vec) {
382
uint32_t h = hash_murmur3_one_real(p_vec.x);
383
h = hash_murmur3_one_real(p_vec.y, h);
384
h = hash_murmur3_one_real(p_vec.z, h);
385
return hash_fmix32(h);
386
}
387
static _FORCE_INLINE_ uint32_t hash(const Vector4 &p_vec) {
388
uint32_t h = hash_murmur3_one_real(p_vec.x);
389
h = hash_murmur3_one_real(p_vec.y, h);
390
h = hash_murmur3_one_real(p_vec.z, h);
391
h = hash_murmur3_one_real(p_vec.w, h);
392
return hash_fmix32(h);
393
}
394
static _FORCE_INLINE_ uint32_t hash(const Color &p_vec) {
395
uint32_t h = hash_murmur3_one_float(p_vec.r);
396
h = hash_murmur3_one_float(p_vec.g, h);
397
h = hash_murmur3_one_float(p_vec.b, h);
398
h = hash_murmur3_one_float(p_vec.a, h);
399
return hash_fmix32(h);
400
}
401
static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) {
402
uint32_t h = hash_murmur3_one_32(uint32_t(p_rect.position.x));
403
h = hash_murmur3_one_32(uint32_t(p_rect.position.y), h);
404
h = hash_murmur3_one_32(uint32_t(p_rect.size.x), h);
405
h = hash_murmur3_one_32(uint32_t(p_rect.size.y), h);
406
return hash_fmix32(h);
407
}
408
static _FORCE_INLINE_ uint32_t hash(const Rect2 &p_rect) {
409
uint32_t h = hash_murmur3_one_real(p_rect.position.x);
410
h = hash_murmur3_one_real(p_rect.position.y, h);
411
h = hash_murmur3_one_real(p_rect.size.x, h);
412
h = hash_murmur3_one_real(p_rect.size.y, h);
413
return hash_fmix32(h);
414
}
415
static _FORCE_INLINE_ uint32_t hash(const AABB &p_aabb) {
416
uint32_t h = hash_murmur3_one_real(p_aabb.position.x);
417
h = hash_murmur3_one_real(p_aabb.position.y, h);
418
h = hash_murmur3_one_real(p_aabb.position.z, h);
419
h = hash_murmur3_one_real(p_aabb.size.x, h);
420
h = hash_murmur3_one_real(p_aabb.size.y, h);
421
h = hash_murmur3_one_real(p_aabb.size.z, h);
422
return hash_fmix32(h);
423
}
424
};
425
426
struct HashHasher {
427
static _FORCE_INLINE_ uint32_t hash(const int32_t hash) { return hash; }
428
static _FORCE_INLINE_ uint32_t hash(const uint32_t hash) { return hash; }
429
static _FORCE_INLINE_ uint64_t hash(const int64_t hash) { return hash; }
430
static _FORCE_INLINE_ uint64_t hash(const uint64_t hash) { return hash; }
431
};
432
433
// TODO: Fold this into HashMapHasherDefault once C++20 concepts are allowed
434
template <typename T>
435
struct HashableHasher {
436
static _FORCE_INLINE_ uint32_t hash(const T &hashable) { return hashable.hash(); }
437
};
438
439
template <typename T>
440
struct HashMapComparatorDefault {
441
static bool compare(const T &p_lhs, const T &p_rhs) {
442
return p_lhs == p_rhs;
443
}
444
};
445
446
template <>
447
struct HashMapComparatorDefault<float> {
448
static bool compare(const float &p_lhs, const float &p_rhs) {
449
return Math::is_same(p_lhs, p_rhs);
450
}
451
};
452
453
template <>
454
struct HashMapComparatorDefault<double> {
455
static bool compare(const double &p_lhs, const double &p_rhs) {
456
return Math::is_same(p_lhs, p_rhs);
457
}
458
};
459
460
template <>
461
struct HashMapComparatorDefault<Color> {
462
static bool compare(const Color &p_lhs, const Color &p_rhs) {
463
return p_lhs.is_same(p_rhs);
464
}
465
};
466
467
template <>
468
struct HashMapComparatorDefault<Vector2> {
469
static bool compare(const Vector2 &p_lhs, const Vector2 &p_rhs) {
470
return p_lhs.is_same(p_rhs);
471
}
472
};
473
474
template <>
475
struct HashMapComparatorDefault<Vector3> {
476
static bool compare(const Vector3 &p_lhs, const Vector3 &p_rhs) {
477
return p_lhs.is_same(p_rhs);
478
}
479
};
480
481
template <>
482
struct HashMapComparatorDefault<Vector4> {
483
static bool compare(const Vector4 &p_lhs, const Vector4 &p_rhs) {
484
return p_lhs.is_same(p_rhs);
485
}
486
};
487
488
template <>
489
struct HashMapComparatorDefault<Rect2> {
490
static bool compare(const Rect2 &p_lhs, const Rect2 &p_rhs) {
491
return p_lhs.is_same(p_rhs);
492
}
493
};
494
495
template <>
496
struct HashMapComparatorDefault<AABB> {
497
static bool compare(const AABB &p_lhs, const AABB &p_rhs) {
498
return p_lhs.is_same(p_rhs);
499
}
500
};
501
502
template <>
503
struct HashMapComparatorDefault<Plane> {
504
static bool compare(const Plane &p_lhs, const Plane &p_rhs) {
505
return p_lhs.is_same(p_rhs);
506
}
507
};
508
509
template <>
510
struct HashMapComparatorDefault<Transform2D> {
511
static bool compare(const Transform2D &p_lhs, const Transform2D &p_rhs) {
512
return p_lhs.is_same(p_rhs);
513
}
514
};
515
516
template <>
517
struct HashMapComparatorDefault<Basis> {
518
static bool compare(const Basis &p_lhs, const Basis &p_rhs) {
519
return p_lhs.is_same(p_rhs);
520
}
521
};
522
523
template <>
524
struct HashMapComparatorDefault<Transform3D> {
525
static bool compare(const Transform3D &p_lhs, const Transform3D &p_rhs) {
526
return p_lhs.is_same(p_rhs);
527
}
528
};
529
530
template <>
531
struct HashMapComparatorDefault<Projection> {
532
static bool compare(const Projection &p_lhs, const Projection &p_rhs) {
533
return p_lhs.is_same(p_rhs);
534
}
535
};
536
537
template <>
538
struct HashMapComparatorDefault<Quaternion> {
539
static bool compare(const Quaternion &p_lhs, const Quaternion &p_rhs) {
540
return p_lhs.is_same(p_rhs);
541
}
542
};
543
544
constexpr uint32_t HASH_TABLE_SIZE_MAX = 29;
545
546
inline constexpr uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = {
547
5,
548
13,
549
23,
550
47,
551
97,
552
193,
553
389,
554
769,
555
1543,
556
3079,
557
6151,
558
12289,
559
24593,
560
49157,
561
98317,
562
196613,
563
393241,
564
786433,
565
1572869,
566
3145739,
567
6291469,
568
12582917,
569
25165843,
570
50331653,
571
100663319,
572
201326611,
573
402653189,
574
805306457,
575
1610612741,
576
};
577
578
// 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.
579
inline constexpr uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = {
580
3689348814741910324,
581
1418980313362273202,
582
802032351030850071,
583
392483916461905354,
584
190172619316593316,
585
95578984837873325,
586
47420935922132524,
587
23987963684927896,
588
11955116055547344,
589
5991147799191151,
590
2998982941588287,
591
1501077717772769,
592
750081082979285,
593
375261795343686,
594
187625172388393,
595
93822606204624,
596
46909513691883,
597
23456218233098,
598
11728086747027,
599
5864041509391,
600
2932024948977,
601
1466014921160,
602
733007198436,
603
366503839517,
604
183251896093,
605
91625960335,
606
45812983922,
607
22906489714,
608
11453246088
609
};
610
611
/**
612
* Fastmod computes ( n mod d ) given the precomputed c much faster than n % d.
613
* The implementation of fastmod is based on the following paper by Daniel Lemire et al.
614
* Faster Remainder by Direct Computation: Applications to Compilers and Software Libraries
615
* https://arxiv.org/abs/1902.01961
616
*/
617
static _FORCE_INLINE_ uint32_t fastmod(const uint32_t n, const uint64_t c, const uint32_t d) {
618
#if defined(_MSC_VER)
619
// Returns the upper 64 bits of the product of two 64-bit unsigned integers.
620
// This intrinsic function is required since MSVC does not support unsigned 128-bit integers.
621
#if defined(_M_X64) || defined(_M_ARM64)
622
return __umulh(c * n, d);
623
#else
624
// Fallback to the slower method for 32-bit platforms.
625
return n % d;
626
#endif // _M_X64 || _M_ARM64
627
#else
628
#ifdef __SIZEOF_INT128__
629
// Prevent compiler warning, because we know what we are doing.
630
uint64_t lowbits = c * n;
631
__extension__ typedef unsigned __int128 uint128;
632
return static_cast<uint64_t>(((uint128)lowbits * d) >> 64);
633
#else
634
// Fallback to the slower method if no 128-bit unsigned integer type is available.
635
return n % d;
636
#endif // __SIZEOF_INT128__
637
#endif // _MSC_VER
638
}
639
640