@@ -27,47 +27,25 @@ type context struct { table [256]byte } -// Returns an MTF encoder over the provided io.Writer -func Encoder(writer io.Writer) io.Writer { - var enc encoder - enc.table = initial - enc.target = writer - return &enc -} - -type encoder struct { - context - target io.Writer -} - -func (c *encoder) Write(data []byte) (int, error) { - var ( - dataLength int = len(data) - buffer []byte = make([]byte, dataLength) - ) - - // io.Write must not modify the passed data in any way - // TODO - check sync.Pool or a local free-list for amortizing buffers - // TODO - use a buffer with a fixed max size to avoid OOM conditions - - // Loop over the input data +// Encodes data in place +func (c *context) encode(data []byte) { for index, value := range data { // Shortcut for sequential, equal values if c.table[0] == value { - buffer[index] = 0 + data[index] = 0 continue } // Loop over the MTF table for j := byte(1); j != 0; j++ { if c.table[j] == value { // Output the value - buffer[index] = j + data[index] = j // Shift the table copy(c.table[1:], c.table[:j]) // Restore the value in front and break @@ -74,15 +52,54 @@ c.table[0] = value break } } } +} + +// Decode data in place +func (c *context) decode(data []byte) { + for index, value := range data { + position := value + + // Shortcut for sequential, equal values + if position == 0 { + data[index] = c.table[0] + continue + } + + // Output the value + data[index] = c.table[position] + + // Shift the table and restore the value in front + copy(c.table[1:], c.table[:position]) + c.table[0] = data[index] + } +} + +// Returns an MTF encoder over the provided io.Reader +func Encoder(reader io.Reader) io.Reader { + var enc encoder + enc.table = initial + enc.source = reader + return &enc +} + +type encoder struct { + context + source io.Reader +} + +// Read and encode data in place +func (c *encoder) Read(output []byte) (count int, err error) { + count, err = c.source.Read(output) + c.encode(output[:count]) - return c.target.Write(buffer) + return count, err } -// Returns an MTF decoder over the provided io.Writer +// Returns an MTF decoder over the provided io.Reader func Decoder(reader io.Reader) io.Reader { var dec decoder dec.table = initial dec.source = reader return &dec @@ -91,33 +108,12 @@ type decoder struct { context source io.Reader } -func (c *decoder) Read(output []byte) (int, error) { - var ( - count int - err error - position byte - ) - - // Read from the source and decode in place +// Read and decode data in place +func (c *decoder) Read(output []byte) (count int, err error) { count, err = c.source.Read(output) - for i := 0; i < count; i++ { - position = output[i] - - // Shortcut for sequential, equal values - if position == 0 { - output[i] = c.table[0] - continue - } - - // Output the value - output[i] = c.table[position] - - // Shift the table and restore the value in front - copy(c.table[1:], c.table[:position]) - c.table[0] = output[i] - } + c.decode(output[:count]) return count, err }