jc/hash/xxhash.jai

84 lines
2.1 KiB
Text

#module_parameters(RUN_TESTS := false);
// Implementation: Demetri Spanos (github.com/demetri/scribbles)
// Jai Port: Jesse Coyle (github.com/Zilarrezko)
XXHash_Seed :: 0;
xxhash64 :: inline (s: string, seed: u32 = XXHash_Seed) -> u64 {
return xxhash64(s.data, s.count, seed);
}
xxhash64 :: inline (x: $T, seed: u32 = XXHash_Seed) -> u64 {
return xxhash64(cast(*u8)*x, size_of(T), seed);
}
xxhash64 :: (key: *void, len: int, seed: u64 = XXHash_Seed) -> u64 {
p1: u64 : 0x9e3779b185ebca87;
p2: u64 : 0xc2b2ae3d27d4eb4f;
p3: u64 : 0x165667b19e3779f9;
p4: u64 : 0x85ebca77c2b2ae63;
p5: u64 : 0x27d4eb2f165667c5;
h: u64 = seed;
s: [4]u64 = ---;
s[0] = h + p1 + p2;
s[1] = h + p2;
s[2] = h;
s[3] = h - p1;
// Bulk work
k32: *u64 = cast(*u64)key;
i: int;
while i < len/32 {
b: [4]u64 = ---;
b[0] = k32[4*i+0];
b[1] = k32[4*i+1];
b[2] = k32[4*i+2];
b[3] = k32[4*i+3];
for j : 0..3
b[j] = b[j]*p2 + s[j];
for j : 0..3
s[j] = (b[j] <<< 31)*p1;
i += 1;
}
// Mix 32 byte state down to 8 byte state
x: u64 = s[2] + p5;
if len > 32 {
x = (s[0] <<< 1) + (s[1] >>> 7) + (s[2] <<< 12) + (s[3] <<< 18);
for i : 0..3 {
ps: u64 = ((s[i]*p2) <<< 31)*p1;
x = (x ^ ps)*p1 + p4;
}
}
x += cast(u64)len;
// 31 max bytes remain...
tail: *u8 = cast(*u8)key + (len/32)*32;
for i : 0 .. (len & 31)/8 - 1 { // No idea why there's a mask then a divide that can be a smaller mask there
b: u64 = (<<cast(*u64)tail)*p2;
b = ((b <<< 31)*p1) ^ x;
x = (b <<< 27)*p1 + p4;
tail += 8;
}
// 7 max bytes remain...
for i : 0 .. (len & 7)/4 - 1 {
b: u64 = x ^ ((<<cast(*u32)tail)*p1);
x = (b <<< 23)*p2 + p3;
tail += 4;
}
// 3 max bytes remain
for i : 0 .. (len & 3) {
b: u64 = x ^ (<<tail)*p5;
x = (b <<< 11)*p1;
}
x = (x ^ (x >> 33))*p2;
x = (x ^ (x >> 29))*p3;
x = (x ^ (x >> 32));
return x;
}