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

internal/lz4block: Simplify portable decoder #159

Merged
merged 1 commit into from Feb 5, 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
40 changes: 11 additions & 29 deletions internal/lz4block/decode_other.go
@@ -1,3 +1,4 @@
//go:build (!amd64 && !arm && !arm64) || appengine || !gc || noasm
// +build !amd64,!arm,!arm64 appengine !gc noasm

package lz4block
Expand All @@ -10,7 +11,6 @@ func decodeBlock(dst, src, dict []byte) (ret int) {
// Restrict capacities so we don't read or write out of bounds.
dst = dst[:len(dst):len(dst)]
src = src[:len(src):len(src)]
dictLen := uint(len(dict))

const hasError = -2
defer func() {
Expand Down Expand Up @@ -102,35 +102,17 @@ func decodeBlock(dst, src, dict []byte) (ret int) {

// Copy the match.
if di < offset {
// The match is beyond our block, meaning in the dictionary
if offset-di > mLen {
// The match is entirely contained in the dictionary. Just copy!
copy(dst[di:di+mLen], dict[dictLen+di-offset:dictLen+di-offset+mLen])
di = di + mLen
} else {
// The match stretches over the dictionary and our block
copySize := offset - di
restSize := mLen - copySize

copy(dst[di:di+copySize], dict[dictLen-copySize:])
di = di + copySize

if di < restSize {
// Overlap - we want to copy more than what we have available,
// so copy byte per byte.
copyFrom := 0
endOfMatch := di + restSize
for di < endOfMatch {
dst[di] = dst[copyFrom]
di = di + 1
copyFrom = copyFrom + 1
}
} else {
copy(dst[di:di+restSize], dst[0:restSize])
di = di + restSize
}
// The match is beyond our block, meaning the first part
// is in the dictionary.
fromDict := dict[uint(len(dict))+di-offset:]
n := uint(copy(dst[di:di+mLen], fromDict))
di += n
if mLen -= n; mLen == 0 {
continue
}
continue
// We copied n = offset-di bytes from the dictionary,
// then set di = di+n = offset, so the following code
// copies from dst[di-offset:] = dst[0:].
}

expanded := dst[di-offset:]
Expand Down
8 changes: 7 additions & 1 deletion internal/lz4block/decode_test.go
Expand Up @@ -228,7 +228,13 @@ func TestDecodeWithDict(t *testing.T) {
// First part in dictionary, rest in dst.
{"\x35foo\x09\x00\x401234", "0barbaz", "foobarbazfoo1234"},

// Same, but >16 bytes before the end,
// Copy end of dictionary three times, then a literal.
{"\x08\x04\x00\x50abcde", "---1234", "123412341234abcde"},

// First part in dictionary, rest in dst, copied multiple times.
{"\x1a1\x05\x00\x50abcde", "---2345", "123451234512345abcde"},

// First part in dictionary, rest in dst, but >16 bytes before the end,
// to test the short match shortcut in the amd64 decoder.
{"\x35abc\x09\x00\xf0\x0f0123456789abcdefghijklmnopqrst", "012defghi",
"abcdefghiabc0123456789abcdefghijklmnopqrst"},
Expand Down