/src/glaze/include/glaze/api/xxh64.hpp
Line | Count | Source |
1 | | // Glaze Library |
2 | | // For the license information refer to glaze.hpp |
3 | | |
4 | | // Copyright (c) 2015 Daniel Kirchner |
5 | | // |
6 | | // Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | | // of this software and associated documentation files (the "Software"), to deal |
8 | | // in the Software without restriction, including without limitation the rights |
9 | | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | | // copies of the Software, and to permit persons to whom the Software is |
11 | | // furnished to do so, subject to the following conditions: |
12 | | // |
13 | | // The above copyright notice and this permission notice shall be included in |
14 | | // all copies or substantial portions of the Software. |
15 | | // |
16 | | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
21 | | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
22 | | // THE SOFTWARE. |
23 | | |
24 | | #pragma once |
25 | | |
26 | | #include <cstdint> |
27 | | |
28 | | // https://github.com/Cyan4973/xxHash |
29 | | // http://cyan4973.github.io/xxHash/ |
30 | | |
31 | | struct xxh64 |
32 | | { |
33 | | static constexpr uint64_t hash(const char* p, uint64_t len, uint64_t seed) |
34 | 0 | { |
35 | 0 | return finalize((len >= 32 ? h32bytes(p, len, seed) : seed + PRIME5) + len, p + (len & ~0x1F), len & 0x1F); |
36 | 0 | } |
37 | | |
38 | | private: |
39 | | static constexpr uint64_t PRIME1 = 11400714785074694791ULL; |
40 | | static constexpr uint64_t PRIME2 = 14029467366897019727ULL; |
41 | | static constexpr uint64_t PRIME3 = 1609587929392839161ULL; |
42 | | static constexpr uint64_t PRIME4 = 9650029242287828579ULL; |
43 | | static constexpr uint64_t PRIME5 = 2870177450012600261ULL; |
44 | | |
45 | 0 | static constexpr uint64_t rotl(uint64_t x, int r) { return ((x << r) | (x >> (64 - r))); } |
46 | | static constexpr uint64_t mix1(const uint64_t h, const uint64_t prime, int rshift) |
47 | 0 | { |
48 | 0 | return (h ^ (h >> rshift)) * prime; |
49 | 0 | } |
50 | 0 | static constexpr uint64_t mix2(const uint64_t p, const uint64_t v = 0) { return rotl(v + p * PRIME2, 31) * PRIME1; } |
51 | 0 | static constexpr uint64_t mix3(const uint64_t h, const uint64_t v) { return (h ^ mix2(v)) * PRIME1 + PRIME4; } |
52 | | #ifdef XXH64_BIG_ENDIAN |
53 | | static constexpr uint32_t endian32(const char* v) |
54 | | { |
55 | | return uint32_t(uint8_t(v[3])) | (uint32_t(uint8_t(v[2])) << 8) | (uint32_t(uint8_t(v[1])) << 16) | |
56 | | (uint32_t(uint8_t(v[0])) << 24); |
57 | | } |
58 | | static constexpr uint64_t endian64(const char* v) |
59 | | { |
60 | | return uint64_t(uint8_t(v[7])) | (uint64_t(uint8_t(v[6])) << 8) | (uint64_t(uint8_t(v[5])) << 16) | |
61 | | (uint64_t(uint8_t(v[4])) << 24) | (uint64_t(uint8_t(v[3])) << 32) | (uint64_t(uint8_t(v[2])) << 40) | |
62 | | (uint64_t(uint8_t(v[1])) << 48) | (uint64_t(uint8_t(v[0])) << 56); |
63 | | } |
64 | | #else |
65 | | static constexpr uint32_t endian32(const char* v) |
66 | 0 | { |
67 | 0 | return uint32_t(uint8_t(v[0])) | (uint32_t(uint8_t(v[1])) << 8) | (uint32_t(uint8_t(v[2])) << 16) | |
68 | 0 | (uint32_t(uint8_t(v[3])) << 24); |
69 | 0 | } |
70 | | static constexpr uint64_t endian64(const char* v) |
71 | 0 | { |
72 | 0 | return uint64_t(uint8_t(v[0])) | (uint64_t(uint8_t(v[1])) << 8) | (uint64_t(uint8_t(v[2])) << 16) | |
73 | 0 | (uint64_t(uint8_t(v[3])) << 24) | (uint64_t(uint8_t(v[4])) << 32) | (uint64_t(uint8_t(v[5])) << 40) | |
74 | 0 | (uint64_t(uint8_t(v[6])) << 48) | (uint64_t(uint8_t(v[7])) << 56); |
75 | 0 | } |
76 | | #endif |
77 | 0 | static constexpr uint64_t fetch64(const char* p, const uint64_t v = 0) { return mix2(endian64(p), v); } |
78 | 0 | static constexpr uint64_t fetch32(const char* p) { return uint64_t(endian32(p)) * PRIME1; } |
79 | 0 | static constexpr uint64_t fetch8(const char* p) { return uint8_t(*p) * PRIME5; } |
80 | | static constexpr uint64_t finalize(const uint64_t h, const char* p, uint64_t len) |
81 | 0 | { |
82 | 0 | return (len >= 8) ? (finalize(rotl(h ^ fetch64(p), 27) * PRIME1 + PRIME4, p + 8, len - 8)) |
83 | 0 | : ((len >= 4) ? (finalize(rotl(h ^ fetch32(p), 23) * PRIME2 + PRIME3, p + 4, len - 4)) |
84 | 0 | : ((len > 0) ? (finalize(rotl(h ^ fetch8(p), 11) * PRIME1, p + 1, len - 1)) |
85 | 0 | : (mix1(mix1(mix1(h, PRIME2, 33), PRIME3, 29), 1, 32)))); |
86 | 0 | } |
87 | | static constexpr uint64_t h32bytes(const char* p, uint64_t len, const uint64_t v1, const uint64_t v2, |
88 | | const uint64_t v3, const uint64_t v4) |
89 | 0 | { |
90 | 0 | return (len >= 32) |
91 | 0 | ? h32bytes(p + 32, len - 32, fetch64(p, v1), fetch64(p + 8, v2), fetch64(p + 16, v3), |
92 | 0 | fetch64(p + 24, v4)) |
93 | 0 | : mix3(mix3(mix3(mix3(rotl(v1, 1) + rotl(v2, 7) + rotl(v3, 12) + rotl(v4, 18), v1), v2), v3), v4); |
94 | 0 | } |
95 | | static constexpr uint64_t h32bytes(const char* p, uint64_t len, const uint64_t seed) |
96 | 0 | { |
97 | 0 | return h32bytes(p, len, seed + PRIME1 + PRIME2, seed + PRIME2, seed, seed - PRIME1); |
98 | 0 | } |
99 | | }; |