Skip to content

Commit

Permalink
Fix hash updates and collisions
Browse files Browse the repository at this point in the history
  • Loading branch information
donmccurdy committed Jan 22, 2024
1 parent 472d87f commit 6648982
Showing 1 changed file with 23 additions and 27 deletions.
50 changes: 23 additions & 27 deletions packages/functions/src/weld.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,15 +422,17 @@ function isPrimEmpty(prim: Primitive): boolean {
class HashTable {
private attributes: { u8: Uint8Array; byteStride: number; paddedByteStride: number }[] = [];

/** Temporary vertex view in 4-byte-aligned memory. */
/** Temporary vertex views in 4-byte-aligned memory. */
private u8: Uint8Array;
private u32: Uint32Array;

constructor(prim: Primitive) {
let byteStride = 0;
for (const attribute of deepListAttributes(prim)) {
byteStride += this._initAttribute(attribute);
}
this.u8 = new Uint8Array(byteStride);
this.u32 = new Uint32Array(this.u8.buffer);
}

private _initAttribute(attribute: Accessor): number {
Expand All @@ -444,14 +446,20 @@ class HashTable {

hash(index: number): number {
// Load vertex into 4-byte-aligned view.
let byteOffset = 0;
for (const { u8, byteStride, paddedByteStride } of this.attributes) {
for (let i = 0; i < paddedByteStride; i++) {
this.u8[i] = i < byteStride ? u8[index * byteStride + i] : 0;
if (i < byteStride) {
this.u8[byteOffset + i] = u8[index * byteStride + i];
} else {
this.u8[byteOffset + i] = 0;
}
}
byteOffset += paddedByteStride;
}

// Compute hash.
return murmurHash2(0, this.u8);
return murmurHash2(0, this.u32);
}

equal(a: number, b: number): boolean {
Expand All @@ -471,35 +479,23 @@ class HashTable {
* - https://github.com/mikolalysenko/murmurhash-js/blob/f19136e9f9c17f8cddc216ca3d44ec7c5c502f60/murmurhash2_gc.js#L14
* - https://github.com/zeux/meshoptimizer/blob/e47e1be6d3d9513153188216455bdbed40a206ef/src/indexgenerator.cpp#L12
*/
function murmurHash2(seed: number, data: Uint8Array) {
let l = data.length,
h = seed ^ l,
i = 0,
k;

while (l >= 4) {
k = (data[i] & 0xff) | ((data[++i] & 0xff) << 8) | ((data[++i] & 0xff) << 16) | ((data[++i] & 0xff) << 24);
export function murmurHash2(h: number, key: Uint32Array): number {
// MurmurHash2
const m = 0x5bd1e995;
const r = 24;

k = (k & 0xffff) * 0x5bd1e995 + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16);
k ^= k >>> 24;
k = (k & 0xffff) * 0x5bd1e995 + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16);
for (let i = 0, il = key.length; i < il; i++) {
let k = key[i];

h = ((h & 0xffff) * 0x5bd1e995 + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k;
k = Math.imul(k, m) >>> 0;
k = (k ^ (k >> r)) >>> 0;
k = Math.imul(k, m) >>> 0;

l -= 4;
++i;
h = Math.imul(h, m) >>> 0;
h = (h ^ k) >>> 0;
}

if (l === 3) h ^= (data[i + 2] & 0xff) << 16;
if (l >= 2) h ^= (data[i + 1] & 0xff) << 8;
if (l >= 1) h ^= data[i] & 0xff;
h = (h & 0xffff) * 0x5bd1e995 + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16);

h ^= h >>> 13;
h = (h & 0xffff) * 0x5bd1e995 + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16);
h ^= h >>> 15;

return h >>> 0;
return h;
}

function hashLookup(table: Uint32Array, buckets: number, hash: HashTable, key: number, empty = EMPTY): number {
Expand Down

0 comments on commit 6648982

Please sign in to comment.