Index: src/0dev.org/encoding/fibonacci/fib.go ================================================================== --- src/0dev.org/encoding/fibonacci/fib.go +++ src/0dev.org/encoding/fibonacci/fib.go @@ -4,18 +4,16 @@ // 1 - 11, 2 - 011, 3 - 0011, 4 - 1011, 5 - 00011 // // Incrementing input by one to allow for zero gives // 0 - 11, 1 - 011, 2 - 0011, 3 - 1011, 4 - 00011 // -// The codes are then reversed so that they are easily stored in uints +// The codes are reversed so that they are easily stored in uints, +// effectively avoiding the need to store the number of leading zeroes // 0 - 11, 1 - 110, 2 - 1100, 3 - 1101, 4 - 11000 -// (so that they are always comparable with each other as there is no need to -// store the leading number of zeroes which are otherwise required) package fibonacci import ( - _ "fmt" "io" ) type Numbers []uint64 @@ -159,50 +157,62 @@ e.buffer = e.buffer[:0] } return total, err } -// func Reader(source io.Reader) io.Reader { -// var dec decoder -// dec.Numbers = New(16) -// dec.source = source -// return &dec -// } - -// type decoder struct { -// Numbers -// source io.Reader -// buffer uint64 -// at byte -// } - -// func (d *decoder) Read(output []byte) (int, error) { -// var ( -// total int -// err error -// ) - -// // While we have suitable buffered data and enough output space -// for (len(output) > 0) && ((d.buffer & (d.buffer >> 1)) > 0) { -// val, len := d.Decode(d.buffer) - -// // Store the decoded byte -// output[0] = byte(val) - -// // Advance the internal and output buffers -// output = output[1:] -// d.buffer >>= len - -// // TODO - decrease d.at as well ? - -// total++ -// } - -// // Termination condition -// if len(output) == 0 { -// return total, nil -// } - -// // count, err := d.source.Read(output) - -// return total, err -// } +func Reader(source io.Reader) io.Reader { + var dec decoder + dec.Numbers = New(16) + dec.source = source + return &dec +} + +type decoder struct { + Numbers + source io.Reader + buffer uint64 + at byte +} + +func (d *decoder) Read(output []byte) (int, error) { + var ( + total int + err error + ) + +start: + // While we have suitable buffered data and enough output space + for (len(output) > 0) && ((d.buffer & (d.buffer >> 1)) > 0) { + val, len := d.Decode(d.buffer) + + // Store the decoded byte + output[0] = byte(val) + + // Advance the internal and output buffers + output = output[1:] + d.buffer >>= len + d.at -= len + + total++ + } + + // Termination condition + if len(output) == 0 || err != nil { + return total, err + } + + // We need to limit the output's size else we could end up with a lot of small values + // that fit neither in the output slice nor in the internal buffer + free := int((63 ^ d.at) >> 3) + if free > len(output) { + free = len(output) + } + + // Read data and transfer to the internal buffer + count, err := d.source.Read(output[:free]) + for _, v := range output[:count] { + d.buffer |= uint64(v) << d.at + d.at += 8 + } + + goto start +} Index: src/0dev.org/encoding/fibonacci/fib_test.go ================================================================== --- src/0dev.org/encoding/fibonacci/fib_test.go +++ src/0dev.org/encoding/fibonacci/fib_test.go @@ -1,8 +1,9 @@ package fibonacci import ( + diff "0dev.org/diff" "bytes" "io" "strings" "testing" ) @@ -34,15 +35,17 @@ t.Errorf("Unexpected difference between encoded and decoded lengths.", encLen, decLen) } } } -func TestWriter(t *testing.T) { - var buf bytes.Buffer - var w io.Writer = Writer(&buf) - var input []byte = make([]byte, 256) - var fib Numbers = New(16) +func TestWriterReader(t *testing.T) { + var ( + buf bytes.Buffer + w io.Writer = Writer(&buf) + input []byte = make([]byte, 256) + fib Numbers = New(16) + ) for i := uint64(0); i < 256; i++ { input[i] = byte(i) } @@ -75,10 +78,26 @@ if loc := strings.Index(output, vs); loc != 0 { t.Fatal("Unexpected location for", i, "value", vs) } output = output[len(vs):] } + + var ( + in *bytes.Reader = bytes.NewReader(buf.Bytes()) + r io.Reader = Reader(in) + out bytes.Buffer + ) + io.Copy(&out, r) + decoded := out.Bytes() + + delta := diff.Diff(diff.D{Len1: len(decoded), Len2: len(input), EqualFunc: func(i, j int) bool { + return decoded[i] == input[j] + }}) + + if len(delta.Added) > 0 || len(delta.Removed) > 0 { + t.Error("Differences detected ", delta) + } } func u2s(b uint64, l byte) (result string) { for i := byte(0); i < l; i++ { if (b & 1) > 0 {