Coverage Report

Created: 2026-07-30 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}