dice-hash
Hash function for stl types and container
Loading...
Searching...
No Matches
xxhash.hpp
1#pragma once
2#include <array>
3#include <cstdint>
4#include <cstring>
5#include <string>
6#include <type_traits>
7#include <vector>
8
9/*
10xxHash - Extremely Fast Hash algorithm
11Header File
12Copyright (C) 2012-2020, Yann Collet.
13Copyright (C) 2017-2020, Red Gavin.
14All rights reserved.
15
16BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
17Redistribution and use in source and binary forms, with or without
18modification, are permitted provided that the following conditions are
19met:
20* Redistributions of source code must retain the above copyright
21notice, this list of conditions and the following disclaimer.
22* Redistributions in binary form must reproduce the above
23copyright notice, this list of conditions and the following disclaimer
24in the documentation and/or other materials provided with the
25distribution.
26THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37You can contact the author at :
38- xxHash source repository : https://github.com/Cyan4973/xxHash
39- xxHash C++ port repository : https://github.com/RedSpah/xxhash_cpp
40*/
41
42/* Intrinsics
43* Sadly has to be included in the global namespace or literally everything breaks
44*/
45#include <immintrin.h>
46
47namespace xxh {
48 /* *************************************
49 * Versioning
50 ***************************************/
51
52 namespace version {
53 constexpr int cpp_version_major = 0;
54 constexpr int cpp_version_minor = 7;
55 constexpr int cpp_version_release = 3;
56 }// namespace version
57
58 constexpr uint32_t version_number() {
59 return version::cpp_version_major * 10000 + version::cpp_version_minor * 100 + version::cpp_version_release;
60 }
61
62
63 /* *************************************
64 * Basic Types - Predefining uint128_t for intrin
65 ***************************************/
66
67 namespace typedefs {
68 struct alignas(16) uint128_t {
69 uint64_t low64 = 0;
70 uint64_t high64 = 0;
71
72 bool operator==(const uint128_t &other) {
73 return (low64 == other.low64 && high64 == other.high64);
74 }
75
76 bool operator>(const uint128_t &other) {
77 return (high64 > other.high64 || low64 > other.low64);
78 }
79
80 bool operator>=(const uint128_t &other) {
81 return (*this > other || *this == other);
82 }
83
84 bool operator<(const uint128_t &other) {
85 return !(*this >= other);
86 }
87
88 bool operator<=(const uint128_t &other) {
89 return !(*this > other);
90 }
91
92 bool operator!=(const uint128_t &other) {
93 return !(*this == other);
94 }
95
96 uint128_t(uint64_t low, uint64_t high) : low64(low), high64(high) {}
97
98 uint128_t() {}
99 };
100
101 }// namespace typedefs
102
104
105
106 /* *************************************
107 * Compiler / Platform Specific Features
108 ***************************************/
109
110 namespace intrin {
116#ifndef XXH_CPU_LITTLE_ENDIAN
117#define XXH_CPU_LITTLE_ENDIAN 1
118#endif
119
120
121 /* Vectorization Detection
122 * NOTE: XXH_NEON and XXH_VSX aren't supported in this C++ port.
123 * The primary reason is that I don't have access to an ARM and PowerPC
124 * machines to test them, and the secondary reason is that I even doubt anyone writing
125 * code for such machines would bother using a C++ port rather than the original C version.
126 */
127#ifndef XXH_VECTOR /* can be predefined on command line */
128#if defined(__AVX2__)
129#define XXH_VECTOR 2 /* AVX2 for Haswell and Bulldozer */
130#elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2))
131#define XXH_VECTOR 1 /* SSE2 for Pentium 4 and all x86_64 */
132#else
133#define XXH_VECTOR 0 /* Portable scalar version */
134#endif
135#endif
136
137 constexpr int vector_mode = XXH_VECTOR;
138
139#if XXH_VECTOR == 2 /* AVX2 for Haswell and Bulldozer */
140 constexpr int acc_align = 32;
141 using avx2_underlying = __m256i;
142 using sse2_underlying = __m128i;
143#elif XXH_VECTOR == 1 /* SSE2 for Pentium 4 and all x86_64 */
144 using avx2_underlying = void;//std::array<__m128i, 2>;
145 using sse2_underlying = __m128i;
146 constexpr int acc_align = 16;
147#else /* Portable scalar version */
148 using avx2_underlying = void;//std::array<uint64_t, 4>;
149 using sse2_underlying = void;//std::array<uint64_t, 2>;
150 constexpr int acc_align = 8;
151#endif
152
153
154 /* Compiler Specifics
155 * Defines inline macros and includes specific compiler's instrinsics.
156 * */
157#ifdef XXH_FORCE_INLINE /* First undefining the symbols in case they're already defined */
158#undef XXH_FORCE_INLINE
159#endif
160#ifdef XXH_NO_INLINE
161#undef XXH_NO_INLINE
162#endif
163
164#ifdef _MSC_VER /* Visual Studio */
165 #pragma warning(disable : 4127)
166#define XXH_FORCE_INLINE static __forceinline
167#define XXH_NO_INLINE static __declspec(noinline)
168#include <intrin.h>
169#elif defined(__GNUC__) /* Clang / GCC */
170#define XXH_FORCE_INLINE static inline __attribute__((always_inline))
171#define XXH_NO_INLINE static __attribute__((noinline))
172#include <mmintrin.h>
173#else
174 #define XXH_FORCE_INLINE static inline
175#define XXH_NO_INLINE static
176#endif
177
178
179 /* Prefetch
180 * Can be disabled by defining XXH_NO_PREFETCH
181 */
182#if defined(XXH_NO_PREFETCH)
183 XXH_FORCE_INLINE void prefetch(const void *ptr) {}
184#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
185 XXH_FORCE_INLINE void prefetch(const void *ptr) { _mm_prefetch((const char *) (ptr), _MM_HINT_T0); }
186#elif defined(__GNUC__)
187 XXH_FORCE_INLINE void prefetch(const void *ptr) { __builtin_prefetch((ptr), 0, 3); }
188#else
189 XXH_FORCE_INLINE void prefetch(const void *ptr) {}
190#endif
191
192
193 /* Restrict
194 * Defines macro for restrict, which in C++ is sadly just a compiler extension (for now).
195 * Can be disabled by defining XXH_NO_RESTRICT
196 */
197#ifdef XXH_RESTRICT
198#undef XXH_RESTRICT
199#endif
200
201#if (defined(__GNUC__) || defined(_MSC_VER)) && defined(__cplusplus) && !defined(XXH_NO_RESTRICT)
202#define XXH_RESTRICT __restrict
203#else
204#define XXH_RESTRICT
205#endif
206
207
208 /* Likely / Unlikely
209 * Defines macros for Likely / Unlikely, which are official in C++20, but sadly this library aims the previous standard.
210 * Not present on MSVC.
211 * Can be disabled by defining XXH_NO_BRANCH_HINTS
212 */
213#if ((defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)) && !defined(XXH_NO_BRANCH_HINTS)
214#define XXH_likely(x) __builtin_expect(x, 1)
215#define XXH_unlikely(x) __builtin_expect(x, 0)
216#else
217 #define XXH_likely(x) (x)
218#define XXH_unlikely(x) (x)
219#endif
220
221
222 namespace bit_ops {
223#if defined(_MSC_VER)
224 static inline uint32_t rotl32(uint32_t x, int32_t r) { return _rotl(x, r); }
225 static inline uint64_t rotl64(uint64_t x, int32_t r) { return _rotl64(x, r); }
226 static inline uint32_t rotr32(uint32_t x, int32_t r) { return _rotr(x, r); }
227 static inline uint64_t rotr64(uint64_t x, int32_t r) { return _rotr64(x, r); }
228#else
229 static inline uint32_t rotl32(uint32_t x, int32_t r) { return ((x << r) | (x >> (32 - r))); }
230 static inline uint64_t rotl64(uint64_t x, int32_t r) { return ((x << r) | (x >> (64 - r))); }
231 static inline uint32_t rotr32(uint32_t x, int32_t r) { return ((x >> r) | (x << (32 - r))); }
232 static inline uint64_t rotr64(uint64_t x, int32_t r) { return ((x >> r) | (x << (64 - r))); }
233#endif
234
235
236#if defined(_MSC_VER) /* Visual Studio */
237 static inline uint32_t swap32(uint32_t x) { return _byteswap_ulong(x); }
238 static inline uint64_t swap64(uint64_t x) { return _byteswap_uint64(x); }
239#elif defined(__GNUC__)
240 static inline uint32_t swap32(uint32_t x) { return __builtin_bswap32(x); }
241 static inline uint64_t swap64(uint64_t x) { return __builtin_bswap64(x); }
242#else
243 static inline uint32_t swap32(uint32_t x) { return ((x << 24) & 0xff000000) | ((x << 8) & 0x00ff0000) | ((x >> 8) & 0x0000ff00) | ((x >> 24) & 0x000000ff); }
244 static inline uint64_t swap64(uint64_t x) { return ((x << 56) & 0xff00000000000000ULL) | ((x << 40) & 0x00ff000000000000ULL) | ((x << 24) & 0x0000ff0000000000ULL) | ((x << 8) & 0x000000ff00000000ULL) | ((x >> 8) & 0x00000000ff000000ULL) | ((x >> 24) & 0x0000000000ff0000ULL) | ((x >> 40) & 0x000000000000ff00ULL) | ((x >> 56) & 0x00000000000000ffULL); }
245#endif
246
247
248#if defined(_MSC_VER) && defined(_M_IX86)// Only for 32-bit MSVC.
249 XXH_FORCE_INLINE uint64_t mult32to64(uint32_t x, uint32_t y) { return __emulu(x, y); }
250#else
251 XXH_FORCE_INLINE uint64_t mult32to64(uint32_t x, uint32_t y) { return (uint64_t)(uint32_t)(x) * (uint64_t)(uint32_t)(y); }
252#endif
253
254
255#if defined(__GNUC__) && !defined(__clang__) && defined(__i386__)
256 __attribute__((__target__("no-sse")))
257#endif
258 static inline uint128_t
259 mult64to128(uint64_t lhs, uint64_t rhs) {
260
261#if defined(__GNUC__) && !defined(__wasm__) && defined(__SIZEOF_INT128__) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128)
262
263 __uint128_t product = (__uint128_t) lhs * (__uint128_t) rhs;
264 uint128_t const r128 = {(uint64_t)(product), (uint64_t)(product >> 64)};
265 return r128;
266
267#elif defined(_M_X64) || defined(_M_IA64)
268
269 #ifndef _MSC_VER
270#pragma intrinsic(_umul128)
271#endif
272 uint64_t product_high;
273 uint64_t const product_low = _umul128(lhs, rhs, &product_high);
274 return uint128_t{product_low, product_high};
275#else
276 uint64_t const lo_lo = bit_ops::mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF);
277 uint64_t const hi_lo = bit_ops::mult32to64(lhs >> 32, rhs & 0xFFFFFFFF);
278 uint64_t const lo_hi = bit_ops::mult32to64(lhs & 0xFFFFFFFF, rhs >> 32);
279 uint64_t const hi_hi = bit_ops::mult32to64(lhs >> 32, rhs >> 32);
280
281 /* Now add the products together. These will never overflow. */
282 uint64_t const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi;
283 uint64_t const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi;
284 uint64_t const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF);
285
286 uint128_t r128 = {lower, upper};
287 return r128;
288#endif
289 }
290 }// namespace bit_ops
291 } // namespace intrin
292
293
294 /* *************************************
295 * Basic Types - Everything else
296 ***************************************/
297
298 namespace typedefs {
299 /* *************************************
300 * Basic Types - Detail
301 ***************************************/
302
303 template<size_t N>
304 struct hash_type {
305 using type = void;
306 };
307
308 template<>
309 struct hash_type<32> {
310 using type = uint32_t;
311 };
312
313 template<>
314 struct hash_type<64> {
315 using type = uint64_t;
316 };
317
318 template<>
319 struct hash_type<128> {
320 using type = uint128_t;
321 };
322
323
324 template<size_t N>
325 struct vec_type {
326 using type = void;
327 };
328
329 template<>
330 struct vec_type<64> {
331 using type = uint64_t;
332 };
333
334 template<>
335 struct vec_type<128> {
336 using type = intrin::sse2_underlying;
337 };
338
339 template<>
340 struct vec_type<256> {
341 using type = intrin::avx2_underlying;
342 };
343
344 /* Rationale
345 * On the surface level uint_type appears to be pointless,
346 * as it is just a copy of hash_type. They do use the same types,
347 * that is true, but the reasoning for the difference is aimed at humans,
348 * not the compiler, as a difference between values that are 'just' numbers,
349 * and those that represent actual hash values.
350 */
351 template<size_t N>
352 struct uint_type {
353 using type = void;
354 };
355
356 template<>
357 struct uint_type<32> {
358 using type = uint32_t;
359 };
360
361 template<>
362 struct uint_type<64> {
363 using type = uint64_t;
364 };
365
366 template<>
367 struct uint_type<128> {
368 using type = uint128_t;
369 };
370 }// namespace typedefs
371
372 template<size_t N>
373 using hash_t = typename typedefs::hash_type<N>::type;
374 using hash32_t = hash_t<32>;
375 using hash64_t = hash_t<64>;
376 using hash128_t = hash_t<128>;
377
378 template<size_t N>
379 using vec_t = typename typedefs::vec_type<N>::type;
380 using vec64_t = vec_t<64>;
381 using vec128_t = vec_t<128>;
382 using vec256_t = vec_t<256>;
383
384 template<size_t N>
385 using uint_t = typename typedefs::uint_type<N>::type;
386
387
388 /* *************************************
389 * Bit Operations
390 ***************************************/
391
392 namespace bit_ops {
393 /* ****************************************
394 * Bit Operations
395 ******************************************/
396
397 template<size_t N>
398 static inline uint_t<N> rotl(uint_t<N> n, int32_t r) {
399 if constexpr (N == 32) {
400 return intrin::bit_ops::rotl32(n, r);
401 }
402
403 if constexpr (N == 64) {
404 return intrin::bit_ops::rotl64(n, r);
405 }
406 }
407
408 template<size_t N>
409 static inline uint_t<N> rotr(uint_t<N> n, int32_t r) {
410 if constexpr (N == 32) {
411 return intrin::bit_ops::rotr32(n, r);
412 }
413
414 if constexpr (N == 64) {
415 return intrin::bit_ops::rotr64(n, r);
416 }
417 }
418
419 template<size_t N>
420 static inline uint_t<N> swap(uint_t<N> n) {
421 if constexpr (N == 32) {
422 return intrin::bit_ops::swap32(n);
423 }
424
425 if constexpr (N == 64) {
426 return intrin::bit_ops::swap64(n);
427 }
428 }
429
430 static inline uint64_t mul32to64(uint32_t x, uint32_t y) {
431 return intrin::bit_ops::mult32to64(x, y);
432 }
433
434 static inline uint128_t mul64to128(uint64_t x, uint64_t y) {
435 return intrin::bit_ops::mult64to128(x, y);
436 }
437
438 static inline uint64_t mul128fold64(uint64_t x, uint64_t y) {
439 uint128_t product = mul64to128(x, y);
440
441 return (product.low64 ^ product.high64);
442 }
443 }// namespace bit_ops
444
445
446 /* *************************************
447 * Memory Functions
448 ***************************************/
449
450 namespace mem_ops {
451
452 /* *************************************
453 * Endianness
454 ***************************************/
455
456 constexpr bool is_little_endian() {
457 return (XXH_CPU_LITTLE_ENDIAN == 1);
458 }
459
460
461 /* *************************************
462 * Memory Access
463 ***************************************/
464
465 template<size_t N>
466 static inline uint_t<N> read(const void *memPtr) {
467 uint_t<N> val;
468
469 memcpy(&val, memPtr, sizeof(val));
470 return val;
471 }
472
473 template<size_t N>
474 static inline uint_t<N> readLE(const void *ptr) {
475 if constexpr (is_little_endian()) {
476 return read<N>(ptr);
477 } else {
478 return bit_ops::swap<N>(read<N>(ptr));
479 }
480 }
481
482 template<size_t N>
483 static inline uint_t<N> readBE(const void *ptr) {
484 if constexpr (is_little_endian()) {
485 return bit_ops::swap<N>(read<N>(ptr));
486 } else {
487 return read<N>(ptr);
488 }
489 }
490
491 template<size_t N>
492 static void writeLE(void *dst, uint_t<N> v) {
493 if constexpr (!is_little_endian()) {
494 v = bit_ops::swap<N>(v);
495 }
496
497 memcpy(dst, &v, sizeof(v));
498 }
499 }// namespace mem_ops
500
501
502 /* *************************************
503 * Vector Functions
504 ***************************************/
505
506 namespace vec_ops {
507 template<size_t N>
508 XXH_FORCE_INLINE vec_t<N> loadu(const vec_t<N> *input) {
509 static_assert(!(N != 128 && N != 256 && N != 64), "Invalid template argument passed to xxh::vec_ops::loadu");
510
511 if constexpr (N == 128) {
512 return _mm_loadu_si128(input);
513 }
514
515 if constexpr (N == 256) {
516 return _mm256_loadu_si256(input);
517 }
518
519 if constexpr (N == 64) {
520 return mem_ops::readLE<64>(input);
521 }
522 }
523
524
525 // 'xorv' instead of 'xor' because 'xor' is a weird wacky alternate operator expression thing.
526 template<size_t N>
527 XXH_FORCE_INLINE vec_t<N> xorv(vec_t<N> a, vec_t<N> b) {
528 static_assert(!(N != 128 && N != 256 && N != 64), "Invalid argument passed to xxh::vec_ops::xorv");
529
530 if constexpr (N == 128) {
531 return _mm_xor_si128(a, b);
532 }
533
534 if constexpr (N == 256) {
535 return _mm256_xor_si256(a, b);
536 }
537
538 if constexpr (N == 64) {
539 return a ^ b;
540 }
541 }
542
543
544 template<size_t N>
545 XXH_FORCE_INLINE vec_t<N> mul(vec_t<N> a, vec_t<N> b) {
546 static_assert(!(N != 128 && N != 256 && N != 64), "Invalid argument passed to xxh::vec_ops::mul");
547
548 if constexpr (N == 128) {
549 return _mm_mul_epu32(a, b);
550 }
551
552 if constexpr (N == 256) {
553 return _mm256_mul_epu32(a, b);
554 }
555
556 if constexpr (N == 64) {
557 return a * b;
558 }
559 }
560
561
562 template<size_t N>
563 XXH_FORCE_INLINE vec_t<N> add(vec_t<N> a, vec_t<N> b) {
564 static_assert(!(N != 128 && N != 256 && N != 64), "Invalid argument passed to xxh::vec_ops::add");
565
566 if constexpr (N == 128) {
567 return _mm_add_epi64(a, b);
568 }
569
570 if constexpr (N == 256) {
571 return _mm256_add_epi64(a, b);
572 }
573
574 if constexpr (N == 64) {
575 return a + b;
576 }
577 }
578
579
580 template<size_t N, uint8_t S1, uint8_t S2, uint8_t S3, uint8_t S4>
581 XXH_FORCE_INLINE vec_t<N> shuffle(vec_t<N> a) {
582 static_assert(!(N != 128 && N != 256 && N != 64), "Invalid argument passed to xxh::vec_ops::shuffle");
583
584 if constexpr (N == 128) {
585 return _mm_shuffle_epi32(a, _MM_SHUFFLE(S1, S2, S3, S4));
586 }
587
588 if constexpr (N == 256) {
589 return _mm256_shuffle_epi32(a, _MM_SHUFFLE(S1, S2, S3, S4));
590 }
591
592 if constexpr (N == 64) {
593 return a;
594 }
595 }
596
597
598 template<size_t N>
599 XXH_FORCE_INLINE vec_t<N> set1(int a) {
600 static_assert(!(N != 128 && N != 256 && N != 64), "Invalid argument passed to xxh::vec_ops::set1");
601
602 if constexpr (N == 128) {
603 return _mm_set1_epi32(a);
604 }
605
606 if constexpr (N == 256) {
607 return _mm256_set1_epi32(a);
608 }
609
610 if constexpr (N == 64) {
611 return a;
612 }
613 }
614
615
616 template<size_t N>
617 XXH_FORCE_INLINE vec_t<N> srli(vec_t<N> n, int a) {
618 static_assert(!(N != 128 && N != 256 && N != 64), "Invalid argument passed to xxh::vec_ops::srli");
619
620 if constexpr (N == 128) {
621 return _mm_srli_epi64(n, a);
622 }
623
624 if constexpr (N == 256) {
625 return _mm256_srli_epi64(n, a);
626 }
627
628 if constexpr (N == 64) {
629 return n >> a;
630 }
631 }
632
633
634 template<size_t N>
635 XXH_FORCE_INLINE vec_t<N> slli(vec_t<N> n, int a) {
636 static_assert(!(N != 128 && N != 256 && N != 64), "Invalid argument passed to xxh::vec_ops::slli");
637
638 if constexpr (N == 128) {
639 return _mm_slli_epi64(n, a);
640 }
641
642 if constexpr (N == 256) {
643 return _mm256_slli_epi64(n, a);
644 }
645
646 if constexpr (N == 64) {
647 return n << a;
648 }
649 }
650 }// namespace vec_ops
651
652
653 /* *************************************
654 * Algorithm Implementation - xxhash
655 ***************************************/
656
657 namespace detail {
658 using namespace mem_ops;
659 using namespace bit_ops;
660
661
662 /* *************************************
663 * Constants
664 ***************************************/
665
666 constexpr static std::array<uint32_t, 5> primes32 = {2654435761U, 2246822519U, 3266489917U, 668265263U, 374761393U};
667 constexpr static std::array<uint64_t, 5> primes64 = {11400714785074694791ULL, 14029467366897019727ULL, 1609587929392839161ULL, 9650029242287828579ULL, 2870177450012600261ULL};
668
669 template<size_t N>
670 constexpr uint_t<N> PRIME(uint64_t n) {
671 if constexpr (N == 32) {
672 return primes32[n - 1];
673 } else {
674 return primes64[n - 1];
675 }
676 }
677
678
679 /* *************************************
680 * Functions
681 ***************************************/
682
683 template<size_t N>
684 static inline uint_t<N> round(uint_t<N> seed, uint_t<N> input) {
685 seed += input * PRIME<N>(2);
686
687 if constexpr (N == 32) {
688 seed = rotl<N>(seed, 13);
689 } else {
690 seed = rotl<N>(seed, 31);
691 }
692
693 seed *= PRIME<N>(1);
694 return seed;
695 }
696
697 static inline uint64_t mergeRound64(hash64_t acc, uint64_t val) {
698 val = round<64>(0, val);
699 acc ^= val;
700 acc = acc * PRIME<64>(1) + PRIME<64>(4);
701 return acc;
702 }
703
704 static inline void endian_align_sub_mergeround(hash64_t &hash_ret, uint64_t v1, uint64_t v2, uint64_t v3, uint64_t v4) {
705 hash_ret = mergeRound64(hash_ret, v1);
706 hash_ret = mergeRound64(hash_ret, v2);
707 hash_ret = mergeRound64(hash_ret, v3);
708 hash_ret = mergeRound64(hash_ret, v4);
709 }
710
711 template<size_t N>
712 static inline hash_t<N> endian_align_sub_ending(hash_t<N> hash_ret, const uint8_t *p, const uint8_t *bEnd) {
713 if constexpr (N == 32) {
714 while ((p + 4) <= bEnd) {
715 hash_ret += readLE<32>(p) * PRIME<32>(3);
716 hash_ret = rotl<32>(hash_ret, 17) * PRIME<32>(4);
717 p += 4;
718 }
719
720 while (p < bEnd) {
721 hash_ret += (*p) * PRIME<32>(5);
722 hash_ret = rotl<32>(hash_ret, 11) * PRIME<32>(1);
723 p++;
724 }
725
726 hash_ret ^= hash_ret >> 15;
727 hash_ret *= PRIME<32>(2);
728 hash_ret ^= hash_ret >> 13;
729 hash_ret *= PRIME<32>(3);
730 hash_ret ^= hash_ret >> 16;
731
732 return hash_ret;
733 } else {
734 while (p + 8 <= bEnd) {
735 const uint64_t k1 = round<64>(0, readLE<64>(p));
736
737 hash_ret ^= k1;
738 hash_ret = rotl<64>(hash_ret, 27) * PRIME<64>(1) + PRIME<64>(4);
739 p += 8;
740 }
741
742 if (p + 4 <= bEnd) {
743 hash_ret ^= static_cast<uint64_t>(readLE<32>(p)) * PRIME<64>(1);
744 hash_ret = rotl<64>(hash_ret, 23) * PRIME<64>(2) + PRIME<64>(3);
745 p += 4;
746 }
747
748 while (p < bEnd) {
749 hash_ret ^= (*p) * PRIME<64>(5);
750 hash_ret = rotl<64>(hash_ret, 11) * PRIME<64>(1);
751 p++;
752 }
753
754 hash_ret ^= hash_ret >> 33;
755 hash_ret *= PRIME<64>(2);
756 hash_ret ^= hash_ret >> 29;
757 hash_ret *= PRIME<64>(3);
758 hash_ret ^= hash_ret >> 32;
759
760 return hash_ret;
761 }
762 }
763
764 template<size_t N>
765 static inline hash_t<N> endian_align(const void *input, size_t len, uint_t<N> seed) {
766 static_assert(!(N != 32 && N != 64), "You can only call endian_align in 32 or 64 bit mode.");
767
768 const uint8_t *p = static_cast<const uint8_t *>(input);
769 const uint8_t *bEnd = p + len;
770 hash_t<N> hash_ret;
771
772 if (len >= (N / 2)) {
773 const uint8_t *const limit = bEnd - (N / 2);
774 uint_t<N> v1 = seed + PRIME<N>(1) + PRIME<N>(2);
775 uint_t<N> v2 = seed + PRIME<N>(2);
776 uint_t<N> v3 = seed + 0;
777 uint_t<N> v4 = seed - PRIME<N>(1);
778
779 do {
780 v1 = round<N>(v1, readLE<N>(p));
781 p += (N / 8);
782 v2 = round<N>(v2, readLE<N>(p));
783 p += (N / 8);
784 v3 = round<N>(v3, readLE<N>(p));
785 p += (N / 8);
786 v4 = round<N>(v4, readLE<N>(p));
787 p += (N / 8);
788 } while (p <= limit);
789
790 hash_ret = rotl<N>(v1, 1) + rotl<N>(v2, 7) + rotl<N>(v3, 12) + rotl<N>(v4, 18);
791
792 if constexpr (N == 64) {
793 endian_align_sub_mergeround(hash_ret, v1, v2, v3, v4);
794 }
795 } else {
796 hash_ret = seed + PRIME<N>(5);
797 }
798
799 hash_ret += static_cast<hash_t<N>>(len);
800
801 return endian_align_sub_ending<N>(hash_ret, p, bEnd);
802 }
803 }// namespace detail
804
805
806 /* *************************************
807 * Algorithm Implementation - xxhash3
808 ***************************************/
809
810 namespace detail3 {
811 using namespace vec_ops;
812 using namespace detail;
813 using namespace mem_ops;
814 using namespace bit_ops;
815
816
817 /* *************************************
818 * Enums
819 ***************************************/
820
821 enum class acc_width : uint8_t { acc_64bits,
822 acc_128bits };
823 enum class vec_mode : uint8_t { scalar = 0,
824 sse2 = 1,
825 avx2 = 2 };
826
827
828 /* *************************************
829 * Constants
830 ***************************************/
831
832 constexpr uint64_t secret_default_size = 192;
833 constexpr uint64_t secret_size_min = 136;
834 constexpr uint64_t secret_consume_rate = 8;
835 constexpr uint64_t stripe_len = 64;
836 constexpr uint64_t acc_nb = 8;
837 constexpr uint64_t prefetch_distance = 384;
838 constexpr uint64_t secret_lastacc_start = 7;
839 constexpr uint64_t secret_mergeaccs_start = 11;
840 constexpr uint64_t midsize_max = 240;
841 constexpr uint64_t midsize_startoffset = 3;
842 constexpr uint64_t midsize_lastoffset = 17;
843
844 constexpr vec_mode vector_mode = static_cast<vec_mode>(intrin::vector_mode);
845 constexpr uint64_t acc_align = intrin::acc_align;
846 constexpr std::array<uint64_t, 3> vector_bit_width{64, 128, 256};
847
848
849 /* *************************************
850 * Defaults
851 ***************************************/
852
853 alignas(64) constexpr uint8_t default_secret[secret_default_size] = {
854 0xb8,
855 0xfe,
856 0x6c,
857 0x39,
858 0x23,
859 0xa4,
860 0x4b,
861 0xbe,
862 0x7c,
863 0x01,
864 0x81,
865 0x2c,
866 0xf7,
867 0x21,
868 0xad,
869 0x1c,
870 0xde,
871 0xd4,
872 0x6d,
873 0xe9,
874 0x83,
875 0x90,
876 0x97,
877 0xdb,
878 0x72,
879 0x40,
880 0xa4,
881 0xa4,
882 0xb7,
883 0xb3,
884 0x67,
885 0x1f,
886 0xcb,
887 0x79,
888 0xe6,
889 0x4e,
890 0xcc,
891 0xc0,
892 0xe5,
893 0x78,
894 0x82,
895 0x5a,
896 0xd0,
897 0x7d,
898 0xcc,
899 0xff,
900 0x72,
901 0x21,
902 0xb8,
903 0x08,
904 0x46,
905 0x74,
906 0xf7,
907 0x43,
908 0x24,
909 0x8e,
910 0xe0,
911 0x35,
912 0x90,
913 0xe6,
914 0x81,
915 0x3a,
916 0x26,
917 0x4c,
918 0x3c,
919 0x28,
920 0x52,
921 0xbb,
922 0x91,
923 0xc3,
924 0x00,
925 0xcb,
926 0x88,
927 0xd0,
928 0x65,
929 0x8b,
930 0x1b,
931 0x53,
932 0x2e,
933 0xa3,
934 0x71,
935 0x64,
936 0x48,
937 0x97,
938 0xa2,
939 0x0d,
940 0xf9,
941 0x4e,
942 0x38,
943 0x19,
944 0xef,
945 0x46,
946 0xa9,
947 0xde,
948 0xac,
949 0xd8,
950 0xa8,
951 0xfa,
952 0x76,
953 0x3f,
954 0xe3,
955 0x9c,
956 0x34,
957 0x3f,
958 0xf9,
959 0xdc,
960 0xbb,
961 0xc7,
962 0xc7,
963 0x0b,
964 0x4f,
965 0x1d,
966 0x8a,
967 0x51,
968 0xe0,
969 0x4b,
970 0xcd,
971 0xb4,
972 0x59,
973 0x31,
974 0xc8,
975 0x9f,
976 0x7e,
977 0xc9,
978 0xd9,
979 0x78,
980 0x73,
981 0x64,
982 0xea,
983 0xc5,
984 0xac,
985 0x83,
986 0x34,
987 0xd3,
988 0xeb,
989 0xc3,
990 0xc5,
991 0x81,
992 0xa0,
993 0xff,
994 0xfa,
995 0x13,
996 0x63,
997 0xeb,
998 0x17,
999 0x0d,
1000 0xdd,
1001 0x51,
1002 0xb7,
1003 0xf0,
1004 0xda,
1005 0x49,
1006 0xd3,
1007 0x16,
1008 0x55,
1009 0x26,
1010 0x29,
1011 0xd4,
1012 0x68,
1013 0x9e,
1014 0x2b,
1015 0x16,
1016 0xbe,
1017 0x58,
1018 0x7d,
1019 0x47,
1020 0xa1,
1021 0xfc,
1022 0x8f,
1023 0xf8,
1024 0xb8,
1025 0xd1,
1026 0x7a,
1027 0xd0,
1028 0x31,
1029 0xce,
1030 0x45,
1031 0xcb,
1032 0x3a,
1033 0x8f,
1034 0x95,
1035 0x16,
1036 0x04,
1037 0x28,
1038 0xaf,
1039 0xd7,
1040 0xfb,
1041 0xca,
1042 0xbb,
1043 0x4b,
1044 0x40,
1045 0x7e,
1046 };
1047
1048 constexpr std::array<uint64_t, 8> init_acc = {PRIME<32>(3), PRIME<64>(1), PRIME<64>(2), PRIME<64>(3), PRIME<64>(4), PRIME<32>(2), PRIME<64>(5), PRIME<32>(1)};
1049
1050
1051 /* *************************************
1052 * Functions
1053 ***************************************/
1054
1055 static hash_t<64> avalanche(hash_t<64> h64) {
1056 constexpr uint64_t avalanche_mul_prime = 0x165667919E3779F9ULL;
1057
1058 h64 ^= h64 >> 37;
1059 h64 *= avalanche_mul_prime;
1060 h64 ^= h64 >> 32;
1061 return h64;
1062 }
1063
1064 template<vec_mode V>
1065 XXH_FORCE_INLINE void accumulate_512(void *XXH_RESTRICT acc, const void *XXH_RESTRICT input, const void *XXH_RESTRICT secret, acc_width width) {
1066 constexpr uint64_t bits = vector_bit_width[static_cast<uint8_t>(V)];
1067
1068 using vec_t = vec_t<bits>;
1069
1070 alignas(sizeof(vec_t)) vec_t *const xacc = static_cast<vec_t *>(acc);
1071 const vec_t *const xinput = static_cast<const vec_t *>(input);
1072 const vec_t *const xsecret = static_cast<const vec_t *>(secret);
1073
1074 for (size_t i = 0; i < stripe_len / sizeof(vec_t); i++) {
1075 vec_t const data_vec = loadu<bits>(xinput + i);
1076 vec_t const key_vec = loadu<bits>(xsecret + i);
1077 vec_t const data_key = xorv<bits>(data_vec, key_vec);
1078 vec_t product = set1<bits>(0);
1079
1080 if constexpr (V != vec_mode::scalar) {
1081 vec_t const data_key_lo = shuffle<bits, 0, 3, 0, 1>(data_key);
1082
1083 product = mul<bits>(data_key, data_key_lo);
1084
1085 if (width == acc_width::acc_128bits) {
1086 vec_t const data_swap = shuffle<bits, 1, 0, 3, 2>(data_vec);
1087 vec_t const sum = add<bits>(xacc[i], data_swap);
1088
1089 xacc[i] = add<bits>(sum, product);
1090 } else {
1091 vec_t const sum = add<bits>(xacc[i], data_vec);
1092
1093 xacc[i] = add<bits>(sum, product);
1094 }
1095 } else {
1096 product = mul32to64(data_key & 0xFFFFFFFF, data_key >> 32);
1097
1098 if (width == acc_width::acc_128bits) {
1099 xacc[i ^ 1] = add<bits>(xacc[i ^ 1], data_vec);
1100 } else {
1101 xacc[i] = add<bits>(xacc[i], data_vec);
1102 }
1103
1104 xacc[i] = add<bits>(xacc[i], product);
1105 }
1106 }
1107 }
1108
1109 template<vec_mode V>
1110 XXH_FORCE_INLINE void scramble_acc(void *XXH_RESTRICT acc, const void *XXH_RESTRICT secret) {
1111 constexpr uint64_t bits = vector_bit_width[static_cast<uint8_t>(V)];
1112 ;
1113
1114 using vec_t = vec_t<bits>;
1115
1116 alignas(sizeof(vec_t)) vec_t *const xacc = (vec_t *) acc;
1117 const vec_t *const xsecret = (const vec_t *) secret;
1118
1119 for (size_t i = 0; i < stripe_len / sizeof(vec_t); i++) {
1120 vec_t const acc_vec = xacc[i];
1121 vec_t const shifted = srli<bits>(acc_vec, 47);
1122 vec_t const data_vec = xorv<bits>(acc_vec, shifted);
1123 vec_t const key_vec = loadu<bits>(xsecret + i);
1124 vec_t const data_key = xorv<bits>(data_vec, key_vec);
1125
1126 if constexpr (V != vec_mode::scalar) {
1127 vec_t const prime32 = set1<bits>(PRIME<32>(1));
1128 vec_t const data_key_hi = shuffle<bits, 0, 3, 0, 1>(data_key);
1129 vec_t const prod_lo = mul<bits>(data_key, prime32);
1130 vec_t const prod_hi = mul<bits>(data_key_hi, prime32);
1131
1132 xacc[i] = add<bits>(prod_lo, vec_ops::slli<bits>(prod_hi, 32));
1133 } else {
1134 xacc[i] = mul<bits>(data_key, PRIME<32>(1));
1135 }
1136 }
1137 }
1138
1139 XXH_FORCE_INLINE void accumulate(uint64_t *XXH_RESTRICT acc, const uint8_t *XXH_RESTRICT input, const uint8_t *XXH_RESTRICT secret, size_t nbStripes, acc_width accWidth) {
1140 for (size_t n = 0; n < nbStripes; n++) {
1141 const uint8_t *const in = input + n * stripe_len;
1142
1143 intrin::prefetch(in + prefetch_distance);
1144 accumulate_512<vector_mode>(acc, in, secret + n * secret_consume_rate, accWidth);
1145 }
1146 }
1147
1148 XXH_FORCE_INLINE void hash_long_internal_loop(uint64_t *XXH_RESTRICT acc, const uint8_t *XXH_RESTRICT input, size_t len, const uint8_t *XXH_RESTRICT secret, size_t secretSize, acc_width accWidth) {
1149 size_t const nb_rounds = (secretSize - stripe_len) / secret_consume_rate;
1150 size_t const block_len = stripe_len * nb_rounds;
1151 size_t const nb_blocks = len / block_len;
1152
1153 for (size_t n = 0; n < nb_blocks; n++) {
1154 accumulate(acc, input + n * block_len, secret, nb_rounds, accWidth);
1155 scramble_acc<vector_mode>(acc, secret + secretSize - stripe_len);
1156 }
1157
1158 /* last partial block */
1159 size_t const nbStripes = (len - (block_len * nb_blocks)) / stripe_len;
1160
1161 accumulate(acc, input + nb_blocks * block_len, secret, nbStripes, accWidth);
1162
1163 /* last stripe */
1164 if (len & (stripe_len - 1)) {
1165 const uint8_t *const p = input + len - stripe_len;
1166
1167 accumulate_512<vector_mode>(acc, p, secret + secretSize - stripe_len - secret_lastacc_start, accWidth);
1168 }
1169 }
1170
1171 XXH_FORCE_INLINE uint64_t mix_2_accs(const uint64_t *XXH_RESTRICT acc, const uint8_t *XXH_RESTRICT secret) {
1172 return mul128fold64(acc[0] ^ readLE<64>(secret), acc[1] ^ readLE<64>(secret + 8));
1173 }
1174
1175 XXH_FORCE_INLINE uint64_t merge_accs(const uint64_t *XXH_RESTRICT acc, const uint8_t *XXH_RESTRICT secret, uint64_t start) {
1176 uint64_t result64 = start;
1177
1178 result64 += mix_2_accs(acc + 0, secret + 0);
1179 result64 += mix_2_accs(acc + 2, secret + 16);
1180 result64 += mix_2_accs(acc + 4, secret + 32);
1181 result64 += mix_2_accs(acc + 6, secret + 48);
1182
1183 return avalanche(result64);
1184 }
1185
1186 XXH_FORCE_INLINE void init_custom_secret(uint8_t *customSecret, uint64_t seed) {
1187 for (uint64_t i = 0; i < secret_default_size / 16; i++) {
1188 writeLE<64>(customSecret + i * 16, readLE<64>(default_secret + i * 16) + seed);
1189 writeLE<64>(customSecret + i * 16 + 8, readLE<64>(default_secret + i * 16 + 8) - seed);
1190 }
1191 }
1192
1193 template<size_t N>
1194 XXH_FORCE_INLINE hash_t<N> len_1to3(const uint8_t *input, size_t len, const uint8_t *secret, uint64_t seed) {
1195 if constexpr (N == 64) {
1196 uint8_t const c1 = input[0];
1197 uint8_t const c2 = input[len >> 1];
1198 uint8_t const c3 = input[len - 1];
1199 uint32_t const combined = ((uint32_t) c1 << 16) | (((uint32_t) c2) << 24) | (((uint32_t) c3) << 0) | (((uint32_t) len) << 8);
1200 uint64_t const bitflip = (readLE<32>(secret) ^ readLE<32>(secret + 4)) + seed;
1201 uint64_t const keyed = (uint64_t) combined ^ bitflip;
1202 uint64_t const mixed = keyed * PRIME<64>(1);
1203
1204 return avalanche(mixed);
1205 } else {
1206 uint8_t const c1 = input[0];
1207 uint8_t const c2 = input[len >> 1];
1208 uint8_t const c3 = input[len - 1];
1209 uint32_t const combinedl = ((uint32_t) c1 << 16) + (((uint32_t) c2) << 24) + (((uint32_t) c3) << 0) + (((uint32_t) len) << 8);
1210 uint32_t const combinedh = rotl<32>(swap<32>(combinedl), 13);
1211 uint64_t const bitflipl = (readLE<32>(secret) ^ readLE<32>(secret + 4)) + seed;
1212 uint64_t const bitfliph = (readLE<32>(secret + 8) ^ readLE<32>(secret + 12)) - seed;
1213 uint64_t const keyed_lo = (uint64_t) combinedl ^ bitflipl;
1214 uint64_t const keyed_hi = (uint64_t) combinedh ^ bitfliph;
1215 uint64_t const mixedl = keyed_lo * PRIME<64>(1);
1216 uint64_t const mixedh = keyed_hi * PRIME<64>(5);
1217 hash128_t const h128 = {avalanche(mixedl), avalanche(mixedh)};
1218
1219 return h128;
1220 }
1221 }
1222
1223 template<size_t N>
1224 XXH_FORCE_INLINE hash_t<N> len_4to8(const uint8_t *input, size_t len, const uint8_t *secret, uint64_t seed) {
1225 constexpr uint64_t mix_constant = 0x9FB21C651E98DF25ULL;
1226
1227 seed ^= (uint64_t) swap<32>((uint32_t) seed) << 32;
1228
1229 if constexpr (N == 64) {
1230 uint32_t const input1 = readLE<32>(input);
1231 uint32_t const input2 = readLE<32>(input + len - 4);
1232 uint64_t const bitflip = (readLE<64>(secret + 8) ^ readLE<64>(secret + 16)) - seed;
1233 uint64_t const input64 = input2 + ((uint64_t) input1 << 32);
1234 uint64_t x = input64 ^ bitflip;
1235
1236 x ^= rotl<64>(x, 49) ^ rotl<64>(x, 24);
1237 x *= mix_constant;
1238 x ^= (x >> 35) + len;
1239 x *= mix_constant;
1240
1241 return (x ^ (x >> 28));
1242 } else {
1243 uint32_t const input_lo = readLE<32>(input);
1244 uint32_t const input_hi = readLE<32>(input + len - 4);
1245 uint64_t const input_64 = input_lo + ((uint64_t) input_hi << 32);
1246 uint64_t const bitflip = (readLE<64>(secret + 16) ^ readLE<64>(secret + 24)) + seed;
1247 uint64_t const keyed = input_64 ^ bitflip;
1248 uint128_t m128 = mul64to128(keyed, PRIME<64>(1) + (len << 2));
1249
1250 m128.high64 += (m128.low64 << 1);
1251 m128.low64 ^= (m128.high64 >> 3);
1252 m128.low64 ^= (m128.low64 >> 35);
1253 m128.low64 *= mix_constant;
1254 m128.low64 ^= (m128.low64 >> 28);
1255 m128.high64 = avalanche(m128.high64);
1256
1257 return m128;
1258 }
1259 }
1260
1261 template<size_t N>
1262 XXH_FORCE_INLINE hash_t<N> len_9to16(const uint8_t *input, size_t len, const uint8_t *secret, uint64_t seed) {
1263 if constexpr (N == 64) {
1264 uint64_t const bitflip1 = (readLE<64>(secret + 24) ^ readLE<64>(secret + 32)) + seed;
1265 uint64_t const bitflip2 = (readLE<64>(secret + 40) ^ readLE<64>(secret + 48)) - seed;
1266 uint64_t const input_lo = readLE<64>(input) ^ bitflip1;
1267 uint64_t const input_hi = readLE<64>(input + len - 8) ^ bitflip2;
1268 uint64_t const acc = len + swap<64>(input_lo) + input_hi + mul128fold64(input_lo, input_hi);
1269
1270 return avalanche(acc);
1271 } else {
1272 uint64_t const bitflipl = (readLE<64>(secret + 32) ^ readLE<64>(secret + 40)) - seed;
1273 uint64_t const bitfliph = (readLE<64>(secret + 48) ^ readLE<64>(secret + 56)) + seed;
1274 uint64_t const input_lo = readLE<64>(input);
1275 uint64_t input_hi = readLE<64>(input + len - 8);
1276 uint128_t m128 = mul64to128(input_lo ^ input_hi ^ bitflipl, PRIME<64>(1));
1277
1278 m128.low64 += (uint64_t)(len - 1) << 54;
1279 input_hi ^= bitfliph;
1280
1281 if constexpr (sizeof(void *) < sizeof(uint64_t))// 32-bit version
1282 {
1283 m128.high64 += (input_hi & 0xFFFFFFFF00000000) + mul32to64((uint32_t) input_hi, PRIME<32>(2));
1284 } else {
1285 m128.high64 += input_hi + mul32to64((uint32_t) input_hi, PRIME<32>(2) - 1);
1286 }
1287
1288 m128.low64 ^= swap<64>(m128.high64);
1289
1290 hash128_t h128 = mul64to128(m128.low64, PRIME<64>(2));
1291
1292 h128.high64 += m128.high64 * PRIME<64>(2);
1293 h128.low64 = avalanche(h128.low64);
1294 h128.high64 = avalanche(h128.high64);
1295
1296 return h128;
1297 }
1298 }
1299
1300 template<size_t N>
1301 XXH_FORCE_INLINE hash_t<N> len_0to16(const uint8_t *input, size_t len, const uint8_t *secret, uint64_t seed) {
1302 if (XXH_likely(len > 8)) {
1303 return len_9to16<N>(input, len, secret, seed);
1304 } else if (XXH_likely(len >= 4)) {
1305 return len_4to8<N>(input, len, secret, seed);
1306 } else if (len) {
1307 return len_1to3<N>(input, len, secret, seed);
1308 } else {
1309 if constexpr (N == 64) {
1310 return avalanche((PRIME<64>(1) + seed) ^ (readLE<64>(secret + 56) ^ readLE<64>(secret + 64)));
1311 } else {
1312 uint64_t const bitflipl = readLE<64>(secret + 64) ^ readLE<64>(secret + 72);
1313 uint64_t const bitfliph = readLE<64>(secret + 80) ^ readLE<64>(secret + 88);
1314
1315 return hash128_t(avalanche((PRIME<64>(1) + seed) ^ bitflipl), avalanche((PRIME<64>(2) - seed) ^ bitfliph));
1316 }
1317 }
1318 }
1319
1320 template<size_t N>
1321 XXH_FORCE_INLINE hash_t<N> hash_long_internal(const uint8_t *XXH_RESTRICT input, size_t len, const uint8_t *XXH_RESTRICT secret = default_secret, size_t secretSize = sizeof(default_secret)) {
1322 alignas(acc_align) std::array<uint64_t, acc_nb> acc = init_acc;
1323
1324 if constexpr (N == 64) {
1325 hash_long_internal_loop(acc.data(), input, len, secret, secretSize, acc_width::acc_64bits);
1326
1327 /* converge into final hash */
1328 return merge_accs(acc.data(), secret + secret_mergeaccs_start, (uint64_t) len * PRIME<64>(1));
1329 } else {
1330 hash_long_internal_loop(acc.data(), input, len, secret, secretSize, acc_width::acc_128bits);
1331
1332 /* converge into final hash */
1333 uint64_t const low64 = merge_accs(acc.data(), secret + secret_mergeaccs_start, (uint64_t) len * PRIME<64>(1));
1334 uint64_t const high64 = merge_accs(acc.data(), secret + secretSize - sizeof(acc) - secret_mergeaccs_start, ~((uint64_t) len * PRIME<64>(2)));
1335
1336 return hash128_t(low64, high64);
1337 }
1338 }
1339
1340 XXH_FORCE_INLINE uint64_t mix_16b(const uint8_t *XXH_RESTRICT input, const uint8_t *XXH_RESTRICT secret, uint64_t seed) {
1341 uint64_t const input_lo = readLE<64>(input);
1342 uint64_t const input_hi = readLE<64>(input + 8);
1343
1344 return mul128fold64(input_lo ^ (readLE<64>(secret) + seed), input_hi ^ (readLE<64>(secret + 8) - seed));
1345 }
1346
1347 XXH_FORCE_INLINE uint128_t mix_32b(uint128_t acc, const uint8_t *input1, const uint8_t *input2, const uint8_t *secret, uint64_t seed) {
1348 acc.low64 += mix_16b(input1, secret + 0, seed);
1349 acc.low64 ^= readLE<64>(input2) + readLE<64>(input2 + 8);
1350 acc.high64 += mix_16b(input2, secret + 16, seed);
1351 acc.high64 ^= readLE<64>(input1) + readLE<64>(input1 + 8);
1352
1353 return acc;
1354 }
1355
1356 template<size_t N>
1357 XXH_FORCE_INLINE hash_t<N> len_17to128(const uint8_t *XXH_RESTRICT input, size_t len, const uint8_t *XXH_RESTRICT secret, uint64_t seed) {
1358 if constexpr (N == 64) {
1359 hash64_t acc = len * PRIME<64>(1);
1360
1361 if (len > 32) {
1362 if (len > 64) {
1363 if (len > 96) {
1364 acc += mix_16b(input + 48, secret + 96, seed);
1365 acc += mix_16b(input + len - 64, secret + 112, seed);
1366 }
1367
1368 acc += mix_16b(input + 32, secret + 64, seed);
1369 acc += mix_16b(input + len - 48, secret + 80, seed);
1370 }
1371
1372 acc += mix_16b(input + 16, secret + 32, seed);
1373 acc += mix_16b(input + len - 32, secret + 48, seed);
1374 }
1375
1376 acc += mix_16b(input + 0, secret + 0, seed);
1377 acc += mix_16b(input + len - 16, secret + 16, seed);
1378
1379 return avalanche(acc);
1380 } else {
1381 hash128_t acc = {len * PRIME<64>(1), 0};
1382
1383 if (len > 32) {
1384 if (len > 64) {
1385 if (len > 96) {
1386 acc = mix_32b(acc, input + 48, input + len - 64, secret + 96, seed);
1387 }
1388
1389 acc = mix_32b(acc, input + 32, input + len - 48, secret + 64, seed);
1390 }
1391
1392 acc = mix_32b(acc, input + 16, input + len - 32, secret + 32, seed);
1393 }
1394
1395 acc = mix_32b(acc, input, input + len - 16, secret, seed);
1396
1397 uint64_t const low64 = acc.low64 + acc.high64;
1398 uint64_t const high64 = (acc.low64 * PRIME<64>(1)) + (acc.high64 * PRIME<64>(4)) + ((len - seed) * PRIME<64>(2));
1399
1400 return {avalanche(low64), (uint64_t) 0 - avalanche(high64)};
1401 }
1402 }
1403
1404 template<size_t N>
1405 XXH_NO_INLINE hash_t<N> len_129to240(const uint8_t *XXH_RESTRICT input, size_t len, const uint8_t *XXH_RESTRICT secret, uint64_t seed) {
1406 if constexpr (N == 64) {
1407 uint64_t acc = len * PRIME<64>(1);
1408 size_t const nbRounds = len / 16;
1409
1410 for (size_t i = 0; i < 8; i++) {
1411 acc += mix_16b(input + (i * 16), secret + (i * 16), seed);
1412 }
1413
1414 acc = avalanche(acc);
1415
1416 for (size_t i = 8; i < nbRounds; i++) {
1417 acc += mix_16b(input + (i * 16), secret + ((i - 8) * 16) + midsize_startoffset, seed);
1418 }
1419
1420 /* last bytes */
1421 acc += mix_16b(input + len - 16, secret + secret_size_min - midsize_lastoffset, seed);
1422
1423 return avalanche(acc);
1424 } else {
1425 hash128_t acc;
1426 uint64_t const nbRounds = len / 32;
1427
1428 acc.low64 = len * PRIME<64>(1);
1429 acc.high64 = 0;
1430
1431 for (size_t i = 0; i < 4; i++) {
1432 acc = mix_32b(acc, input + (i * 32), input + (i * 32) + 16, secret + (i * 32), seed);
1433 }
1434
1435 acc.low64 = avalanche(acc.low64);
1436 acc.high64 = avalanche(acc.high64);
1437
1438 for (size_t i = 4; i < nbRounds; i++) {
1439 acc = mix_32b(acc, input + (i * 32), input + (i * 32) + 16, secret + midsize_startoffset + ((i - 4) * 32), seed);
1440 }
1441
1442 /* last bytes */
1443 acc = mix_32b(acc, input + len - 16, input + len - 32, secret + secret_size_min - midsize_lastoffset - 16, 0ULL - seed);
1444
1445 uint64_t const low64 = acc.low64 + acc.high64;
1446 uint64_t const high64 = (acc.low64 * PRIME<64>(1)) + (acc.high64 * PRIME<64>(4)) + ((len - seed) * PRIME<64>(2));
1447
1448 return {avalanche(low64), (uint64_t) 0 - avalanche(high64)};
1449 }
1450 }
1451
1452 template<size_t N>
1453 XXH_NO_INLINE hash_t<N> xxhash3_impl(const void *XXH_RESTRICT input, size_t len, hash64_t seed, const void *XXH_RESTRICT secret = default_secret, size_t secretSize = secret_default_size) {
1454 alignas(8) uint8_t custom_secret[secret_default_size];
1455 const void *short_secret = secret;
1456
1457 if (seed != 0) {
1458 init_custom_secret(custom_secret, seed);
1459 secret = custom_secret;
1460 secretSize = secret_default_size;
1461 short_secret = default_secret;
1462 }
1463
1464 if (len <= 16) {
1465 return len_0to16<N>(static_cast<const uint8_t *>(input), len, static_cast<const uint8_t *>(short_secret), seed);
1466 } else if (len <= 128) {
1467 return len_17to128<N>(static_cast<const uint8_t *>(input), len, static_cast<const uint8_t *>(short_secret), seed);
1468 } else if (len <= midsize_max) {
1469 return len_129to240<N>(static_cast<const uint8_t *>(input), len, static_cast<const uint8_t *>(short_secret), seed);
1470 } else {
1471 return hash_long_internal<N>(static_cast<const uint8_t *>(input), len, static_cast<const uint8_t *>(secret), secretSize);
1472 }
1473 }
1474 }// namespace detail3
1475
1476
1477 /* *************************************
1478 * Public Access Point - xxhash
1479 ***************************************/
1480
1481 template<size_t bit_mode>
1482 inline hash_t<bit_mode> xxhash(const void *input, size_t len, uint_t<bit_mode> seed = 0) {
1483 static_assert(!(bit_mode != 32 && bit_mode != 64), "xxhash can only be used in 32 and 64 bit modes.");
1484 return detail::endian_align<bit_mode>(input, len, seed);
1485 }
1486
1487 template<size_t bit_mode, typename T>
1488 inline hash_t<bit_mode> xxhash(const std::basic_string<T> &input, uint_t<bit_mode> seed = 0) {
1489 static_assert(!(bit_mode != 32 && bit_mode != 64), "xxhash can only be used in 32 and 64 bit modes.");
1490 return detail::endian_align<bit_mode>(static_cast<const void *>(input.data()), input.length() * sizeof(T), seed);
1491 }
1492
1493 template<size_t bit_mode, typename ContiguousIterator>
1494 inline hash_t<bit_mode> xxhash(ContiguousIterator begin, ContiguousIterator end, uint_t<bit_mode> seed = 0) {
1495 static_assert(!(bit_mode != 32 && bit_mode != 64), "xxhash can only be used in 32 and 64 bit modes.");
1496 using T = typename std::decay_t<decltype(*end)>;
1497 return detail::endian_align<bit_mode>(static_cast<const void *>(&*begin), (end - begin) * sizeof(T), seed);
1498 }
1499
1500 template<size_t bit_mode, typename T>
1501 inline hash_t<bit_mode> xxhash(const std::vector<T> &input, uint_t<bit_mode> seed = 0) {
1502 static_assert(!(bit_mode != 32 && bit_mode != 64), "xxhash can only be used in 32 and 64 bit modes.");
1503 return detail::endian_align<bit_mode>(static_cast<const void *>(input.data()), input.size() * sizeof(T), seed);
1504 }
1505
1506 template<size_t bit_mode, typename T, size_t AN>
1507 inline hash_t<bit_mode> xxhash(const std::array<T, AN> &input, uint_t<bit_mode> seed = 0) {
1508 static_assert(!(bit_mode != 32 && bit_mode != 64), "xxhash can only be used in 32 and 64 bit modes.");
1509 return detail::endian_align<bit_mode>(static_cast<const void *>(input.data()), AN * sizeof(T), seed);
1510 }
1511
1512 template<size_t bit_mode, typename T>
1513 inline hash_t<bit_mode> xxhash(const std::initializer_list<T> &input, uint_t<bit_mode> seed = 0) {
1514 static_assert(!(bit_mode != 32 && bit_mode != 64), "xxhash can only be used in 32 and 64 bit modes.");
1515 return detail::endian_align<bit_mode>(static_cast<const void *>(input.begin()), input.size() * sizeof(T), seed);
1516 }
1517
1518
1519 /* *************************************
1520 * Public Access Point - xxhash3
1521 ***************************************/
1522
1523 template<size_t bit_mode>
1524 inline hash_t<bit_mode> xxhash3(const void *input, size_t len, uint64_t seed = 0) {
1525 static_assert(!(bit_mode != 128 && bit_mode != 64), "xxhash3 can only be used in 64 and 128 bit modes.");
1526 return detail3::xxhash3_impl<bit_mode>(input, len, seed);
1527 }
1528
1529 template<size_t bit_mode>
1530 inline hash_t<bit_mode> xxhash3(const void *input, size_t len, const void *secret, size_t secretSize) {
1531 static_assert(!(bit_mode != 128 && bit_mode != 64), "xxhash3 can only be used in 64 and 128 bit modes.");
1532 return detail3::xxhash3_impl<bit_mode>(input, len, 0, secret, secretSize);
1533 }
1534
1535 template<size_t bit_mode, typename T>
1536 inline hash_t<bit_mode> xxhash3(const std::basic_string<T> &input, uint64_t seed = 0) {
1537 static_assert(!(bit_mode != 128 && bit_mode != 64), "xxhash3 can only be used in 64 and 128 bit modes.");
1538 return detail3::xxhash3_impl<bit_mode>(static_cast<const void *>(input.data()), input.length() * sizeof(T), seed);
1539 }
1540
1541 template<size_t bit_mode, typename T>
1542 inline hash_t<bit_mode> xxhash3(const std::basic_string<T> &input, const void *secret, size_t secretSize) {
1543 static_assert(!(bit_mode != 128 && bit_mode != 64), "xxhash3 can only be used in 64 and 128 bit modes.");
1544 return detail3::xxhash3_impl<bit_mode>(static_cast<const void *>(input.data()), input.length() * sizeof(T), 0, secret, secretSize);
1545 }
1546
1547 template<size_t N, typename ContiguousIterator>
1548 inline hash_t<N> xxhash3(ContiguousIterator begin, ContiguousIterator end, uint64_t seed = 0) {
1549 static_assert(!(N != 128 && N != 64), "xxhash3 can only be used in 64 and 128 bit modes.");
1550 using T = typename std::decay_t<decltype(*end)>;
1551 return detail3::xxhash3_impl<N>(static_cast<const void *>(&*begin), (end - begin) * sizeof(T), seed);
1552 }
1553
1554 template<size_t bit_mode, typename ContiguousIterator>
1555 inline hash_t<bit_mode> xxhash3(ContiguousIterator begin, ContiguousIterator end, const void *secret, size_t secretSize) {
1556 static_assert(!(bit_mode != 128 && bit_mode != 64), "xxhash3 can only be used in 64 and 128 bit modes.");
1557 using T = typename std::decay_t<decltype(*end)>;
1558 return detail3::xxhash3_impl<bit_mode>(static_cast<const void *>(&*begin), (end - begin) * sizeof(T), 0, secret, secretSize);
1559 }
1560
1561 template<size_t bit_mode, typename T>
1562 inline hash_t<bit_mode> xxhash3(const std::vector<T> &input, uint64_t seed = 0) {
1563 static_assert(!(bit_mode != 128 && bit_mode != 64), "xxhash3 can only be used in 64 and 128 bit modes.");
1564 return detail3::xxhash3_impl<bit_mode>(static_cast<const void *>(input.data()), input.size() * sizeof(T), seed);
1565 }
1566
1567 template<size_t bit_mode, typename T>
1568 inline hash_t<bit_mode> xxhash3(const std::vector<T> &input, const void *secret, size_t secretSize) {
1569 static_assert(!(bit_mode != 128 && bit_mode != 64), "xxhash3 can only be used in 64 and 128 bit modes.");
1570 return detail3::xxhash3_impl<bit_mode>(static_cast<const void *>(input.data()), input.size() * sizeof(T), 0, secret, secretSize);
1571 }
1572
1573 template<size_t bit_mode, typename T, size_t AN>
1574 inline hash_t<bit_mode> xxhash3(const std::array<T, AN> &input, uint64_t seed = 0) {
1575 static_assert(!(bit_mode != 128 && bit_mode != 64), "xxhash3 can only be used in 64 and 128 bit modes.");
1576 return detail3::xxhash3_impl<bit_mode>(static_cast<const void *>(input.data()), AN * sizeof(T), seed);
1577 }
1578
1579 template<size_t bit_mode, typename T, size_t AN>
1580 inline hash_t<bit_mode> xxhash3(const std::array<T, AN> &input, const void *secret, size_t secretSize) {
1581 static_assert(!(bit_mode != 128 && bit_mode != 64), "xxhash3 can only be used in 64 and 128 bit modes.");
1582 return detail3::xxhash3_impl<bit_mode>(static_cast<const void *>(input.data()), AN * sizeof(T), 0, secret, secretSize);
1583 }
1584
1585 template<size_t bit_mode, typename T>
1586 inline hash_t<bit_mode> xxhash3(const std::initializer_list<T> &input, uint64_t seed = 0) {
1587 static_assert(!(bit_mode != 128 && bit_mode != 64), "xxhash3 can only be used in 64 and 128 bit modes.");
1588 return detail3::xxhash3_impl<bit_mode>(static_cast<const void *>(input.begin()), input.size() * sizeof(T), seed);
1589 }
1590
1591 template<size_t bit_mode, typename T>
1592 inline hash_t<bit_mode> xxhash3(const std::initializer_list<T> &input, const void *secret, size_t secretSize) {
1593 static_assert(!(bit_mode != 128 && bit_mode != 64), "xxhash3 can only be used in 64 and 128 bit modes.");
1594 return detail3::xxhash3_impl<bit_mode>(static_cast<const void *>(input.begin()), input.size() * sizeof(T), 0, secret, secretSize);
1595 }
1596
1597
1598 /* *************************************
1599 * Hash streaming - xxhash
1600 ***************************************/
1601
1602 template<size_t bit_mode>
1604 uint64_t total_len = 0;
1605 uint_t<bit_mode> v1 = 0, v2 = 0, v3 = 0, v4 = 0;
1606 std::array<hash_t<bit_mode>, 4> mem = {0, 0, 0, 0};
1607 uint32_t memsize = 0;
1608
1609 inline void update_impl(const void *input, size_t length) {
1610 const uint8_t *p = reinterpret_cast<const uint8_t *>(input);
1611 const uint8_t *const bEnd = p + length;
1612
1613 total_len += length;
1614
1615 if (memsize + length < (bit_mode / 2)) { /* fill in tmp buffer */
1616 memcpy(reinterpret_cast<uint8_t *>(mem.data()) + memsize, input, length);
1617 memsize += static_cast<uint32_t>(length);
1618 return;
1619 }
1620
1621 if (memsize > 0) { /* some data left from previous update */
1622 memcpy(reinterpret_cast<uint8_t *>(mem.data()) + memsize, input, (bit_mode / 2) - memsize);
1623
1624 const uint_t<bit_mode> *ptr = mem.data();
1625
1626 v1 = detail::round<bit_mode>(v1, mem_ops::readLE<bit_mode>(ptr));
1627 ptr++;
1628 v2 = detail::round<bit_mode>(v2, mem_ops::readLE<bit_mode>(ptr));
1629 ptr++;
1630 v3 = detail::round<bit_mode>(v3, mem_ops::readLE<bit_mode>(ptr));
1631 ptr++;
1632 v4 = detail::round<bit_mode>(v4, mem_ops::readLE<bit_mode>(ptr));
1633
1634 p += (bit_mode / 2) - memsize;
1635 memsize = 0;
1636 }
1637
1638 if (p <= bEnd - (bit_mode / 2)) {
1639 const uint8_t *const limit = bEnd - (bit_mode / 2);
1640
1641 do {
1642 v1 = detail::round<bit_mode>(v1, mem_ops::readLE<bit_mode>(p));
1643 p += (bit_mode / 8);
1644 v2 = detail::round<bit_mode>(v2, mem_ops::readLE<bit_mode>(p));
1645 p += (bit_mode / 8);
1646 v3 = detail::round<bit_mode>(v3, mem_ops::readLE<bit_mode>(p));
1647 p += (bit_mode / 8);
1648 v4 = detail::round<bit_mode>(v4, mem_ops::readLE<bit_mode>(p));
1649 p += (bit_mode / 8);
1650 } while (p <= limit);
1651 }
1652
1653 if (p < bEnd) {
1654 memcpy(mem.data(), p, static_cast<size_t>(bEnd - p));
1655 memsize = static_cast<uint32_t>(bEnd - p);
1656 }
1657 }
1658
1659 inline hash_t<bit_mode> digest_impl() const {
1660 const uint8_t *p = reinterpret_cast<const uint8_t *>(mem.data());
1661 const uint8_t *const bEnd = reinterpret_cast<const uint8_t *>(mem.data()) + memsize;
1662 hash_t<bit_mode> hash_ret;
1663
1664 if (total_len >= (bit_mode / 2)) {
1665 hash_ret = bit_ops::rotl<bit_mode>(v1, 1) + bit_ops::rotl<bit_mode>(v2, 7) + bit_ops::rotl<bit_mode>(v3, 12) + bit_ops::rotl<bit_mode>(v4, 18);
1666
1667 if constexpr (bit_mode == 64) {
1668 detail::endian_align_sub_mergeround(hash_ret, v1, v2, v3, v4);
1669 }
1670 } else {
1671 hash_ret = v3 + detail::PRIME<bit_mode>(5);
1672 }
1673
1674 hash_ret += static_cast<hash_t<bit_mode>>(total_len);
1675
1676 return detail::endian_align_sub_ending<bit_mode>(hash_ret, p, bEnd);
1677 }
1678
1679 public:
1680 hash_state_t(uint_t<bit_mode> seed = 0) {
1681 static_assert(!(bit_mode != 32 && bit_mode != 64), "xxhash streaming can only be used in 32 and 64 bit modes.");
1682 v1 = seed + detail::PRIME<bit_mode>(1) + detail::PRIME<bit_mode>(2);
1683 v2 = seed + detail::PRIME<bit_mode>(2);
1684 v3 = seed + 0;
1685 v4 = seed - detail::PRIME<bit_mode>(1);
1686 };
1687
1688 hash_state_t operator=(hash_state_t<bit_mode> &other) {
1689 memcpy(this, &other, sizeof(hash_state_t<bit_mode>));
1690 }
1691
1692 void reset(uint_t<bit_mode> seed = 0) {
1693 memset(this, 0, sizeof(hash_state_t<bit_mode>));
1694 v1 = seed + detail::PRIME<bit_mode>(1) + detail::PRIME<bit_mode>(2);
1695 v2 = seed + detail::PRIME<bit_mode>(2);
1696 v3 = seed + 0;
1697 v4 = seed - detail::PRIME<bit_mode>(1);
1698 }
1699
1700 void update(const void *input, size_t length) {
1701 return update_impl(input, length);
1702 }
1703
1704 template<typename T>
1705 void update(const std::basic_string<T> &input) {
1706 return update_impl(static_cast<const void *>(input.data()), input.length() * sizeof(T));
1707 }
1708
1709 template<typename ContiguousIterator>
1710 void update(ContiguousIterator begin, ContiguousIterator end) {
1711 using T = typename std::decay_t<decltype(*end)>;
1712 return update_impl(static_cast<const void *>(&*begin), (end - begin) * sizeof(T));
1713 }
1714
1715 template<typename T>
1716 void update(const std::vector<T> &input) {
1717 return update_impl(static_cast<const void *>(input.data()), input.size() * sizeof(T));
1718 }
1719
1720 template<typename T, size_t AN>
1721 void update(const std::array<T, AN> &input) {
1722 return update_impl(static_cast<const void *>(input.data()), AN * sizeof(T));
1723 }
1724
1725 template<typename T>
1726 void update(const std::initializer_list<T> &input) {
1727 return update_impl(static_cast<const void *>(input.begin()), input.size() * sizeof(T));
1728 }
1729
1730 hash_t<bit_mode> digest() const {
1731 return digest_impl();
1732 }
1733 };
1734
1737
1738
1739 /* *************************************
1740 * Hash streaming - xxhash3
1741 ***************************************/
1742
1743 template<size_t bit_mode>
1744 class alignas(64) hash3_state_t {
1745 constexpr static int internal_buffer_size = 256;
1746 constexpr static int internal_buffer_stripes = (internal_buffer_size / detail3::stripe_len);
1747 constexpr static detail3::acc_width accWidth = (bit_mode == 64) ? detail3::acc_width::acc_64bits : detail3::acc_width::acc_128bits;
1748
1749 alignas(64) uint64_t acc[8];
1750 alignas(64) uint8_t customSecret[detail3::secret_default_size]; /* used to store a custom secret generated from the seed. Makes state larger. Design might change */
1751 alignas(64) uint8_t buffer[internal_buffer_size];
1752 uint32_t bufferedSize = 0;
1753 uint32_t nbStripesPerBlock = 0;
1754 uint32_t nbStripesSoFar = 0;
1755 uint32_t secretLimit = 0;
1756 uint32_t reserved32 = 0;
1757 uint32_t reserved32_2 = 0;
1758 uint64_t totalLen = 0;
1759 uint64_t seed = 0;
1760 uint64_t reserved64 = 0;
1761 const uint8_t *secret = nullptr; /* note : there is some padding after, due to alignment on 64 bytes */
1762
1763
1764 void consume_stripes(uint64_t *acc, uint32_t &nbStripesSoFar, size_t totalStripes, const uint8_t *input, detail3::acc_width accWidth) {
1765 if (nbStripesPerBlock - nbStripesSoFar <= totalStripes) /* need a scrambling operation */
1766 {
1767 size_t const nbStripes = nbStripesPerBlock - nbStripesSoFar;
1768
1769 detail3::accumulate(acc, input, secret + (nbStripesSoFar * detail3::secret_consume_rate), nbStripes, accWidth);
1770 detail3::scramble_acc<detail3::vector_mode>(acc, secret + secretLimit);
1771 detail3::accumulate(acc, input + nbStripes * detail3::stripe_len, secret, totalStripes - nbStripes, accWidth);
1772 nbStripesSoFar = (uint32_t)(totalStripes - nbStripes);
1773 } else {
1774 detail3::accumulate(acc, input, secret + (nbStripesSoFar * detail3::secret_consume_rate), totalStripes, accWidth);
1775 nbStripesSoFar += (uint32_t) totalStripes;
1776 }
1777 }
1778
1779 void update_impl(const void *input_, size_t len) {
1780 const uint8_t *input = static_cast<const uint8_t *>(input_);
1781 const uint8_t *const bEnd = input + len;
1782
1783 totalLen += len;
1784
1785 if (bufferedSize + len <= internal_buffer_size) { /* fill in tmp buffer */
1786 memcpy(buffer + bufferedSize, input, len);
1787 bufferedSize += (uint32_t) len;
1788 return;
1789 }
1790 /* input now > XXH3_INTERNALBUFFER_SIZE */
1791
1792 if (bufferedSize > 0) { /* some input within internal buffer: fill then consume it */
1793 size_t const loadSize = internal_buffer_size - bufferedSize;
1794
1795 memcpy(buffer + bufferedSize, input, loadSize);
1796 input += loadSize;
1797 consume_stripes(acc, nbStripesSoFar, internal_buffer_stripes, buffer, accWidth);
1798 bufferedSize = 0;
1799 }
1800
1801 /* consume input by full buffer quantities */
1802 if (input + internal_buffer_size <= bEnd) {
1803 const uint8_t *const limit = bEnd - internal_buffer_size;
1804
1805 do {
1806 consume_stripes(acc, nbStripesSoFar, internal_buffer_stripes, input, accWidth);
1807 input += internal_buffer_size;
1808 } while (input <= limit);
1809 }
1810
1811 if (input < bEnd) { /* some remaining input input : buffer it */
1812 memcpy(buffer, input, (size_t)(bEnd - input));
1813 bufferedSize = (uint32_t)(bEnd - input);
1814 }
1815 }
1816
1817 void digest_long(uint64_t *acc_, detail3::acc_width accWidth) {
1818 memcpy(acc_, acc, sizeof(acc)); /* digest locally, state remains unaltered, and can continue ingesting more input afterwards */
1819
1820 if (bufferedSize >= detail3::stripe_len) {
1821 size_t const totalNbStripes = bufferedSize / detail3::stripe_len;
1822 uint32_t nbStripesSoFar = this->nbStripesSoFar;
1823
1824 consume_stripes(acc_, nbStripesSoFar, totalNbStripes, buffer, accWidth);
1825
1826 if (bufferedSize % detail3::stripe_len) { /* one last partial stripe */
1827 detail3::accumulate_512<detail3::vector_mode>(acc_, buffer + bufferedSize - detail3::stripe_len, secret + secretLimit - detail3::secret_lastacc_start, accWidth);
1828 }
1829 } else { /* bufferedSize < STRIPE_LEN */
1830 if (bufferedSize > 0) { /* one last stripe */
1831 uint8_t lastStripe[detail3::stripe_len];
1832 size_t const catchupSize = detail3::stripe_len - bufferedSize;
1833 memcpy(lastStripe, buffer + sizeof(buffer) - catchupSize, catchupSize);
1834 memcpy(lastStripe + catchupSize, buffer, bufferedSize);
1835 detail3::accumulate_512<detail3::vector_mode>(acc_, lastStripe, secret + secretLimit - detail3::secret_lastacc_start, accWidth);
1836 }
1837 }
1838 }
1839
1840 public:
1841 hash3_state_t operator=(hash3_state_t &other) {
1842 memcpy(this, &other, sizeof(hash3_state_t));
1843 }
1844
1845 hash3_state_t(uint64_t seed = 0) {
1846 static_assert(!(bit_mode != 128 && bit_mode != 64), "xxhash3 streaming can only be used in 64 and 128 bit modes.");
1847 reset(seed);
1848 }
1849
1850 hash3_state_t(const void *secret, size_t secretSize) {
1851 static_assert(!(bit_mode != 128 && bit_mode != 64), "xxhash3 streaming can only be used in 64 and 128 bit modes.");
1852 reset(secret, secretSize);
1853 }
1854
1855 void reset(uint64_t seed = 0) {
1856 memset(this, 0, sizeof(*this));
1857 memcpy(acc, detail3::init_acc.data(), sizeof(detail3::init_acc));
1858 (*this).seed = seed;
1859
1860 if (seed == 0) {
1861 secret = detail3::default_secret;
1862 } else {
1863 detail3::init_custom_secret(customSecret, seed);
1864 secret = customSecret;
1865 }
1866
1867 secretLimit = (uint32_t)(detail3::secret_default_size - detail3::stripe_len);
1868 nbStripesPerBlock = secretLimit / detail3::secret_consume_rate;
1869 }
1870
1871 void reset(const void *secret, size_t secretSize) {
1872 memset(this, 0, sizeof(*this));
1873 memcpy(acc, detail3::init_acc.data(), sizeof(detail3::init_acc));
1874 seed = 0;
1875
1876 (*this).secret = (const uint8_t *) secret;
1877 secretLimit = (uint32_t)(secretSize - detail3::stripe_len);
1878 nbStripesPerBlock = secretLimit / detail3::secret_consume_rate;
1879 }
1880
1881 void update(const void *input, size_t len) {
1882 return update_impl(static_cast<const void *>(input), len);
1883 }
1884
1885 template<typename T>
1886 void update(const std::basic_string<T> &input) {
1887 return update_impl(static_cast<const void *>(input.data()), input.length() * sizeof(T));
1888 }
1889
1890 template<typename ContiguousIterator>
1891 void update(ContiguousIterator begin, ContiguousIterator end) {
1892 using T = typename std::decay_t<decltype(*end)>;
1893 return update_impl(static_cast<const void *>(&*begin), (end - begin) * sizeof(T));
1894 }
1895
1896 template<typename T>
1897 void update(const std::vector<T> &input) {
1898 return update_impl(static_cast<const void *>(input.data()), input.size() * sizeof(T));
1899 }
1900
1901 template<typename T, size_t AN>
1902 void update(const std::array<T, AN> &input) {
1903 return update_impl(static_cast<const void *>(input.data()), AN * sizeof(T));
1904 }
1905
1906 template<typename T>
1907 void update(const std::initializer_list<T> &input) {
1908 return update_impl(static_cast<const void *>(input.begin()), input.size() * sizeof(T));
1909 }
1910
1911 hash_t<bit_mode> digest() {
1912 if (totalLen > detail3::midsize_max) {
1913 alignas(detail3::acc_align) hash64_t acc[detail3::acc_nb];
1914
1915 digest_long(acc, accWidth);
1916
1917 if constexpr (bit_mode == 64) {
1918 return detail3::merge_accs(acc, secret + detail3::secret_mergeaccs_start, (uint64_t) totalLen * detail::PRIME<64>(1));
1919 } else {
1920 uint64_t const low64 = detail3::merge_accs(acc, secret + detail3::secret_mergeaccs_start, (uint64_t) totalLen * detail::PRIME<64>(1));
1921 uint64_t const high64 = detail3::merge_accs(acc, secret + secretLimit + detail3::stripe_len - sizeof(acc) - detail3::secret_mergeaccs_start, ~((uint64_t) totalLen * detail::PRIME<64>(2)));
1922
1923 return {low64, high64};
1924 }
1925 } else {
1926 return detail3::xxhash3_impl<bit_mode>(buffer, totalLen, seed, secret, secretLimit + detail3::stripe_len);
1927 }
1928 }
1929 };
1930
1933
1934
1935 /* *************************************
1936 * Canonical represenation
1937 ***************************************/
1938
1939 template<size_t bit_mode>
1941 std::array<uint8_t, bit_mode / 8> digest{0};
1942
1943 canonical_t(hash_t<bit_mode> hash) {
1944 if constexpr (bit_mode < 128) {
1945 if (mem_ops::is_little_endian()) {
1946 hash = bit_ops::swap<bit_mode>(hash);
1947 }
1948
1949 memcpy(digest.data(), &hash, sizeof(canonical_t<bit_mode>));
1950 } else {
1951 if (mem_ops::is_little_endian()) {
1952 hash.low64 = bit_ops::swap<64>(hash.low64);
1953 hash.high64 = bit_ops::swap<64>(hash.high64);
1954 }
1955
1956 memcpy(digest.data(), &hash.high64, sizeof(hash.high64));
1957 memcpy(digest.data() + sizeof(hash.high64), &hash.low64, sizeof(hash.low64));
1958 }
1959 }
1960
1961 hash_t<bit_mode> get_hash() const {
1962 if constexpr (bit_mode < 128) {
1963 return mem_ops::readBE<bit_mode>(&digest);
1964 } else {
1965 return {mem_ops::readBE<64>(&digest[8]), mem_ops::readBE<64>(&digest)};
1966 }
1967 }
1968 };
1969
1973}// namespace xxh
Definition xxhash.hpp:1744
Definition xxhash.hpp:1603
Definition xxhash.hpp:1940
Definition xxhash.hpp:304
Definition xxhash.hpp:68
Definition xxhash.hpp:352
Definition xxhash.hpp:325