Check-in [1f73d90f65]
Overview
Comment:The decompressor now tries to fill in the whole output buffer in a single call.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1f73d90f65ec364f62075e5c5a5b0666be2b116b
User & Date: spaskalev on 2014-12-21 23:24:04
Other Links: manifest | tags
Context
2014-12-22
16:41
Integrate the decompressor2 branch into trunk now that it is faster. check-in: 6d10a1d28f user: spaskalev tags: trunk
2014-12-21
23:24
The decompressor now tries to fill in the whole output buffer in a single call. check-in: 1f73d90f65 user: spaskalev tags: trunk
22:52
Removed TODOs, renamed readCount->rc, wrapped->reader check-in: 630530df49 user: spaskalev tags: trunk
Changes

Modified src/0dev.org/predictor/predictor.go from [090d2f3fd4] to [9dfe9174f8].

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

148
149
150
151



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190

191







192
193
194
195
196
// and decompresses data according to the predictor algorithm
func Decompressor(reader io.Reader) io.Reader {
	var ctx context
	ctx.input = make([]byte, 0, 8)

	return decompressor(func(output []byte) (int, error) {
		var (
			err       error
			flags     byte
			rc, total int
		)

		// Sanity check for space to read into
		if len(output) == 0 {
			return 0, nil
		}

		// 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 flags
		rc, err = reader.Read(ctx.input[:1])
		if rc == 0 || (err != nil && err != io.EOF) {
			return rc, err



		}

		ctx.input = ctx.input[:8]
		flags = ctx.input[0]

		var i uint = 0
		for ; i < 8; i++ {
			if flags&(1<<i) > 0 {
				// Guess was right
				ctx.input[i] = ctx.table[ctx.hash]
			} else {
				rc, err = reader.Read(ctx.input[i:(i + 1)])

				if err == io.EOF {
					break
				}

				if err != nil {
					return rc, err
				}

				if rc == 0 { // treat as EoF
					break
				}

				ctx.table[ctx.hash] = ctx.input[i]
			}

			ctx.hash = (ctx.hash << 4) ^ uint16(ctx.input[i])
		}

		rc = copy(output, ctx.input[:i])

		total += rc

		// Place any remaining bytes in the buffer
		if uint(rc) < i {
			ctx.input = ctx.input[:copy(ctx.input, ctx.input[rc:i])]
		} else {

			ctx.input = ctx.input[:0]







		}

		return total, err
	})
}







|
|
|


















>


|
|
>
>
>





<
|
|










|













<



|


>

>
>
>
>
>
>
>





120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// and decompresses data according to the predictor algorithm
func Decompressor(reader io.Reader) io.Reader {
	var ctx context
	ctx.input = make([]byte, 0, 8)

	return decompressor(func(output []byte) (int, error) {
		var (
			err          error
			flags        byte
			i, rc, total int
		)

		// Sanity check for space to read into
		if len(output) == 0 {
			return 0, nil
		}

		// 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
		}

	loop:
		// Read the flags
		rc, err = reader.Read(ctx.input[:1])
		if err != nil && err != io.EOF {
			return 0, err
		}
		if rc == 0 {
			return total, err
		}

		ctx.input = ctx.input[:8]
		flags = ctx.input[0]


		for i = 0; i < 8; i++ {
			if flags&(1<<uint(i)) > 0 {
				// Guess was right
				ctx.input[i] = ctx.table[ctx.hash]
			} else {
				rc, err = reader.Read(ctx.input[i:(i + 1)])

				if err == io.EOF {
					break
				}

				if err != nil {
					return total, err
				}

				if rc == 0 { // treat as EoF
					break
				}

				ctx.table[ctx.hash] = ctx.input[i]
			}

			ctx.hash = (ctx.hash << 4) ^ uint16(ctx.input[i])
		}

		rc = copy(output, ctx.input[:i])

		total += rc

		// Place any remaining bytes in the buffer
		if rc < i {
			ctx.input = ctx.input[:copy(ctx.input, ctx.input[rc:i])]
		} else {
			// Clear the buffer
			ctx.input = ctx.input[:0]

			// Advance the output buffer ...
			output = output[i:]
			// ... and decompress the next block if there is any space left
			if len(output) > 0 && err != io.EOF {
				goto loop
			}
		}

		return total, err
	})
}

Modified src/0dev.org/predictor/predictor_test.go from [dd11cf49de] to [0dde784b22].

136
137
138
139
140
141
142
143
144
145
146
147
148
149

	// Diff the result against the initial input
	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\ntrace:  %#x\noutput: %#x\n",
			delta, input, trace, decompressed)
	}

	// All is good :)
	return nil
}







|
|





136
137
138
139
140
141
142
143
144
145
146
147
148
149

	// Diff the result against the initial input
	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: (%d) %#x\ntrace: (%d) %#x\noutput: (%d) %#x\n",
			delta, len(input), input, len(trace), trace, len(decompressed), decompressed)
	}

	// All is good :)
	return nil
}