Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
hash-fct.C
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
32# include <ctime>
33# include <gsl/gsl_rng.h>
34# include <stdexcept>
35# include <limits>
36# include <mutex>
37# include <shared_mutex>
38# include <atomic>
39# include "hash-fct.H"
40
41# include <ah-errors.H>
42
43namespace Aleph
44{
45
46const unsigned Default_Hash_Seed = 52679987;
47
48static long tab[256];
49
50// once_flag guards the one-time population of tab[].
51// is_jsw_initialized() needs a separate atomic so it can be queried without
52// re-entering the once_flag.
53static std::once_flag jsw_init_flag;
54static std::atomic<bool> init{false};
55
56// shared_mutex: readers (jsw_hash) acquire shared lock; writer (init_jsw(seed))
57// acquires exclusive lock, preventing data races during re-seed.
58static std::shared_mutex jsw_mtx;
59
60// ============================================================================
61// Helpers
62// ============================================================================
63
64#ifdef __GNUC__
65#define FORCE_INLINE __attribute__((always_inline)) inline
66#else
67#define FORCE_INLINE inline
68#endif
69
71{
72 return (x << r) | (x >> (32 - r));
73}
74
76{
77 return (x << r) | (x >> (64 - r));
78}
79
80#define ROTL32(x,y) rotl32(x,y)
81#define ROTL64(x,y) rotl64(x,y)
82
83#define BIG_CONSTANT(x) (x##LLU)
84
85//-----------------------------------------------------------------------------
86// Block read - if your platform needs to do endian-swapping or can only
87// handle aligned reads, do the conversion here
88
89#define getblock(p, i) (p[i])
90
91//-----------------------------------------------------------------------------
92// Finalization mix - force all bits of a hash block to avalanche
93
95{
96 h ^= h >> 16;
97 h *= 0x85ebca6b;
98 h ^= h >> 13;
99 h *= 0xc2b2ae35;
100 h ^= h >> 16;
101
102 return h;
103}
104
106{
107 k ^= k >> 33;
108 k *= BIG_CONSTANT(0xff51afd7ed558ccd);
109 k ^= k >> 33;
110 k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
111 k ^= k >> 33;
112
113 return k;
114}
115
116static FORCE_INLINE size_t fold_hash64_to_size_t(std::uint64_t hash) noexcept
117{
118 if constexpr (std::numeric_limits<size_t>::digits >= 64)
119 return static_cast<size_t>(hash);
120 else
121 {
122 constexpr unsigned bits = std::numeric_limits<size_t>::digits;
123 const std::uint64_t mask = (std::uint64_t{1} << bits) - 1;
124 hash ^= hash >> bits;
125 return static_cast<size_t>(hash & mask);
126 }
127}
128
129static FORCE_INLINE std::uint32_t read_le32(const std::uint8_t * p) noexcept
130{
131 return static_cast<std::uint32_t>(p[0])
132 | (static_cast<std::uint32_t>(p[1]) << 8)
133 | (static_cast<std::uint32_t>(p[2]) << 16)
134 | (static_cast<std::uint32_t>(p[3]) << 24);
135}
136
137static FORCE_INLINE std::uint64_t read_le64(const std::uint8_t * p) noexcept
138{
139 return static_cast<std::uint64_t>(p[0])
140 | (static_cast<std::uint64_t>(p[1]) << 8)
141 | (static_cast<std::uint64_t>(p[2]) << 16)
142 | (static_cast<std::uint64_t>(p[3]) << 24)
143 | (static_cast<std::uint64_t>(p[4]) << 32)
144 | (static_cast<std::uint64_t>(p[5]) << 40)
145 | (static_cast<std::uint64_t>(p[6]) << 48)
146 | (static_cast<std::uint64_t>(p[7]) << 56);
147}
148
149static FORCE_INLINE void write_le32(std::uint8_t * p, std::uint32_t value) noexcept
150{
151 p[0] = static_cast<std::uint8_t>(value);
152 p[1] = static_cast<std::uint8_t>(value >> 8);
153 p[2] = static_cast<std::uint8_t>(value >> 16);
154 p[3] = static_cast<std::uint8_t>(value >> 24);
155}
156
157static FORCE_INLINE void write_le64(std::uint8_t * p, std::uint64_t value) noexcept
158{
159 write_le32(p, static_cast<std::uint32_t>(value));
160 write_le32(p + 4, static_cast<std::uint32_t>(value >> 32));
161}
162
163static FORCE_INLINE std::uint64_t mul_xor_fold64(std::uint64_t lhs,
164 std::uint64_t rhs) noexcept
165{
166#ifdef __SIZEOF_INT128__
167 const __uint128_t prod = static_cast<__uint128_t>(lhs) * rhs;
168 return static_cast<std::uint64_t>(prod)
169 ^ static_cast<std::uint64_t>(prod >> 64);
170#else
171 const std::uint64_t lhs_lo = lhs & 0xffffffffULL;
172 const std::uint64_t lhs_hi = lhs >> 32;
173 const std::uint64_t rhs_lo = rhs & 0xffffffffULL;
174 const std::uint64_t rhs_hi = rhs >> 32;
175 const std::uint64_t ll = lhs_lo * rhs_lo;
176 const std::uint64_t lh = lhs_lo * rhs_hi;
177 const std::uint64_t hl = lhs_hi * rhs_lo;
178 const std::uint64_t hh = lhs_hi * rhs_hi;
179 // Accumulate the low 64 bits in two separate additions and track carries
180 // individually. A single `if (low < ll)` would miss a carry from the
181 // second addition when both additions overflow.
182 const std::uint64_t mid = lh << 32;
183 std::uint64_t low = ll + mid;
184 std::uint64_t carry = low < ll ? 1u : 0u;
185 const std::uint64_t mid2 = hl << 32;
186 low += mid2;
187 carry += low < mid2 ? 1u : 0u;
188 std::uint64_t high = hh + (lh >> 32) + (hl >> 32) + carry;
189 return low ^ high;
190#endif
191}
192
193static FORCE_INLINE std::uint64_t xxh64_round(std::uint64_t acc,
194 std::uint64_t input) noexcept
195{
196 constexpr std::uint64_t prime2 = 14029467366897019727ULL;
197 constexpr std::uint64_t prime1 = 11400714785074694791ULL;
198 acc += input * prime2;
199 acc = ROTL64(acc, 31);
200 acc *= prime1;
201 return acc;
202}
203
204static FORCE_INLINE std::uint64_t xxh64_merge_round(std::uint64_t acc,
205 std::uint64_t value) noexcept
206{
207 constexpr std::uint64_t prime1 = 11400714785074694791ULL;
208 constexpr std::uint64_t prime4 = 9650029242287828579ULL;
209 value = xxh64_round(0, value);
210 acc ^= value;
211 acc = acc * prime1 + prime4;
212 return acc;
213}
214
215static FORCE_INLINE std::uint64_t wyhash_mix(std::uint64_t lhs,
216 std::uint64_t rhs) noexcept
217{
218 return mul_xor_fold64(lhs, rhs);
219}
220
221static FORCE_INLINE std::uint32_t jsw_fallback_next(std::uint32_t &state) noexcept
222{
223 state = state * 1664525u + 1013904223u;
224 return state;
225}
226
227// ============================================================================
228// Initialization and classic hashes
229// ============================================================================
230
231// Internal helper: populate tab[] from a given seed.
232// Must be called either via std::call_once or with jsw_mtx held.
233static void jsw_fill_table(std::uint32_t seed) noexcept
234{
236 if (r == nullptr)
237 {
238 std::uint32_t state = seed == 0 ? Default_Hash_Seed : seed;
239 for (int i = 0; i < 256; ++i)
240 tab[i] = static_cast<long>(jsw_fallback_next(state));
241 init.store(true, std::memory_order_release);
242 return;
243 }
244
246 for (int i = 0; i < 256; ++i)
247 tab[i] = gsl_rng_get(r);
249 // Release store: any thread that subsequently reads init==true with an
250 // acquire load is guaranteed to observe the fully populated tab[].
251 init.store(true, std::memory_order_release);
252}
253
255{
256 return init.load(std::memory_order_acquire);
257}
258
259// No-arg overload uses a fixed deterministic seed so results are
260// reproducible across runs. Call init_jsw(custom_seed) before first
261// hash use if a custom seed is required.
263{
264 // std::call_once guarantees exactly-once, race-free execution even when
265 // multiple threads call jsw_hash() for the first time concurrently.
266 try
267 {
269 }
270 catch (const std::system_error &)
271 {
272 // call_once failed to acquire its internal synchronization primitive;
273 // fall back to a mutex-protected direct init so this noexcept function
274 // does not terminate the process.
275 std::unique_lock<std::shared_mutex> lock(jsw_mtx);
276 if (not init.load(std::memory_order_acquire))
278 }
279}
280
281void init_jsw(std::uint32_t seed) noexcept
282{
283 // Exclusive lock: blocks all concurrent jsw_hash() readers (shared_lock)
284 // until the new table is fully written, preventing data races during re-seed.
285 // Bypasses call_once intentionally so re-seeding with a different seed works.
286 std::unique_lock<std::shared_mutex> lock(jsw_mtx);
288}
289
290size_t jsw_hash(const void * key, size_t len) noexcept
291{
292 if (not init.load(std::memory_order_acquire))
293 {
294 // Serialize lazy init with init_jsw(seed) by acquiring the exclusive lock
295 // before call_once, so both paths go through the same mutex+once-flag.
296 std::unique_lock<std::shared_mutex> init_lock(jsw_mtx);
297 try
298 {
300 }
301 catch (const std::system_error &)
302 {
303 // Mutex already held; call directly as fallback to stay noexcept.
304 if (not init.load(std::memory_order_acquire))
306 }
307 }
308
309 // Shared lock: allows concurrent readers; excluded only during init.
310 std::shared_lock<std::shared_mutex> lock(jsw_mtx);
311 const unsigned char *p = (const unsigned char*) key;
312 size_t h = 16777551;
313
314 for (size_t i = 0; i < len; i++)
315 h = (h << 1 | h >> 31) ^ tab[p[i]];
316
317 return h;
318}
319
320size_t jsw_hash(const char * key) noexcept
321{
322 if (not init.load(std::memory_order_acquire))
323 {
324 std::unique_lock<std::shared_mutex> init_lock(jsw_mtx);
325 try
326 {
328 }
329 catch (const std::system_error &)
330 {
331 // Mutex already held; call directly as fallback to stay noexcept.
332 if (not init.load(std::memory_order_acquire))
334 }
335 }
336
337 std::shared_lock<std::shared_mutex> lock(jsw_mtx);
338 const unsigned char * p = (const unsigned char*) key;
339 size_t h = 16777551;
340
341 while (*p)
342 h = (h << 1 | h >> 31) ^ tab[*p++];
343
344 return h;
345}
346
347#define jen_mix(a,b,c) \
348{ \
349 a -= c; a ^= ROTL32(c, 4); c += b; \
350 b -= a; b ^= ROTL32(a, 6); a += c; \
351 c -= b; c ^= ROTL32(b, 8); b += a; \
352 a -= c; a ^= ROTL32(c,16); c += b; \
353 b -= a; b ^= ROTL32(a,19); a += c; \
354 c -= b; c ^= ROTL32(b, 4); b += a; \
355}
356
357#define jen_final(a,b,c) \
358{ \
359 c ^= b; c -= ROTL32(b,14); \
360 a ^= c; a -= ROTL32(c,11); \
361 b ^= a; b -= ROTL32(a,25); \
362 c ^= b; c -= ROTL32(b,16); \
363 a ^= c; a -= ROTL32(c,4); \
364 b ^= a; b -= ROTL32(a,14); \
365 c ^= b; c -= ROTL32(b,24); \
366}
367
368size_t jen_hash(const void *key, size_t length, unsigned initval) noexcept
369{
370 uint32_t a,b,c; /* internal state */
371 a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
372
373 const uint8_t *p = static_cast<const uint8_t *>(key);
374
375 /*------ all but the last block: safe reads and jen_mix() ------*/
376 while (length > 12)
377 {
378 uint32_t k[3];
379 memcpy(k, p, 12);
380 a += k[0];
381 b += k[1];
382 c += k[2];
383 jen_mix(a,b,c);
384 length -= 12;
385 p += 12;
386 }
387
388 /*----------------------------- handle the last (up to 11) bytes */
389 switch(length)
390 {
391 case 12: c+=((uint32_t)p[11])<<24; [[fallthrough]];
392 case 11: c+=((uint32_t)p[10])<<16; [[fallthrough]];
393 case 10: c+=((uint32_t)p[9])<<8; [[fallthrough]];
394 case 9 : c+=p[8]; [[fallthrough]];
395 case 8 : b+=((uint32_t)p[7])<<24; [[fallthrough]];
396 case 7 : b+=((uint32_t)p[6])<<16; [[fallthrough]];
397 case 6 : b+=((uint32_t)p[5])<<8; [[fallthrough]];
398 case 5 : b+=p[4]; [[fallthrough]];
399 case 4 : a+=((uint32_t)p[3])<<24; [[fallthrough]];
400 case 3 : a+=((uint32_t)p[2])<<16; [[fallthrough]];
401 case 2 : a+=((uint32_t)p[1])<<8; [[fallthrough]];
402 case 1 : a+=p[0];
403 break;
404 case 0 : return static_cast<size_t>(c);
405 }
406
407 jen_final(a,b,c);
408 return static_cast<size_t>(c);
409}
410
411// ============================================================================
412// Modern hashes
413// ============================================================================
414
415void MurmurHash3_x86_32 ( const void * key, int len,
416 uint32_t seed, void * out )
417{
418 const uint8_t * data = (const uint8_t*)key;
419 const int nblocks = len / 4;
420 int i;
421
422 uint32_t h1 = seed;
423
424 uint32_t c1 = 0xcc9e2d51;
425 uint32_t c2 = 0x1b873593;
426
427 //----------
428 // body
429
430 for(i = 0; i < nblocks; i++)
431 {
432 uint32_t k1 = read_le32(data + i*4);
433
434 k1 *= c1;
435 k1 = ROTL32(k1,15);
436 k1 *= c2;
437
438 h1 ^= k1;
439 h1 = ROTL32(h1,13);
440 h1 = h1*5+0xe6546b64;
441 }
442
443 //----------
444 // tail
445
446 const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
447
448 uint32_t k1 = 0;
449
450 switch(len & 3)
451 {
452 case 3: k1 ^= tail[2] << 16; [[fallthrough]];
453 case 2: k1 ^= tail[1] << 8; [[fallthrough]];
454 case 1: k1 ^= tail[0];
455 k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
456 };
457
458 //----------
459 // finalization
460
461 h1 ^= len;
462
463 h1 = fmix32(h1);
464
465 write_le32(static_cast<std::uint8_t *>(out), h1);
466}
467
468void MurmurHash3_x86_128 ( const void * key, const int len,
469 uint32_t seed, void * out )
470{
471 const uint8_t * data = (const uint8_t*)key;
472 const int nblocks = len / 16;
473 int i;
474
475 uint32_t h1 = seed;
476 uint32_t h2 = seed;
477 uint32_t h3 = seed;
478 uint32_t h4 = seed;
479
480 uint32_t c1 = 0x239b961b;
481 uint32_t c2 = 0xab0e9789;
482 uint32_t c3 = 0x38b34ae5;
483 uint32_t c4 = 0xa1e38b93;
484
485 //----------
486 // body
487
488 for(i = 0; i < nblocks; i++)
489 {
490 const uint8_t * block = data + i*16;
491 uint32_t k1 = read_le32(block);
492 uint32_t k2 = read_le32(block + 4);
493 uint32_t k3 = read_le32(block + 8);
494 uint32_t k4 = read_le32(block + 12);
495
496 k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
497
498 h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
499
500 k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
501
502 h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
503
504 k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
505
506 h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
507
508 k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
509
510 h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
511 }
512
513 //----------
514 // tail
515
516 const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
517
518 uint32_t k1 = 0;
519 uint32_t k2 = 0;
520 uint32_t k3 = 0;
521 uint32_t k4 = 0;
522
523 switch(len & 15)
524 {
525 case 15: k4 ^= tail[14] << 16; [[fallthrough]];
526 case 14: k4 ^= tail[13] << 8; [[fallthrough]];
527 case 13: k4 ^= tail[12] << 0;
528 k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
529 [[fallthrough]];
530 case 12: k3 ^= tail[11] << 24; [[fallthrough]];
531 case 11: k3 ^= tail[10] << 16; [[fallthrough]];
532 case 10: k3 ^= tail[ 9] << 8; [[fallthrough]];
533 case 9: k3 ^= tail[ 8] << 0;
534 k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
535 [[fallthrough]];
536 case 8: k2 ^= tail[ 7] << 24; [[fallthrough]];
537 case 7: k2 ^= tail[ 6] << 16; [[fallthrough]];
538 case 6: k2 ^= tail[ 5] << 8; [[fallthrough]];
539 case 5: k2 ^= tail[ 4] << 0;
540 k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
541 [[fallthrough]];
542 case 4: k1 ^= tail[ 3] << 24; [[fallthrough]];
543 case 3: k1 ^= tail[ 2] << 16; [[fallthrough]];
544 case 2: k1 ^= tail[ 1] << 8; [[fallthrough]];
545 case 1: k1 ^= tail[ 0] << 0;
546 k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
547 };
548
549 //----------
550 // finalization
551
552 h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
553
554 h1 += h2; h1 += h3; h1 += h4;
555 h2 += h1; h3 += h1; h4 += h1;
556
557 h1 = fmix32(h1);
558 h2 = fmix32(h2);
559 h3 = fmix32(h3);
560 h4 = fmix32(h4);
561
562 h1 += h2; h1 += h3; h1 += h4;
563 h2 += h1; h3 += h1; h4 += h1;
564
565 auto * out_bytes = static_cast<std::uint8_t *>(out);
567 write_le32(out_bytes + 4, h2);
568 write_le32(out_bytes + 8, h3);
569 write_le32(out_bytes + 12, h4);
570}
571
572void MurmurHash3_x64_128 ( const void * key, const int len,
573 const uint32_t seed, void * out )
574{
575 const uint8_t * data = (const uint8_t*)key;
576 const int nblocks = len / 16;
577 int i;
578
579 uint64_t h1 = seed;
580 uint64_t h2 = seed;
581
582 uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
583 uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
584
585 //----------
586 // body
587
588 for(i = 0; i < nblocks; i++)
589 {
590 const uint8_t * block = data + i*16;
591 uint64_t k1 = read_le64(block);
592 uint64_t k2 = read_le64(block + 8);
593
594 k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
595
596 h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
597
598 k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
599
600 h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
601 }
602
603 //----------
604 // tail
605
606 const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
607
608 uint64_t k1 = 0;
609 uint64_t k2 = 0;
610
611 switch(len & 15)
612 {
613 case 15: k2 ^= (uint64_t)(tail[14]) << 48; [[fallthrough]];
614 case 14: k2 ^= (uint64_t)(tail[13]) << 40; [[fallthrough]];
615 case 13: k2 ^= (uint64_t)(tail[12]) << 32; [[fallthrough]];
616 case 12: k2 ^= (uint64_t)(tail[11]) << 24; [[fallthrough]];
617 case 11: k2 ^= (uint64_t)(tail[10]) << 16; [[fallthrough]];
618 case 10: k2 ^= (uint64_t)(tail[ 9]) << 8; [[fallthrough]];
619 case 9: k2 ^= (uint64_t)(tail[ 8]) << 0;
620 k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
621 [[fallthrough]];
622 case 8: k1 ^= (uint64_t)(tail[ 7]) << 56; [[fallthrough]];
623 case 7: k1 ^= (uint64_t)(tail[ 6]) << 48; [[fallthrough]];
624 case 6: k1 ^= (uint64_t)(tail[ 5]) << 40; [[fallthrough]];
625 case 5: k1 ^= (uint64_t)(tail[ 4]) << 32; [[fallthrough]];
626 case 4: k1 ^= (uint64_t)(tail[ 3]) << 24; [[fallthrough]];
627 case 3: k1 ^= (uint64_t)(tail[ 2]) << 16; [[fallthrough]];
628 case 2: k1 ^= (uint64_t)(tail[ 1]) << 8; [[fallthrough]];
629 case 1: k1 ^= (uint64_t)(tail[ 0]) << 0;
630 k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
631 };
632
633 //----------
634 // finalization
635
636 h1 ^= len; h2 ^= len;
637
638 h1 += h2;
639 h2 += h1;
640
641 h1 = fmix64(h1);
642 h2 = fmix64(h2);
643
644 h1 += h2;
645 h2 += h1;
646
647 auto * out_bytes = static_cast<std::uint8_t *>(out);
649 write_le64(out_bytes + 8, h2);
650}
651
652size_t xxhash64_hash(const void * key, size_t len, std::uint64_t seed) noexcept
653{
654 constexpr std::uint64_t prime1 = 11400714785074694791ULL;
655 constexpr std::uint64_t prime2 = 14029467366897019727ULL;
656 constexpr std::uint64_t prime3 = 1609587929392839161ULL;
657 constexpr std::uint64_t prime4 = 9650029242287828579ULL;
658 constexpr std::uint64_t prime5 = 2870177450012600261ULL;
659
660 const auto * p = static_cast<const std::uint8_t *>(key);
661
662 // Guard against nullptr + 0 UB; compute canonical empty-buffer result.
663 if (len == 0)
664 {
665 std::uint64_t hash = seed + prime5;
666 hash ^= hash >> 33;
667 hash *= prime2;
668 hash ^= hash >> 29;
669 hash *= prime3;
670 hash ^= hash >> 32;
671 return fold_hash64_to_size_t(hash);
672 }
673
674 const auto * const end = p + len;
675 std::uint64_t hash = 0;
676
677 if (len >= 32)
678 {
679 const auto * const limit = end - 32;
680 std::uint64_t v1 = seed + prime1 + prime2;
681 std::uint64_t v2 = seed + prime2;
682 std::uint64_t v3 = seed + 0;
683 std::uint64_t v4 = seed - prime1;
684
685 do
686 {
687 v1 = xxh64_round(v1, read_le64(p)); p += 8;
688 v2 = xxh64_round(v2, read_le64(p)); p += 8;
689 v3 = xxh64_round(v3, read_le64(p)); p += 8;
690 v4 = xxh64_round(v4, read_le64(p)); p += 8;
691 }
692 while (p <= limit);
693
694 hash = ROTL64(v1, 1) + ROTL64(v2, 7) + ROTL64(v3, 12) + ROTL64(v4, 18);
695 hash = xxh64_merge_round(hash, v1);
696 hash = xxh64_merge_round(hash, v2);
697 hash = xxh64_merge_round(hash, v3);
698 hash = xxh64_merge_round(hash, v4);
699 }
700 else
701 hash = seed + prime5;
702
703 hash += len;
704
705 while (p + 8 <= end)
706 {
707 const std::uint64_t k1 = xxh64_round(0, read_le64(p));
708 hash ^= k1;
709 hash = ROTL64(hash, 27) * prime1 + prime4;
710 p += 8;
711 }
712
713 if (p + 4 <= end)
714 {
715 hash ^= static_cast<std::uint64_t>(read_le32(p)) * prime1;
716 hash = ROTL64(hash, 23) * prime2 + prime3;
717 p += 4;
718 }
719
720 while (p < end)
721 {
722 hash ^= static_cast<std::uint64_t>(*p++) * prime5;
723 hash = ROTL64(hash, 11) * prime1;
724 }
725
726 hash ^= hash >> 33;
727 hash *= prime2;
728 hash ^= hash >> 29;
729 hash *= prime3;
730 hash ^= hash >> 32;
731
732 return fold_hash64_to_size_t(hash);
733}
734
735size_t wyhash_hash(const void * key, size_t len, std::uint64_t seed) noexcept
736{
737 static constexpr std::uint64_t secret[] =
738 {
739 0xa0761d6478bd642fULL,
740 0xe7037ed1a0b428dbULL,
741 0x8ebc6af09c88c6e3ULL,
742 0x589965cc75374cc3ULL
743 };
744
745 const auto * p = static_cast<const std::uint8_t *>(key);
746 std::uint64_t a = 0;
747 std::uint64_t b = 0;
748 std::uint64_t remaining = len;
749
750 seed ^= secret[0];
751
752 auto read_wyr3 = [] (const std::uint8_t * data, size_t n) noexcept
753 {
754 return (static_cast<std::uint64_t>(data[0]) << 16)
755 | (static_cast<std::uint64_t>(data[n >> 1]) << 8)
756 | static_cast<std::uint64_t>(data[n - 1]);
757 };
758
759 if (remaining <= 16)
760 {
761 if (remaining >= 4)
762 {
763 const size_t delta = (remaining >> 3) << 2;
764 a = (static_cast<std::uint64_t>(read_le32(p)) << 32)
765 | read_le32(p + delta);
766 b = (static_cast<std::uint64_t>(read_le32(p + remaining - 4)) << 32)
767 | read_le32(p + remaining - 4 - delta);
768 }
769 else if (remaining > 0)
770 a = read_wyr3(p, remaining);
771 }
772 else
773 {
774 if (remaining > 48)
775 {
776 std::uint64_t see1 = seed;
777 std::uint64_t see2 = seed;
778 do
779 {
780 seed = wyhash_mix(read_le64(p) ^ secret[1], read_le64(p + 8) ^ seed);
781 see1 = wyhash_mix(read_le64(p + 16) ^ secret[2],
782 read_le64(p + 24) ^ see1);
783 see2 = wyhash_mix(read_le64(p + 32) ^ secret[3],
784 read_le64(p + 40) ^ see2);
785 p += 48;
786 remaining -= 48;
787 }
788 while (remaining > 48);
789 seed ^= see1 ^ see2;
790 }
791
792 while (remaining > 16)
793 {
794 seed = wyhash_mix(read_le64(p) ^ secret[1], read_le64(p + 8) ^ seed);
795 p += 16;
796 remaining -= 16;
797 }
798
799 a = read_le64(p + remaining - 16);
800 b = read_le64(p + remaining - 8);
801 }
802
803 return static_cast<size_t>(
804 wyhash_mix(secret[1] ^ len, wyhash_mix(a ^ secret[1], b ^ seed)));
805}
806
807size_t siphash24_hash(const void * key, size_t len,
808 std::uint64_t key0, std::uint64_t key1) noexcept
809{
810 const auto * in = static_cast<const std::uint8_t *>(key);
811
812 std::uint64_t v0 = 0x736f6d6570736575ULL ^ key0;
813 std::uint64_t v1 = 0x646f72616e646f6dULL ^ key1;
814 std::uint64_t v2 = 0x6c7967656e657261ULL ^ key0;
815 std::uint64_t v3 = 0x7465646279746573ULL ^ key1;
816
817 auto sipround = [&]() noexcept
818 {
819 v0 += v1;
820 v1 = ROTL64(v1, 13);
821 v1 ^= v0;
822 v0 = ROTL64(v0, 32);
823 v2 += v3;
824 v3 = ROTL64(v3, 16);
825 v3 ^= v2;
826 v0 += v3;
827 v3 = ROTL64(v3, 21);
828 v3 ^= v0;
829 v2 += v1;
830 v1 = ROTL64(v1, 17);
831 v1 ^= v2;
832 v2 = ROTL64(v2, 32);
833 };
834
835 // Guard against nullptr + 0 UB when computing end; also handles empty input.
836 if (len == 0)
837 {
838 const std::uint64_t b = 0; // len << 56 where len = 0
839 v3 ^= b;
840 sipround(); sipround();
841 v0 ^= b;
842 v2 ^= 0xff;
844 return static_cast<size_t>(v0 ^ v1 ^ v2 ^ v3);
845 }
846
847 const auto * const end = in + (len - (len & 7));
848
849 for (; in != end; in += 8)
850 {
851 const std::uint64_t m = read_le64(in);
852 v3 ^= m;
853 sipround();
854 sipround();
855 v0 ^= m;
856 }
857
858 std::uint64_t b = static_cast<std::uint64_t>(len) << 56;
859 switch (len & 7)
860 {
861 case 7: b |= static_cast<std::uint64_t>(in[6]) << 48; [[fallthrough]];
862 case 6: b |= static_cast<std::uint64_t>(in[5]) << 40; [[fallthrough]];
863 case 5: b |= static_cast<std::uint64_t>(in[4]) << 32; [[fallthrough]];
864 case 4: b |= static_cast<std::uint64_t>(in[3]) << 24; [[fallthrough]];
865 case 3: b |= static_cast<std::uint64_t>(in[2]) << 16; [[fallthrough]];
866 case 2: b |= static_cast<std::uint64_t>(in[1]) << 8; [[fallthrough]];
867 case 1: b |= static_cast<std::uint64_t>(in[0]); [[fallthrough]];
868 default: break;
869 }
870
871 v3 ^= b;
872 sipround();
873 sipround();
874 v0 ^= b;
875 v2 ^= 0xff;
876 sipround();
877 sipround();
878 sipround();
879 sipround();
880
881 return static_cast<size_t>(v0 ^ v1 ^ v2 ^ v3);
882}
883
884} // end namespace Aleph
Exception handling system with formatted messages for Aleph-w.
long double h
Definition btreepic.C:154
size_t size_t int32_t value
Definition ca-c-api.h:116
size_t size_t int32_t * out
Definition ca-c-api.h:120
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
size_t jsw_hash(const void *key, size_t len) noexcept
JSW hash (Julienne Walker)
Definition hash-fct.C:290
size_t xxhash64_hash(const void *key, size_t len, std::uint64_t seed) noexcept
xxHash64 from the xxHash family.
Definition hash-fct.C:652
size_t jen_hash(const void *key, size_t length, unsigned initval) noexcept
Jenkins hash (lookup3)
Definition hash-fct.C:368
size_t siphash24_hash(const void *key, size_t len, std::uint64_t key0, std::uint64_t key1) noexcept
SipHash-2-4 keyed hash.
Definition hash-fct.C:807
bool is_jsw_initialized() noexcept
Checks if the jsw_hash() lookup table has been initialized.
Definition hash-fct.C:254
void init_jsw() noexcept
Initializes the randomized lookup table used by jsw_hash().
Definition hash-fct.C:262
size_t wyhash_hash(const void *key, size_t len, std::uint64_t seed) noexcept
wyhash non-cryptographic hash.
Definition hash-fct.C:735
#define ROTL64(x, y)
Definition hash-fct.C:81
#define jen_final(a, b, c)
Definition hash-fct.C:357
#define BIG_CONSTANT(x)
Definition hash-fct.C:83
#define jen_mix(a, b, c)
Definition hash-fct.C:347
#define ROTL32(x, y)
Definition hash-fct.C:80
#define FORCE_INLINE
Definition hash-fct.C:67
Standard hash functions for Aleph types.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
static void write_le32(std::uint8_t *p, std::uint32_t value) noexcept
Definition hash-fct.C:149
static uint32_t fmix32(uint32_t h)
Definition hash-fct.C:94
void MurmurHash3_x86_32(const void *key, int len, uint32_t seed, void *out)
Definition hash-fct.C:415
static std::uint64_t xxh64_round(std::uint64_t acc, std::uint64_t input) noexcept
Definition hash-fct.C:193
void MurmurHash3_x64_128(const void *key, const int len, const uint32_t seed, void *out)
Definition hash-fct.C:572
static std::once_flag jsw_init_flag
Definition hash-fct.C:53
static std::uint64_t mul_xor_fold64(std::uint64_t lhs, std::uint64_t rhs) noexcept
Definition hash-fct.C:163
static std::shared_mutex jsw_mtx
Definition hash-fct.C:58
static long & low(typename GT::Node *p)
Internal helper: low-link value stored directly in NODE_COOKIE(p).
static uint32_t rotl32(uint32_t x, int8_t r)
Definition hash-fct.C:70
static std::uint64_t wyhash_mix(std::uint64_t lhs, std::uint64_t rhs) noexcept
Definition hash-fct.C:215
static long tab[256]
Definition hash-fct.C:48
static uint64_t fmix64(uint64_t k)
Definition hash-fct.C:105
static uint64_t rotl64(uint64_t x, int8_t r)
Definition hash-fct.C:75
static void write_le64(std::uint8_t *p, std::uint64_t value) noexcept
Definition hash-fct.C:157
void MurmurHash3_x86_128(const void *key, const int len, uint32_t seed, void *out)
Definition hash-fct.C:468
static std::uint64_t read_le64(const std::uint8_t *p) noexcept
Definition hash-fct.C:137
const unsigned Default_Hash_Seed
Definition hash-fct.C:46
static std::uint32_t jsw_fallback_next(std::uint32_t &state) noexcept
Definition hash-fct.C:221
static size_t fold_hash64_to_size_t(std::uint64_t hash) noexcept
Definition hash-fct.C:116
static std::uint32_t read_le32(const std::uint8_t *p) noexcept
Definition hash-fct.C:129
static void jsw_fill_table(std::uint32_t seed) noexcept
Definition hash-fct.C:233
static std::atomic< bool > init
Definition hash-fct.C:54
static std::uint64_t xxh64_merge_round(std::uint64_t acc, std::uint64_t value) noexcept
Definition hash-fct.C:204
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
ValueArg< size_t > seed
Definition testHash.C:53
static int * k
gsl_rng * r