2023-07-22 15:02:22 +00:00
|
|
|
package hash
|
|
|
|
|
|
|
|
import (
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Bytes hashes the given byte slice.
|
|
|
|
func Bytes(in []byte) uint64 {
|
2024-06-18 14:17:02 +00:00
|
|
|
i := 0
|
|
|
|
x := uint64(0)
|
2023-07-22 15:02:22 +00:00
|
|
|
|
|
|
|
// Cache lines on modern processors are 64 bytes long.
|
2023-07-23 09:40:22 +00:00
|
|
|
// A single uint64 consumes 8 bytes.
|
2023-07-22 15:02:22 +00:00
|
|
|
// That means we should read 8 uint64 at a time.
|
|
|
|
for ; i < len(in)-63; i += 64 {
|
|
|
|
words := (*[8]uint64)(unsafe.Pointer(&in[i]))
|
2023-07-22 22:46:39 +00:00
|
|
|
x = mix(x, words[0])
|
|
|
|
x = mix(x, words[1])
|
|
|
|
x = mix(x, words[2])
|
|
|
|
x = mix(x, words[3])
|
|
|
|
x = mix(x, words[4])
|
|
|
|
x = mix(x, words[5])
|
|
|
|
x = mix(x, words[6])
|
|
|
|
x = mix(x, words[7])
|
2023-07-22 15:02:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// While we have at least 8 bytes left, convert them to uint64.
|
|
|
|
for ; i < len(in)-7; i += 8 {
|
2023-07-22 22:46:39 +00:00
|
|
|
word := *(*uint64)(unsafe.Pointer(&in[i]))
|
|
|
|
x = mix(x, word)
|
2023-07-22 15:02:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Hash the remaining bytes.
|
2024-06-18 14:17:02 +00:00
|
|
|
if i < len(in) {
|
|
|
|
word := uint64(0)
|
|
|
|
|
|
|
|
for ; i < len(in); i++ {
|
|
|
|
word = (word << 8) | uint64(in[i])
|
|
|
|
}
|
|
|
|
|
|
|
|
x = mix(x, word)
|
2023-07-22 15:02:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This helps to avoid clashes between different lengths
|
|
|
|
// of all-zero bytes by making the data length significant.
|
2023-07-22 22:46:39 +00:00
|
|
|
x = mix(x, uint64(len(in)))
|
2023-07-22 15:02:22 +00:00
|
|
|
|
|
|
|
return x
|
|
|
|
}
|
2023-07-22 22:46:39 +00:00
|
|
|
|
|
|
|
func mix(x uint64, b uint64) uint64 {
|
2024-06-18 14:17:02 +00:00
|
|
|
return (x + b) * 0x9E3779B97F4A7C15
|
2023-07-22 22:46:39 +00:00
|
|
|
}
|