123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- package farm
- // This file provides a 32-bit hash equivalent to CityHash32 (v1.1.1)
- // and a 128-bit hash equivalent to CityHash128 (v1.1.1). It also provides
- // a seeded 32-bit hash function similar to CityHash32.
- func hash32Len13to24Seed(s []byte, seed uint32) uint32 {
- slen := len(s)
- a := fetch32(s, -4+(slen>>1))
- b := fetch32(s, 4)
- c := fetch32(s, slen-8)
- d := fetch32(s, (slen >> 1))
- e := fetch32(s, 0)
- f := fetch32(s, slen-4)
- h := d*c1 + uint32(slen) + seed
- a = rotate32(a, 12) + f
- h = mur(c, h) + a
- a = rotate32(a, 3) + c
- h = mur(e, h) + a
- a = rotate32(a+f, 12) + d
- h = mur(b^seed, h) + a
- return fmix(h)
- }
- func hash32Len0to4(s []byte, seed uint32) uint32 {
- slen := len(s)
- b := seed
- c := uint32(9)
- for i := 0; i < slen; i++ {
- v := uint32(s[i])
- b = (b * c1) + v
- c ^= b
- }
- return fmix(mur(b, mur(uint32(slen), c)))
- }
- func hash128to64(x uint128) uint64 {
- // Murmur-inspired hashing.
- const mul uint64 = 0x9ddfea08eb382d69
- a := (x.lo ^ x.hi) * mul
- a ^= (a >> 47)
- b := (x.hi ^ a) * mul
- b ^= (b >> 47)
- b *= mul
- return b
- }
- type uint128 struct {
- lo uint64
- hi uint64
- }
- // A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
- // of any length representable in signed long. Based on City and Murmur.
- func cityMurmur(s []byte, seed uint128) uint128 {
- slen := len(s)
- a := seed.lo
- b := seed.hi
- var c uint64
- var d uint64
- l := slen - 16
- if l <= 0 { // len <= 16
- a = shiftMix(a*k1) * k1
- c = b*k1 + hashLen0to16(s)
- if slen >= 8 {
- d = shiftMix(a + fetch64(s, 0))
- } else {
- d = shiftMix(a + c)
- }
- } else { // len > 16
- c = hashLen16(fetch64(s, slen-8)+k1, a)
- d = hashLen16(b+uint64(slen), c+fetch64(s, slen-16))
- a += d
- for {
- a ^= shiftMix(fetch64(s, 0)*k1) * k1
- a *= k1
- b ^= a
- c ^= shiftMix(fetch64(s, 8)*k1) * k1
- c *= k1
- d ^= c
- s = s[16:]
- l -= 16
- if l <= 0 {
- break
- }
- }
- }
- a = hashLen16(a, c)
- b = hashLen16(d, b)
- return uint128{a ^ b, hashLen16(b, a)}
- }
- func cityHash128WithSeed(s []byte, seed uint128) uint128 {
- slen := len(s)
- if slen < 128 {
- return cityMurmur(s, seed)
- }
- endIdx := ((slen - 1) / 128) * 128
- lastBlockIdx := endIdx + ((slen - 1) & 127) - 127
- last := s[lastBlockIdx:]
- // We expect len >= 128 to be the common case. Keep 56 bytes of state:
- // v, w, x, y, and z.
- var v1, v2 uint64
- var w1, w2 uint64
- x := seed.lo
- y := seed.hi
- z := uint64(slen) * k1
- v1 = rotate64(y^k1, 49)*k1 + fetch64(s, 0)
- v2 = rotate64(v1, 42)*k1 + fetch64(s, 8)
- w1 = rotate64(y+z, 35)*k1 + x
- w2 = rotate64(x+fetch64(s, 88), 53) * k1
- // This is the same inner loop as CityHash64(), manually unrolled.
- for {
- x = rotate64(x+y+v1+fetch64(s, 8), 37) * k1
- y = rotate64(y+v2+fetch64(s, 48), 42) * k1
- x ^= w2
- y += v1 + fetch64(s, 40)
- z = rotate64(z+w1, 33) * k1
- v1, v2 = weakHashLen32WithSeeds(s, v2*k1, x+w1)
- w1, w2 = weakHashLen32WithSeeds(s[32:], z+w2, y+fetch64(s, 16))
- z, x = x, z
- s = s[64:]
- x = rotate64(x+y+v1+fetch64(s, 8), 37) * k1
- y = rotate64(y+v2+fetch64(s, 48), 42) * k1
- x ^= w2
- y += v1 + fetch64(s, 40)
- z = rotate64(z+w1, 33) * k1
- v1, v2 = weakHashLen32WithSeeds(s, v2*k1, x+w1)
- w1, w2 = weakHashLen32WithSeeds(s[32:], z+w2, y+fetch64(s, 16))
- z, x = x, z
- s = s[64:]
- slen -= 128
- if slen < 128 {
- break
- }
- }
- x += rotate64(v1+z, 49) * k0
- y = y*k0 + rotate64(w2, 37)
- z = z*k0 + rotate64(w1, 27)
- w1 *= 9
- v1 *= k0
- // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
- for tailDone := 0; tailDone < slen; {
- tailDone += 32
- y = rotate64(x+y, 42)*k0 + v2
- w1 += fetch64(last, 128-tailDone+16)
- x = x*k0 + w1
- z += w2 + fetch64(last, 128-tailDone)
- w2 += v1
- v1, v2 = weakHashLen32WithSeeds(last[128-tailDone:], v1+z, v2)
- v1 *= k0
- }
- // At this point our 56 bytes of state should contain more than
- // enough information for a strong 128-bit hash. We use two
- // different 56-byte-to-8-byte hashes to get a 16-byte final result.
- x = hashLen16(x, v1)
- y = hashLen16(y+z, w1)
- return uint128{hashLen16(x+v2, w2) + y,
- hashLen16(x+w2, y+v2)}
- }
- func cityHash128(s []byte) uint128 {
- slen := len(s)
- if slen >= 16 {
- return cityHash128WithSeed(s[16:], uint128{fetch64(s, 0), fetch64(s, 8) + k0})
- }
- return cityHash128WithSeed(s, uint128{k0, k1})
- }
- // Fingerprint128 is a 128-bit fingerprint function for byte-slices
- func Fingerprint128(s []byte) (lo, hi uint64) {
- h := cityHash128(s)
- return h.lo, h.hi
- }
- // Fingerprint64 is a 64-bit fingerprint function for byte-slices
- func Fingerprint64(s []byte) uint64 {
- return Hash64(s)
- }
- // Fingerprint32 is a 32-bit fingerprint function for byte-slices
- func Fingerprint32(s []byte) uint32 {
- return Hash32(s)
- }
- // Hash128 is a 128-bit hash function for byte-slices
- func Hash128(s []byte) (lo, hi uint64) {
- return Fingerprint128(s)
- }
- // Hash128WithSeed is a 128-bit hash function for byte-slices and a 128-bit seed
- func Hash128WithSeed(s []byte, seed0, seed1 uint64) (lo, hi uint64) {
- h := cityHash128WithSeed(s, uint128{seed0, seed1})
- return h.lo, h.hi
- }
|