Overview
| Comment: | Added documentation for the decompressor |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
89bfe973847c1cc1e9bf81a1d583bbea |
| User & Date: | spaskalev on 2014-12-22 19:52:05.580 |
| Other Links: | manifest | tags |
Context
|
2014-12-23
| ||
| 07:52 | Added package ioutil with io.Writer and io.Reader function wrappers check-in: 2bcd5307ea user: spaskalev tags: trunk | |
|
2014-12-22
| ||
| 19:52 | Added documentation for the decompressor check-in: 89bfe97384 user: spaskalev tags: trunk | |
| 19:28 | Extracted the predictor's hash function as a method of the context struct. Minor changes to the decompressor's variables. check-in: 9dfd3cb1a2 user: spaskalev tags: trunk | |
Changes
Modified src/0dev.org/predictor/predictor.go
from [a4885df9dd]
to [290c8bbbe5].
| ︙ | ︙ | |||
14 15 16 17 18 19 20 | } // The following hash code is the heart of the algorithm: // It builds a sliding hash sum of the previous 3-and-a-bit // characters which will be used to index the guess table. // A better hash function would result in additional compression, // at the expense of time. | | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
}
// The following hash code is the heart of the algorithm:
// It builds a sliding hash sum of the previous 3-and-a-bit
// characters which will be used to index the guess table.
// A better hash function would result in additional compression,
// at the expense of time.
func (ctx *context) update(val byte) {
ctx.hash = (ctx.hash << 4) ^ uint16(val)
}
type compressor func([]byte) error
func (w compressor) Write(data []byte) (int, error) {
return len(data), w(data)
}
|
| ︙ | ︙ | |||
90 91 92 93 94 95 96 |
// Guess was right - don't output
buf[0] |= 1 << uint(i)
} else {
// Guess was wrong, output char
ctx.table[ctx.hash] = current
buf = append(buf, current)
}
| | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
// Guess was right - don't output
buf[0] |= 1 << uint(i)
} else {
// Guess was wrong, output char
ctx.table[ctx.hash] = current
buf = append(buf, current)
}
ctx.update(current)
}
if _, err := writer.Write(buf); err != nil {
return err
}
// Reset the flags and buffer for the next iteration
|
| ︙ | ︙ | |||
146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
// Check whether we have leftover data in the buffer
if len(ctx.input) > 0 {
rc = copy(output, ctx.input)
// Check whether we still have leftover data in the buffer :)
if rc < len(ctx.input) {
ctx.input = ctx.input[:copy(ctx.input, ctx.input[rc:])]
}
return rc, nil
}
// Read the next prediction header
readHeader:
| > > | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
// Check whether we have leftover data in the buffer
if len(ctx.input) > 0 {
rc = copy(output, ctx.input)
// Check whether we still have leftover data in the buffer :)
if rc < len(ctx.input) {
// Shift the remaining bytes at the start of the buffer
// and resize the buffer accordingly
ctx.input = ctx.input[:copy(ctx.input, ctx.input[rc:])]
}
return rc, nil
}
// Read the next prediction header
readHeader:
|
| ︙ | ︙ | |||
188 189 190 191 192 193 194 |
// Walk the buffer, filling in the predicted blanks,
// relocating read bytes and and updating the guess table
for i, a := 0, predicted; i < rc; i++ {
if (flags & (1 << uint(i))) > 0 {
// Guess succeeded, fill in from the table
ctx.input[i] = ctx.table[ctx.hash]
} else {
| | | | < | < > > | > | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
// Walk the buffer, filling in the predicted blanks,
// relocating read bytes and and updating the guess table
for i, a := 0, predicted; i < rc; i++ {
if (flags & (1 << uint(i))) > 0 {
// Guess succeeded, fill in from the table
ctx.input[i] = ctx.table[ctx.hash]
} else {
// Relocate a read byte and advance the read byte index
ctx.input[i], a = ctx.input[a], a+1
// Guess failed, update the table
ctx.table[ctx.hash] = ctx.input[i]
}
// Update the hash
ctx.update(ctx.input[i])
}
// Copy the decompressed data to the output and accumulate the count
copied = copy(output, ctx.input[:rc])
total += copied
// Check for remaining bytes that dont fit in the output buffer
if copied < rc {
// Shift the remaining bytes at the start of the buffer
// and resize the buffer accordingly
ctx.input = ctx.input[:copy(ctx.input, ctx.input[copied:rc])]
} else {
// Clear the buffer
ctx.input = ctx.input[:0]
// Loop for another pass if there is available space in the output
output = output[copied:]
if len(output) > 0 && err == nil {
goto readHeader
}
}
return total, err
})
}
|