206 lines
5.4 KiB
Go
206 lines
5.4 KiB
Go
// Package xxHash32 implements the very fast xxHash hashing algorithm (32 bits version).
|
|
// (https://github.com/Cyan4973/xxHash/)
|
|
package xxHash32
|
|
|
|
import "hash"
|
|
|
|
const (
|
|
prime32_1 = 2654435761
|
|
prime32_2 = 2246822519
|
|
prime32_3 = 3266489917
|
|
prime32_4 = 668265263
|
|
prime32_5 = 374761393
|
|
)
|
|
|
|
type xxHash struct {
|
|
seed uint32
|
|
v1 uint32
|
|
v2 uint32
|
|
v3 uint32
|
|
v4 uint32
|
|
totalLen uint64
|
|
buf [16]byte
|
|
bufused int
|
|
}
|
|
|
|
// New returns a new Hash32 instance.
|
|
func New(seed uint32) hash.Hash32 {
|
|
xxh := &xxHash{seed: seed}
|
|
xxh.Reset()
|
|
return xxh
|
|
}
|
|
|
|
// Sum appends the current hash to b and returns the resulting slice.
|
|
// It does not change the underlying hash state.
|
|
func (xxh xxHash) 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 *xxHash) Reset() {
|
|
xxh.v1 = xxh.seed + prime32_1 + prime32_2
|
|
xxh.v2 = xxh.seed + prime32_2
|
|
xxh.v3 = xxh.seed
|
|
xxh.v4 = xxh.seed - prime32_1
|
|
xxh.totalLen = 0
|
|
xxh.bufused = 0
|
|
}
|
|
|
|
// Size returns the number of bytes returned by Sum().
|
|
func (xxh *xxHash) Size() int {
|
|
return 4
|
|
}
|
|
|
|
// BlockSize gives the minimum number of bytes accepted by Write().
|
|
func (xxh *xxHash) BlockSize() int {
|
|
return 1
|
|
}
|
|
|
|
// Write adds input bytes to the Hash.
|
|
// It never returns an error.
|
|
func (xxh *xxHash) Write(input []byte) (int, error) {
|
|
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
|
|
}
|
|
|
|
p := 0
|
|
if m > 0 {
|
|
// some data left from previous update
|
|
copy(xxh.buf[xxh.bufused:], input[:r])
|
|
xxh.bufused += len(input) - r
|
|
|
|
// fast rotl(13)
|
|
p32 := xxh.v1 + (uint32(xxh.buf[p+3])<<24|uint32(xxh.buf[p+2])<<16|uint32(xxh.buf[p+1])<<8|uint32(xxh.buf[p]))*prime32_2
|
|
xxh.v1 = (p32<<13 | p32>>19) * prime32_1
|
|
p += 4
|
|
p32 = xxh.v2 + (uint32(xxh.buf[p+3])<<24|uint32(xxh.buf[p+2])<<16|uint32(xxh.buf[p+1])<<8|uint32(xxh.buf[p]))*prime32_2
|
|
xxh.v2 = (p32<<13 | p32>>19) * prime32_1
|
|
p += 4
|
|
p32 = xxh.v3 + (uint32(xxh.buf[p+3])<<24|uint32(xxh.buf[p+2])<<16|uint32(xxh.buf[p+1])<<8|uint32(xxh.buf[p]))*prime32_2
|
|
xxh.v3 = (p32<<13 | p32>>19) * prime32_1
|
|
p += 4
|
|
p32 = xxh.v4 + (uint32(xxh.buf[p+3])<<24|uint32(xxh.buf[p+2])<<16|uint32(xxh.buf[p+1])<<8|uint32(xxh.buf[p]))*prime32_2
|
|
xxh.v4 = (p32<<13 | p32>>19) * prime32_1
|
|
|
|
p = r
|
|
xxh.bufused = 0
|
|
}
|
|
|
|
for n := n - 16; p <= n; {
|
|
p32 := xxh.v1 + (uint32(input[p+3])<<24|uint32(input[p+2])<<16|uint32(input[p+1])<<8|uint32(input[p]))*prime32_2
|
|
xxh.v1 = (p32<<13 | p32>>19) * prime32_1
|
|
p += 4
|
|
p32 = xxh.v2 + (uint32(input[p+3])<<24|uint32(input[p+2])<<16|uint32(input[p+1])<<8|uint32(input[p]))*prime32_2
|
|
xxh.v2 = (p32<<13 | p32>>19) * prime32_1
|
|
p += 4
|
|
p32 = xxh.v3 + (uint32(input[p+3])<<24|uint32(input[p+2])<<16|uint32(input[p+1])<<8|uint32(input[p]))*prime32_2
|
|
xxh.v3 = (p32<<13 | p32>>19) * prime32_1
|
|
p += 4
|
|
p32 = xxh.v4 + (uint32(input[p+3])<<24|uint32(input[p+2])<<16|uint32(input[p+1])<<8|uint32(input[p]))*prime32_2
|
|
xxh.v4 = (p32<<13 | p32>>19) * prime32_1
|
|
p += 4
|
|
}
|
|
|
|
copy(xxh.buf[xxh.bufused:], input[p:])
|
|
xxh.bufused += len(input) - p
|
|
|
|
return n, nil
|
|
}
|
|
|
|
// Sum32 returns the 32 bits Hash value.
|
|
func (xxh *xxHash) Sum32() uint32 {
|
|
h32 := uint32(xxh.totalLen)
|
|
if xxh.totalLen >= 16 {
|
|
h32 += ((xxh.v1 << 1) | (xxh.v1 >> 31)) +
|
|
((xxh.v2 << 7) | (xxh.v2 >> 25)) +
|
|
((xxh.v3 << 12) | (xxh.v3 >> 20)) +
|
|
((xxh.v4 << 18) | (xxh.v4 >> 14))
|
|
} else {
|
|
h32 += xxh.seed + prime32_5
|
|
}
|
|
|
|
p := 0
|
|
n := xxh.bufused
|
|
for n := n - 4; p <= n; p += 4 {
|
|
h32 += (uint32(xxh.buf[p+3])<<24 | uint32(xxh.buf[p+2])<<16 | uint32(xxh.buf[p+1])<<8 | uint32(xxh.buf[p])) * prime32_3
|
|
h32 = ((h32 << 17) | (h32 >> 15)) * prime32_4
|
|
}
|
|
for ; p < n; p++ {
|
|
h32 += uint32(xxh.buf[p]) * prime32_5
|
|
h32 = ((h32 << 11) | (h32 >> 21)) * prime32_1
|
|
}
|
|
|
|
h32 ^= h32 >> 15
|
|
h32 *= prime32_2
|
|
h32 ^= h32 >> 13
|
|
h32 *= prime32_3
|
|
h32 ^= h32 >> 16
|
|
|
|
return h32
|
|
}
|
|
|
|
// Checksum returns the 32bits Hash value.
|
|
func Checksum(input []byte, seed uint32) uint32 {
|
|
n := len(input)
|
|
h32 := uint32(n)
|
|
|
|
if n < 16 {
|
|
h32 += seed + prime32_5
|
|
} else {
|
|
v1 := seed + prime32_1 + prime32_2
|
|
v2 := seed + prime32_2
|
|
v3 := seed
|
|
v4 := seed - prime32_1
|
|
p := 0
|
|
for p <= n-16 {
|
|
v1 += (uint32(input[p+3])<<24 | uint32(input[p+2])<<16 | uint32(input[p+1])<<8 | uint32(input[p])) * prime32_2
|
|
v1 = (v1<<13 | v1>>19) * prime32_1
|
|
p += 4
|
|
v2 += (uint32(input[p+3])<<24 | uint32(input[p+2])<<16 | uint32(input[p+1])<<8 | uint32(input[p])) * prime32_2
|
|
v2 = (v2<<13 | v2>>19) * prime32_1
|
|
p += 4
|
|
v3 += (uint32(input[p+3])<<24 | uint32(input[p+2])<<16 | uint32(input[p+1])<<8 | uint32(input[p])) * prime32_2
|
|
v3 = (v3<<13 | v3>>19) * prime32_1
|
|
p += 4
|
|
v4 += (uint32(input[p+3])<<24 | uint32(input[p+2])<<16 | uint32(input[p+1])<<8 | uint32(input[p])) * prime32_2
|
|
v4 = (v4<<13 | v4>>19) * prime32_1
|
|
p += 4
|
|
}
|
|
input = input[p:]
|
|
n -= p
|
|
h32 += ((v1 << 1) | (v1 >> 31)) +
|
|
((v2 << 7) | (v2 >> 25)) +
|
|
((v3 << 12) | (v3 >> 20)) +
|
|
((v4 << 18) | (v4 >> 14))
|
|
}
|
|
|
|
p := 0
|
|
for p <= n-4 {
|
|
h32 += (uint32(input[p+3])<<24 | uint32(input[p+2])<<16 | uint32(input[p+1])<<8 | uint32(input[p])) * prime32_3
|
|
h32 = ((h32 << 17) | (h32 >> 15)) * prime32_4
|
|
p += 4
|
|
}
|
|
for p < n {
|
|
h32 += uint32(input[p]) * prime32_5
|
|
h32 = ((h32 << 11) | (h32 >> 21)) * prime32_1
|
|
p++
|
|
}
|
|
|
|
h32 ^= h32 >> 15
|
|
h32 *= prime32_2
|
|
h32 ^= h32 >> 13
|
|
h32 *= prime32_3
|
|
h32 ^= h32 >> 16
|
|
|
|
return h32
|
|
}
|