| ... | @@ -21,48 +21,121 @@ const MAXDCODES = 30; | ... | @@ -21,48 +21,121 @@ const MAXDCODES = 30; |
| 21 | const MAXCODES = MAXLCODES + MAXDCODES; | 21 | const MAXCODES = MAXLCODES + MAXDCODES; |
| 22 | const FIXLCODES = 288; | 22 | const FIXLCODES = 288; |
| 23 | | 23 | |
| | 24 | // The maximum length of a Huffman code's prefix we can decode using the fast |
| | 25 | // path. The factor 9 is inherited from Zlib, tweaking the value showed little |
| | 26 | // or no changes in the profiler output. |
| | 27 | const PREFIX_LUT_BITS = 9; |
| | 28 | |
| 24 | const Huffman = struct { | 29 | const Huffman = struct { |
| | 30 | // Number of codes for each possible length |
| 25 | count: [MAXBITS + 1]u16, | 31 | count: [MAXBITS + 1]u16, |
| | 32 | // Mapping between codes and symbols |
| 26 | symbol: [MAXCODES]u16, | 33 | symbol: [MAXCODES]u16, |
| 27 | | 34 | |
| 28 | fn construct(self: *Huffman, length: []const u16) !void { | 35 | // The decoding process uses a trick explained by Mark Adler in [1]. |
| | 36 | // We basically precompute for a fixed number of codes (0 <= x <= 2^N-1) |
| | 37 | // the symbol and the effective code length we'd get if the decoder was run |
| | 38 | // on the given N-bit sequence. |
| | 39 | // A code with length 0 means the sequence is not a valid prefix for this |
| | 40 | // canonical Huffman code and we have to decode it using a slower method. |
| | 41 | // |
| | 42 | // [1] https://github.com/madler/zlib/blob/v1.2.11/doc/algorithm.txt#L58 |
| | 43 | prefix_lut: [1 << PREFIX_LUT_BITS]u16, |
| | 44 | prefix_lut_len: [1 << PREFIX_LUT_BITS]u16, |
| | 45 | // The following info refer to the codes of length PREFIX_LUT_BITS+1 and are |
| | 46 | // used to bootstrap the bit-by-bit reading method if the fast-path fails. |
| | 47 | last_code: u16, |
| | 48 | last_index: u16, |
| | 49 | |
| | 50 | fn construct(self: *Huffman, code_length: []const u16) !void { |
| 29 | for (self.count) |*val| { | 51 | for (self.count) |*val| { |
| 30 | val.* = 0; | 52 | val.* = 0; |
| 31 | } | 53 | } |
| 32 | | 54 | |
| 33 | for (length) |val| { | 55 | for (code_length) |len| { |
| 34 | self.count[val] += 1; | 56 | self.count[len] += 1; |
| 35 | } | 57 | } |
| 36 | | 58 | |
| 37 | if (self.count[0] == length.len) | 59 | // All zero. |
| | 60 | if (self.count[0] == code_length.len) |
| 38 | return; | 61 | return; |
| 39 | | 62 | |
| 40 | var left: isize = 1; | 63 | var left: isize = 1; |
| 41 | for (self.count[1..]) |val| { | 64 | for (self.count[1..]) |val| { |
| | 65 | // Each added bit doubles the amount of codes. |
| 42 | left *= 2; | 66 | left *= 2; |
| | 67 | // Make sure the number of codes with this length isn't too high. |
| 43 | left -= @as(isize, @bitCast(i16, val)); | 68 | left -= @as(isize, @bitCast(i16, val)); |
| 44 | if (left < 0) | 69 | if (left < 0) |
| 45 | return error.InvalidTree; | 70 | return error.InvalidTree; |
| 46 | } | 71 | } |
| 47 | | 72 | |
| 48 | var offs: [MAXBITS + 1]u16 = undefined; | 73 | // Compute the offset of the first symbol represented by a code of a |
| | 74 | // given length in the symbol table, together with the first canonical |
| | 75 | // Huffman code for that length. |
| | 76 | var offset: [MAXBITS + 1]u16 = undefined; |
| | 77 | var codes: [MAXBITS + 1]u16 = undefined; |
| 49 | { | 78 | { |
| | 79 | offset[1] = 0; |
| | 80 | codes[1] = 0; |
| 50 | var len: usize = 1; | 81 | var len: usize = 1; |
| 51 | offs[1] = 0; | | |
| 52 | while (len < MAXBITS) : (len += 1) { | 82 | while (len < MAXBITS) : (len += 1) { |
| 53 | offs[len + 1] = offs[len] + self.count[len]; | 83 | offset[len + 1] = offset[len] + self.count[len]; |
| | 84 | codes[len + 1] = (codes[len] + self.count[len]) << 1; |
| 54 | } | 85 | } |
| 55 | } | 86 | } |
| 56 | | 87 | |
| 57 | for (length) |val, symbol| { | 88 | self.prefix_lut_len = mem.zeroes(@TypeOf(self.prefix_lut_len)); |
| 58 | if (val != 0) { | 89 | |
| 59 | self.symbol[offs[val]] = @truncate(u16, symbol); | 90 | for (code_length) |len, symbol| { |
| 60 | offs[val] += 1; | 91 | if (len != 0) { |
| | 92 | // Fill the symbol table. |
| | 93 | // The symbols are assigned sequentially for each length. |
| | 94 | self.symbol[offset[len]] = @truncate(u16, symbol); |
| | 95 | // Track the last assigned offset |
| | 96 | offset[len] += 1; |
| | 97 | } |
| | 98 | |
| | 99 | if (len == 0 or len > PREFIX_LUT_BITS) |
| | 100 | continue; |
| | 101 | |
| | 102 | // Given a Huffman code of length N we have to massage it so |
| | 103 | // that it becomes an index in the lookup table. |
| | 104 | // The bit order is reversed as the fast path reads the bit |
| | 105 | // sequence MSB to LSB using an &, the order is flipped wrt the |
| | 106 | // one obtained by reading bit-by-bit. |
| | 107 | // The codes are prefix-free, if the prefix matches we can |
| | 108 | // safely ignore the trail bits. We do so by replicating the |
| | 109 | // symbol info for each combination of the trailing bits. |
| | 110 | const bits_to_fill = @intCast(u5, PREFIX_LUT_BITS - len); |
| | 111 | const rev_code = bitReverse(codes[len], len); |
| | 112 | // Track the last used code, but only for lengths < PREFIX_LUT_BITS |
| | 113 | codes[len] += 1; |
| | 114 | |
| | 115 | var j: usize = 0; |
| | 116 | while (j < @as(usize, 1) << bits_to_fill) : (j += 1) { |
| | 117 | const index = rev_code | (j << @intCast(u5, len)); |
| | 118 | assert(self.prefix_lut_len[index] == 0); |
| | 119 | self.prefix_lut[index] = @truncate(u16, symbol); |
| | 120 | self.prefix_lut_len[index] = @truncate(u16, len); |
| 61 | } | 121 | } |
| 62 | } | 122 | } |
| | 123 | |
| | 124 | self.last_code = codes[PREFIX_LUT_BITS + 1]; |
| | 125 | self.last_index = offset[PREFIX_LUT_BITS + 1] - self.count[PREFIX_LUT_BITS + 1]; |
| 63 | } | 126 | } |
| 64 | }; | 127 | }; |
| 65 | | 128 | |
| | 129 | // Reverse bit-by-bit a N-bit value |
| | 130 | fn bitReverse(x: usize, N: usize) usize { |
| | 131 | var tmp: usize = 0; |
| | 132 | var i: usize = 0; |
| | 133 | while (i < N) : (i += 1) { |
| | 134 | tmp |= ((x >> @intCast(u5, i)) & 1) << @intCast(u5, N - i - 1); |
| | 135 | } |
| | 136 | return tmp; |
| | 137 | } |
| | 138 | |
| 66 | pub fn InflateStream(comptime ReaderType: type) type { | 139 | pub fn InflateStream(comptime ReaderType: type) type { |
| 67 | return struct { | 140 | return struct { |
| 68 | const Self = @This(); | 141 | const Self = @This(); |
| ... | @@ -83,7 +156,7 @@ pub fn InflateStream(comptime ReaderType: type) type { | ... | @@ -83,7 +156,7 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 83 | }; | 156 | }; |
| 84 | pub const Reader = io.Reader(*Self, Error, read); | 157 | pub const Reader = io.Reader(*Self, Error, read); |
| 85 | | 158 | |
| 86 | bit_reader: io.BitReader(.Little, ReaderType), | 159 | inner_reader: ReaderType, |
| 87 | | 160 | |
| 88 | // True if the decoder met the end of the compressed stream, no further | 161 | // True if the decoder met the end of the compressed stream, no further |
| 89 | // data can be decompressed | 162 | // data can be decompressed |
| ... | @@ -135,7 +208,7 @@ pub fn InflateStream(comptime ReaderType: type) type { | ... | @@ -135,7 +208,7 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 135 | | 208 | |
| 136 | // Insert a single byte into the window. | 209 | // Insert a single byte into the window. |
| 137 | // Assumes there's enough space. | 210 | // Assumes there's enough space. |
| 138 | fn appendUnsafe(self: *WSelf, value: u8) void { | 211 | inline fn appendUnsafe(self: *WSelf, value: u8) void { |
| 139 | self.buf[self.wi] = value; | 212 | self.buf[self.wi] = value; |
| 140 | self.wi = (self.wi + 1) & (self.buf.len - 1); | 213 | self.wi = (self.wi + 1) & (self.buf.len - 1); |
| 141 | self.el += 1; | 214 | self.el += 1; |
| ... | @@ -180,7 +253,7 @@ pub fn InflateStream(comptime ReaderType: type) type { | ... | @@ -180,7 +253,7 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 180 | // of the window memory for the non-overlapping case. | 253 | // of the window memory for the non-overlapping case. |
| 181 | var i: usize = 0; | 254 | var i: usize = 0; |
| 182 | while (i < N) : (i += 1) { | 255 | while (i < N) : (i += 1) { |
| 183 | const index = (self.wi -% distance) % self.buf.len; | 256 | const index = (self.wi -% distance) & (self.buf.len - 1); |
| 184 | self.appendUnsafe(self.buf[index]); | 257 | self.appendUnsafe(self.buf[index]); |
| 185 | } | 258 | } |
| 186 | | 259 | |
| ... | @@ -196,13 +269,36 @@ pub fn InflateStream(comptime ReaderType: type) type { | ... | @@ -196,13 +269,36 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 196 | hdist: *Huffman, | 269 | hdist: *Huffman, |
| 197 | hlen: *Huffman, | 270 | hlen: *Huffman, |
| 198 | | 271 | |
| | 272 | // Temporary buffer for the bitstream, only bits 0..`bits_left` are |
| | 273 | // considered valid. |
| | 274 | bits: u32, |
| | 275 | bits_left: usize, |
| | 276 | |
| | 277 | fn peekBits(self: *Self, bits: usize) !u32 { |
| | 278 | while (self.bits_left < bits) { |
| | 279 | const byte = try self.inner_reader.readByte(); |
| | 280 | self.bits |= @as(u32, byte) << @intCast(u5, self.bits_left); |
| | 281 | self.bits_left += 8; |
| | 282 | } |
| | 283 | return self.bits & ((@as(u32, 1) << @intCast(u5, bits)) - 1); |
| | 284 | } |
| | 285 | fn readBits(self: *Self, bits: usize) !u32 { |
| | 286 | const val = self.peekBits(bits); |
| | 287 | self.discardBits(bits); |
| | 288 | return val; |
| | 289 | } |
| | 290 | fn discardBits(self: *Self, bits: usize) void { |
| | 291 | self.bits >>= @intCast(u5, bits); |
| | 292 | self.bits_left -= bits; |
| | 293 | } |
| | 294 | |
| 199 | fn stored(self: *Self) !void { | 295 | fn stored(self: *Self) !void { |
| 200 | // Discard the remaining bits, the lenght field is always | 296 | // Discard the remaining bits, the lenght field is always |
| 201 | // byte-aligned (and so is the data) | 297 | // byte-aligned (and so is the data) |
| 202 | self.bit_reader.alignToByte(); | 298 | self.discardBits(self.bits_left); |
| 203 | | 299 | |
| 204 | const length = (try self.bit_reader.readBitsNoEof(u16, 16)); | 300 | const length = try self.inner_reader.readIntLittle(u16); |
| 205 | const length_cpl = (try self.bit_reader.readBitsNoEof(u16, 16)); | 301 | const length_cpl = try self.inner_reader.readIntLittle(u16); |
| 206 | | 302 | |
| 207 | if (length != ~length_cpl) | 303 | if (length != ~length_cpl) |
| 208 | return error.InvalidStoredSize; | 304 | return error.InvalidStoredSize; |
| ... | @@ -237,11 +333,11 @@ pub fn InflateStream(comptime ReaderType: type) type { | ... | @@ -237,11 +333,11 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 237 | | 333 | |
| 238 | fn dynamic(self: *Self) !void { | 334 | fn dynamic(self: *Self) !void { |
| 239 | // Number of length codes | 335 | // Number of length codes |
| 240 | const nlen = (try self.bit_reader.readBitsNoEof(usize, 5)) + 257; | 336 | const nlen = (try self.readBits(5)) + 257; |
| 241 | // Number of distance codes | 337 | // Number of distance codes |
| 242 | const ndist = (try self.bit_reader.readBitsNoEof(usize, 5)) + 1; | 338 | const ndist = (try self.readBits(5)) + 1; |
| 243 | // Number of code length codes | 339 | // Number of code length codes |
| 244 | const ncode = (try self.bit_reader.readBitsNoEof(usize, 4)) + 4; | 340 | const ncode = (try self.readBits(4)) + 4; |
| 245 | | 341 | |
| 246 | if (nlen > MAXLCODES or ndist > MAXDCODES) | 342 | if (nlen > MAXLCODES or ndist > MAXDCODES) |
| 247 | return error.BadCounts; | 343 | return error.BadCounts; |
| ... | @@ -259,7 +355,7 @@ pub fn InflateStream(comptime ReaderType: type) type { | ... | @@ -259,7 +355,7 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 259 | | 355 | |
| 260 | // Read the code lengths, missing ones are left as zero | 356 | // Read the code lengths, missing ones are left as zero |
| 261 | for (ORDER[0..ncode]) |val| { | 357 | for (ORDER[0..ncode]) |val| { |
| 262 | lengths[val] = try self.bit_reader.readBitsNoEof(u16, 3); | 358 | lengths[val] = @intCast(u16, try self.readBits(3)); |
| 263 | } | 359 | } |
| 264 | | 360 | |
| 265 | try lencode.construct(lengths[0..]); | 361 | try lencode.construct(lengths[0..]); |
| ... | @@ -284,7 +380,7 @@ pub fn InflateStream(comptime ReaderType: type) type { | ... | @@ -284,7 +380,7 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 284 | if (i == 0) return error.NoLastLength; | 380 | if (i == 0) return error.NoLastLength; |
| 285 | | 381 | |
| 286 | const last_length = lengths[i - 1]; | 382 | const last_length = lengths[i - 1]; |
| 287 | const repeat = 3 + (try self.bit_reader.readBitsNoEof(usize, 2)); | 383 | const repeat = 3 + (try self.readBits(2)); |
| 288 | const last_index = i + repeat; | 384 | const last_index = i + repeat; |
| 289 | while (i < last_index) : (i += 1) { | 385 | while (i < last_index) : (i += 1) { |
| 290 | lengths[i] = last_length; | 386 | lengths[i] = last_length; |
| ... | @@ -292,11 +388,11 @@ pub fn InflateStream(comptime ReaderType: type) type { | ... | @@ -292,11 +388,11 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 292 | }, | 388 | }, |
| 293 | 17 => { | 389 | 17 => { |
| 294 | // repeat zero 3..10 times | 390 | // repeat zero 3..10 times |
| 295 | i += 3 + (try self.bit_reader.readBitsNoEof(usize, 3)); | 391 | i += 3 + (try self.readBits(3)); |
| 296 | }, | 392 | }, |
| 297 | 18 => { | 393 | 18 => { |
| 298 | // repeat zero 11..138 times | 394 | // repeat zero 11..138 times |
| 299 | i += 11 + (try self.bit_reader.readBitsNoEof(usize, 7)); | 395 | i += 11 + (try self.readBits(7)); |
| 300 | }, | 396 | }, |
| 301 | else => return error.InvalidSymbol, | 397 | else => return error.InvalidSymbol, |
| 302 | } | 398 | } |
| ... | @@ -359,11 +455,11 @@ pub fn InflateStream(comptime ReaderType: type) type { | ... | @@ -359,11 +455,11 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 359 | // Length/distance pair | 455 | // Length/distance pair |
| 360 | const length_symbol = symbol - 257; | 456 | const length_symbol = symbol - 257; |
| 361 | const length = LENS[length_symbol] + | 457 | const length = LENS[length_symbol] + |
| 362 | try self.bit_reader.readBitsNoEof(u16, LEXT[length_symbol]); | 458 | @intCast(u16, try self.readBits(LEXT[length_symbol])); |
| 363 | | 459 | |
| 364 | const distance_symbol = try self.decode(distcode); | 460 | const distance_symbol = try self.decode(distcode); |
| 365 | const distance = DISTS[distance_symbol] + | 461 | const distance = DISTS[distance_symbol] + |
| 366 | try self.bit_reader.readBitsNoEof(u16, DEXT[distance_symbol]); | 462 | @intCast(u16, try self.readBits(DEXT[distance_symbol])); |
| 367 | | 463 | |
| 368 | if (distance > self.window.buf.len) | 464 | if (distance > self.window.buf.len) |
| 369 | return error.InvalidDistance; | 465 | return error.InvalidDistance; |
| ... | @@ -385,13 +481,29 @@ pub fn InflateStream(comptime ReaderType: type) type { | ... | @@ -385,13 +481,29 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 385 | } | 481 | } |
| 386 | | 482 | |
| 387 | fn decode(self: *Self, h: *Huffman) !u16 { | 483 | fn decode(self: *Self, h: *Huffman) !u16 { |
| 388 | var len: usize = 1; | 484 | // Fast path, read some bits and hope they're prefixes of some code |
| 389 | var code: usize = 0; | 485 | const prefix = try self.peekBits(PREFIX_LUT_BITS); |
| 390 | var first: usize = 0; | 486 | if (h.prefix_lut_len[prefix] != 0) { |
| 391 | var index: usize = 0; | 487 | self.discardBits(h.prefix_lut_len[prefix]); |
| | 488 | return h.prefix_lut[prefix]; |
| | 489 | } |
| | 490 | |
| | 491 | // The sequence we've read is not a prefix of any code of length <= |
| | 492 | // PREFIX_LUT_BITS, keep decoding it using a slower method |
| | 493 | self.discardBits(PREFIX_LUT_BITS); |
| | 494 | |
| | 495 | // Speed up the decoding by starting from the first code length |
| | 496 | // that's not covered by the table |
| | 497 | var len: usize = PREFIX_LUT_BITS + 1; |
| | 498 | var first: usize = h.last_code; |
| | 499 | var index: usize = h.last_index; |
| | 500 | |
| | 501 | // Reverse the prefix so that the LSB becomes the MSB and make space |
| | 502 | // for the next bit |
| | 503 | var code = bitReverse(prefix, PREFIX_LUT_BITS + 1); |
| 392 | | 504 | |
| 393 | while (len <= MAXBITS) : (len += 1) { | 505 | while (len <= MAXBITS) : (len += 1) { |
| 394 | code |= try self.bit_reader.readBitsNoEof(usize, 1); | 506 | code |= try self.readBits(1); |
| 395 | const count = h.count[len]; | 507 | const count = h.count[len]; |
| 396 | if (code < first + count) | 508 | if (code < first + count) |
| 397 | return h.symbol[index + (code - first)]; | 509 | return h.symbol[index + (code - first)]; |
| ... | @@ -411,8 +523,8 @@ pub fn InflateStream(comptime ReaderType: type) type { | ... | @@ -411,8 +523,8 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 411 | // The compressed stream is done | 523 | // The compressed stream is done |
| 412 | if (self.seen_eos) return; | 524 | if (self.seen_eos) return; |
| 413 | | 525 | |
| 414 | const last = try self.bit_reader.readBitsNoEof(u1, 1); | 526 | const last = @intCast(u1, try self.readBits(1)); |
| 415 | const kind = try self.bit_reader.readBitsNoEof(u2, 2); | 527 | const kind = @intCast(u2, try self.readBits(2)); |
| 416 | | 528 | |
| 417 | self.seen_eos = last != 0; | 529 | self.seen_eos = last != 0; |
| 418 | | 530 | |
| ... | @@ -439,7 +551,7 @@ pub fn InflateStream(comptime ReaderType: type) type { | ... | @@ -439,7 +551,7 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 439 | var i: usize = 0; | 551 | var i: usize = 0; |
| 440 | while (i < N) : (i += 1) { | 552 | while (i < N) : (i += 1) { |
| 441 | var tmp: [1]u8 = undefined; | 553 | var tmp: [1]u8 = undefined; |
| 442 | if ((try self.bit_reader.read(&tmp)) != 1) { | 554 | if ((try self.inner_reader.read(&tmp)) != 1) { |
| 443 | // Unexpected end of stream, keep this error | 555 | // Unexpected end of stream, keep this error |
| 444 | // consistent with the use of readBitsNoEof | 556 | // consistent with the use of readBitsNoEof |
| 445 | return error.EndOfStream; | 557 | return error.EndOfStream; |
| ... | @@ -478,12 +590,14 @@ pub fn InflateStream(comptime ReaderType: type) type { | ... | @@ -478,12 +590,14 @@ pub fn InflateStream(comptime ReaderType: type) type { |
| 478 | assert(math.isPowerOfTwo(window_slice.len)); | 590 | assert(math.isPowerOfTwo(window_slice.len)); |
| 479 | | 591 | |
| 480 | return Self{ | 592 | return Self{ |
| 481 | .bit_reader = io.bitReader(.Little, source), | 593 | .inner_reader = source, |
| 482 | .window = .{ .buf = window_slice }, | 594 | .window = .{ .buf = window_slice }, |
| 483 | .seen_eos = false, | 595 | .seen_eos = false, |
| 484 | .state = .DecodeBlockHeader, | 596 | .state = .DecodeBlockHeader, |
| 485 | .hdist = undefined, | 597 | .hdist = undefined, |
| 486 | .hlen = undefined, | 598 | .hlen = undefined, |
| | 599 | .bits = 0, |
| | 600 | .bits_left = 0, |
| 487 | }; | 601 | }; |
| 488 | } | 602 | } |
| 489 | | 603 | |