farmhashuo.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package farm
  2. func uoH(x, y, mul uint64, r uint) uint64 {
  3. a := (x ^ y) * mul
  4. a ^= (a >> 47)
  5. b := (y ^ a) * mul
  6. return rotate64(b, r) * mul
  7. }
  8. // Hash64WithSeeds hashes a byte slice and two uint64 seeds and returns a uint64 hash value
  9. func Hash64WithSeeds(s []byte, seed0, seed1 uint64) uint64 {
  10. slen := len(s)
  11. if slen <= 64 {
  12. return naHash64WithSeeds(s, seed0, seed1)
  13. }
  14. // For strings over 64 bytes we loop. Internal state consists of
  15. // 64 bytes: u, v, w, x, y, and z.
  16. x := seed0
  17. y := seed1*k2 + 113
  18. z := shiftMix(y*k2) * k2
  19. v := uint128{seed0, seed1}
  20. var w uint128
  21. u := x - z
  22. x *= k2
  23. mul := k2 + (u & 0x82)
  24. // Set end so that after the loop we have 1 to 64 bytes left to process.
  25. endIdx := ((slen - 1) / 64) * 64
  26. last64Idx := endIdx + ((slen - 1) & 63) - 63
  27. last64 := s[last64Idx:]
  28. for len(s) > 64 {
  29. a0 := fetch64(s, 0)
  30. a1 := fetch64(s, 8)
  31. a2 := fetch64(s, 16)
  32. a3 := fetch64(s, 24)
  33. a4 := fetch64(s, 32)
  34. a5 := fetch64(s, 40)
  35. a6 := fetch64(s, 48)
  36. a7 := fetch64(s, 56)
  37. x += a0 + a1
  38. y += a2
  39. z += a3
  40. v.lo += a4
  41. v.hi += a5 + a1
  42. w.lo += a6
  43. w.hi += a7
  44. x = rotate64(x, 26)
  45. x *= 9
  46. y = rotate64(y, 29)
  47. z *= mul
  48. v.lo = rotate64(v.lo, 33)
  49. v.hi = rotate64(v.hi, 30)
  50. w.lo ^= x
  51. w.lo *= 9
  52. z = rotate64(z, 32)
  53. z += w.hi
  54. w.hi += z
  55. z *= 9
  56. u, y = y, u
  57. z += a0 + a6
  58. v.lo += a2
  59. v.hi += a3
  60. w.lo += a4
  61. w.hi += a5 + a6
  62. x += a1
  63. y += a7
  64. y += v.lo
  65. v.lo += x - y
  66. v.hi += w.lo
  67. w.lo += v.hi
  68. w.hi += x - y
  69. x += w.hi
  70. w.hi = rotate64(w.hi, 34)
  71. u, z = z, u
  72. s = s[64:]
  73. }
  74. // Make s point to the last 64 bytes of input.
  75. s = last64
  76. u *= 9
  77. v.hi = rotate64(v.hi, 28)
  78. v.lo = rotate64(v.lo, 20)
  79. w.lo += (uint64(slen-1) & 63)
  80. u += y
  81. y += u
  82. x = rotate64(y-x+v.lo+fetch64(s, 8), 37) * mul
  83. y = rotate64(y^v.hi^fetch64(s, 48), 42) * mul
  84. x ^= w.hi * 9
  85. y += v.lo + fetch64(s, 40)
  86. z = rotate64(z+w.lo, 33) * mul
  87. v.lo, v.hi = weakHashLen32WithSeeds(s, v.hi*mul, x+w.lo)
  88. w.lo, w.hi = weakHashLen32WithSeeds(s[32:], z+w.hi, y+fetch64(s, 16))
  89. return uoH(hashLen16Mul(v.lo+x, w.lo^y, mul)+z-u,
  90. uoH(v.hi+y, w.hi+z, k2, 30)^x,
  91. k2,
  92. 31)
  93. }
  94. // Hash64WithSeed hashes a byte slice and a uint64 seed and returns a uint64 hash value
  95. func Hash64WithSeed(s []byte, seed uint64) uint64 {
  96. if len(s) <= 64 {
  97. return naHash64WithSeed(s, seed)
  98. }
  99. return Hash64WithSeeds(s, 0, seed)
  100. }
  101. // Hash64 hashes a byte slice and returns a uint64 hash value
  102. func Hash64(s []byte) uint64 {
  103. if len(s) <= 64 {
  104. return naHash64(s)
  105. }
  106. return Hash64WithSeeds(s, 81, 0)
  107. }