aboutsummaryrefslogtreecommitdiff
path: root/internal/adler32/adler32_amd64.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/adler32/adler32_amd64.go')
-rw-r--r--internal/adler32/adler32_amd64.go181
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)
}