aboutsummaryrefslogtreecommitdiff
path: root/src/compress
diff options
context:
space:
mode:
authorNigel Tao <nigeltao@golang.org>2016-10-29 13:23:50 +1100
committerNigel Tao <nigeltao@golang.org>2016-10-30 22:52:14 +0000
commit590fce48849cc7f81b890d6e9b6120fc6681e19a (patch)
tree61bd9d4bb44fe7c31e374ab9f1273df93e30ce90 /src/compress
parentf135106ec7cf68b47a5b83a1c2b5dd7eda0d614c (diff)
downloadgo-590fce48849cc7f81b890d6e9b6120fc6681e19a.tar.gz
go-590fce48849cc7f81b890d6e9b6120fc6681e19a.zip
compress/flate: tighten the BestSpeed max match offset bound.
Previously, we were off by one. Also fix a comment typo. Change-Id: Ib94d23acc56d5fccd44144f71655481f98803ac8 Reviewed-on: https://go-review.googlesource.com/32149 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com> Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/compress')
-rw-r--r--src/compress/flate/deflate_test.go59
-rw-r--r--src/compress/flate/deflatefast.go8
2 files changed, 62 insertions, 5 deletions
diff --git a/src/compress/flate/deflate_test.go b/src/compress/flate/deflate_test.go
index 415e97262f..0f41695bf3 100644
--- a/src/compress/flate/deflate_test.go
+++ b/src/compress/flate/deflate_test.go
@@ -798,3 +798,62 @@ func TestBestSpeedMatch(t *testing.T) {
}
}
}
+
+func TestBestSpeedMaxMatchOffset(t *testing.T) {
+ const abc, xyz = "abcdefgh", "stuvwxyz"
+ for _, matchBefore := range []bool{false, true} {
+ for _, extra := range []int{0, inputMargin - 1, inputMargin, inputMargin + 1, 2 * inputMargin} {
+ for offsetAdj := -5; offsetAdj <= +5; offsetAdj++ {
+ report := func(desc string, err error) {
+ t.Errorf("matchBefore=%t, extra=%d, offsetAdj=%d: %s%v",
+ matchBefore, extra, offsetAdj, desc, err)
+ }
+
+ offset := maxMatchOffset + offsetAdj
+
+ // Make src to be a []byte of the form
+ // "%s%s%s%s%s" % (abc, zeros0, xyzMaybe, abc, zeros1)
+ // where:
+ // zeros0 is approximately maxMatchOffset zeros.
+ // xyzMaybe is either xyz or the empty string.
+ // zeros1 is between 0 and 30 zeros.
+ // The difference between the two abc's will be offset, which
+ // is maxMatchOffset plus or minus a small adjustment.
+ src := make([]byte, offset+len(abc)+extra)
+ copy(src, abc)
+ if !matchBefore {
+ copy(src[offset-len(xyz):], xyz)
+ }
+ copy(src[offset:], abc)
+
+ buf := new(bytes.Buffer)
+ w, err := NewWriter(buf, BestSpeed)
+ if err != nil {
+ report("NewWriter: ", err)
+ continue
+ }
+ if _, err := w.Write(src); err != nil {
+ report("Write: ", err)
+ continue
+ }
+ if err := w.Close(); err != nil {
+ report("Writer.Close: ", err)
+ continue
+ }
+
+ r := NewReader(buf)
+ dst, err := ioutil.ReadAll(r)
+ r.Close()
+ if err != nil {
+ report("ReadAll: ", err)
+ continue
+ }
+
+ if !bytes.Equal(dst, src) {
+ report("", fmt.Errorf("bytes differ after round-tripping"))
+ continue
+ }
+ }
+ }
+ }
+}
diff --git a/src/compress/flate/deflatefast.go b/src/compress/flate/deflatefast.go
index 5201b2ee1c..a1636a37d6 100644
--- a/src/compress/flate/deflatefast.go
+++ b/src/compress/flate/deflatefast.go
@@ -55,7 +55,7 @@ func newDeflateFast() *deflateFast {
return &deflateFast{cur: maxStoreBlockSize, prev: make([]byte, 0, maxStoreBlockSize)}
}
-// encode encodes a block given in src and encodes tokens
+// encode encodes a block given in src and appends tokens
// to dst and returns the result.
func (e *deflateFast) encode(dst []token, src []byte) []token {
// Ensure that e.cur doesn't wrap.
@@ -116,8 +116,7 @@ func (e *deflateFast) encode(dst []token, src []byte) []token {
nextHash = hash(now)
offset := s - (candidate.offset - e.cur)
- // TODO: >= should be >, and add a test for that.
- if offset >= maxMatchOffset || cv != candidate.val {
+ if offset > maxMatchOffset || cv != candidate.val {
// Out of range or not matched.
cv = now
continue
@@ -171,8 +170,7 @@ func (e *deflateFast) encode(dst []token, src []byte) []token {
e.table[currHash&tableMask] = tableEntry{offset: e.cur + s, val: uint32(x)}
offset := s - (candidate.offset - e.cur)
- // TODO: >= should be >, and add a test for that.
- if offset >= maxMatchOffset || uint32(x) != candidate.val {
+ if offset > maxMatchOffset || uint32(x) != candidate.val {
cv = uint32(x >> 8)
nextHash = hash(cv)
s++