UNPKG

@instantdb/core

Version:

Instant's core local abstraction

78 lines (71 loc) 2.52 kB
/** * * Unique Hashing implementation inspired by djb2/fnv1a algorithms, * where we are not concerned with the hash being decoded. * Focuses on speed while maintaining good hash distribution * * Note: We could also use something like Murmurhash instead * https://github.com/jensyt/imurmurhash-js/blob/master/imurmurhash.js * * @param {any} input - Value to hash * @returns {string} - Hash in hex format */ export default function weakHash(input: any): string { // Handle primitives without JSON stringify for better performance if (typeof input === 'number') { // Use a larger number space for numeric values return (Math.abs(input * 2654435761) >>> 0).toString(16); } if (typeof input === 'boolean') return input ? '1' : '0'; if (input === null) return 'null'; if (input === undefined) return 'undefined'; // For strings, use FNV-1a algorithm if (typeof input === 'string') { let hash = 0x811c9dc5; // FNV offset basis (32 bit) for (let i = 0; i < input.length; i++) { hash ^= input.charCodeAt(i); hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24); hash = hash >>> 0; // Convert to unsigned 32-bit after each iteration } return hash.toString(16); } // For arrays, hash elements directly if (Array.isArray(input)) { let hash = 0x811c9dc5; for (let i = 0; i < input.length; i++) { // Add array position to hash calculation hash ^= (i + 1) * 2654435761; // Recursively hash array elements const elementHash = weakHash(input[i]); // Mix the element hash into the running hash for (let j = 0; j < elementHash.length; j++) { hash ^= elementHash.charCodeAt(j); hash *= 16777619; // FNV prime (32 bit) hash = hash >>> 0; } } return hash.toString(16); } // For objects, hash keys and values if (typeof input === 'object') { let hash = 0x811c9dc5; const keys = Object.keys(input).sort(); // Sort for consistency for (let i = 0; i < keys.length; i++) { const key = keys[i]; // Hash the key using string hash const keyHash = weakHash(key); hash ^= parseInt(keyHash, 16); hash *= 16777619; hash = hash >>> 0; // Hash the value recursively const valueHash = weakHash(input[key]); hash ^= parseInt(valueHash, 16); hash *= 16777619; hash = hash >>> 0; } return hash.toString(16); } // Fallback for other types return weakHash(String(input)); }