Created
February 24, 2014 22:28
-
-
Save favila/9198622 to your computer and use it in GitHub Desktop.
Implementation of murmur3 in clojurescript. Is a port of https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Murmur3.java See also a js version at https://gist.github.com/favila/9088146
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns murmur3 | |
"Implementation of clojure.lang.Murmur3 in clojurescript (assuming javascript numerics). | |
by Francis Avila 2014-02-24") | |
(def imul | |
"32-bit signed integer multiply with overflow; alias of js/Math.imul. | |
Does not follow unchecked-multiply-int semantics! Only two args accepted; if | |
args are missing returns 0." | |
(if (exists? (aget js/Math "imul")) | |
(aget js/Math "imul") | |
(fn [a b] | |
(let [ah (bit-and (unsigned-bit-shift-right a 16) 0xffff) | |
al (bit-and a 0xffff) | |
bh (bit-and (unsigned-bit-shift-right b 16) 0xffff) | |
bl (bit-and b 0xffff)] | |
(int (unsigned-bit-shift-right | |
(+ (* al bl) (bit-shift-left (+ (* ah bl) (* al bh)) 16)) 0)))))) | |
(def ^:private ^:const seed 0) | |
(def ^:private ^:const c1 (int 0xcc9e2d51)) | |
(def ^:private ^:const c2 (int 0x1b873593)) | |
(defn mix-k1 [k1] | |
(let [k1 (imul k1 c1) | |
;; k1 = rotateLeft(k1, 15) | |
k1 (bit-or (bit-shift-left k1 15) (unsigned-bit-shift-right k1 17))] | |
(imul k1 c2))) | |
(defn mix-h1 [h1 k1] | |
(let [h1 (bit-xor h1 k1) | |
;; h1 = rotateLeft(h1, 13) | |
h1 (bit-or (bit-shift-left h1 13) (unsigned-bit-shift-right h1 19))] | |
(int (unchecked-add-int (imul h1 5) (int 0xe6546b64))))) | |
(defn fmix [h1 len] | |
(as-> h1 | |
(bit-xor h1 len) | |
(bit-xor h1 (unsigned-bit-shift-right h1 16)) | |
(imul h1 (int 0x85ebca6b)) | |
(bit-xor h1 (unsigned-bit-shift-right h1 13)) | |
(imul h1 (int 0xc2b2ae35)) | |
(bit-xor h1 (unsigned-bit-shift-right h1 16)))) | |
(defn mix-coll-hash [hash count] | |
(let [k1 (mix-k1 hash) | |
h1 (mix-h1 seed k1)] | |
(fmix h1 count))) | |
(defn hash-int [input] | |
(if (zero? input) | |
0 | |
(let [k1 (mix-k1 input) | |
h1 (mix-h1 seed k1)] | |
(fmix h1 4)))) | |
(defn bigint-high-bits | |
"Return the high 21 bits of a 53-bit js integer as a signed 32-bit integer. | |
`(js/Number.isInteger i)` must be true for the results to be meaningful." | |
[i] | |
(int (/ (- i (unsigned-bit-shift-right i 0)) 0x100000000))) | |
(defn hash-long [input] | |
(if (zero? input) | |
0 | |
(let [low (int input) | |
high (bigint-high-bits input) | |
k1 (mix-k1 low) | |
h1 (mix-h1 seed k1) | |
k1 (mix-k1 high) | |
h1 (mix-h1 h1 k1)] | |
(fmix h1 8)))) | |
(defn hash-string [input] | |
(let [l (alength input)] | |
(loop [i 1 h1 seed] | |
(if (< i l) | |
(let [k1 (mix-k1 (bit-or (.charCodeAt input (dec i)) | |
(bit-shift-left (.charCodeAt input i) 16)))] | |
(recur (+ i 2) (mix-h1 h1 k1))) | |
(let [h1 (if (== i 1) | |
(->> (.charCodeAt input (dec i)) | |
(mix-k1) | |
(bit-xor h1)) | |
h1)] | |
(fmix h1 (int (+ l l)))))))) | |
(defn hash-unordered [xs] | |
(loop [n 0 hsh 0 xs (seq xs)] | |
(if (nil? xs) | |
(mix-coll-hash hsh n) | |
(recur (inc n) (int (+ hsh (hash (first xs)))) (next xs))))) | |
(defn hash-ordered [xs] | |
(loop [n 0 hsh 1 xs (seq xs)] | |
(if (nil? xs) | |
(mix-coll-hash hsh n) | |
(recur (inc n) (int (+ (imul 31 hsh) (hash (first xs)))) (next xs))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment