Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zstd: Rewrite matchLen to make it inlineable #701

Merged
merged 1 commit into from Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 1 addition & 18 deletions zstd/enc_base.go
Expand Up @@ -126,24 +126,7 @@ func (e *fastBase) matchlen(s, t int32, src []byte) int32 {
panic(fmt.Sprintf("len(src)-s (%d) > maxCompressedBlockSize (%d)", len(src)-int(s), maxCompressedBlockSize))
}
}
a := src[s:]
b := src[t:]
b = b[:len(a)]
end := int32((len(a) >> 3) << 3)
for i := int32(0); i < end; i += 8 {
if diff := load6432(a, i) ^ load6432(b, i); diff != 0 {
return i + int32(bits.TrailingZeros64(diff)>>3)
}
}

a = a[end:]
b = b[end:]
for i := range a {
if a[i] != b[i] {
return int32(i) + end
}
}
return int32(len(a)) + end
return int32(matchLen(src[s:], src[t:]))
}

// Reset the encoding table.
Expand Down
27 changes: 11 additions & 16 deletions zstd/zstd.go
Expand Up @@ -110,26 +110,25 @@ func printf(format string, a ...interface{}) {
}
}

// matchLen returns the maximum length.
// matchLen returns the maximum common prefix length of a and b.
// a must be the shortest of the two.
// The function also returns whether all bytes matched.
func matchLen(a, b []byte) int {
b = b[:len(a)]
for i := 0; i < len(a)-7; i += 8 {
if diff := load64(a, i) ^ load64(b, i); diff != 0 {
return i + (bits.TrailingZeros64(diff) >> 3)
func matchLen(a, b []byte) (n int) {
for ; len(a) >= 8 && len(b) >= 8; a, b = a[8:], b[8:] {
diff := binary.LittleEndian.Uint64(a) ^ binary.LittleEndian.Uint64(b)
if diff != 0 {
return n + bits.TrailingZeros64(diff)>>3
}
n += 8
}

checked := (len(a) >> 3) << 3
a = a[checked:]
b = b[checked:]
for i := range a {
if a[i] != b[i] {
return i + checked
break
}
n++
}
return len(a) + checked
return n

}

func load3232(b []byte, i int32) uint32 {
Expand All @@ -140,10 +139,6 @@ func load6432(b []byte, i int32) uint64 {
return binary.LittleEndian.Uint64(b[i:])
}

func load64(b []byte, i int) uint64 {
return binary.LittleEndian.Uint64(b[i:])
}

type byter interface {
Bytes() []byte
Len() int
Expand Down
21 changes: 21 additions & 0 deletions zstd/zstd_test.go
Expand Up @@ -31,3 +31,24 @@ func TestMain(m *testing.M) {
}
os.Exit(ec)
}

func TestMatchLen(t *testing.T) {
a := make([]byte, 130)
for i := range a {
a[i] = byte(i)
}
b := append([]byte{}, a...)

check := func(x, y []byte, l int) {
if m := matchLen(x, y); m != l {
t.Error("expected", l, "got", m)
}
}

for l := range a {
a[l] = ^a[l]
check(a, b, l)
check(a[:l], b, l)
a[l] = ^a[l]
}
}