2020-06-05 20:47:39 +00:00
|
|
|
// Package xxh32 implements the very fast XXH hashing algorithm (32 bits version).
|
|
|
|
// (https://github.com/Cyan4973/XXH/)
|
|
|
|
package xxh32
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2020-10-16 05:06:27 +00:00
|
|
|
prime1 uint32 = 2654435761
|
|
|
|
prime2 uint32 = 2246822519
|
|
|
|
prime3 uint32 = 3266489917
|
|
|
|
prime4 uint32 = 668265263
|
|
|
|
prime5 uint32 = 374761393
|
|
|
|
|
|
|
|
primeMask = 0xFFFFFFFF
|
|
|
|
prime1plus2 = uint32((uint64(prime1) + uint64(prime2)) & primeMask) // 606290984
|
|
|
|
prime1minus = uint32((-int64(prime1)) & primeMask) // 1640531535
|
2020-06-05 20:47:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// XXHZero represents an xxhash32 object with seed 0.
|
|
|
|
type XXHZero struct {
|
2020-11-06 18:41:42 +00:00
|
|
|
v [4]uint32
|
2020-06-05 20:47:39 +00:00
|
|
|
totalLen uint64
|
|
|
|
buf [16]byte
|
|
|
|
bufused int
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sum appends the current hash to b and returns the resulting slice.
|
|
|
|
// It does not change the underlying hash state.
|
|
|
|
func (xxh XXHZero) Sum(b []byte) []byte {
|
|
|
|
h32 := xxh.Sum32()
|
|
|
|
return append(b, byte(h32), byte(h32>>8), byte(h32>>16), byte(h32>>24))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset resets the Hash to its initial state.
|
|
|
|
func (xxh *XXHZero) Reset() {
|
2020-11-06 18:41:42 +00:00
|
|
|
xxh.v[0] = prime1plus2
|
|
|
|
xxh.v[1] = prime2
|
|
|
|
xxh.v[2] = 0
|
|
|
|
xxh.v[3] = prime1minus
|
2020-06-05 20:47:39 +00:00
|
|
|
xxh.totalLen = 0
|
|
|
|
xxh.bufused = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Size returns the number of bytes returned by Sum().
|
|
|
|
func (xxh *XXHZero) Size() int {
|
|
|
|
return 4
|
|
|
|
}
|
|
|
|
|
2020-11-06 18:41:42 +00:00
|
|
|
// BlockSizeIndex gives the minimum number of bytes accepted by Write().
|
2020-06-05 20:47:39 +00:00
|
|
|
func (xxh *XXHZero) BlockSize() int {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write adds input bytes to the Hash.
|
|
|
|
// It never returns an error.
|
|
|
|
func (xxh *XXHZero) Write(input []byte) (int, error) {
|
|
|
|
if xxh.totalLen == 0 {
|
|
|
|
xxh.Reset()
|
|
|
|
}
|
|
|
|
n := len(input)
|
|
|
|
m := xxh.bufused
|
|
|
|
|
|
|
|
xxh.totalLen += uint64(n)
|
|
|
|
|
|
|
|
r := len(xxh.buf) - m
|
|
|
|
if n < r {
|
|
|
|
copy(xxh.buf[m:], input)
|
|
|
|
xxh.bufused += len(input)
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
2020-11-06 18:41:42 +00:00
|
|
|
var buf *[16]byte
|
|
|
|
if m != 0 {
|
2020-06-05 20:47:39 +00:00
|
|
|
// some data left from previous update
|
2020-11-06 18:41:42 +00:00
|
|
|
buf = &xxh.buf
|
|
|
|
c := copy(buf[m:], input)
|
|
|
|
n -= c
|
|
|
|
input = input[c:]
|
|
|
|
}
|
|
|
|
update(&xxh.v, buf, input)
|
|
|
|
xxh.bufused = copy(xxh.buf[:], input[n-n%16:])
|
2020-06-05 20:47:39 +00:00
|
|
|
|
2020-11-06 18:41:42 +00:00
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Portable version of update. This updates v by processing all of buf
|
|
|
|
// (if not nil) and all full 16-byte blocks of input.
|
|
|
|
func updateGo(v *[4]uint32, buf *[16]byte, input []byte) {
|
|
|
|
// Causes compiler to work directly from registers instead of stack:
|
|
|
|
v1, v2, v3, v4 := v[0], v[1], v[2], v[3]
|
|
|
|
|
|
|
|
if buf != nil {
|
2020-10-16 05:06:27 +00:00
|
|
|
v1 = rol13(v1+binary.LittleEndian.Uint32(buf[:])*prime2) * prime1
|
|
|
|
v2 = rol13(v2+binary.LittleEndian.Uint32(buf[4:])*prime2) * prime1
|
|
|
|
v3 = rol13(v3+binary.LittleEndian.Uint32(buf[8:])*prime2) * prime1
|
|
|
|
v4 = rol13(v4+binary.LittleEndian.Uint32(buf[12:])*prime2) * prime1
|
2020-06-05 20:47:39 +00:00
|
|
|
}
|
|
|
|
|
2020-11-06 18:41:42 +00:00
|
|
|
for ; len(input) >= 16; input = input[16:] {
|
|
|
|
sub := input[:16] //BCE hint for compiler
|
2020-10-16 05:06:27 +00:00
|
|
|
v1 = rol13(v1+binary.LittleEndian.Uint32(sub[:])*prime2) * prime1
|
|
|
|
v2 = rol13(v2+binary.LittleEndian.Uint32(sub[4:])*prime2) * prime1
|
|
|
|
v3 = rol13(v3+binary.LittleEndian.Uint32(sub[8:])*prime2) * prime1
|
|
|
|
v4 = rol13(v4+binary.LittleEndian.Uint32(sub[12:])*prime2) * prime1
|
2020-06-05 20:47:39 +00:00
|
|
|
}
|
2020-11-06 18:41:42 +00:00
|
|
|
v[0], v[1], v[2], v[3] = v1, v2, v3, v4
|
2020-06-05 20:47:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Sum32 returns the 32 bits Hash value.
|
|
|
|
func (xxh *XXHZero) Sum32() uint32 {
|
|
|
|
h32 := uint32(xxh.totalLen)
|
|
|
|
if h32 >= 16 {
|
2020-11-06 18:41:42 +00:00
|
|
|
h32 += rol1(xxh.v[0]) + rol7(xxh.v[1]) + rol12(xxh.v[2]) + rol18(xxh.v[3])
|
2020-06-05 20:47:39 +00:00
|
|
|
} else {
|
2020-10-16 05:06:27 +00:00
|
|
|
h32 += prime5
|
2020-06-05 20:47:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p := 0
|
|
|
|
n := xxh.bufused
|
|
|
|
buf := xxh.buf
|
|
|
|
for n := n - 4; p <= n; p += 4 {
|
2020-10-16 05:06:27 +00:00
|
|
|
h32 += binary.LittleEndian.Uint32(buf[p:p+4]) * prime3
|
|
|
|
h32 = rol17(h32) * prime4
|
2020-06-05 20:47:39 +00:00
|
|
|
}
|
|
|
|
for ; p < n; p++ {
|
2020-10-16 05:06:27 +00:00
|
|
|
h32 += uint32(buf[p]) * prime5
|
|
|
|
h32 = rol11(h32) * prime1
|
2020-06-05 20:47:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
h32 ^= h32 >> 15
|
2020-10-16 05:06:27 +00:00
|
|
|
h32 *= prime2
|
2020-06-05 20:47:39 +00:00
|
|
|
h32 ^= h32 >> 13
|
2020-10-16 05:06:27 +00:00
|
|
|
h32 *= prime3
|
2020-06-05 20:47:39 +00:00
|
|
|
h32 ^= h32 >> 16
|
|
|
|
|
|
|
|
return h32
|
|
|
|
}
|
|
|
|
|
2020-11-06 18:41:42 +00:00
|
|
|
// Portable version of ChecksumZero.
|
|
|
|
func checksumZeroGo(input []byte) uint32 {
|
2020-06-05 20:47:39 +00:00
|
|
|
n := len(input)
|
|
|
|
h32 := uint32(n)
|
|
|
|
|
|
|
|
if n < 16 {
|
2020-10-16 05:06:27 +00:00
|
|
|
h32 += prime5
|
2020-06-05 20:47:39 +00:00
|
|
|
} else {
|
2020-10-16 05:06:27 +00:00
|
|
|
v1 := prime1plus2
|
|
|
|
v2 := prime2
|
2020-06-05 20:47:39 +00:00
|
|
|
v3 := uint32(0)
|
2020-10-16 05:06:27 +00:00
|
|
|
v4 := prime1minus
|
2020-06-05 20:47:39 +00:00
|
|
|
p := 0
|
|
|
|
for n := n - 16; p <= n; p += 16 {
|
|
|
|
sub := input[p:][:16] //BCE hint for compiler
|
2020-10-16 05:06:27 +00:00
|
|
|
v1 = rol13(v1+binary.LittleEndian.Uint32(sub[:])*prime2) * prime1
|
|
|
|
v2 = rol13(v2+binary.LittleEndian.Uint32(sub[4:])*prime2) * prime1
|
|
|
|
v3 = rol13(v3+binary.LittleEndian.Uint32(sub[8:])*prime2) * prime1
|
|
|
|
v4 = rol13(v4+binary.LittleEndian.Uint32(sub[12:])*prime2) * prime1
|
2020-06-05 20:47:39 +00:00
|
|
|
}
|
|
|
|
input = input[p:]
|
|
|
|
n -= p
|
|
|
|
h32 += rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
|
|
|
|
}
|
|
|
|
|
|
|
|
p := 0
|
|
|
|
for n := n - 4; p <= n; p += 4 {
|
2020-10-16 05:06:27 +00:00
|
|
|
h32 += binary.LittleEndian.Uint32(input[p:p+4]) * prime3
|
|
|
|
h32 = rol17(h32) * prime4
|
2020-06-05 20:47:39 +00:00
|
|
|
}
|
|
|
|
for p < n {
|
2020-10-16 05:06:27 +00:00
|
|
|
h32 += uint32(input[p]) * prime5
|
|
|
|
h32 = rol11(h32) * prime1
|
2020-06-05 20:47:39 +00:00
|
|
|
p++
|
|
|
|
}
|
|
|
|
|
|
|
|
h32 ^= h32 >> 15
|
2020-10-16 05:06:27 +00:00
|
|
|
h32 *= prime2
|
2020-06-05 20:47:39 +00:00
|
|
|
h32 ^= h32 >> 13
|
2020-10-16 05:06:27 +00:00
|
|
|
h32 *= prime3
|
2020-06-05 20:47:39 +00:00
|
|
|
h32 ^= h32 >> 16
|
|
|
|
|
|
|
|
return h32
|
|
|
|
}
|
|
|
|
|
|
|
|
func rol1(u uint32) uint32 {
|
|
|
|
return u<<1 | u>>31
|
|
|
|
}
|
|
|
|
|
|
|
|
func rol7(u uint32) uint32 {
|
|
|
|
return u<<7 | u>>25
|
|
|
|
}
|
|
|
|
|
|
|
|
func rol11(u uint32) uint32 {
|
|
|
|
return u<<11 | u>>21
|
|
|
|
}
|
|
|
|
|
|
|
|
func rol12(u uint32) uint32 {
|
|
|
|
return u<<12 | u>>20
|
|
|
|
}
|
|
|
|
|
|
|
|
func rol13(u uint32) uint32 {
|
|
|
|
return u<<13 | u>>19
|
|
|
|
}
|
|
|
|
|
|
|
|
func rol17(u uint32) uint32 {
|
|
|
|
return u<<17 | u>>15
|
|
|
|
}
|
|
|
|
|
|
|
|
func rol18(u uint32) uint32 {
|
|
|
|
return u<<18 | u>>14
|
|
|
|
}
|