68 lines
1.4 KiB
Go
68 lines
1.4 KiB
Go
package hash
|
|
|
|
import (
|
|
"unsafe"
|
|
)
|
|
|
|
// Bytes hashes the given byte slice.
|
|
func Bytes(in []byte) uint64 {
|
|
return add(0, in)
|
|
}
|
|
|
|
// add implements the actual hashing.
|
|
func add(x uint64, in []byte) uint64 {
|
|
var i int
|
|
|
|
// Cache lines on modern processors are 64 bytes long.
|
|
// A single uint64 consumes 64 bits (8 bytes).
|
|
// That means we should read 8 uint64 at a time.
|
|
for ; i < len(in)-63; i += 64 {
|
|
words := (*[8]uint64)(unsafe.Pointer(&in[i]))
|
|
|
|
x += words[0]
|
|
x = (x << 1) | (x >> (64 - 1))
|
|
|
|
x += words[1]
|
|
x = (x << 1) | (x >> (64 - 1))
|
|
|
|
x += words[2]
|
|
x = (x << 1) | (x >> (64 - 1))
|
|
|
|
x += words[3]
|
|
x = (x << 1) | (x >> (64 - 1))
|
|
|
|
x += words[4]
|
|
x = (x << 1) | (x >> (64 - 1))
|
|
|
|
x += words[5]
|
|
x = (x << 1) | (x >> (64 - 1))
|
|
|
|
x += words[6]
|
|
x = (x << 1) | (x >> (64 - 1))
|
|
|
|
x += words[7]
|
|
x = (x << 1) | (x >> (64 - 1))
|
|
}
|
|
|
|
// While we have at least 8 bytes left, convert them to uint64.
|
|
for ; i < len(in)-7; i += 8 {
|
|
x += *(*uint64)(unsafe.Pointer(&in[i]))
|
|
x = (x << 1) | (x >> (64 - 1))
|
|
}
|
|
|
|
// Hash the remaining bytes.
|
|
// At this point we know that there are less than 8 bytes left,
|
|
// so we can shift each iteration by 8 bits to assure that hashes
|
|
// for tiny data buffers are always unique.
|
|
for ; i < len(in); i++ {
|
|
x += uint64(in[i])
|
|
x = (x << 8) | (x >> (64 - 8))
|
|
}
|
|
|
|
// This helps to avoid clashes between different lengths
|
|
// of all-zero bytes by making the data length significant.
|
|
x += uint64(len(in))
|
|
|
|
return x
|
|
}
|