/src/CMake/Utilities/cmrapidhash/rapidhash.h
Line | Count | Source |
1 | | /* |
2 | | * rapidhash V3 - Very fast, high quality, platform-independent hashing algorithm. |
3 | | * |
4 | | * Based on 'wyhash', by Wang Yi <godspeed_china@yeah.net> |
5 | | * |
6 | | * Copyright (C) 2025 Nicolas De Carli |
7 | | * |
8 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
9 | | * of this software and associated documentation files (the "Software"), to deal |
10 | | * in the Software without restriction, including without limitation the rights |
11 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
12 | | * copies of the Software, and to permit persons to whom the Software is |
13 | | * furnished to do so, subject to the following conditions: |
14 | | * |
15 | | * The above copyright notice and this permission notice shall be included in all |
16 | | * copies or substantial portions of the Software. |
17 | | * |
18 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
23 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
24 | | * SOFTWARE. |
25 | | * |
26 | | * You can contact the author at: |
27 | | * - rapidhash source repository: https://github.com/Nicoshev/rapidhash |
28 | | */ |
29 | | |
30 | | /* |
31 | | * Includes. |
32 | | */ |
33 | | #include <stdint.h> |
34 | | #include <string.h> |
35 | | #if defined(_MSC_VER) |
36 | | # include <intrin.h> |
37 | | # if defined(_M_X64) && !defined(_M_ARM64EC) |
38 | | # pragma intrinsic(_umul128) |
39 | | # endif |
40 | | #endif |
41 | | |
42 | | /* |
43 | | * C/C++ macros. |
44 | | */ |
45 | | |
46 | | #ifdef _MSC_VER |
47 | | # define RAPIDHASH_ALWAYS_INLINE __forceinline |
48 | | #elif defined(__GNUC__) |
49 | | # define RAPIDHASH_ALWAYS_INLINE inline __attribute__((__always_inline__)) |
50 | | #else |
51 | | # define RAPIDHASH_ALWAYS_INLINE inline |
52 | | #endif |
53 | | |
54 | | #ifdef __cplusplus |
55 | | # define RAPIDHASH_NOEXCEPT noexcept |
56 | | # define RAPIDHASH_CONSTEXPR constexpr |
57 | | # ifndef RAPIDHASH_INLINE |
58 | | # define RAPIDHASH_INLINE RAPIDHASH_ALWAYS_INLINE |
59 | | # endif |
60 | | # if __cplusplus >= 201402L && ((defined(__GNUC__) && __GNUC__ > 5) || defined(__INTEL_COMPILER) || defined(__clang__)) |
61 | | # define RAPIDHASH_INLINE_CONSTEXPR RAPIDHASH_ALWAYS_INLINE constexpr |
62 | | # else |
63 | | # define RAPIDHASH_INLINE_CONSTEXPR RAPIDHASH_ALWAYS_INLINE |
64 | | # endif |
65 | | #else |
66 | | # define RAPIDHASH_NOEXCEPT |
67 | | # define RAPIDHASH_CONSTEXPR static const |
68 | | # ifndef RAPIDHASH_INLINE |
69 | | # define RAPIDHASH_INLINE static RAPIDHASH_ALWAYS_INLINE |
70 | | # endif |
71 | | # define RAPIDHASH_INLINE_CONSTEXPR RAPIDHASH_INLINE |
72 | | #endif |
73 | | |
74 | | /* |
75 | | * Unrolled macro. |
76 | | * Improves large input speed, but increases code size and worsens small input speed. |
77 | | * |
78 | | * RAPIDHASH_COMPACT: Normal behavior. |
79 | | * RAPIDHASH_UNROLLED: |
80 | | * |
81 | | */ |
82 | | #ifndef RAPIDHASH_UNROLLED |
83 | | # define RAPIDHASH_COMPACT |
84 | | #elif defined(RAPIDHASH_COMPACT) |
85 | | # error "cannot define RAPIDHASH_COMPACT and RAPIDHASH_UNROLLED simultaneously." |
86 | | #endif |
87 | | |
88 | | /* |
89 | | * Protection macro, alters behaviour of rapid_mum multiplication function. |
90 | | * |
91 | | * RAPIDHASH_FAST: Normal behavior, max speed. |
92 | | * RAPIDHASH_PROTECTED: Extra protection against entropy loss. |
93 | | */ |
94 | | #ifndef RAPIDHASH_PROTECTED |
95 | | # define RAPIDHASH_FAST |
96 | | #elif defined(RAPIDHASH_FAST) |
97 | | # error "cannot define RAPIDHASH_PROTECTED and RAPIDHASH_FAST simultaneously." |
98 | | #endif |
99 | | |
100 | | /* |
101 | | * Likely and unlikely macros. |
102 | | */ |
103 | | #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) |
104 | | # define _likely_(x) __builtin_expect(x,1) |
105 | | # define _unlikely_(x) __builtin_expect(x,0) |
106 | | #else |
107 | | # define _likely_(x) (x) |
108 | | # define _unlikely_(x) (x) |
109 | | #endif |
110 | | |
111 | | /* |
112 | | * Endianness macros. |
113 | | */ |
114 | | #ifndef RAPIDHASH_LITTLE_ENDIAN |
115 | | # if defined(_WIN32) || defined(__LITTLE_ENDIAN__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) |
116 | | # define RAPIDHASH_LITTLE_ENDIAN |
117 | | # elif defined(__BIG_ENDIAN__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) |
118 | | # define RAPIDHASH_BIG_ENDIAN |
119 | | # else |
120 | | # warning "could not determine endianness! Falling back to little endian." |
121 | | # define RAPIDHASH_LITTLE_ENDIAN |
122 | | # endif |
123 | | #endif |
124 | | |
125 | | /* |
126 | | * Default secret parameters. |
127 | | */ |
128 | | RAPIDHASH_CONSTEXPR uint64_t rapid_secret[8] = { |
129 | | 0x2d358dccaa6c78a5ull, |
130 | | 0x8bb84b93962eacc9ull, |
131 | | 0x4b33a62ed433d4a3ull, |
132 | | 0x4d5a2da51de1aa47ull, |
133 | | 0xa0761d6478bd642full, |
134 | | 0xe7037ed1a0b428dbull, |
135 | | 0x90ed1765281c388cull, |
136 | | 0xaaaaaaaaaaaaaaaaull}; |
137 | | |
138 | | /* |
139 | | * 64*64 -> 128bit multiply function. |
140 | | * |
141 | | * @param A Address of 64-bit number. |
142 | | * @param B Address of 64-bit number. |
143 | | * |
144 | | * Calculates 128-bit C = *A * *B. |
145 | | * |
146 | | * When RAPIDHASH_FAST is defined: |
147 | | * Overwrites A contents with C's low 64 bits. |
148 | | * Overwrites B contents with C's high 64 bits. |
149 | | * |
150 | | * When RAPIDHASH_PROTECTED is defined: |
151 | | * Xors and overwrites A contents with C's low 64 bits. |
152 | | * Xors and overwrites B contents with C's high 64 bits. |
153 | | */ |
154 | 0 | RAPIDHASH_INLINE_CONSTEXPR void rapid_mum(uint64_t *A, uint64_t *B) RAPIDHASH_NOEXCEPT { |
155 | 0 | #if defined(__SIZEOF_INT128__) |
156 | 0 | __uint128_t r=*A; r*=*B; |
157 | 0 | #ifdef RAPIDHASH_PROTECTED |
158 | 0 | *A^=(uint64_t)r; *B^=(uint64_t)(r>>64); |
159 | 0 | #else |
160 | 0 | *A=(uint64_t)r; *B=(uint64_t)(r>>64); |
161 | 0 | #endif |
162 | 0 | #elif defined(_MSC_VER) && (defined(_WIN64) || defined(_M_HYBRID_CHPE_ARM64)) |
163 | 0 | #if defined(_M_X64) |
164 | 0 | #ifdef RAPIDHASH_PROTECTED |
165 | 0 | uint64_t a, b; |
166 | 0 | a=_umul128(*A,*B,&b); |
167 | 0 | *A^=a; *B^=b; |
168 | 0 | #else |
169 | 0 | *A=_umul128(*A,*B,B); |
170 | 0 | #endif |
171 | 0 | #else |
172 | 0 | #ifdef RAPIDHASH_PROTECTED |
173 | 0 | uint64_t a, b; |
174 | 0 | b = __umulh(*A, *B); |
175 | 0 | a = *A * *B; |
176 | 0 | *A^=a; *B^=b; |
177 | 0 | #else |
178 | 0 | uint64_t c = __umulh(*A, *B); |
179 | 0 | *A = *A * *B; |
180 | 0 | *B = c; |
181 | 0 | #endif |
182 | 0 | #endif |
183 | 0 | #else |
184 | 0 | uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B; |
185 | 0 | uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t<rl; |
186 | 0 | uint64_t lo=t+(rm1<<32); |
187 | 0 | c+=lo<t; |
188 | 0 | uint64_t hi=rh+(rm0>>32)+(rm1>>32)+c; |
189 | 0 | #ifdef RAPIDHASH_PROTECTED |
190 | 0 | *A^=lo; *B^=hi; |
191 | 0 | #else |
192 | 0 | *A=lo; *B=hi; |
193 | 0 | #endif |
194 | 0 | #endif |
195 | 0 | } |
196 | | |
197 | | /* |
198 | | * Multiply and xor mix function. |
199 | | * |
200 | | * @param A 64-bit number. |
201 | | * @param B 64-bit number. |
202 | | * |
203 | | * Calculates 128-bit C = A * B. |
204 | | * Returns 64-bit xor between high and low 64 bits of C. |
205 | | */ |
206 | 0 | RAPIDHASH_INLINE_CONSTEXPR uint64_t rapid_mix(uint64_t A, uint64_t B) RAPIDHASH_NOEXCEPT { rapid_mum(&A,&B); return A^B; } |
207 | | |
208 | | /* |
209 | | * Read functions. |
210 | | */ |
211 | | #ifdef RAPIDHASH_LITTLE_ENDIAN |
212 | 0 | RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint64_t v; memcpy(&v, p, sizeof(uint64_t)); return v;} |
213 | 0 | RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint32_t v; memcpy(&v, p, sizeof(uint32_t)); return v;} |
214 | | #elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) |
215 | | RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint64_t v; memcpy(&v, p, sizeof(uint64_t)); return __builtin_bswap64(v);} |
216 | | RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint32_t v; memcpy(&v, p, sizeof(uint32_t)); return __builtin_bswap32(v);} |
217 | | #elif defined(_MSC_VER) |
218 | | RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint64_t v; memcpy(&v, p, sizeof(uint64_t)); return _byteswap_uint64(v);} |
219 | | RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint32_t v; memcpy(&v, p, sizeof(uint32_t)); return _byteswap_ulong(v);} |
220 | | #else |
221 | | RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { |
222 | | uint64_t v; memcpy(&v, p, 8); |
223 | | return (((v >> 56) & 0xff)| ((v >> 40) & 0xff00)| ((v >> 24) & 0xff0000)| ((v >> 8) & 0xff000000)| ((v << 8) & 0xff00000000)| ((v << 24) & 0xff0000000000)| ((v << 40) & 0xff000000000000)| ((v << 56) & 0xff00000000000000)); |
224 | | } |
225 | | RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { |
226 | | uint32_t v; memcpy(&v, p, 4); |
227 | | return (((v >> 24) & 0xff)| ((v >> 8) & 0xff00)| ((v << 8) & 0xff0000)| ((v << 24) & 0xff000000)); |
228 | | } |
229 | | #endif |
230 | | |
231 | | /* |
232 | | * rapidhash main function. |
233 | | * |
234 | | * @param key Buffer to be hashed. |
235 | | * @param len @key length, in bytes. |
236 | | * @param seed 64-bit seed used to alter the hash result predictably. |
237 | | * @param secret Triplet of 64-bit secrets used to alter hash result predictably. |
238 | | * |
239 | | * Returns a 64-bit hash. |
240 | | */ |
241 | 0 | RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_internal(const void *key, size_t len, uint64_t seed, const uint64_t* secret) RAPIDHASH_NOEXCEPT { |
242 | 0 | const uint8_t *p=(const uint8_t *)key; |
243 | 0 | seed ^= rapid_mix(seed ^ secret[2], secret[1]); |
244 | 0 | uint64_t a=0, b=0; |
245 | 0 | size_t i = len; |
246 | 0 | if (_likely_(len <= 16)) { |
247 | 0 | if (len >= 4) { |
248 | 0 | seed ^= len; |
249 | 0 | if (len >= 8) { |
250 | 0 | const uint8_t* plast = p + len - 8; |
251 | 0 | a = rapid_read64(p); |
252 | 0 | b = rapid_read64(plast); |
253 | 0 | } else { |
254 | 0 | const uint8_t* plast = p + len - 4; |
255 | 0 | a = rapid_read32(p); |
256 | 0 | b = rapid_read32(plast); |
257 | 0 | } |
258 | 0 | } else if (len > 0) { |
259 | 0 | a = (((uint64_t)p[0])<<45)|p[len-1]; |
260 | 0 | b = p[len>>1]; |
261 | 0 | } else |
262 | 0 | a = b = 0; |
263 | 0 | } else { |
264 | 0 | uint64_t see1 = seed, see2 = seed; |
265 | 0 | uint64_t see3 = seed, see4 = seed; |
266 | 0 | uint64_t see5 = seed, see6 = seed; |
267 | 0 | #ifdef RAPIDHASH_COMPACT |
268 | 0 | if (i > 112) { |
269 | 0 | do { |
270 | 0 | seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed); |
271 | 0 | see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1); |
272 | 0 | see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2); |
273 | 0 | see3 = rapid_mix(rapid_read64(p + 48) ^ secret[3], rapid_read64(p + 56) ^ see3); |
274 | 0 | see4 = rapid_mix(rapid_read64(p + 64) ^ secret[4], rapid_read64(p + 72) ^ see4); |
275 | 0 | see5 = rapid_mix(rapid_read64(p + 80) ^ secret[5], rapid_read64(p + 88) ^ see5); |
276 | 0 | see6 = rapid_mix(rapid_read64(p + 96) ^ secret[6], rapid_read64(p + 104) ^ see6); |
277 | 0 | p += 112; |
278 | 0 | i -= 112; |
279 | 0 | } while(i > 112); |
280 | 0 | seed ^= see1; |
281 | 0 | see2 ^= see3; |
282 | 0 | see4 ^= see5; |
283 | 0 | seed ^= see6; |
284 | 0 | see2 ^= see4; |
285 | 0 | seed ^= see2; |
286 | 0 | } |
287 | 0 | #else |
288 | 0 | if (i > 224) { |
289 | 0 | do { |
290 | 0 | seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed); |
291 | 0 | see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1); |
292 | 0 | see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2); |
293 | 0 | see3 = rapid_mix(rapid_read64(p + 48) ^ secret[3], rapid_read64(p + 56) ^ see3); |
294 | 0 | see4 = rapid_mix(rapid_read64(p + 64) ^ secret[4], rapid_read64(p + 72) ^ see4); |
295 | 0 | see5 = rapid_mix(rapid_read64(p + 80) ^ secret[5], rapid_read64(p + 88) ^ see5); |
296 | 0 | see6 = rapid_mix(rapid_read64(p + 96) ^ secret[6], rapid_read64(p + 104) ^ see6); |
297 | 0 | seed = rapid_mix(rapid_read64(p + 112) ^ secret[0], rapid_read64(p + 120) ^ seed); |
298 | 0 | see1 = rapid_mix(rapid_read64(p + 128) ^ secret[1], rapid_read64(p + 136) ^ see1); |
299 | 0 | see2 = rapid_mix(rapid_read64(p + 144) ^ secret[2], rapid_read64(p + 152) ^ see2); |
300 | 0 | see3 = rapid_mix(rapid_read64(p + 160) ^ secret[3], rapid_read64(p + 168) ^ see3); |
301 | 0 | see4 = rapid_mix(rapid_read64(p + 176) ^ secret[4], rapid_read64(p + 184) ^ see4); |
302 | 0 | see5 = rapid_mix(rapid_read64(p + 192) ^ secret[5], rapid_read64(p + 200) ^ see5); |
303 | 0 | see6 = rapid_mix(rapid_read64(p + 208) ^ secret[6], rapid_read64(p + 216) ^ see6); |
304 | 0 | p += 224; |
305 | 0 | i -= 224; |
306 | 0 | } while (i > 224); |
307 | 0 | } |
308 | 0 | if (i > 112) { |
309 | 0 | seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed); |
310 | 0 | see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1); |
311 | 0 | see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2); |
312 | 0 | see3 = rapid_mix(rapid_read64(p + 48) ^ secret[3], rapid_read64(p + 56) ^ see3); |
313 | 0 | see4 = rapid_mix(rapid_read64(p + 64) ^ secret[4], rapid_read64(p + 72) ^ see4); |
314 | 0 | see5 = rapid_mix(rapid_read64(p + 80) ^ secret[5], rapid_read64(p + 88) ^ see5); |
315 | 0 | see6 = rapid_mix(rapid_read64(p + 96) ^ secret[6], rapid_read64(p + 104) ^ see6); |
316 | 0 | p += 112; |
317 | 0 | i -= 112; |
318 | 0 | } |
319 | 0 | seed ^= see1; |
320 | 0 | see2 ^= see3; |
321 | 0 | see4 ^= see5; |
322 | 0 | seed ^= see6; |
323 | 0 | see2 ^= see4; |
324 | 0 | seed ^= see2; |
325 | 0 | #endif |
326 | 0 | if (i > 16) { |
327 | 0 | seed = rapid_mix(rapid_read64(p) ^ secret[2], rapid_read64(p + 8) ^ seed); |
328 | 0 | if (i > 32) { |
329 | 0 | seed = rapid_mix(rapid_read64(p + 16) ^ secret[2], rapid_read64(p + 24) ^ seed); |
330 | 0 | if (i > 48) { |
331 | 0 | seed = rapid_mix(rapid_read64(p + 32) ^ secret[1], rapid_read64(p + 40) ^ seed); |
332 | 0 | if (i > 64) { |
333 | 0 | seed = rapid_mix(rapid_read64(p + 48) ^ secret[1], rapid_read64(p + 56) ^ seed); |
334 | 0 | if (i > 80) { |
335 | 0 | seed = rapid_mix(rapid_read64(p + 64) ^ secret[2], rapid_read64(p + 72) ^ seed); |
336 | 0 | if (i > 96) { |
337 | 0 | seed = rapid_mix(rapid_read64(p + 80) ^ secret[1], rapid_read64(p + 88) ^ seed); |
338 | 0 | } |
339 | 0 | } |
340 | 0 | } |
341 | 0 | } |
342 | 0 | } |
343 | 0 | } |
344 | 0 | a=rapid_read64(p+i-16) ^ i; b=rapid_read64(p+i-8); |
345 | 0 | } |
346 | 0 | a ^= secret[1]; |
347 | 0 | b ^= seed; |
348 | 0 | rapid_mum(&a, &b); |
349 | 0 | return rapid_mix(a ^ secret[7], b ^ secret[1] ^ i); |
350 | 0 | } |
351 | | |
352 | | /* |
353 | | * rapidhashMicro main function. |
354 | | * |
355 | | * @param key Buffer to be hashed. |
356 | | * @param len @key length, in bytes. |
357 | | * @param seed 64-bit seed used to alter the hash result predictably. |
358 | | * @param secret Triplet of 64-bit secrets used to alter hash result predictably. |
359 | | * |
360 | | * Returns a 64-bit hash. |
361 | | */ |
362 | 0 | RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashMicro_internal(const void *key, size_t len, uint64_t seed, const uint64_t* secret) RAPIDHASH_NOEXCEPT { |
363 | 0 | const uint8_t *p=(const uint8_t *)key; |
364 | 0 | seed ^= rapid_mix(seed ^ secret[2], secret[1]); |
365 | 0 | uint64_t a=0, b=0; |
366 | 0 | size_t i = len; |
367 | 0 | if (_likely_(len <= 16)) { |
368 | 0 | if (len >= 4) { |
369 | 0 | seed ^= len; |
370 | 0 | if (len >= 8) { |
371 | 0 | const uint8_t* plast = p + len - 8; |
372 | 0 | a = rapid_read64(p); |
373 | 0 | b = rapid_read64(plast); |
374 | 0 | } else { |
375 | 0 | const uint8_t* plast = p + len - 4; |
376 | 0 | a = rapid_read32(p); |
377 | 0 | b = rapid_read32(plast); |
378 | 0 | } |
379 | 0 | } else if (len > 0) { |
380 | 0 | a = (((uint64_t)p[0])<<45)|p[len-1]; |
381 | 0 | b = p[len>>1]; |
382 | 0 | } else |
383 | 0 | a = b = 0; |
384 | 0 | } else { |
385 | 0 | if (i > 80) { |
386 | 0 | uint64_t see1 = seed, see2 = seed; |
387 | 0 | uint64_t see3 = seed, see4 = seed; |
388 | 0 | do { |
389 | 0 | seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed); |
390 | 0 | see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1); |
391 | 0 | see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2); |
392 | 0 | see3 = rapid_mix(rapid_read64(p + 48) ^ secret[3], rapid_read64(p + 56) ^ see3); |
393 | 0 | see4 = rapid_mix(rapid_read64(p + 64) ^ secret[4], rapid_read64(p + 72) ^ see4); |
394 | 0 | p += 80; |
395 | 0 | i -= 80; |
396 | 0 | } while(i > 80); |
397 | 0 | seed ^= see1; |
398 | 0 | see2 ^= see3; |
399 | 0 | seed ^= see4; |
400 | 0 | seed ^= see2; |
401 | 0 | } |
402 | 0 | if (i > 16) { |
403 | 0 | seed = rapid_mix(rapid_read64(p) ^ secret[2], rapid_read64(p + 8) ^ seed); |
404 | 0 | if (i > 32) { |
405 | 0 | seed = rapid_mix(rapid_read64(p + 16) ^ secret[2], rapid_read64(p + 24) ^ seed); |
406 | 0 | if (i > 48) { |
407 | 0 | seed = rapid_mix(rapid_read64(p + 32) ^ secret[1], rapid_read64(p + 40) ^ seed); |
408 | 0 | if (i > 64) { |
409 | 0 | seed = rapid_mix(rapid_read64(p + 48) ^ secret[1], rapid_read64(p + 56) ^ seed); |
410 | 0 | } |
411 | 0 | } |
412 | 0 | } |
413 | 0 | } |
414 | 0 | a=rapid_read64(p+i-16) ^ i; b=rapid_read64(p+i-8); |
415 | 0 | } |
416 | 0 | a ^= secret[1]; |
417 | 0 | b ^= seed; |
418 | 0 | rapid_mum(&a, &b); |
419 | 0 | return rapid_mix(a ^ secret[7], b ^ secret[1] ^ i); |
420 | 0 | } |
421 | | |
422 | | /* |
423 | | * rapidhashNano main function. |
424 | | * |
425 | | * @param key Buffer to be hashed. |
426 | | * @param len @key length, in bytes. |
427 | | * @param seed 64-bit seed used to alter the hash result predictably. |
428 | | * @param secret Triplet of 64-bit secrets used to alter hash result predictably. |
429 | | * |
430 | | * Returns a 64-bit hash. |
431 | | */ |
432 | 0 | RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashNano_internal(const void *key, size_t len, uint64_t seed, const uint64_t* secret) RAPIDHASH_NOEXCEPT { |
433 | 0 | const uint8_t *p=(const uint8_t *)key; |
434 | 0 | seed ^= rapid_mix(seed ^ secret[2], secret[1]); |
435 | 0 | uint64_t a=0, b=0; |
436 | 0 | size_t i = len; |
437 | 0 | if (_likely_(len <= 16)) { |
438 | 0 | if (len >= 4) { |
439 | 0 | seed ^= len; |
440 | 0 | if (len >= 8) { |
441 | 0 | const uint8_t* plast = p + len - 8; |
442 | 0 | a = rapid_read64(p); |
443 | 0 | b = rapid_read64(plast); |
444 | 0 | } else { |
445 | 0 | const uint8_t* plast = p + len - 4; |
446 | 0 | a = rapid_read32(p); |
447 | 0 | b = rapid_read32(plast); |
448 | 0 | } |
449 | 0 | } else if (len > 0) { |
450 | 0 | a = (((uint64_t)p[0])<<45)|p[len-1]; |
451 | 0 | b = p[len>>1]; |
452 | 0 | } else |
453 | 0 | a = b = 0; |
454 | 0 | } else { |
455 | 0 | if (i > 48) { |
456 | 0 | uint64_t see1 = seed, see2 = seed; |
457 | 0 | do { |
458 | 0 | seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed); |
459 | 0 | see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1); |
460 | 0 | see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2); |
461 | 0 | p += 48; |
462 | 0 | i -= 48; |
463 | 0 | } while(i > 48); |
464 | 0 | seed ^= see1; |
465 | 0 | seed ^= see2; |
466 | 0 | } |
467 | 0 | if (i > 16) { |
468 | 0 | seed = rapid_mix(rapid_read64(p) ^ secret[2], rapid_read64(p + 8) ^ seed); |
469 | 0 | if (i > 32) { |
470 | 0 | seed = rapid_mix(rapid_read64(p + 16) ^ secret[2], rapid_read64(p + 24) ^ seed); |
471 | 0 | } |
472 | 0 | } |
473 | 0 | a=rapid_read64(p+i-16) ^ i; b=rapid_read64(p+i-8); |
474 | 0 | } |
475 | 0 | a ^= secret[1]; |
476 | 0 | b ^= seed; |
477 | 0 | rapid_mum(&a, &b); |
478 | 0 | return rapid_mix(a ^ secret[7], b ^ secret[1] ^ i); |
479 | 0 | } |
480 | | |
481 | | /* |
482 | | * rapidhash seeded hash function. |
483 | | * |
484 | | * @param key Buffer to be hashed. |
485 | | * @param len @key length, in bytes. |
486 | | * @param seed 64-bit seed used to alter the hash result predictably. |
487 | | * |
488 | | * Calls rapidhash_internal using provided parameters and default secrets. |
489 | | * |
490 | | * Returns a 64-bit hash. |
491 | | */ |
492 | 0 | RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_withSeed(const void *key, size_t len, uint64_t seed) RAPIDHASH_NOEXCEPT { |
493 | 0 | return rapidhash_internal(key, len, seed, rapid_secret); |
494 | 0 | } |
495 | | |
496 | | /* |
497 | | * rapidhash general purpose hash function. |
498 | | * |
499 | | * @param key Buffer to be hashed. |
500 | | * @param len @key length, in bytes. |
501 | | * |
502 | | * Calls rapidhash_withSeed using provided parameters and the default seed. |
503 | | * |
504 | | * Returns a 64-bit hash. |
505 | | */ |
506 | 0 | RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash(const void *key, size_t len) RAPIDHASH_NOEXCEPT { |
507 | 0 | return rapidhash_withSeed(key, len, 0); |
508 | 0 | } |
509 | | |
510 | | /* |
511 | | * rapidhashMicro seeded hash function. |
512 | | * |
513 | | * Designed for HPC and server applications, where cache misses make a noticeable performance detriment. |
514 | | * Clang-18+ compiles it to ~140 instructions without stack usage, both on x86-64 and aarch64. |
515 | | * Faster for sizes up to 512 bytes, just 15%-20% slower for inputs above 1kb. |
516 | | * |
517 | | * @param key Buffer to be hashed. |
518 | | * @param len @key length, in bytes. |
519 | | * @param seed 64-bit seed used to alter the hash result predictably. |
520 | | * |
521 | | * Calls rapidhash_internal using provided parameters and default secrets. |
522 | | * |
523 | | * Returns a 64-bit hash. |
524 | | */ |
525 | 0 | RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashMicro_withSeed(const void *key, size_t len, uint64_t seed) RAPIDHASH_NOEXCEPT { |
526 | 0 | return rapidhashMicro_internal(key, len, seed, rapid_secret); |
527 | 0 | } |
528 | | |
529 | | /* |
530 | | * rapidhashMicro hash function. |
531 | | * |
532 | | * @param key Buffer to be hashed. |
533 | | * @param len @key length, in bytes. |
534 | | * |
535 | | * Calls rapidhash_withSeed using provided parameters and the default seed. |
536 | | * |
537 | | * Returns a 64-bit hash. |
538 | | */ |
539 | 0 | RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashMicro(const void *key, size_t len) RAPIDHASH_NOEXCEPT { |
540 | 0 | return rapidhashMicro_withSeed(key, len, 0); |
541 | 0 | } |
542 | | |
543 | | /* |
544 | | * rapidhashNano seeded hash function. |
545 | | * |
546 | | * @param key Buffer to be hashed. |
547 | | * @param len @key length, in bytes. |
548 | | * @param seed 64-bit seed used to alter the hash result predictably. |
549 | | * |
550 | | * Calls rapidhash_internal using provided parameters and default secrets. |
551 | | * |
552 | | * Returns a 64-bit hash. |
553 | | */ |
554 | 0 | RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashNano_withSeed(const void *key, size_t len, uint64_t seed) RAPIDHASH_NOEXCEPT { |
555 | 0 | return rapidhashNano_internal(key, len, seed, rapid_secret); |
556 | 0 | } |
557 | | |
558 | | /* |
559 | | * rapidhashNano hash function. |
560 | | * |
561 | | * Designed for Mobile and embedded applications, where keeping a small code size is a top priority. |
562 | | * Clang-18+ compiles it to less than 100 instructions without stack usage, both on x86-64 and aarch64. |
563 | | * The fastest for sizes up to 48 bytes, but may be considerably slower for larger inputs. |
564 | | * |
565 | | * @param key Buffer to be hashed. |
566 | | * @param len @key length, in bytes. |
567 | | * |
568 | | * Calls rapidhash_withSeed using provided parameters and the default seed. |
569 | | * |
570 | | * Returns a 64-bit hash. |
571 | | */ |
572 | 0 | RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashNano(const void *key, size_t len) RAPIDHASH_NOEXCEPT { |
573 | 0 | return rapidhashNano_withSeed(key, len, 0); |
574 | 0 | } |