xxhash.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Package xxhash implements the 64-bit variant of xxHash (XXH64) as described
  2. // at http://cyan4973.github.io/xxHash/.
  3. package xxhash
  4. import (
  5. "encoding/binary"
  6. "hash"
  7. )
  8. const (
  9. prime1 uint64 = 11400714785074694791
  10. prime2 uint64 = 14029467366897019727
  11. prime3 uint64 = 1609587929392839161
  12. prime4 uint64 = 9650029242287828579
  13. prime5 uint64 = 2870177450012600261
  14. )
  15. // NOTE(caleb): I'm using both consts and vars of the primes. Using consts where
  16. // possible in the Go code is worth a small (but measurable) performance boost
  17. // by avoiding some MOVQs. Vars are needed for the asm and also are useful for
  18. // convenience in the Go code in a few places where we need to intentionally
  19. // avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the
  20. // result overflows a uint64).
  21. var (
  22. prime1v = prime1
  23. prime2v = prime2
  24. prime3v = prime3
  25. prime4v = prime4
  26. prime5v = prime5
  27. )
  28. type xxh struct {
  29. v1 uint64
  30. v2 uint64
  31. v3 uint64
  32. v4 uint64
  33. total int
  34. mem [32]byte
  35. n int // how much of mem is used
  36. }
  37. // New creates a new hash.Hash64 that implements the 64-bit xxHash algorithm.
  38. func New() hash.Hash64 {
  39. var x xxh
  40. x.Reset()
  41. return &x
  42. }
  43. func (x *xxh) Reset() {
  44. x.n = 0
  45. x.total = 0
  46. x.v1 = prime1v + prime2
  47. x.v2 = prime2
  48. x.v3 = 0
  49. x.v4 = -prime1v
  50. }
  51. func (x *xxh) Size() int { return 8 }
  52. func (x *xxh) BlockSize() int { return 32 }
  53. // Write adds more data to x. It always returns len(b), nil.
  54. func (x *xxh) Write(b []byte) (n int, err error) {
  55. n = len(b)
  56. x.total += len(b)
  57. if x.n+len(b) < 32 {
  58. // This new data doesn't even fill the current block.
  59. copy(x.mem[x.n:], b)
  60. x.n += len(b)
  61. return
  62. }
  63. if x.n > 0 {
  64. // Finish off the partial block.
  65. copy(x.mem[x.n:], b)
  66. x.v1 = round(x.v1, u64(x.mem[0:8]))
  67. x.v2 = round(x.v2, u64(x.mem[8:16]))
  68. x.v3 = round(x.v3, u64(x.mem[16:24]))
  69. x.v4 = round(x.v4, u64(x.mem[24:32]))
  70. b = b[32-x.n:]
  71. x.n = 0
  72. }
  73. if len(b) >= 32 {
  74. // One or more full blocks left.
  75. b = writeBlocks(x, b)
  76. }
  77. // Store any remaining partial block.
  78. copy(x.mem[:], b)
  79. x.n = len(b)
  80. return
  81. }
  82. func (x *xxh) Sum(b []byte) []byte {
  83. s := x.Sum64()
  84. return append(
  85. b,
  86. byte(s>>56),
  87. byte(s>>48),
  88. byte(s>>40),
  89. byte(s>>32),
  90. byte(s>>24),
  91. byte(s>>16),
  92. byte(s>>8),
  93. byte(s),
  94. )
  95. }
  96. func (x *xxh) Sum64() uint64 {
  97. var h uint64
  98. if x.total >= 32 {
  99. v1, v2, v3, v4 := x.v1, x.v2, x.v3, x.v4
  100. h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
  101. h = mergeRound(h, v1)
  102. h = mergeRound(h, v2)
  103. h = mergeRound(h, v3)
  104. h = mergeRound(h, v4)
  105. } else {
  106. h = x.v3 + prime5
  107. }
  108. h += uint64(x.total)
  109. i, end := 0, x.n
  110. for ; i+8 <= end; i += 8 {
  111. k1 := round(0, u64(x.mem[i:i+8]))
  112. h ^= k1
  113. h = rol27(h)*prime1 + prime4
  114. }
  115. if i+4 <= end {
  116. h ^= uint64(u32(x.mem[i:i+4])) * prime1
  117. h = rol23(h)*prime2 + prime3
  118. i += 4
  119. }
  120. for i < end {
  121. h ^= uint64(x.mem[i]) * prime5
  122. h = rol11(h) * prime1
  123. i++
  124. }
  125. h ^= h >> 33
  126. h *= prime2
  127. h ^= h >> 29
  128. h *= prime3
  129. h ^= h >> 32
  130. return h
  131. }
  132. func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) }
  133. func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
  134. func round(acc, input uint64) uint64 {
  135. acc += input * prime2
  136. acc = rol31(acc)
  137. acc *= prime1
  138. return acc
  139. }
  140. func mergeRound(acc, val uint64) uint64 {
  141. val = round(0, val)
  142. acc ^= val
  143. acc = acc*prime1 + prime4
  144. return acc
  145. }