From 3cf48d6b34c84b884f86d6675d84c2d7440f0320 Mon Sep 17 00:00:00 2001 From: Judah Caruso Date: Sat, 17 May 2025 02:20:27 -0600 Subject: [PATCH] add hash module --- hash/module.jai | 2 ++ hash/murmur.jai | 59 +++++++++++++++++++++++++++++++++++ hash/xxhash.jai | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 hash/module.jai create mode 100644 hash/murmur.jai create mode 100644 hash/xxhash.jai diff --git a/hash/module.jai b/hash/module.jai new file mode 100644 index 0000000..e870ffa --- /dev/null +++ b/hash/module.jai @@ -0,0 +1,2 @@ +#load "murmur.jai"; +#load "xxhash.jai"; diff --git a/hash/murmur.jai b/hash/murmur.jai new file mode 100644 index 0000000..2da4c50 --- /dev/null +++ b/hash/murmur.jai @@ -0,0 +1,59 @@ +// Implementation: Demetri Spanos (github.com/demetri/scribbles) +// Jai Port: Jesse Coyle (github.com/Zilarrezko) + +MurMur_Seed : u32 : 0xa3c91521; + +murmur32 :: inline (s: string, seed: u32 = MurMur_Seed) -> u32 { + return murmur32(s.data, s.count, seed); +} + +murmur32 :: inline (x: $T, seed: u32 = MurMur_Seed) -> u32 { + d: []u8 = ---; + d.data = cast(*u8)*x; + d.count = size_of(T); + return murmur32(d.data, d.count, seed); +} + +murmur32 :: (key: *void, len: int, seed: u32 = MurMur_Seed) -> u32 { + scrambler :: (k: u32) -> u32 #expand { + c1: u32 : 0xcc9e2d51; + c2: u32 : 0x1b873593; + r1: int : 15; + k = k*c1; + k = k <<< r1; + k = k*c2; + return k; + } + + h: u32 = seed; + tail: *u8 = cast(*u8)key + (len/4)*4; + p: *u32 = cast(*u32)key; + + while cast(*u8)p < tail { + k: u32 = <> 16; h *= 0x85ebca6b; + h ^= h >> 13; h *= 0xc2b2ae35; + h ^= h >> 16; + return h; +} diff --git a/hash/xxhash.jai b/hash/xxhash.jai new file mode 100644 index 0000000..28c7f0f --- /dev/null +++ b/hash/xxhash.jai @@ -0,0 +1,82 @@ +// 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 = (<> 33))*p2; + x = (x ^ (x >> 29))*p3; + x = (x ^ (x >> 32)); + return x; +}