1
0
mirror of https://github.com/golang/go synced 2024-11-19 17:24:41 -07:00

compress/lzw: do not use background goroutines

Programs expect that Read and Write are synchronous.
The background goroutines make the implementation
a little easier, but they introduce asynchrony that
trips up calling code.  Remove them.

R=golang-dev, nigeltao
CC=golang-dev
https://golang.org/cl/4548080
This commit is contained in:
Russ Cox 2011-06-07 14:37:06 -04:00
parent 8cd7aac223
commit 63dae3c3be
2 changed files with 135 additions and 96 deletions

View File

@ -32,13 +32,48 @@ const (
MSB MSB
) )
const (
maxWidth = 12
decoderInvalidCode = 0xffff
flushBuffer = 1 << maxWidth
)
// decoder is the state from which the readXxx method converts a byte // decoder is the state from which the readXxx method converts a byte
// stream into a code stream. // stream into a code stream.
type decoder struct { type decoder struct {
r io.ByteReader r io.ByteReader
bits uint32 bits uint32
nBits uint nBits uint
width uint width uint
read func(*decoder) (uint16, os.Error) // readLSB or readMSB
litWidth int // width in bits of literal codes
err os.Error
// The first 1<<litWidth codes are literal codes.
// The next two codes mean clear and EOF.
// Other valid codes are in the range [lo, hi] where lo := clear + 2,
// with the upper bound incrementing on each code seen.
// overflow is the code at which hi overflows the code width.
// last is the most recently seen code, or decoderInvalidCode.
clear, eof, hi, overflow, last uint16
// Each code c in [lo, hi] expands to two or more bytes. For c != hi:
// suffix[c] is the last of these bytes.
// prefix[c] is the code for all but the last byte.
// This code can either be a literal code or another code in [lo, c).
// The c == hi case is a special case.
suffix [1 << maxWidth]uint8
prefix [1 << maxWidth]uint16
// buf is a scratch buffer for reconstituting the bytes that a code expands to.
// Code suffixes are written right-to-left from the end of the buffer.
buf [1 << maxWidth]byte
// output is the temporary output buffer.
// It is flushed when it contains >= 1<<maxWidth bytes,
// so that there is always room to copy buf into it while decoding.
output [2 * 1 << maxWidth]byte
o int // write index into output
toRead []byte // bytes to return from Read
} }
// readLSB returns the next code for "Least Significant Bits first" data. // readLSB returns the next code for "Least Significant Bits first" data.
@ -73,119 +108,113 @@ func (d *decoder) readMSB() (uint16, os.Error) {
return code, nil return code, nil
} }
// decode decompresses bytes from r and writes them to pw. func (d *decoder) Read(b []byte) (int, os.Error) {
// read specifies how to decode bytes into codes. for {
// litWidth is the width in bits of literal codes. if len(d.toRead) > 0 {
func decode(r io.Reader, read func(*decoder) (uint16, os.Error), litWidth int, pw *io.PipeWriter) { n := copy(b, d.toRead)
br, ok := r.(io.ByteReader) d.toRead = d.toRead[n:]
if !ok { return n, nil
br = bufio.NewReader(r) }
if d.err != nil {
return 0, d.err
}
d.decode()
} }
pw.CloseWithError(decode1(pw, br, read, uint(litWidth))) panic("unreachable")
} }
func decode1(pw *io.PipeWriter, r io.ByteReader, read func(*decoder) (uint16, os.Error), litWidth uint) os.Error { // decode decompresses bytes from r and leaves them in d.toRead.
const ( // read specifies how to decode bytes into codes.
maxWidth = 12 // litWidth is the width in bits of literal codes.
invalidCode = 0xffff func (d *decoder) decode() {
)
d := decoder{r, 0, 0, 1 + litWidth}
w := bufio.NewWriter(pw)
// The first 1<<litWidth codes are literal codes.
// The next two codes mean clear and EOF.
// Other valid codes are in the range [lo, hi] where lo := clear + 2,
// with the upper bound incrementing on each code seen.
clear := uint16(1) << litWidth
eof, hi := clear+1, clear+1
// overflow is the code at which hi overflows the code width.
overflow := uint16(1) << d.width
var (
// Each code c in [lo, hi] expands to two or more bytes. For c != hi:
// suffix[c] is the last of these bytes.
// prefix[c] is the code for all but the last byte.
// This code can either be a literal code or another code in [lo, c).
// The c == hi case is a special case.
suffix [1 << maxWidth]uint8
prefix [1 << maxWidth]uint16
// buf is a scratch buffer for reconstituting the bytes that a code expands to.
// Code suffixes are written right-to-left from the end of the buffer.
buf [1 << maxWidth]byte
)
// Loop over the code stream, converting codes into decompressed bytes. // Loop over the code stream, converting codes into decompressed bytes.
last := uint16(invalidCode)
for { for {
code, err := read(&d) code, err := d.read(d)
if err != nil { if err != nil {
if err == os.EOF { if err == os.EOF {
err = io.ErrUnexpectedEOF err = io.ErrUnexpectedEOF
} }
return err d.err = err
return
} }
switch { switch {
case code < clear: case code < d.clear:
// We have a literal code. // We have a literal code.
if err := w.WriteByte(uint8(code)); err != nil { d.output[d.o] = uint8(code)
return err d.o++
} if d.last != decoderInvalidCode {
if last != invalidCode {
// Save what the hi code expands to. // Save what the hi code expands to.
suffix[hi] = uint8(code) d.suffix[d.hi] = uint8(code)
prefix[hi] = last d.prefix[d.hi] = d.last
} }
case code == clear: case code == d.clear:
d.width = 1 + litWidth d.width = 1 + uint(d.litWidth)
hi = eof d.hi = d.eof
overflow = 1 << d.width d.overflow = 1 << d.width
last = invalidCode d.last = decoderInvalidCode
continue continue
case code == eof: case code == d.eof:
return w.Flush() d.flush()
case code <= hi: d.err = os.EOF
c, i := code, len(buf)-1 return
if code == hi { case code <= d.hi:
c, i := code, len(d.buf)-1
if code == d.hi {
// code == hi is a special case which expands to the last expansion // code == hi is a special case which expands to the last expansion
// followed by the head of the last expansion. To find the head, we walk // followed by the head of the last expansion. To find the head, we walk
// the prefix chain until we find a literal code. // the prefix chain until we find a literal code.
c = last c = d.last
for c >= clear { for c >= d.clear {
c = prefix[c] c = d.prefix[c]
} }
buf[i] = uint8(c) d.buf[i] = uint8(c)
i-- i--
c = last c = d.last
} }
// Copy the suffix chain into buf and then write that to w. // Copy the suffix chain into buf and then write that to w.
for c >= clear { for c >= d.clear {
buf[i] = suffix[c] d.buf[i] = d.suffix[c]
i-- i--
c = prefix[c] c = d.prefix[c]
} }
buf[i] = uint8(c) d.buf[i] = uint8(c)
if _, err := w.Write(buf[i:]); err != nil { d.o += copy(d.output[d.o:], d.buf[i:])
return err if d.last != decoderInvalidCode {
}
if last != invalidCode {
// Save what the hi code expands to. // Save what the hi code expands to.
suffix[hi] = uint8(c) d.suffix[d.hi] = uint8(c)
prefix[hi] = last d.prefix[d.hi] = d.last
} }
default: default:
return os.NewError("lzw: invalid code") d.err = os.NewError("lzw: invalid code")
return
} }
last, hi = code, hi+1 d.last, d.hi = code, d.hi+1
if hi >= overflow { if d.hi >= d.overflow {
if d.width == maxWidth { if d.width == maxWidth {
last = invalidCode d.last = decoderInvalidCode
continue } else {
d.width++
d.overflow <<= 1
} }
d.width++ }
overflow <<= 1 if d.o >= flushBuffer {
d.flush()
return
} }
} }
panic("unreachable") panic("unreachable")
} }
func (d *decoder) flush() {
d.toRead = d.output[:d.o]
d.o = 0
}
func (d *decoder) Close() os.Error {
d.err = os.EINVAL // in case any Reads come along
return nil
}
// NewReader creates a new io.ReadCloser that satisfies reads by decompressing // NewReader creates a new io.ReadCloser that satisfies reads by decompressing
// the data read from r. // the data read from r.
// It is the caller's responsibility to call Close on the ReadCloser when // It is the caller's responsibility to call Close on the ReadCloser when
@ -193,21 +222,31 @@ func decode1(pw *io.PipeWriter, r io.ByteReader, read func(*decoder) (uint16, os
// The number of bits to use for literal codes, litWidth, must be in the // The number of bits to use for literal codes, litWidth, must be in the
// range [2,8] and is typically 8. // range [2,8] and is typically 8.
func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser { func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser {
pr, pw := io.Pipe() d := new(decoder)
var read func(*decoder) (uint16, os.Error)
switch order { switch order {
case LSB: case LSB:
read = (*decoder).readLSB d.read = (*decoder).readLSB
case MSB: case MSB:
read = (*decoder).readMSB d.read = (*decoder).readMSB
default: default:
pw.CloseWithError(os.NewError("lzw: unknown order")) d.err = os.NewError("lzw: unknown order")
return pr return d
} }
if litWidth < 2 || 8 < litWidth { if litWidth < 2 || 8 < litWidth {
pw.CloseWithError(fmt.Errorf("lzw: litWidth %d out of range", litWidth)) d.err = fmt.Errorf("lzw: litWidth %d out of range", litWidth)
return pr return d
} }
go decode(r, read, litWidth, pw) if br, ok := r.(io.ByteReader); ok {
return pr d.r = br
} else {
d.r = bufio.NewReader(r)
}
d.litWidth = litWidth
d.width = 1 + uint(litWidth)
d.clear = uint16(1) << uint(litWidth)
d.eof, d.hi = d.clear+1, d.clear+1
d.overflow = uint16(1) << d.width
d.last = decoderInvalidCode
return d
} }

View File

@ -77,13 +77,13 @@ func testFile(t *testing.T, fn string, order Order, litWidth int) {
t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err1) t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err1)
return return
} }
if len(b0) != len(b1) { if len(b1) != len(b0) {
t.Errorf("%s (order=%d litWidth=%d): length mismatch %d versus %d", fn, order, litWidth, len(b0), len(b1)) t.Errorf("%s (order=%d litWidth=%d): length mismatch %d != %d", fn, order, litWidth, len(b1), len(b0))
return return
} }
for i := 0; i < len(b0); i++ { for i := 0; i < len(b0); i++ {
if b0[i] != b1[i] { if b1[i] != b0[i] {
t.Errorf("%s (order=%d litWidth=%d): mismatch at %d, 0x%02x versus 0x%02x\n", fn, order, litWidth, i, b0[i], b1[i]) t.Errorf("%s (order=%d litWidth=%d): mismatch at %d, 0x%02x != 0x%02x\n", fn, order, litWidth, i, b1[i], b0[i])
return return
} }
} }