Check-in [4dfcff962c]
Overview
SHA1:4dfcff962c763b560a5af8101c2f3f3ad059ae8c
Date: 2014-12-25 00:55:43
User: spaskalev
Comment:Predictor's compressor and decompressor structures now implement io.Writer/io.Reader in order to deal away with function indirection but they do not follow the required semantics. Those are provided by the SizedWriter/SizedReader wrappers returned by the constructor functions.
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | folders | manifest
Tags And Properties
Context
2014-12-25
01:25
[2b1ed8e45e] Removed pdc's output buffer when decompressing as io.Copy uses a sufficiently-large buffer internally. (user: spaskalev, tags: trunk)
00:55
[4dfcff962c] Predictor's compressor and decompressor structures now implement io.Writer/io.Reader in order to deal away with function indirection but they do not follow the required semantics. Those are provided by the SizedWriter/SizedReader wrappers returned by the constructor functions. (user: spaskalev, tags: trunk)
00:43
[50507bd510] Extracted predictor's compressor and decompressor code into separate structs that embed Sized{Writer,Reader} (user: spaskalev, tags: trunk)
Changes

Modified src/0dev.org/predictor/predictor.go from [cb877636af] to [3161320c11].

    27     27   // Returns an io.Writer implementation that wraps the provided io.Writer
    28     28   // and compresses data according to the predictor algorithm
    29     29   //
    30     30   // It can buffer data as the predictor mandates 8-byte blocks with a header.
    31     31   // A call with no data will force a flush.
    32     32   func Compressor(writer io.Writer) io.Writer {
    33     33   	var cmp compressor
    34         -	cmp.Writer = iou.SizedWriter(iou.WriterFunc(cmp.compress), 8)
    35     34   	cmp.target = writer
    36         -	return &cmp
           35  +	return iou.SizedWriter(&cmp, 8)
    37     36   }
    38     37   
    39     38   type compressor struct {
    40     39   	context
    41         -	io.Writer
    42     40   	target io.Writer
    43     41   }
    44     42   
    45         -func (ctx *compressor) compress(data []byte) (int, error) {
           43  +// Note: this method does not implement the full io.Writer's Write() semantics
           44  +func (ctx *compressor) Write(data []byte) (int, error) {
    46     45   	var (
    47     46   		blockSize  int = 8
    48     47   		datalength int = len(data)
    49     48   	)
    50     49   
    51     50   	if datalength == 0 {
    52     51   		return 0, nil
................................................................................
    82     81   	return datalength, nil
    83     82   }
    84     83   
    85     84   // Returns an io.Reader implementation that wraps the provided io.Reader
    86     85   // and decompresses data according to the predictor algorithm
    87     86   func Decompressor(reader io.Reader) io.Reader {
    88     87   	var dcmp decompressor
    89         -	dcmp.Reader = iou.SizedReader(iou.ReaderFunc(dcmp.decompress), 8)
    90     88   	dcmp.source = reader
    91         -	dcmp.input = make([]byte, 0, 8)
    92         -	return &dcmp
           89  +	dcmp.input = make([]byte, 8)
           90  +	return iou.SizedReader(&dcmp, 8)
    93     91   }
    94     92   
    95     93   type decompressor struct {
    96     94   	context
    97         -	io.Reader
    98     95   	source io.Reader
    99     96   	input  []byte
   100     97   }
   101     98   
   102         -func (ctx *decompressor) decompress(output []byte) (int, error) {
           99  +// Note: this method does not implement the full io.Reader's Read() semantics
          100  +func (ctx *decompressor) Read(output []byte) (int, error) {
   103    101   	var (
   104    102   		err               error
   105    103   		flags, predicted  byte
   106    104   		rc, total, copied int
   107    105   	)
   108    106   
   109    107   	// Read the next prediction header
................................................................................
   112    110   	// Fail on error unless it is EOF
   113    111   	if err != nil && err != io.EOF {
   114    112   		return total, err
   115    113   	} else if rc == 0 {
   116    114   		return total, err
   117    115   	}
   118    116   
   119         -	// Extend the buffer, copy the prediction header
   120         -	//  and calculate the number of subsequent bytes to read
   121         -	ctx.input = ctx.input[:8]
          117  +	// Copy the prediction header and calculate the number of subsequent bytes to read
   122    118   	flags = ctx.input[0]
   123    119   	predicted = bits.Hamming(flags)
   124    120   
   125    121   	// Read the non-predicted bytes and place them in the end of the buffer
   126    122   	rc, err = ctx.source.Read(ctx.input[predicted:])
   127    123   retryData:
   128    124   	if rc < int(8-predicted) && err == nil {
................................................................................
   152    148   		ctx.update(ctx.input[i])
   153    149   	}
   154    150   
   155    151   	// Copy the decompressed data to the output and accumulate the count
   156    152   	copied = copy(output, ctx.input[:rc])
   157    153   	total += copied
   158    154   
   159         -	// Clear the buffer
   160         -	ctx.input = ctx.input[:0]
   161         -
   162    155   	// Loop for another pass if there is available space in the output
   163    156   	output = output[copied:]
   164    157   	if len(output) > 0 && err == nil {
   165    158   		goto readHeader
   166    159   	}
   167    160   
   168    161   	return total, err
   169    162   }