Last active

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

Port just enough of Murmur3 32bit to javascript for clojurescript. Goal is to produce identical results and capabilities as this class: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Murmur3.java

View murmur3_32.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
/**
* Javascript port of Clojure's flavor of Murmur3.
* See https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Murmur3.java
*
* Find at: https://gist.github.com/favila/9088146
* By favila (Francis Avila) 2014-02-19
*/
goog.provide('cljs.lang.murmur3');
goog.require('cljs.core');
 
goog.scope(function(){
"use strict";
 
var murmur3 = cljs.lang.murmur3;
 
/**
* imul polyfill
*
* @param {number} a
* @param {number} b
* @return {number}
* @nosideeffects
*/
murmur3.imul = Math['imul'] ||
// Using bracket notation for Math.imul because goog compiler lacks an extern for it.
function (a, b) {
var c = a & 65535, d = b & 65535;
return c * d + ((a >>> 16 & 65535) * d + c * (b >>> 16 & 65535) << 16 >>> 0) | 0;
};
 
 
/** @const */
murmur3.SEED = 0;
 
 
/** @const */
murmur3.C1 = 0xcc9e2d51;
 
 
/** @const */
murmur3.C2 = 0x1b873593;
 
 
/**
* @param {number} k1 32-bit signed int
* @return {number} 32-bit signed int
*/
murmur3.mixK1 = function(k1) {
// Mask-and-shifts are to emulate multiplication overflow. Otherwise we
// could lose some bits of the significand if k1 is large enough.
// k1 *= murmur3.C1
k1 = murmur3.imul(k1, murmur3.C1);
k1 = (k1 << 15) | (k1 >>> 17); // rotateLeft(k1, 15)
// k1 *= murmur3.C2
k1 = murmur3.imul(k1, murmur3.C2);
return k1;
};
 
 
/**
* @param {number} h1 32-bit signed int
* @param {number} k1 32-bit signed int
* @return {number} 32-bit signed int
*/
murmur3.mixH1 = function(h1, k1) {
h1 ^= k1;
h1 = (h1 << 13) | (h1 >>> 19); // rotateLeft(h1, 13)
// h1 = h1 * 5 + 0xe6546b64
h1 = (murmur3.imul(h1, 5) + 0xe6546b64) | 0;
return h1;
};
 
 
/**
* @param {number} h1 32-bit signed int
* @param {number} length 32-bit signed int
* @return {number} 32-bit signed int
*/
murmur3.fmix = function(h1, length) {
h1 ^= length;
h1 ^= h1 >>> 16;
// h1 *= 0x85ebca6b
h1 = murmur3.imul(h1, 0x85ebca6b);
h1 ^= h1 >>> 13;
// h1 *= 0xc2b2ae35
h1 = murmur3.imul(h1, 0xc2b2ae35);
h1 ^= h1 >>> 16;
return h1;
};
 
 
/**
* @param {number} hash 32-bit signed int
* @param {number} count 32-bit signed int
* @return {number} 32-bit signed int
*/
murmur3.mixCollHash = function(hash, count){
var h1 = murmur3.SEED;
var k1 = murmur3.mixK1(hash);
h1 = murmur3.mixH1(h1, k1);
return murmur3.fmix(h1, count);
};
 
 
/**
* @param {number} input 32-bit signed int
* @return {number} 32-bit signed int
*/
murmur3.hashInt = function(input){
if (input === 0) return 0;
var k1 = murmur3.mixK1(input);
var h1 = murmur3.mixH1(murmur3.SEED, k1);
return murmur3.fmix(h1, 4);
};
 
// FIXME: No murmur3.hashLong() because no 64-bit longs in js. However, we may
// get up to 6.5 byte ints by retrieving the high 2.5 bytes with division.
// Should we try to hash the upper int range as if it were a full long? If so,
// should it replace hashInt() for all JS-number hashing, or only be used if
// we are out of 4-byte range?
 
 
/**
* Hash a string.
*
* @param {string} input input string
* @return {number}
*/
murmur3.hashUnencodedChars = function(input){
var h1 = murmur3.SEED, k1 = 0, i = 1, l = input.length;
 
while(i < l) {
k1 = input.charCodeAt(i - 1) | (input.charCodeAt(i) << 16);
i += 2;
k1 = murmur3.mixK1(k1);
h1 = murmur3.mixH1(h1, k1);
}
 
if (i === l) {
k1 = input.charCodeAt(i - 1);
k1 = murmur3.mixK1(k1);
h1 ^= k1;
}
 
return murmur3.fmix(h1, (l + l) |0);
};
 
 
//FIXME: Probably hashOrdered and hashUnordered should be implemented in clojurescript?
/**
* @param {*} xs seqable
* @return {number} 32-bit signed int
*/
murmur3.hashOrdered = function(xs){
var n = 0, hash = 1;
xs = cljs.core.seq(xs);
 
while (xs !== null) {
// hash = 31 * hash + cljs.core.hash(cljs.core.first(xs));
hash = (murmur3.imul(31, hash) + cljs.core.hash(cljs.core.first(xs))) | 0;
++n;
xs = cljs.core.next(xs);
}
 
return murmur3.mixCollHash(hash, n);
};
 
 
/**
* @param {*} xs seqable
* @return {number} 32-bit signed int
*/
murmur3.hashUnordered = function(xs) {
var hash = 0, n = 0;
xs = cljs.core.seq(xs);
 
while (xs !== null) {
hash = (hash + cljs.core.hash(cljs.core.first(xs))) | 0;
++n;
xs = cljs.core.next(xs);
}
return murmur3.mixCollHash(hash, n);
}
 
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.