farmhashna.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package farm
  2. func shiftMix(val uint64) uint64 {
  3. return val ^ (val >> 47)
  4. }
  5. func hashLen16(u, v uint64) uint64 {
  6. return hash128to64(uint128{u, v})
  7. }
  8. func hashLen16Mul(u, v, mul uint64) uint64 {
  9. // Murmur-inspired hashing.
  10. a := (u ^ v) * mul
  11. a ^= (a >> 47)
  12. b := (v ^ a) * mul
  13. b ^= (b >> 47)
  14. b *= mul
  15. return b
  16. }
  17. func hashLen0to16(s []byte) uint64 {
  18. slen := uint64(len(s))
  19. if slen >= 8 {
  20. mul := k2 + slen*2
  21. a := fetch64(s, 0) + k2
  22. b := fetch64(s, int(slen-8))
  23. c := rotate64(b, 37)*mul + a
  24. d := (rotate64(a, 25) + b) * mul
  25. return hashLen16Mul(c, d, mul)
  26. }
  27. if slen >= 4 {
  28. mul := k2 + slen*2
  29. a := fetch32(s, 0)
  30. return hashLen16Mul(slen+(uint64(a)<<3), uint64(fetch32(s, int(slen-4))), mul)
  31. }
  32. if slen > 0 {
  33. a := s[0]
  34. b := s[slen>>1]
  35. c := s[slen-1]
  36. y := uint32(a) + (uint32(b) << 8)
  37. z := uint32(slen) + (uint32(c) << 2)
  38. return shiftMix(uint64(y)*k2^uint64(z)*k0) * k2
  39. }
  40. return k2
  41. }
  42. // This probably works well for 16-byte strings as well, but it may be overkill
  43. // in that case.
  44. func hashLen17to32(s []byte) uint64 {
  45. slen := len(s)
  46. mul := k2 + uint64(slen*2)
  47. a := fetch64(s, 0) * k1
  48. b := fetch64(s, 8)
  49. c := fetch64(s, slen-8) * mul
  50. d := fetch64(s, slen-16) * k2
  51. return hashLen16Mul(rotate64(a+b, 43)+rotate64(c, 30)+d, a+rotate64(b+k2, 18)+c, mul)
  52. }
  53. // Return a 16-byte hash for 48 bytes. Quick and dirty.
  54. // Callers do best to use "random-looking" values for a and b.
  55. func weakHashLen32WithSeedsWords(w, x, y, z, a, b uint64) (uint64, uint64) {
  56. a += w
  57. b = rotate64(b+a+z, 21)
  58. c := a
  59. a += x
  60. a += y
  61. b += rotate64(a, 44)
  62. return a + z, b + c
  63. }
  64. // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
  65. func weakHashLen32WithSeeds(s []byte, a, b uint64) (uint64, uint64) {
  66. return weakHashLen32WithSeedsWords(fetch64(s, 0),
  67. fetch64(s, 8),
  68. fetch64(s, 16),
  69. fetch64(s, 24),
  70. a,
  71. b)
  72. }
  73. // Return an 8-byte hash for 33 to 64 bytes.
  74. func hashLen33to64(s []byte) uint64 {
  75. slen := len(s)
  76. mul := k2 + uint64(slen)*2
  77. a := fetch64(s, 0) * k2
  78. b := fetch64(s, 8)
  79. c := fetch64(s, slen-8) * mul
  80. d := fetch64(s, slen-16) * k2
  81. y := rotate64(a+b, 43) + rotate64(c, 30) + d
  82. z := hashLen16Mul(y, a+rotate64(b+k2, 18)+c, mul)
  83. e := fetch64(s, 16) * mul
  84. f := fetch64(s, 24)
  85. g := (y + fetch64(s, slen-32)) * mul
  86. h := (z + fetch64(s, slen-24)) * mul
  87. return hashLen16Mul(rotate64(e+f, 43)+rotate64(g, 30)+h, e+rotate64(f+a, 18)+g, mul)
  88. }
  89. // NOTE: s must be <= 64 bytes
  90. func naHash64(s []byte) uint64 {
  91. slen := len(s)
  92. const seed uint64 = 81
  93. if slen <= 16 {
  94. return hashLen0to16(s)
  95. }
  96. if slen <= 32 {
  97. return hashLen17to32(s)
  98. }
  99. return hashLen33to64(s)
  100. }
  101. func naHash64WithSeed(s []byte, seed uint64) uint64 {
  102. return naHash64WithSeeds(s, k2, seed)
  103. }
  104. func naHash64WithSeeds(s []byte, seed0, seed1 uint64) uint64 {
  105. return hashLen16(naHash64(s)-seed0, seed1)
  106. }