Last active
February 23, 2025 07:24
-
-
Save ziap/e764030011b8ad6a161faf3b67f5c117 to your computer and use it in GitHub Desktop.
A custom fast, non-cryptographic hash function
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
static inline uint64_t multiply_mix(uint64_t x, uint64_t y) { | |
__uint128_t m = (__uint128_t)x * (__uint128_t)y; | |
uint64_t hi = m >> 64; | |
uint64_t lo = m; | |
return lo ^ hi; | |
} | |
static inline uint64_t zxhash(const void *key, int len, uint64_t seed) { | |
const uint64_t secret = 0x9e3779b97f4a7c15; | |
uint64_t h = multiply_mix(seed ^ 0x243f6a8885a308d3, len ^ 0x13198a2e03707344); | |
if (len < 8) { | |
const uint8_t *bytes = key; | |
uint64_t block = 0; | |
switch (len) { | |
case 7: block |= (uint64_t)bytes[6] << 48; | |
case 6: block |= (uint64_t)bytes[5] << 40; | |
case 5: block |= (uint64_t)bytes[4] << 32; | |
case 4: block |= (uint64_t)bytes[3] << 24; | |
case 3: block |= (uint64_t)bytes[2] << 16; | |
case 2: block |= (uint64_t)bytes[1] << 8; | |
case 1: block |= (uint64_t)bytes[0]; | |
} | |
h = multiply_mix(h, block ^ secret); | |
} else if (len < 128) { | |
const uint64_t *view = key; | |
while (len > 16) { | |
h = multiply_mix(h ^ view[0], view[1] ^ secret); | |
view += 2; | |
len -= 16; | |
} | |
h ^= *(const uint64_t *)((const uint8_t *)view + len - 8); | |
const uint64_t block = (len > 8) ? view[0] : 0; | |
h = multiply_mix(h, block ^ secret); | |
} else { | |
uint64_t s0 = 0xa4093822299f31d0; | |
uint64_t s1 = 0x082efa98ec4e6c89; | |
uint64_t s2 = 0x452821e638d01377; | |
uint64_t s3 = 0xbe5466cf34e90c6c; | |
const uint64_t *view = key; | |
while (len > 64) { | |
s0 = multiply_mix(s0 ^ view[0], view[1] ^ secret); | |
s1 = multiply_mix(s1 ^ view[2], view[3] ^ secret); | |
s2 = multiply_mix(s2 ^ view[4], view[5] ^ secret); | |
s3 = multiply_mix(s3 ^ view[6], view[7] ^ secret); | |
view += 8; | |
len -= 64; | |
} | |
const uint64_t *final = (const uint64_t *)((const uint8_t *)view + len - 64); | |
s0 = multiply_mix(s0 ^ final[0], s2 ^ final[1]); | |
s1 = multiply_mix(s1 ^ final[2], s3 ^ final[3]); | |
s0 = multiply_mix(s0 ^ final[4], s1 ^ final[5]); | |
h = multiply_mix(h ^ final[6], s0 ^ final[7]); | |
} | |
return multiply_mix(h ^ len, 0xffebb71d94fcdaf9); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment