Index: src/0dev.org/predictor/predictor.go ================================================================== --- src/0dev.org/predictor/predictor.go +++ src/0dev.org/predictor/predictor.go @@ -31,46 +31,43 @@ bufferLength int = len(ctx.input) ) // Force a flush if we are called with no data to write if len(data) == 0 { + // Nothing to flush if the buffer is empty though if len(ctx.input) == 0 { return nil } // We can't have more than 7 bytes in the buffer so this is safe data, blockSize, bufferLength = ctx.input, len(ctx.input), 0 } // Check if there are pending bytes in the buffer if len(data) < blockSize || bufferLength > 0 { - // Check whether we have enough bytes for a complete block - if len(data) > 8-bufferLength { - // Fill the buffer ... - ctx.input = append(ctx.input, data[:8-bufferLength]...) - // ... and recurse, calling ourselves with the full buffer - err = write(ctx.input) - if err != nil { - return err - } - - // Clear the buffer - ctx.input = ctx.input[:0] - - // Handle remaining bytes, if any - var remaining []byte = data[8-bufferLength:] - if len(remaining) > 0 { - // Recurse, calling ourselves with the rest of the bytes - err = write(data[8-bufferLength:]) - if err != nil { - return err - } - } - } else { - // Add the insufficient data to the buffer and return - ctx.input = append(ctx.input, data...) + + // If the current buffer + new data can fit into a block + if (len(data) + bufferLength) <= blockSize { + ctx.input = append(ctx.input, data...) + + // Flush the block if the buffer fills it + if len(ctx.input) == blockSize { + return write(nil) + } + // ... otherwise just return return nil } + + // The current buffer + new data overflow the block size + // Complete the block, flush it ... + ctx.input = append(ctx.input, data[:blockSize-bufferLength]...) + err = write(nil) + if err != nil { + return err + } + // ... and stage the rest of the data in the buffer + ctx.input = append(ctx.input, data[blockSize-bufferLength:]...) + return nil } var buf []byte = make([]byte, 1, blockSize+1) for block := 0; block < len(data)/blockSize; block++ { for i := 0; i < blockSize; i++ { Index: src/0dev.org/predictor/predictor_test.go ================================================================== --- src/0dev.org/predictor/predictor_test.go +++ src/0dev.org/predictor/predictor_test.go @@ -62,61 +62,65 @@ if len(delta.Added) > 0 || len(delta.Removed) > 0 { t.Error("Unexpected decompressed output", delta) } } -func TestEmptyCycle(t *testing.T) { - var input []byte = []byte{} - - if err := cycle(input); err != nil { - t.Error(err) - } -} - -func TestPartialCycle(t *testing.T) { - var input []byte = []byte{0, 1, 2, 3} - - if err := cycle(input); err != nil { - t.Error(err) - } -} - -func TestBlockCycle(t *testing.T) { - var input []byte = []byte{0, 1, 2, 3, 4, 5, 6, 7} - - if err := cycle(input); err != nil { - t.Error(err) - } -} - -func TestBlockPartialCycle(t *testing.T) { - var input []byte = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - - if err := cycle(input); err != nil { - t.Error(err) - } -} - -func TestDualBlockCycle(t *testing.T) { - var input []byte = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} - - if err := cycle(input); err != nil { - t.Error(err) - } -} - -func cycle(input []byte) error { +var testData = [][]byte{ + []byte{}, + []byte{0, 1, 2, 3}, + []byte{0, 1, 2, 3, 4, 5, 6, 7}, + []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, + []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, +} + +func TestCycle(t *testing.T) { + for i := 0; i < len(testData); i++ { + if err := cycle(testData[i], len(testData[i])); err != nil { + t.Error(err) + } + } +} + +func TestStepCycle(t *testing.T) { + for i := 0; i < len(testData); i++ { + for j := 1; j < len(testData); j++ { + if err := cycle(testData[i], j); err != nil { + t.Error("Error for testData[", i, "], step[", j, "] ", err) + } + } + } +} + +func cycle(input []byte, step int) error { var ( buf bytes.Buffer err error ) + + if step > len(input) { + return nil + } // Create a compressor and write the given data compressor := Compressor(&buf) - err = compressor(input) - if err != nil { - return err + + var data []byte = input + var trace []byte = make([]byte, 0) + + for len(data) > 0 { + if step <= len(data) { + + trace = append(trace, data[:step]...) + + err = compressor(data[:step]) + if err != nil { + return err + } + data = data[step:] + } else { + step = len(data) + } } // Flush the compressor err = compressor(nil) if err != nil { @@ -134,12 +138,12 @@ delta := diff.Diff(diff.D{len(input), len(decompressed), func(i, j int) bool { return input[i] == decompressed[j] }}) // Return a well-formated error if any differences are found if len(delta.Added) > 0 || len(delta.Removed) > 0 { - return fmt.Errorf("Unexpected decompressed output %v\ninput: %#x\noutput: %#x\n", - delta, input, decompressed) + return fmt.Errorf("Unexpected decompressed output %v\ninput: %#x\ntrace: %#x\noutput: %#x\n", + delta, input, trace, decompressed) } // All is good :) return nil }