#ifndef CHIBIHASH64__HGUARD
#define CHIBIHASH64__HGUARD
// small, fast 64 bit hash function (version 2).
//
// https://github.com/N-R-K/ChibiHash
//
// This is free and unencumbered software released into the public domain.
// For more information, please refer to
#include
#include
static inline uint64_t chibihash64__load32le(const uint8_t *p)
{
return (uint64_t)p[0] << 0 | (uint64_t)p[1] << 8 |
(uint64_t)p[2] << 16 | (uint64_t)p[3] << 24;
}
static inline uint64_t chibihash64__load64le(const uint8_t *p)
{
return chibihash64__load32le(p) | (chibihash64__load32le(p+4) << 32);
}
static inline uint64_t chibihash64__rotl(uint64_t x, int n)
{
return (x << n) | (x >> (-n & 63));
}
static inline uint64_t
chibihash64_v2(const void *keyIn, ptrdiff_t len, uint64_t seed)
{
const uint8_t *p = (const uint8_t *)keyIn;
ptrdiff_t l = len;
const uint64_t K = UINT64_C(0x2B7E151628AED2A7); // digits of e
uint64_t seed2 = chibihash64__rotl(seed-K, 15) + chibihash64__rotl(seed-K, 47);
uint64_t h[4] = { seed, seed+K, seed2, seed2+(K*K^K) };
// depending on your system unrolling might (or might not) make things
// a tad bit faster on large strings. on my system, it actually makes
// things slower.
// generally speaking, the cost of bigger code size is usually not
// worth the trade-off since larger code-size will hinder inlinability
// but depending on your needs, you may want to uncomment the pragma
// below to unroll the loop.
//#pragma GCC unroll 2
for (; l >= 32; l -= 32) {
for (int i = 0; i < 4; ++i, p += 8) {
uint64_t stripe = chibihash64__load64le(p);
h[i] = (stripe + h[i]) * K;
h[(i+1)&3] += chibihash64__rotl(stripe, 27);
}
}
for (; l >= 8; l -= 8, p += 8) {
h[0] ^= chibihash64__load32le(p+0); h[0] *= K;
h[1] ^= chibihash64__load32le(p+4); h[1] *= K;
}
if (l >= 4) {
h[2] ^= chibihash64__load32le(p);
h[3] ^= chibihash64__load32le(p + l - 4);
} else if (l > 0) {
h[2] ^= p[0];
h[3] ^= p[l/2] | ((uint64_t)p[l-1] << 8);
}
h[0] += chibihash64__rotl(h[2] * K, 31) ^ (h[2] >> 31);
h[1] += chibihash64__rotl(h[3] * K, 31) ^ (h[3] >> 31);
h[0] *= K; h[0] ^= h[0] >> 31;
h[1] += h[0];
uint64_t x = (uint64_t)len * K;
x ^= chibihash64__rotl(x, 29);
x += seed;
x ^= h[1];
x ^= chibihash64__rotl(x, 15) ^ chibihash64__rotl(x, 42);
x *= K;
x ^= chibihash64__rotl(x, 13) ^ chibihash64__rotl(x, 31);
return x;
}
#endif // CHIBIHASH64__HGUARD