summaryrefslogtreecommitdiff
path: root/vendor/github.com/zeebo/xxh3/hasher.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/zeebo/xxh3/hasher.go')
-rw-r--r--vendor/github.com/zeebo/xxh3/hasher.go239
1 files changed, 239 insertions, 0 deletions
diff --git a/vendor/github.com/zeebo/xxh3/hasher.go b/vendor/github.com/zeebo/xxh3/hasher.go
new file mode 100644
index 000000000..d9789980a
--- /dev/null
+++ b/vendor/github.com/zeebo/xxh3/hasher.go
@@ -0,0 +1,239 @@
+package xxh3
+
+import (
+ "encoding/binary"
+ "hash"
+)
+
+// Hasher implements the hash.Hash interface
+type Hasher struct {
+ acc [8]u64
+ blk u64
+ len u64
+ key ptr
+ buf [_block + _stripe]byte
+ seed u64
+}
+
+var (
+ _ hash.Hash = (*Hasher)(nil)
+ _ hash.Hash64 = (*Hasher)(nil)
+)
+
+// New returns a new Hasher that implements the hash.Hash interface.
+func New() *Hasher {
+ return new(Hasher)
+}
+
+// NewSeed returns a new Hasher that implements the hash.Hash interface.
+func NewSeed(seed uint64) *Hasher {
+ var h Hasher
+ h.Reset()
+ h.seed = seed
+ h.key = key
+
+ // Only initiate once, not on reset.
+ if seed != 0 {
+ h.key = ptr(&[secretSize]byte{})
+ initSecret(h.key, seed)
+ }
+ return &h
+}
+
+// Reset resets the Hash to its initial state.
+func (h *Hasher) Reset() {
+ h.acc = [8]u64{
+ prime32_3, prime64_1, prime64_2, prime64_3,
+ prime64_4, prime32_2, prime64_5, prime32_1,
+ }
+ h.blk = 0
+ h.len = 0
+}
+
+// BlockSize returns the hash's underlying block size.
+// The Write method will accept any amount of data, but
+// it may operate more efficiently if all writes are a
+// multiple of the block size.
+func (h *Hasher) BlockSize() int { return _stripe }
+
+// Size returns the number of bytes Sum will return.
+func (h *Hasher) Size() int { return 8 }
+
+// Sum appends the current hash to b and returns the resulting slice.
+// It does not change the underlying hash state.
+func (h *Hasher) Sum(b []byte) []byte {
+ var tmp [8]byte
+ binary.BigEndian.PutUint64(tmp[:], h.Sum64())
+ return append(b, tmp[:]...)
+}
+
+// Write adds more data to the running hash.
+// It never returns an error.
+func (h *Hasher) Write(buf []byte) (int, error) {
+ h.update(buf)
+ return len(buf), nil
+}
+
+// WriteString adds more data to the running hash.
+// It never returns an error.
+func (h *Hasher) WriteString(buf string) (int, error) {
+ h.updateString(buf)
+ return len(buf), nil
+}
+
+func (h *Hasher) update(buf []byte) {
+ // relies on the data pointer being the first word in the string header
+ h.updateString(*(*string)(ptr(&buf)))
+}
+
+func (h *Hasher) updateString(buf string) {
+ if h.key == nil {
+ h.key = key
+ h.Reset()
+ }
+
+ // On first write, if more than 1 block, process without copy.
+ for h.len == 0 && len(buf) > len(h.buf) {
+ if hasAVX2 {
+ accumBlockAVX2(&h.acc, *(*ptr)(ptr(&buf)), h.key)
+ } else if hasSSE2 {
+ accumBlockSSE(&h.acc, *(*ptr)(ptr(&buf)), h.key)
+ } else {
+ accumBlockScalar(&h.acc, *(*ptr)(ptr(&buf)), h.key)
+ }
+ buf = buf[_block:]
+ h.blk++
+ }
+
+ for len(buf) > 0 {
+ if h.len < u64(len(h.buf)) {
+ n := copy(h.buf[h.len:], buf)
+ h.len += u64(n)
+ buf = buf[n:]
+ continue
+ }
+
+ if hasAVX2 {
+ accumBlockAVX2(&h.acc, ptr(&h.buf), h.key)
+ } else if hasSSE2 {
+ accumBlockSSE(&h.acc, ptr(&h.buf), h.key)
+ } else {
+ accumBlockScalar(&h.acc, ptr(&h.buf), h.key)
+ }
+
+ h.blk++
+ h.len = _stripe
+ copy(h.buf[:_stripe], h.buf[_block:])
+ }
+}
+
+// Sum64 returns the 64-bit hash of the written data.
+func (h *Hasher) Sum64() uint64 {
+ if h.key == nil {
+ h.key = key
+ h.Reset()
+ }
+
+ if h.blk == 0 {
+ if h.seed == 0 {
+ return Hash(h.buf[:h.len])
+ }
+ return HashSeed(h.buf[:h.len], h.seed)
+ }
+
+ l := h.blk*_block + h.len
+ acc := l * prime64_1
+ accs := h.acc
+
+ if h.len > 0 {
+ // We are only ever doing 1 block here, so no avx512.
+ if hasAVX2 {
+ accumAVX2(&accs, ptr(&h.buf[0]), h.key, h.len)
+ } else if hasSSE2 {
+ accumSSE(&accs, ptr(&h.buf[0]), h.key, h.len)
+ } else {
+ accumScalar(&accs, ptr(&h.buf[0]), h.key, h.len)
+ }
+ }
+
+ if h.seed == 0 {
+ acc += mulFold64(accs[0]^key64_011, accs[1]^key64_019)
+ acc += mulFold64(accs[2]^key64_027, accs[3]^key64_035)
+ acc += mulFold64(accs[4]^key64_043, accs[5]^key64_051)
+ acc += mulFold64(accs[6]^key64_059, accs[7]^key64_067)
+ } else {
+ secret := h.key
+ acc += mulFold64(accs[0]^readU64(secret, 11), accs[1]^readU64(secret, 19))
+ acc += mulFold64(accs[2]^readU64(secret, 27), accs[3]^readU64(secret, 35))
+ acc += mulFold64(accs[4]^readU64(secret, 43), accs[5]^readU64(secret, 51))
+ acc += mulFold64(accs[6]^readU64(secret, 59), accs[7]^readU64(secret, 67))
+ }
+
+ acc = xxh3Avalanche(acc)
+
+ return acc
+}
+
+// Sum128 returns the 128-bit hash of the written data.
+func (h *Hasher) Sum128() Uint128 {
+ if h.key == nil {
+ h.key = key
+ h.Reset()
+ }
+
+ if h.blk == 0 {
+ if h.seed == 0 {
+ return Hash128(h.buf[:h.len])
+ }
+ return Hash128Seed(h.buf[:h.len], h.seed)
+ }
+
+ l := h.blk*_block + h.len
+ acc := Uint128{Lo: l * prime64_1, Hi: ^(l * prime64_2)}
+ accs := h.acc
+
+ if h.len > 0 {
+ // We are only ever doing 1 block here, so no avx512.
+ if hasAVX2 {
+ accumAVX2(&accs, ptr(&h.buf[0]), h.key, h.len)
+ } else if hasSSE2 {
+ accumSSE(&accs, ptr(&h.buf[0]), h.key, h.len)
+ } else {
+ accumScalar(&accs, ptr(&h.buf[0]), h.key, h.len)
+ }
+ }
+
+ if h.seed == 0 {
+ acc.Lo += mulFold64(accs[0]^key64_011, accs[1]^key64_019)
+ acc.Hi += mulFold64(accs[0]^key64_117, accs[1]^key64_125)
+
+ acc.Lo += mulFold64(accs[2]^key64_027, accs[3]^key64_035)
+ acc.Hi += mulFold64(accs[2]^key64_133, accs[3]^key64_141)
+
+ acc.Lo += mulFold64(accs[4]^key64_043, accs[5]^key64_051)
+ acc.Hi += mulFold64(accs[4]^key64_149, accs[5]^key64_157)
+
+ acc.Lo += mulFold64(accs[6]^key64_059, accs[7]^key64_067)
+ acc.Hi += mulFold64(accs[6]^key64_165, accs[7]^key64_173)
+ } else {
+ secret := h.key
+ const hi_off = 117 - 11
+
+ acc.Lo += mulFold64(accs[0]^readU64(secret, 11), accs[1]^readU64(secret, 19))
+ acc.Hi += mulFold64(accs[0]^readU64(secret, 11+hi_off), accs[1]^readU64(secret, 19+hi_off))
+
+ acc.Lo += mulFold64(accs[2]^readU64(secret, 27), accs[3]^readU64(secret, 35))
+ acc.Hi += mulFold64(accs[2]^readU64(secret, 27+hi_off), accs[3]^readU64(secret, 35+hi_off))
+
+ acc.Lo += mulFold64(accs[4]^readU64(secret, 43), accs[5]^readU64(secret, 51))
+ acc.Hi += mulFold64(accs[4]^readU64(secret, 43+hi_off), accs[5]^readU64(secret, 51+hi_off))
+
+ acc.Lo += mulFold64(accs[6]^readU64(secret, 59), accs[7]^readU64(secret, 67))
+ acc.Hi += mulFold64(accs[6]^readU64(secret, 59+hi_off), accs[7]^readU64(secret, 67+hi_off))
+ }
+
+ acc.Lo = xxh3Avalanche(acc.Lo)
+ acc.Hi = xxh3Avalanche(acc.Hi)
+
+ return acc
+}