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