UNPKG

@azure/cosmos

Version:
440 lines • 14.3 kB
// +----------------------------------------------------------------------+ // | murmurHash3js.js v3.0.1 // https://github.com/pid/murmurHash3js // | A javascript implementation of MurmurHash3's x86 hashing algorithms. | // |----------------------------------------------------------------------| // | Copyright (c) 2012-2015 Karan Lyons | // | https://github.com/karanlyons/murmurHash3.js/blob/c1778f75792abef7bdd74bc85d2d4e1a3d25cfe9/murmurHash3.js | // | Freely distributable under the MIT license. | // +----------------------------------------------------------------------+ // PRIVATE FUNCTIONS // ----------------- import { hexStringToUint8Array, uint8ArrayToHex } from "../uint8.js"; function _x86Multiply(m, n) { // // Given two 32bit ints, returns the two multiplied together as a // 32bit int. // return (m & 0xffff) * n + ((((m >>> 16) * n) & 0xffff) << 16); } function _x86Rotl(m, n) { // // Given a 32bit int and an int representing a number of bit positions, // returns the 32bit int rotated left by that number of positions. // return (m << n) | (m >>> (32 - n)); } function _x86Fmix(h) { // // Given a block, returns murmurHash3's final x86 mix of that block. // h ^= h >>> 16; h = _x86Multiply(h, 0x85ebca6b); h ^= h >>> 13; h = _x86Multiply(h, 0xc2b2ae35); h ^= h >>> 16; return h; } function _x64Add(m, n) { // // Given two 64bit ints (as an array of two 32bit ints) returns the two // added together as a 64bit int (as an array of two 32bit ints). // m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff]; n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff]; const o = [0, 0, 0, 0]; o[3] += m[3] + n[3]; o[2] += o[3] >>> 16; o[3] &= 0xffff; o[2] += m[2] + n[2]; o[1] += o[2] >>> 16; o[2] &= 0xffff; o[1] += m[1] + n[1]; o[0] += o[1] >>> 16; o[1] &= 0xffff; o[0] += m[0] + n[0]; o[0] &= 0xffff; return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]]; } function _x64Multiply(m, n) { // // Given two 64bit ints (as an array of two 32bit ints) returns the two // multiplied together as a 64bit int (as an array of two 32bit ints). // m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff]; n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff]; const o = [0, 0, 0, 0]; o[3] += m[3] * n[3]; o[2] += o[3] >>> 16; o[3] &= 0xffff; o[2] += m[2] * n[3]; o[1] += o[2] >>> 16; o[2] &= 0xffff; o[2] += m[3] * n[2]; o[1] += o[2] >>> 16; o[2] &= 0xffff; o[1] += m[1] * n[3]; o[0] += o[1] >>> 16; o[1] &= 0xffff; o[1] += m[2] * n[2]; o[0] += o[1] >>> 16; o[1] &= 0xffff; o[1] += m[3] * n[1]; o[0] += o[1] >>> 16; o[1] &= 0xffff; o[0] += m[0] * n[3] + m[1] * n[2] + m[2] * n[1] + m[3] * n[0]; o[0] &= 0xffff; return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]]; } function _x64Rotl(m, n) { // // Given a 64bit int (as an array of two 32bit ints) and an int // representing a number of bit positions, returns the 64bit int (as an // array of two 32bit ints) rotated left by that number of positions. // n %= 64; if (n === 32) { return [m[1], m[0]]; } else if (n < 32) { return [(m[0] << n) | (m[1] >>> (32 - n)), (m[1] << n) | (m[0] >>> (32 - n))]; } else { n -= 32; return [(m[1] << n) | (m[0] >>> (32 - n)), (m[0] << n) | (m[1] >>> (32 - n))]; } } function _x64LeftShift(m, n) { // // Given a 64bit int (as an array of two 32bit ints) and an int // representing a number of bit positions, returns the 64bit int (as an // array of two 32bit ints) shifted left by that number of positions. // n %= 64; if (n === 0) { return m; } else if (n < 32) { return [(m[0] << n) | (m[1] >>> (32 - n)), m[1] << n]; } else { return [m[1] << (n - 32), 0]; } } function _x64Xor(m, n) { // // Given two 64bit ints (as an array of two 32bit ints) returns the two // xored together as a 64bit int (as an array of two 32bit ints). // return [m[0] ^ n[0], m[1] ^ n[1]]; } function _x64Fmix(h) { // // Given a block, returns murmurHash3's final x64 mix of that block. // (`[0, h[0] >>> 1]` is a 33 bit unsigned right shift. This is the // only place where we need to right shift 64bit ints.) // h = _x64Xor(h, [0, h[0] >>> 1]); h = _x64Multiply(h, [0xff51afd7, 0xed558ccd]); h = _x64Xor(h, [0, h[0] >>> 1]); h = _x64Multiply(h, [0xc4ceb9fe, 0x1a85ec53]); h = _x64Xor(h, [0, h[0] >>> 1]); return h; } // PUBLIC FUNCTIONS // ---------------- function x86Hash32(bytes, seed) { // // Given a string and an optional seed as an int, returns a 32 bit hash // using the x86 flavor of MurmurHash3, as an unsigned int. // seed = seed || 0; const remainder = bytes.length % 4; const blocks = bytes.length - remainder; let h1 = seed; let k1 = 0; const c1 = 0xcc9e2d51; const c2 = 0x1b873593; let j = 0; for (let i = 0; i < blocks; i = i + 4) { k1 = bytes[i] | (bytes[i + 1] << 8) | (bytes[i + 2] << 16) | (bytes[i + 3] << 24); k1 = _x86Multiply(k1, c1); k1 = _x86Rotl(k1, 15); k1 = _x86Multiply(k1, c2); h1 ^= k1; h1 = _x86Rotl(h1, 13); h1 = _x86Multiply(h1, 5) + 0xe6546b64; j = i + 4; } k1 = 0; switch (remainder) { case 3: k1 ^= bytes[j + 2] << 16; case 2: k1 ^= bytes[j + 1] << 8; case 1: k1 ^= bytes[j]; k1 = _x86Multiply(k1, c1); k1 = _x86Rotl(k1, 15); k1 = _x86Multiply(k1, c2); h1 ^= k1; } h1 ^= bytes.length; h1 = _x86Fmix(h1); return h1 >>> 0; } function x86Hash128(bytes, seed) { // // Given a string and an optional seed as an int, returns a 128 bit // hash using the x86 flavor of MurmurHash3, as an unsigned hex. // seed = seed || 0; const remainder = bytes.length % 16; const blocks = bytes.length - remainder; let h1 = seed; let h2 = seed; let h3 = seed; let h4 = seed; let k1 = 0; let k2 = 0; let k3 = 0; let k4 = 0; const c1 = 0x239b961b; const c2 = 0xab0e9789; const c3 = 0x38b34ae5; const c4 = 0xa1e38b93; let j = 0; for (let i = 0; i < blocks; i = i + 16) { k1 = bytes[i] | (bytes[i + 1] << 8) | (bytes[i + 2] << 16) | (bytes[i + 3] << 24); k2 = bytes[i + 4] | (bytes[i + 5] << 8) | (bytes[i + 6] << 16) | (bytes[i + 7] << 24); k3 = bytes[i + 8] | (bytes[i + 9] << 8) | (bytes[i + 10] << 16) | (bytes[i + 11] << 24); k4 = bytes[i + 12] | (bytes[i + 13] << 8) | (bytes[i + 14] << 16) | (bytes[i + 15] << 24); k1 = _x86Multiply(k1, c1); k1 = _x86Rotl(k1, 15); k1 = _x86Multiply(k1, c2); h1 ^= k1; h1 = _x86Rotl(h1, 19); h1 += h2; h1 = _x86Multiply(h1, 5) + 0x561ccd1b; k2 = _x86Multiply(k2, c2); k2 = _x86Rotl(k2, 16); k2 = _x86Multiply(k2, c3); h2 ^= k2; h2 = _x86Rotl(h2, 17); h2 += h3; h2 = _x86Multiply(h2, 5) + 0x0bcaa747; k3 = _x86Multiply(k3, c3); k3 = _x86Rotl(k3, 17); k3 = _x86Multiply(k3, c4); h3 ^= k3; h3 = _x86Rotl(h3, 15); h3 += h4; h3 = _x86Multiply(h3, 5) + 0x96cd1c35; k4 = _x86Multiply(k4, c4); k4 = _x86Rotl(k4, 18); k4 = _x86Multiply(k4, c1); h4 ^= k4; h4 = _x86Rotl(h4, 13); h4 += h1; h4 = _x86Multiply(h4, 5) + 0x32ac3b17; j = i + 16; } k1 = 0; k2 = 0; k3 = 0; k4 = 0; switch (remainder) { case 15: k4 ^= bytes[j + 14] << 16; case 14: k4 ^= bytes[j + 13] << 8; case 13: k4 ^= bytes[j + 12]; k4 = _x86Multiply(k4, c4); k4 = _x86Rotl(k4, 18); k4 = _x86Multiply(k4, c1); h4 ^= k4; case 12: k3 ^= bytes[j + 11] << 24; case 11: k3 ^= bytes[j + 10] << 16; case 10: k3 ^= bytes[j + 9] << 8; case 9: k3 ^= bytes[j + 8]; k3 = _x86Multiply(k3, c3); k3 = _x86Rotl(k3, 17); k3 = _x86Multiply(k3, c4); h3 ^= k3; case 8: k2 ^= bytes[j + 7] << 24; case 7: k2 ^= bytes[j + 6] << 16; case 6: k2 ^= bytes[j + 5] << 8; case 5: k2 ^= bytes[j + 4]; k2 = _x86Multiply(k2, c2); k2 = _x86Rotl(k2, 16); k2 = _x86Multiply(k2, c3); h2 ^= k2; case 4: k1 ^= bytes[j + 3] << 24; case 3: k1 ^= bytes[j + 2] << 16; case 2: k1 ^= bytes[j + 1] << 8; case 1: k1 ^= bytes[j]; k1 = _x86Multiply(k1, c1); k1 = _x86Rotl(k1, 15); k1 = _x86Multiply(k1, c2); h1 ^= k1; } h1 ^= bytes.length; h2 ^= bytes.length; h3 ^= bytes.length; h4 ^= bytes.length; h1 += h2; h1 += h3; h1 += h4; h2 += h1; h3 += h1; h4 += h1; h1 = _x86Fmix(h1); h2 = _x86Fmix(h2); h3 = _x86Fmix(h3); h4 = _x86Fmix(h4); h1 += h2; h1 += h3; h1 += h4; h2 += h1; h3 += h1; h4 += h1; return (("00000000" + (h1 >>> 0).toString(16)).slice(-8) + ("00000000" + (h2 >>> 0).toString(16)).slice(-8) + ("00000000" + (h3 >>> 0).toString(16)).slice(-8) + ("00000000" + (h4 >>> 0).toString(16)).slice(-8)); } function x64Hash128(bytes, seed) { // // Given a string and an optional seed as an int, returns a 128 bit // hash using the x64 flavor of MurmurHash3, as an unsigned hex. // seed = seed || 0; const remainder = bytes.length % 16; const blocks = bytes.length - remainder; let h1 = [0, seed]; let h2 = [0, seed]; let k1 = [0, 0]; let k2 = [0, 0]; const c1 = [0x87c37b91, 0x114253d5]; const c2 = [0x4cf5ad43, 0x2745937f]; let j = 0; for (let i = 0; i < blocks; i = i + 16) { k1 = [ bytes[i + 4] | (bytes[i + 5] << 8) | (bytes[i + 6] << 16) | (bytes[i + 7] << 24), bytes[i] | (bytes[i + 1] << 8) | (bytes[i + 2] << 16) | (bytes[i + 3] << 24), ]; k2 = [ bytes[i + 12] | (bytes[i + 13] << 8) | (bytes[i + 14] << 16) | (bytes[i + 15] << 24), bytes[i + 8] | (bytes[i + 9] << 8) | (bytes[i + 10] << 16) | (bytes[i + 11] << 24), ]; k1 = _x64Multiply(k1, c1); k1 = _x64Rotl(k1, 31); k1 = _x64Multiply(k1, c2); h1 = _x64Xor(h1, k1); h1 = _x64Rotl(h1, 27); h1 = _x64Add(h1, h2); h1 = _x64Add(_x64Multiply(h1, [0, 5]), [0, 0x52dce729]); k2 = _x64Multiply(k2, c2); k2 = _x64Rotl(k2, 33); k2 = _x64Multiply(k2, c1); h2 = _x64Xor(h2, k2); h2 = _x64Rotl(h2, 31); h2 = _x64Add(h2, h1); h2 = _x64Add(_x64Multiply(h2, [0, 5]), [0, 0x38495ab5]); j = i + 16; } k1 = [0, 0]; k2 = [0, 0]; switch (remainder) { case 15: k2 = _x64Xor(k2, _x64LeftShift([0, bytes[j + 14]], 48)); case 14: k2 = _x64Xor(k2, _x64LeftShift([0, bytes[j + 13]], 40)); case 13: k2 = _x64Xor(k2, _x64LeftShift([0, bytes[j + 12]], 32)); case 12: k2 = _x64Xor(k2, _x64LeftShift([0, bytes[j + 11]], 24)); case 11: k2 = _x64Xor(k2, _x64LeftShift([0, bytes[j + 10]], 16)); case 10: k2 = _x64Xor(k2, _x64LeftShift([0, bytes[j + 9]], 8)); case 9: k2 = _x64Xor(k2, [0, bytes[j + 8]]); k2 = _x64Multiply(k2, c2); k2 = _x64Rotl(k2, 33); k2 = _x64Multiply(k2, c1); h2 = _x64Xor(h2, k2); case 8: k1 = _x64Xor(k1, _x64LeftShift([0, bytes[j + 7]], 56)); case 7: k1 = _x64Xor(k1, _x64LeftShift([0, bytes[j + 6]], 48)); case 6: k1 = _x64Xor(k1, _x64LeftShift([0, bytes[j + 5]], 40)); case 5: k1 = _x64Xor(k1, _x64LeftShift([0, bytes[j + 4]], 32)); case 4: k1 = _x64Xor(k1, _x64LeftShift([0, bytes[j + 3]], 24)); case 3: k1 = _x64Xor(k1, _x64LeftShift([0, bytes[j + 2]], 16)); case 2: k1 = _x64Xor(k1, _x64LeftShift([0, bytes[j + 1]], 8)); case 1: k1 = _x64Xor(k1, [0, bytes[j]]); k1 = _x64Multiply(k1, c1); k1 = _x64Rotl(k1, 31); k1 = _x64Multiply(k1, c2); h1 = _x64Xor(h1, k1); } h1 = _x64Xor(h1, [0, bytes.length]); h2 = _x64Xor(h2, [0, bytes.length]); h1 = _x64Add(h1, h2); h2 = _x64Add(h2, h1); h1 = _x64Fmix(h1); h2 = _x64Fmix(h2); h1 = _x64Add(h1, h2); h2 = _x64Add(h2, h1); // Here we reverse h1 and h2 in Cosmos // This is an implementation detail and not part of the public spec // Convert h1 to hex string and then to Uint8Array. const h1Hex = ("00000000" + (h1[0] >>> 0).toString(16)).slice(-8) + ("00000000" + (h1[1] >>> 0).toString(16)).slice(-8); const h1Buff = hexStringToUint8Array(h1Hex); const h1Reversed = uint8ArrayToHex(reverse(h1Buff)); const h2Hex = ("00000000" + (h2[0] >>> 0).toString(16)).slice(-8) + ("00000000" + (h2[1] >>> 0).toString(16)).slice(-8); const h2Buff = hexStringToUint8Array(h2Hex); const h2Reversed = uint8ArrayToHex(reverse(h2Buff)); return h1Reversed + h2Reversed; } export function reverse(buff) { const uint8array = new Uint8Array(buff.length); for (let i = 0, j = buff.length - 1; i <= j; ++i, --j) { uint8array[i] = buff[j]; uint8array[j] = buff[i]; } return uint8array; } export default { version: "3.0.0", x86: { hash32: x86Hash32, hash128: x86Hash128, }, x64: { hash128: x64Hash128, }, inputValidation: true, }; //# sourceMappingURL=murmurHash.js.map