package scala.util
import java.lang.Integer.{ rotateLeft => rotl }
import scala.collection.Iterator
class MurmurHash[@specialized(Int,Long,Float,Double) T](seed: Int) extends (T => Unit) {
import MurmurHash._
private var h = startHash(seed)
private var c = hiddenMagicA
private var k = hiddenMagicB
private var hashed = false
private var hashvalue = h
def reset() {
h = startHash(seed)
c = hiddenMagicA
k = hiddenMagicB
hashed = false
}
def apply(t: T) {
h = extendHash(h,t.##,c,k)
c = nextMagicA(c)
k = nextMagicB(k)
hashed = false
}
def append(i: Int) {
h = extendHash(h,i,c,k)
c = nextMagicA(c)
k = nextMagicB(k)
hashed = false
}
def hash = {
if (!hashed) {
hashvalue = finalizeHash(h)
hashed = true
}
hashvalue
}
override def hashCode = hash
}
object MurmurHash {
final private val visibleMagic = 0x971e137b
final private val hiddenMagicA = 0x95543787
final private val hiddenMagicB = 0x2ad7eb25
final private val visibleMixer = 0x52dce729
final private val hiddenMixerA = 0x7b7d159c
final private val hiddenMixerB = 0x6bce6396
final private val finalMixer1 = 0x85ebca6b
final private val finalMixer2 = 0xc2b2ae35
final private val seedString = 0xf7ca7fd2
final private val seedArray = 0x3c074a61
val storedMagicA =
Iterator.iterate(hiddenMagicA)(nextMagicA).take(23).toArray
val storedMagicB =
Iterator.iterate(hiddenMagicB)(nextMagicB).take(23).toArray
def startHash(seed: Int) = seed ^ visibleMagic
def startMagicA = hiddenMagicA
def startMagicB = hiddenMagicB
def extendHash(hash: Int, value: Int, magicA: Int, magicB: Int) = {
(hash ^ rotl(value*magicA,11)*magicB)*3 + visibleMixer
}
def nextMagicA(magicA: Int) = magicA*5 + hiddenMixerA
def nextMagicB(magicB: Int) = magicB*5 + hiddenMixerB
def finalizeHash(hash: Int) = {
var i = (hash ^ (hash>>>16))
i *= finalMixer1
i ^= (i >>> 13)
i *= finalMixer2
i ^= (i >>> 16)
i
}
def arrayHash[@specialized T](a: Array[T]) = {
var h = startHash(a.length * seedArray)
var c = hiddenMagicA
var k = hiddenMagicB
var j = 0
while (j < a.length) {
h = extendHash(h, a(j).##, c, k)
c = nextMagicA(c)
k = nextMagicB(k)
j += 1
}
finalizeHash(h)
}
def stringHash(s: String) = {
var h = startHash(s.length * seedString)
var c = hiddenMagicA
var k = hiddenMagicB
var j = 0
while (j+1 < s.length) {
val i = (s.charAt(j)<<16) + s.charAt(j+1);
h = extendHash(h,i,c,k)
c = nextMagicA(c)
k = nextMagicB(k)
j += 2
}
if (j < s.length) h = extendHash(h,s.charAt(j),c,k)
finalizeHash(h)
}
def symmetricHash[T](xs: collection.TraversableOnce[T], seed: Int) = {
var a,b,n = 0
var c = 1
xs.seq.foreach(i => {
val h = i.##
a += h
b ^= h
if (h != 0) c *= h
n += 1
})
var h = startHash(seed * n)
h = extendHash(h, a, storedMagicA(0), storedMagicB(0))
h = extendHash(h, b, storedMagicA(1), storedMagicB(1))
h = extendHash(h, c, storedMagicA(2), storedMagicB(2))
finalizeHash(h)
}
}