Skip to content

Instantly share code, notes, and snippets.

@jsnanigans
Created April 17, 2023 09:39
Show Gist options
  • Save jsnanigans/a4a4d80ab29f04260703b0681477986f to your computer and use it in GitHub Desktop.
Save jsnanigans/a4a4d80ab29f04260703b0681477986f to your computer and use it in GitHub Desktop.
murmur3_32 TS
function hashText(text: string, seed = 42): number {
const encoder = new TextEncoder();
const inputUint8Array = encoder.encode(text);
return murmur3_32(inputUint8Array, inputUint8Array.length, seed);
}
function murmur3_32(key: Uint8Array, len: number, seed: number): number {
const c1 = 0xcc9e2d51;
const c2 = 0x1b873593;
const r1 = 15;
const r2 = 13;
const m = 5;
const n = 0xe6546b64;
let hash = seed;
function rol(value: number, shift: number): number {
return (value << shift) | (value >>> (32 - shift));
}
for (let i = 0; i < len - (len % 4); i += 4) {
let k =
key[i] | (key[i + 1] << 8) | (key[i + 2] << 16) | (key[i + 3] << 24);
k = (k * c1) | 0;
k = rol(k, r1);
k = (k * c2) | 0;
hash ^= k;
hash = rol(hash, r2);
hash = (hash * m + n) | 0;
}
let remainingBytes = 0;
switch (len % 4) {
case 3:
remainingBytes ^= key[len - 3] << 16;
break;
case 2:
remainingBytes ^= key[len - 2] << 8;
break;
case 1:
remainingBytes ^= key[len - 1];
remainingBytes = (remainingBytes * c1) | 0;
remainingBytes = rol(remainingBytes, r1);
remainingBytes = (remainingBytes * c2) | 0;
hash ^= remainingBytes;
}
hash ^= len;
hash ^= hash >>> 16;
hash = (hash * 0x85ebca6b) | 0;
hash ^= hash >>> 13;
hash = (hash * 0xc2b2ae35) | 0;
hash ^= hash >>> 16;
return hash >>> 0;
}
import hashText from "src/lib/hashText";
// mock "new TextEncoder()" and set it on the global.TextEncoder is not defined
class TextEncoder {
encode(input: string): Uint8Array {
return new Uint8Array(input.split("").map((char) => char.charCodeAt(0)));
}
}
(globalThis as any).TextEncoder = TextEncoder;
describe('hashText', () => {
it('should return the same hash for the same input and seed', () => {
const input = 'Hello, world!';
const hash1 = hashText(input);
const hash2 = hashText(input);
expect(hash1).toStrictEqual(hash2);
});
it('should return different hashes for different inputs with the same seed', () => {
const input1 = 'Hello, world!';
const input2 = 'Second String';
const hash1 = hashText(input1);
const hash2 = hashText(input2);
expect(hash1).not.toStrictEqual(hash2);
});
it('should return different hashes for the same input with different seeds', () => {
const input = 'Hello, world!';
const seed1 = 42;
const seed2 = 84;
const hash1 = hashText(input, seed1);
const hash2 = hashText(input, seed2);
expect(hash1).not.toStrictEqual(hash2);
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment