Skip to content

Instantly share code, notes, and snippets.

@favila
Created February 24, 2014 22:28
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save favila/9198622 to your computer and use it in GitHub Desktop.
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
(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