type BunHashRuntime = { hash: { xxHash32(data: string | Uint8Array, seed: number): number } } const runtime = globalThis as typeof globalThis & { Bun?: BunHashRuntime } const encoder = new TextEncoder() const PRIME32_1 = 0x9e3779b1 const PRIME32_2 = 0x85ebca77 const PRIME32_3 = 0xc2b2ae3d const PRIME32_4 = 0x27d4eb2f const PRIME32_5 = 0x165667b1 function rotateLeft32(value: number, bits: number): number { return ((value << bits) | (value >>> (32 - bits))) >>> 0 } function readUint32LittleEndian(input: Uint8Array, offset: number): number { return ( ((input[offset] ?? 0) | ((input[offset + 1] ?? 0) << 8) | ((input[offset + 2] ?? 0) << 16) | ((input[offset + 3] ?? 0) << 24)) >>> 0 ) } function round32(accumulator: number, value: number): number { const added = (accumulator + Math.imul(value, PRIME32_2)) >>> 0 return Math.imul(rotateLeft32(added, 13), PRIME32_1) >>> 0 } function xxHash32Js(input: Uint8Array, seed: number): number { let offset = 0 const length = input.length let hash: number if (length >= 16) { const limit = length - 16 let value1 = (seed + PRIME32_1 + PRIME32_2) >>> 0 let value2 = (seed + PRIME32_2) >>> 0 let value3 = seed >>> 0 let value4 = (seed - PRIME32_1) >>> 0 while (offset <= limit) { value1 = round32(value1, readUint32LittleEndian(input, offset)) offset += 4 value2 = round32(value2, readUint32LittleEndian(input, offset)) offset += 4 value3 = round32(value3, readUint32LittleEndian(input, offset)) offset += 4 value4 = round32(value4, readUint32LittleEndian(input, offset)) offset += 4 } hash = (rotateLeft32(value1, 1) + rotateLeft32(value2, 7)) >>> 0 hash = (hash + rotateLeft32(value3, 12)) >>> 0 hash = (hash + rotateLeft32(value4, 18)) >>> 0 } else { hash = (seed + PRIME32_5) >>> 0 } hash = (hash + length) >>> 0 while (offset + 4 <= length) { hash = (hash + Math.imul(readUint32LittleEndian(input, offset), PRIME32_3)) >>> 0 hash = Math.imul(rotateLeft32(hash, 17), PRIME32_4) >>> 0 offset += 4 } while (offset < length) { hash = (hash + Math.imul(input[offset] ?? 0, PRIME32_5)) >>> 0 hash = Math.imul(rotateLeft32(hash, 11), PRIME32_1) >>> 0 offset += 1 } hash = (hash ^ (hash >>> 15)) >>> 0 hash = Math.imul(hash, PRIME32_2) >>> 0 hash = (hash ^ (hash >>> 13)) >>> 0 hash = Math.imul(hash, PRIME32_3) >>> 0 return (hash ^ (hash >>> 16)) >>> 0 } export function hashXxh32(input: string, seed: number): number { const bun = runtime.Bun if (bun !== undefined) { return bun.hash.xxHash32(input, seed) } return xxHash32Js(encoder.encode(input), seed >>> 0) }