Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Replace murmur hash with djb2 hash
Browse files Browse the repository at this point in the history
In profiling StyleSheet.create, I noticed that much of the time was
spent hashing. So, I found a faster hashing algorithm.

The implementation was taken from:

  https://github.com/darkskyapp/string-hash

According to this StackExchange post, this algorithm doesn't have as
good of randomness, but it has about the same percentage of collisions.
I don't think randomness matters for this application, so I think this
is okay.

  http://softwareengineering.stackexchange.com/a/145633

Using similar methodology to #202, this appears to make StylSheet.create
~15% faster (~220ms to ~185ms).
lencioni committed Mar 4, 2017
1 parent e30ed7b commit 64df84d
Showing 1 changed file with 13 additions and 42 deletions.
55 changes: 13 additions & 42 deletions src/util.js
Original file line number Diff line number Diff line change
@@ -152,52 +152,23 @@ export const stringifyValue = (
};

/**
* JS Implementation of MurmurHash2
* JS Implementation of djb2
*
* @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} str ASCII only
* @return {string} Base 36 encoded hash result
* @see https://github.com/darkskyapp/string-hash
*/
function murmurhash2_32_gc(str) {
let l = str.length;
let h = l;
let i = 0;
let k;

while (l >= 4) {
k = ((str.charCodeAt(i) & 0xff)) |
((str.charCodeAt(++i) & 0xff) << 8) |
((str.charCodeAt(++i) & 0xff) << 16) |
((str.charCodeAt(++i) & 0xff) << 24);

k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));
k ^= k >>> 24;
k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));

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

l -= 4;
++i;
}

/* eslint-disable no-fallthrough */ // forgive existing code
switch (l) {
case 3: h ^= (str.charCodeAt(i + 2) & 0xff) << 16;
case 2: h ^= (str.charCodeAt(i + 1) & 0xff) << 8;
case 1: h ^= (str.charCodeAt(i) & 0xff);
h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));
}
/* eslint-enable no-fallthrough */
function djb2Hash(str) {
let hash = 5381;
let i = str.length;

h ^= h >>> 13;
h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));
h ^= h >>> 15;
while(i) {
hash = (hash * 33) ^ str.charCodeAt(--i);
}

return (h >>> 0).toString(36);
/* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
* integers. Since we want the results to be always positive, convert the
* signed int to an unsigned by doing an unsigned bitshift. */
return "" + (hash >>> 0);
}

// Hash a javascript object using JSON.stringify. This is very fast, about 3
@@ -208,7 +179,7 @@ function murmurhash2_32_gc(str) {
// this to produce consistent hashes browsers need to have a consistent
// ordering of objects. Ben Alpert says that Facebook depends on this, so we
// can probably depend on this too.
export const hashObject = (object /* : ObjectMap */) /* : string */ => murmurhash2_32_gc(JSON.stringify(object));
export const hashObject = (object /* : ObjectMap */) /* : string */ => djb2Hash(JSON.stringify(object));


const IMPORTANT_RE = /^([^:]+:.*?)( !important)?;$/;

0 comments on commit 64df84d

Please sign in to comment.