Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: larvit/larvitutils
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: cf356385880994571092852e8a309d9ee99f25a4
Choose a base ref
...
head repository: larvit/larvitutils
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 05f7ef4527ed6877c241d28f12a7c56b2b5cdb14
Choose a head ref
  • 1 commit
  • 3 files changed
  • 1 contributor

Commits on Nov 5, 2019

  1. Copy the full SHA
    05f7ef4 View commit details
Showing with 79 additions and 21 deletions.
  1. +70 −20 index.js
  2. +1 −1 package.json
  3. +8 −0 test/hashStringToString.js
90 changes: 70 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
@@ -158,6 +158,71 @@ Utils.prototype.Log = function Log(options) {
}
};

/**
* JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
*
* @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
* @see http://github.com/garycourt/murmurhash-js
* @author <a href="mailto:aappleby@gmail.com">Austin Appleby</a>
* @see http://sites.google.com/site/murmurhash/
*
* @param {string} key ASCII only
* @param {number} seed Positive integer only
* @return {number} 32-bit positive integer hash
*/

function murmurhash3_32_gc(key, seed) {
let remainder; let bytes; let h1; let h1b; let c1; let c2; let k1; let i;

remainder = key.length & 3; // Same as key.length % 4
bytes = key.length - remainder;
h1 = seed;
c1 = 0xcc9e2d51;
c2 = 0x1b873593;
i = 0;

while (i < bytes) {
k1 =
((key.charCodeAt(i) & 0xff)) |
((key.charCodeAt(++i) & 0xff) << 8) |
((key.charCodeAt(++i) & 0xff) << 16) |
((key.charCodeAt(++i) & 0xff) << 24);
++i;

k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;
k1 = (k1 << 15) | (k1 >>> 17);
k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;

h1 ^= k1;
h1 = (h1 << 13) | (h1 >>> 19);
h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;
h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));
}

k1 = 0;

switch (remainder) {
case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
case 1: k1 ^= (key.charCodeAt(i) & 0xff);

k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
k1 = (k1 << 15) | (k1 >>> 17);
k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
h1 ^= k1;
}

h1 ^= key.length;

h1 ^= h1 >>> 16;
h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
h1 ^= h1 >>> 13;
h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;
h1 ^= h1 >>> 16;

return h1 >>> 0;
}

/**
* Hash string into another string (A-Z, 0-9)
*
@@ -171,26 +236,11 @@ Utils.prototype.hashStringToString = function hashStringToString(str, length) {
const base = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const resultIndices = new Array(length);

// Generate an index salt so that similar input strings will give different result strings
let indexSalt = 0;
for (let i = 0; i < str.length; i++) {
indexSalt += (1 << str.charCodeAt(i)) >>> 0;
}

if (str.length >= length) {
// Input string is longer or same length as desired result string length
for (let i = 0; i < str.length; ++i) {
const resultIndex = i % length;
const valueIndex = Math.abs(((resultIndices[resultIndex] ? resultIndices[resultIndex] : 0) + ((1 << str.charCodeAt(i))) + indexSalt + i) % base.length);
resultIndices[resultIndex] = valueIndex;
}
} else {
// Result string string is longer than the input string
for (let i = 0; i < resultIndices.length; ++i) {
const resultIndex = i;
const valueIndex = Math.abs((((1 << str.charCodeAt(i % str.length)) * i) + indexSalt) % base.length);
resultIndices[resultIndex] = valueIndex;
}
for (let i = 0; i < resultIndices.length; ++i) {
const indexHash = murmurhash3_32_gc(str, i);

const valueIndex = Math.abs(indexHash % base.length);
resultIndices[i] = valueIndex;
}

const result = resultIndices.map(x => base[x]).join('');
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "larvitutils",
"version": "2.3.2",
"version": "2.3.3",
"description": "Misc utils",
"main": "index.js",
"devDependencies": {
8 changes: 8 additions & 0 deletions test/hashStringToString.js
Original file line number Diff line number Diff line change
@@ -47,3 +47,11 @@ test('hashStringToString() - Hash string where all characters are the same shoul

t.end();
});

test('hashStringToString() - Two similar strings should not give the same hash (bug fixed so using exact strings that caused trouble here)', t => {
const str1 = 'L266' + '9560-13';
const str2 = 'L266' + '9500-13';

t.notEqual(utils.hashStringToString(str1, 6), utils.hashStringToString(str2, 6));
t.end();
});