mirror of https://github.com/tidwall/tile38.git
250 lines
8.2 KiB
Go
250 lines
8.2 KiB
Go
// Package xxHash64 implements the very fast xxHash hashing algorithm (64 bits version).
|
|
// (https://github.com/Cyan4973/xxHash/)
|
|
package xxHash64
|
|
|
|
import "hash"
|
|
|
|
const (
|
|
prime64_1 = 11400714785074694791
|
|
prime64_2 = 14029467366897019727
|
|
prime64_3 = 1609587929392839161
|
|
prime64_4 = 9650029242287828579
|
|
prime64_5 = 2870177450012600261
|
|
)
|
|
|
|
type xxHash struct {
|
|
seed uint64
|
|
v1 uint64
|
|
v2 uint64
|
|
v3 uint64
|
|
v4 uint64
|
|
totalLen uint64
|
|
buf [32]byte
|
|
bufused int
|
|
}
|
|
|
|
// New returns a new Hash64 instance.
|
|
func New(seed uint64) hash.Hash64 {
|
|
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 {
|
|
h64 := xxh.Sum64()
|
|
return append(b, byte(h64), byte(h64>>8), byte(h64>>16), byte(h64>>24), byte(h64>>32), byte(h64>>40), byte(h64>>48), byte(h64>>56))
|
|
}
|
|
|
|
// Reset resets the Hash to its initial state.
|
|
func (xxh *xxHash) Reset() {
|
|
xxh.v1 = xxh.seed + prime64_1 + prime64_2
|
|
xxh.v2 = xxh.seed + prime64_2
|
|
xxh.v3 = xxh.seed
|
|
xxh.v4 = xxh.seed - prime64_1
|
|
xxh.totalLen = 0
|
|
xxh.bufused = 0
|
|
}
|
|
|
|
// Size returns the number of bytes returned by Sum().
|
|
func (xxh *xxHash) Size() int {
|
|
return 8
|
|
}
|
|
|
|
// 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(31)
|
|
p64 := xxh.v1 + (uint64(xxh.buf[p+7])<<56|uint64(xxh.buf[p+6])<<48|uint64(xxh.buf[p+5])<<40|uint64(xxh.buf[p+4])<<32|uint64(xxh.buf[p+3])<<24|uint64(xxh.buf[p+2])<<16|uint64(xxh.buf[p+1])<<8|uint64(xxh.buf[p]))*prime64_2
|
|
xxh.v1 = (p64<<31 | p64>>33) * prime64_1
|
|
p += 8
|
|
p64 = xxh.v2 + (uint64(xxh.buf[p+7])<<56|uint64(xxh.buf[p+6])<<48|uint64(xxh.buf[p+5])<<40|uint64(xxh.buf[p+4])<<32|uint64(xxh.buf[p+3])<<24|uint64(xxh.buf[p+2])<<16|uint64(xxh.buf[p+1])<<8|uint64(xxh.buf[p]))*prime64_2
|
|
xxh.v2 = (p64<<31 | p64>>33) * prime64_1
|
|
p += 8
|
|
p64 = xxh.v3 + (uint64(xxh.buf[p+7])<<56|uint64(xxh.buf[p+6])<<48|uint64(xxh.buf[p+5])<<40|uint64(xxh.buf[p+4])<<32|uint64(xxh.buf[p+3])<<24|uint64(xxh.buf[p+2])<<16|uint64(xxh.buf[p+1])<<8|uint64(xxh.buf[p]))*prime64_2
|
|
xxh.v3 = (p64<<31 | p64>>33) * prime64_1
|
|
p += 8
|
|
p64 = xxh.v4 + (uint64(xxh.buf[p+7])<<56|uint64(xxh.buf[p+6])<<48|uint64(xxh.buf[p+5])<<40|uint64(xxh.buf[p+4])<<32|uint64(xxh.buf[p+3])<<24|uint64(xxh.buf[p+2])<<16|uint64(xxh.buf[p+1])<<8|uint64(xxh.buf[p]))*prime64_2
|
|
xxh.v4 = (p64<<31 | p64>>33) * prime64_1
|
|
|
|
p = r
|
|
xxh.bufused = 0
|
|
}
|
|
|
|
for n := n - 32; p <= n; {
|
|
p64 := xxh.v1 + (uint64(input[p+7])<<56|uint64(input[p+6])<<48|uint64(input[p+5])<<40|uint64(input[p+4])<<32|uint64(input[p+3])<<24|uint64(input[p+2])<<16|uint64(input[p+1])<<8|uint64(input[p]))*prime64_2
|
|
xxh.v1 = (p64<<31 | p64>>33) * prime64_1
|
|
p += 8
|
|
p64 = xxh.v2 + (uint64(input[p+7])<<56|uint64(input[p+6])<<48|uint64(input[p+5])<<40|uint64(input[p+4])<<32|uint64(input[p+3])<<24|uint64(input[p+2])<<16|uint64(input[p+1])<<8|uint64(input[p]))*prime64_2
|
|
xxh.v2 = (p64<<31 | p64>>33) * prime64_1
|
|
p += 8
|
|
p64 = xxh.v3 + (uint64(input[p+7])<<56|uint64(input[p+6])<<48|uint64(input[p+5])<<40|uint64(input[p+4])<<32|uint64(input[p+3])<<24|uint64(input[p+2])<<16|uint64(input[p+1])<<8|uint64(input[p]))*prime64_2
|
|
xxh.v3 = (p64<<31 | p64>>33) * prime64_1
|
|
p += 8
|
|
p64 = xxh.v4 + (uint64(input[p+7])<<56|uint64(input[p+6])<<48|uint64(input[p+5])<<40|uint64(input[p+4])<<32|uint64(input[p+3])<<24|uint64(input[p+2])<<16|uint64(input[p+1])<<8|uint64(input[p]))*prime64_2
|
|
xxh.v4 = (p64<<31 | p64>>33) * prime64_1
|
|
p += 8
|
|
}
|
|
|
|
copy(xxh.buf[xxh.bufused:], input[p:])
|
|
xxh.bufused += len(input) - p
|
|
|
|
return n, nil
|
|
}
|
|
|
|
// Sum64 returns the 64bits Hash value.
|
|
func (xxh *xxHash) Sum64() uint64 {
|
|
var h64 uint64
|
|
if xxh.totalLen >= 32 {
|
|
h64 = ((xxh.v1 << 1) | (xxh.v1 >> 63)) +
|
|
((xxh.v2 << 7) | (xxh.v2 >> 57)) +
|
|
((xxh.v3 << 12) | (xxh.v3 >> 52)) +
|
|
((xxh.v4 << 18) | (xxh.v4 >> 46))
|
|
|
|
xxh.v1 *= prime64_2
|
|
h64 ^= ((xxh.v1 << 31) | (xxh.v1 >> 33)) * prime64_1
|
|
h64 = h64*prime64_1 + prime64_4
|
|
|
|
xxh.v2 *= prime64_2
|
|
h64 ^= ((xxh.v2 << 31) | (xxh.v2 >> 33)) * prime64_1
|
|
h64 = h64*prime64_1 + prime64_4
|
|
|
|
xxh.v3 *= prime64_2
|
|
h64 ^= ((xxh.v3 << 31) | (xxh.v3 >> 33)) * prime64_1
|
|
h64 = h64*prime64_1 + prime64_4
|
|
|
|
xxh.v4 *= prime64_2
|
|
h64 ^= ((xxh.v4 << 31) | (xxh.v4 >> 33)) * prime64_1
|
|
h64 = h64*prime64_1 + prime64_4 + xxh.totalLen
|
|
} else {
|
|
h64 = xxh.seed + prime64_5 + xxh.totalLen
|
|
}
|
|
|
|
p := 0
|
|
n := xxh.bufused
|
|
for n := n - 8; p <= n; p += 8 {
|
|
p64 := (uint64(xxh.buf[p+7])<<56 | uint64(xxh.buf[p+6])<<48 | uint64(xxh.buf[p+5])<<40 | uint64(xxh.buf[p+4])<<32 | uint64(xxh.buf[p+3])<<24 | uint64(xxh.buf[p+2])<<16 | uint64(xxh.buf[p+1])<<8 | uint64(xxh.buf[p])) * prime64_2
|
|
h64 ^= ((p64 << 31) | (p64 >> 33)) * prime64_1
|
|
h64 = ((h64<<27)|(h64>>37))*prime64_1 + prime64_4
|
|
}
|
|
if p+4 <= n {
|
|
h64 ^= (uint64(xxh.buf[p+3])<<24 | uint64(xxh.buf[p+2])<<16 | uint64(xxh.buf[p+1])<<8 | uint64(xxh.buf[p])) * prime64_1
|
|
h64 = ((h64<<23)|(h64>>41))*prime64_2 + prime64_3
|
|
p += 4
|
|
}
|
|
for ; p < n; p++ {
|
|
h64 ^= uint64(xxh.buf[p]) * prime64_5
|
|
h64 = ((h64 << 11) | (h64 >> 53)) * prime64_1
|
|
}
|
|
|
|
h64 ^= h64 >> 33
|
|
h64 *= prime64_2
|
|
h64 ^= h64 >> 29
|
|
h64 *= prime64_3
|
|
h64 ^= h64 >> 32
|
|
|
|
return h64
|
|
}
|
|
|
|
// Checksum returns the 64bits Hash value.
|
|
func Checksum(input []byte, seed uint64) uint64 {
|
|
n := len(input)
|
|
var h64 uint64
|
|
|
|
if n >= 32 {
|
|
v1 := seed + prime64_1 + prime64_2
|
|
v2 := seed + prime64_2
|
|
v3 := seed
|
|
v4 := seed - prime64_1
|
|
p := 0
|
|
for n := n - 32; p <= n; {
|
|
p64 := v1 + (uint64(input[p+7])<<56|uint64(input[p+6])<<48|uint64(input[p+5])<<40|uint64(input[p+4])<<32|uint64(input[p+3])<<24|uint64(input[p+2])<<16|uint64(input[p+1])<<8|uint64(input[p]))*prime64_2
|
|
v1 = (p64<<31 | p64>>33) * prime64_1
|
|
p += 8
|
|
p64 = v2 + (uint64(input[p+7])<<56|uint64(input[p+6])<<48|uint64(input[p+5])<<40|uint64(input[p+4])<<32|uint64(input[p+3])<<24|uint64(input[p+2])<<16|uint64(input[p+1])<<8|uint64(input[p]))*prime64_2
|
|
v2 = (p64<<31 | p64>>33) * prime64_1
|
|
p += 8
|
|
p64 = v3 + (uint64(input[p+7])<<56|uint64(input[p+6])<<48|uint64(input[p+5])<<40|uint64(input[p+4])<<32|uint64(input[p+3])<<24|uint64(input[p+2])<<16|uint64(input[p+1])<<8|uint64(input[p]))*prime64_2
|
|
v3 = (p64<<31 | p64>>33) * prime64_1
|
|
p += 8
|
|
p64 = v4 + (uint64(input[p+7])<<56|uint64(input[p+6])<<48|uint64(input[p+5])<<40|uint64(input[p+4])<<32|uint64(input[p+3])<<24|uint64(input[p+2])<<16|uint64(input[p+1])<<8|uint64(input[p]))*prime64_2
|
|
v4 = (p64<<31 | p64>>33) * prime64_1
|
|
p += 8
|
|
}
|
|
|
|
h64 = ((v1 << 1) | (v1 >> 63)) +
|
|
((v2 << 7) | (v2 >> 57)) +
|
|
((v3 << 12) | (v3 >> 52)) +
|
|
((v4 << 18) | (v4 >> 46))
|
|
|
|
v1 *= prime64_2
|
|
h64 ^= ((v1 << 31) | (v1 >> 33)) * prime64_1
|
|
h64 = h64*prime64_1 + prime64_4
|
|
|
|
v2 *= prime64_2
|
|
h64 ^= ((v2 << 31) | (v2 >> 33)) * prime64_1
|
|
h64 = h64*prime64_1 + prime64_4
|
|
|
|
v3 *= prime64_2
|
|
h64 ^= ((v3 << 31) | (v3 >> 33)) * prime64_1
|
|
h64 = h64*prime64_1 + prime64_4
|
|
|
|
v4 *= prime64_2
|
|
h64 ^= ((v4 << 31) | (v4 >> 33)) * prime64_1
|
|
h64 = h64*prime64_1 + prime64_4 + uint64(n)
|
|
|
|
input = input[p:]
|
|
n -= p
|
|
} else {
|
|
h64 = seed + prime64_5 + uint64(n)
|
|
}
|
|
|
|
p := 0
|
|
for n := n - 8; p <= n; p += 8 {
|
|
p64 := (uint64(input[p+7])<<56 | uint64(input[p+6])<<48 | uint64(input[p+5])<<40 | uint64(input[p+4])<<32 | uint64(input[p+3])<<24 | uint64(input[p+2])<<16 | uint64(input[p+1])<<8 | uint64(input[p])) * prime64_2
|
|
h64 ^= ((p64 << 31) | (p64 >> 33)) * prime64_1
|
|
h64 = ((h64<<27)|(h64>>37))*prime64_1 + prime64_4
|
|
}
|
|
if p+4 <= n {
|
|
h64 ^= (uint64(input[p+3])<<24 | uint64(input[p+2])<<16 | uint64(input[p+1])<<8 | uint64(input[p])) * prime64_1
|
|
h64 = ((h64<<23)|(h64>>41))*prime64_2 + prime64_3
|
|
p += 4
|
|
}
|
|
for ; p < n; p++ {
|
|
h64 ^= uint64(input[p]) * prime64_5
|
|
h64 = ((h64 << 11) | (h64 >> 53)) * prime64_1
|
|
}
|
|
|
|
h64 ^= h64 >> 33
|
|
h64 *= prime64_2
|
|
h64 ^= h64 >> 29
|
|
h64 *= prime64_3
|
|
h64 ^= h64 >> 32
|
|
|
|
return h64
|
|
}
|