diff options
Diffstat (limited to 'internal/adler32/adler32_amd64.go')
| -rw-r--r-- | internal/adler32/adler32_amd64.go | 181 |
1 files changed, 71 insertions, 110 deletions
diff --git a/internal/adler32/adler32_amd64.go b/internal/adler32/adler32_amd64.go index a109ccc9..75a34c72 100644 --- a/internal/adler32/adler32_amd64.go +++ b/internal/adler32/adler32_amd64.go @@ -1,130 +1,91 @@ -//go:build amd64 && !purego - package adler32 -import "golang.org/x/sys/cpu" +import ( + "encoding/binary" + "errors" + "hash" + "hash/adler32" + + "golang.org/x/sys/cpu" +) + +// The size of an Adler-32 checksum in bytes. +const Size = 4 + +var ( + hasSSE3 = cpu.X86.HasSSE3 + hasAVX2 = cpu.X86.HasAVX2 +) + +// digest represents the partial evaluation of a checksum. +// The low 16 bits are s1, the high 16 bits are s2. +type digest uint32 -var updateFn func(d digest, p []byte) digest = updateGeneric +func (d *digest) Reset() { *d = 1 } -func init() { - switch { - case cpu.X86.HasAVX2: - updateFn = updateAVX2 - default: - updateFn = updateGeneric +// New returns a new hash.Hash32 computing the Adler-32 checksum. +func New() hash.Hash32 { + if !hasSSE3 { + return adler32.New() } + d := new(digest) + d.Reset() + return d } -func update(d digest, p []byte) digest { - return updateFn(d, p) +func (d *digest) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + b = binary.BigEndian.AppendUint32(b, uint32(*d)) + return b, nil } -func updateGeneric(d digest, p []byte) digest { - s1, s2 := uint32(d&0xffff), uint32(d>>16) - - for len(p) > 0 { - var q []byte - if len(p) > nmax { - p, q = p[:nmax], p[nmax:] - } +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("hash/adler32: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("hash/adler32: invalid hash state size") + } + *d = digest(binary.BigEndian.Uint32(b[len(magic):])) + return nil +} - for len(p) >= 32 { - v := p[:32] - p = p[32:] +func (d *digest) Size() int { return Size } - s1 += uint32(v[0]) - s2 += s1 - s1 += uint32(v[1]) - s2 += s1 - s1 += uint32(v[2]) - s2 += s1 - s1 += uint32(v[3]) - s2 += s1 - s1 += uint32(v[4]) - s2 += s1 - s1 += uint32(v[5]) - s2 += s1 - s1 += uint32(v[6]) - s2 += s1 - s1 += uint32(v[7]) - s2 += s1 - s1 += uint32(v[8]) - s2 += s1 - s1 += uint32(v[9]) - s2 += s1 - s1 += uint32(v[10]) - s2 += s1 - s1 += uint32(v[11]) - s2 += s1 - s1 += uint32(v[12]) - s2 += s1 - s1 += uint32(v[13]) - s2 += s1 - s1 += uint32(v[14]) - s2 += s1 - s1 += uint32(v[15]) - s2 += s1 - s1 += uint32(v[16]) - s2 += s1 - s1 += uint32(v[17]) - s2 += s1 - s1 += uint32(v[18]) - s2 += s1 - s1 += uint32(v[19]) - s2 += s1 - s1 += uint32(v[20]) - s2 += s1 - s1 += uint32(v[21]) - s2 += s1 - s1 += uint32(v[22]) - s2 += s1 - s1 += uint32(v[23]) - s2 += s1 - s1 += uint32(v[24]) - s2 += s1 - s1 += uint32(v[25]) - s2 += s1 - s1 += uint32(v[26]) - s2 += s1 - s1 += uint32(v[27]) - s2 += s1 - s1 += uint32(v[28]) - s2 += s1 - s1 += uint32(v[29]) - s2 += s1 - s1 += uint32(v[30]) - s2 += s1 - s1 += uint32(v[31]) - s2 += s1 - } +func (d *digest) BlockSize() int { return 4 } - for i := 0; i < len(p); i++ { - x := p[i] - s1 += uint32(x) - s2 += s1 +func (d *digest) Write(data []byte) (nn int, err error) { + if len(data) >= 64 { + var h uint32 + if hasAVX2 { + h = adler32_avx2(uint32(*d), data) + } else { + h = adler32_sse3(uint32(*d), data) } - - s1 %= mod - s2 %= mod - p = q + *d = digest(h) + } else { + h := update(uint32(*d), data) + *d = digest(h) } - - return digest(s2<<16 | s1) + return len(data), nil } -//go:noescape -func adler32AVX2(state uint32, b []byte) uint32 +func (d *digest) Sum32() uint32 { return uint32(*d) } -func updateAVX2(d digest, p []byte) digest { - s := uint32(d) - for len(p) > 0 { - chunk := p - if len(chunk) > nmax { - chunk = p[:nmax] - } - s = adler32AVX2(s, chunk) +func (d *digest) Sum(in []byte) []byte { + s := uint32(*d) + return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s)) +} + +// Checksum returns the Adler-32 checksum of data. +func Checksum(data []byte) uint32 { + if !hasSSE3 || len(data) < 64 { + return update(1, data) + } - p = p[len(chunk):] + if hasAVX2 { + return adler32_avx2(1, data) } - return digest(s) + return adler32_sse3(1, data) } |
