118 lines
2.5 KiB
Go
118 lines
2.5 KiB
Go
|
package farm
|
||
|
|
||
|
func uoH(x, y, mul uint64, r uint) uint64 {
|
||
|
a := (x ^ y) * mul
|
||
|
a ^= (a >> 47)
|
||
|
b := (y ^ a) * mul
|
||
|
return rotate64(b, r) * mul
|
||
|
}
|
||
|
|
||
|
// Hash64WithSeeds hashes a byte slice and two uint64 seeds and returns a uint64 hash value
|
||
|
func Hash64WithSeeds(s []byte, seed0, seed1 uint64) uint64 {
|
||
|
slen := len(s)
|
||
|
if slen <= 64 {
|
||
|
return naHash64WithSeeds(s, seed0, seed1)
|
||
|
}
|
||
|
|
||
|
// For strings over 64 bytes we loop.
|
||
|
// Internal state consists of 64 bytes: u, v, w, x, y, and z.
|
||
|
x := seed0
|
||
|
y := seed1*k2 + 113
|
||
|
z := shiftMix(y*k2) * k2
|
||
|
v := uint128{seed0, seed1}
|
||
|
var w uint128
|
||
|
u := x - z
|
||
|
x *= k2
|
||
|
mul := k2 + (u & 0x82)
|
||
|
|
||
|
// Set end so that after the loop we have 1 to 64 bytes left to process.
|
||
|
endIdx := ((slen - 1) / 64) * 64
|
||
|
last64Idx := endIdx + ((slen - 1) & 63) - 63
|
||
|
last64 := s[last64Idx:]
|
||
|
|
||
|
for len(s) > 64 {
|
||
|
a0 := fetch64(s, 0)
|
||
|
a1 := fetch64(s, 8)
|
||
|
a2 := fetch64(s, 16)
|
||
|
a3 := fetch64(s, 24)
|
||
|
a4 := fetch64(s, 32)
|
||
|
a5 := fetch64(s, 40)
|
||
|
a6 := fetch64(s, 48)
|
||
|
a7 := fetch64(s, 56)
|
||
|
x += a0 + a1
|
||
|
y += a2
|
||
|
z += a3
|
||
|
v.lo += a4
|
||
|
v.hi += a5 + a1
|
||
|
w.lo += a6
|
||
|
w.hi += a7
|
||
|
|
||
|
x = rotate64(x, 26)
|
||
|
x *= 9
|
||
|
y = rotate64(y, 29)
|
||
|
z *= mul
|
||
|
v.lo = rotate64(v.lo, 33)
|
||
|
v.hi = rotate64(v.hi, 30)
|
||
|
w.lo ^= x
|
||
|
w.lo *= 9
|
||
|
z = rotate64(z, 32)
|
||
|
z += w.hi
|
||
|
w.hi += z
|
||
|
z *= 9
|
||
|
u, y = y, u
|
||
|
|
||
|
z += a0 + a6
|
||
|
v.lo += a2
|
||
|
v.hi += a3
|
||
|
w.lo += a4
|
||
|
w.hi += a5 + a6
|
||
|
x += a1
|
||
|
y += a7
|
||
|
|
||
|
y += v.lo
|
||
|
v.lo += x - y
|
||
|
v.hi += w.lo
|
||
|
w.lo += v.hi
|
||
|
w.hi += x - y
|
||
|
x += w.hi
|
||
|
w.hi = rotate64(w.hi, 34)
|
||
|
u, z = z, u
|
||
|
s = s[64:]
|
||
|
}
|
||
|
// Make s point to the last 64 bytes of input.
|
||
|
s = last64
|
||
|
u *= 9
|
||
|
v.hi = rotate64(v.hi, 28)
|
||
|
v.lo = rotate64(v.lo, 20)
|
||
|
w.lo += (uint64(slen-1) & 63)
|
||
|
u += y
|
||
|
y += u
|
||
|
x = rotate64(y-x+v.lo+fetch64(s, 8), 37) * mul
|
||
|
y = rotate64(y^v.hi^fetch64(s, 48), 42) * mul
|
||
|
x ^= w.hi * 9
|
||
|
y += v.lo + fetch64(s, 40)
|
||
|
z = rotate64(z+w.lo, 33) * mul
|
||
|
v.lo, v.hi = weakHashLen32WithSeeds(s, v.hi*mul, x+w.lo)
|
||
|
w.lo, w.hi = weakHashLen32WithSeeds(s[32:], z+w.hi, y+fetch64(s, 16))
|
||
|
return uoH(hashLen16Mul(v.lo+x, w.lo^y, mul)+z-u,
|
||
|
uoH(v.hi+y, w.hi+z, k2, 30)^x,
|
||
|
k2,
|
||
|
31)
|
||
|
}
|
||
|
|
||
|
// Hash64WithSeed hashes a byte slice and a uint64 seed and returns a uint64 hash value
|
||
|
func Hash64WithSeed(s []byte, seed uint64) uint64 {
|
||
|
if len(s) <= 64 {
|
||
|
return naHash64WithSeed(s, seed)
|
||
|
}
|
||
|
return Hash64WithSeeds(s, 0, seed)
|
||
|
}
|
||
|
|
||
|
// Hash64 hashes a byte slice and returns a uint64 hash value
|
||
|
func Hash64(s []byte) uint64 {
|
||
|
if len(s) <= 64 {
|
||
|
return naHash64(s)
|
||
|
}
|
||
|
return Hash64WithSeeds(s, 81, 0)
|
||
|
}
|