package xxh3
import (
"encoding/binary"
"hash"
)
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 )
)
func New () *Hasher {
return new (Hasher )
}
func NewSeed (seed uint64 ) *Hasher {
var h Hasher
h .Reset ()
h .seed = seed
h .key = key
if seed != 0 {
h .key = ptr (&[secretSize ]byte {})
initSecret (h .key , seed )
}
return &h
}
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
}
func (h *Hasher ) BlockSize () int { return _stripe }
func (h *Hasher ) Size () int { return 8 }
func (h *Hasher ) Sum (b []byte ) []byte {
var tmp [8 ]byte
binary .BigEndian .PutUint64 (tmp [:], h .Sum64 ())
return append (b , tmp [:]...)
}
func (h *Hasher ) Write (buf []byte ) (int , error ) {
h .update (buf )
return len (buf ), nil
}
func (h *Hasher ) WriteString (buf string ) (int , error ) {
h .updateString (buf )
return len (buf ), nil
}
func (h *Hasher ) update (buf []byte ) {
h .updateString (*(*string )(ptr (&buf )))
}
func (h *Hasher ) updateString (buf string ) {
if h .key == nil {
h .key = key
h .Reset ()
}
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 :])
}
}
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 {
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
}
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 {
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
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .