@@ -37,6 +37,8 @@ const State = union(enum) {
37
37
stored_block : u16 ,
38
38
fixed_block ,
39
39
dynamic_block ,
40
+ dynamic_block_literal : u8 ,
41
+ dynamic_block_match : u16 ,
40
42
protocol_footer ,
41
43
end ,
42
44
};
@@ -63,7 +65,7 @@ const direct_vtable: Reader.VTable = .{
63
65
const indirect_vtable : Reader.VTable = .{
64
66
.stream = streamIndirect ,
65
67
.rebase = rebaseFallible ,
66
- .discard = discard ,
68
+ .discard = discardIndirect ,
67
69
.readVec = readVec ,
68
70
};
69
71
@@ -128,6 +130,26 @@ fn discard(r: *Reader, limit: std.Io.Limit) Reader.Error!usize {
128
130
return n ;
129
131
}
130
132
133
+ fn discardIndirect (r : * Reader , limit : std.Io.Limit ) Reader.Error ! usize {
134
+ const d : * Decompress = @alignCast (@fieldParentPtr ("reader" , r ));
135
+ if (r .end + flate .history_len > r .buffer .len ) rebase (r , flate .history_len );
136
+ var writer : Writer = .{
137
+ .buffer = r .buffer ,
138
+ .end = r .end ,
139
+ .vtable = &.{ .drain = Writer .unreachableDrain },
140
+ };
141
+ {
142
+ defer r .end = writer .end ;
143
+ _ = streamFallible (d , & writer , .limited (writer .buffer .len - writer .end )) catch | err | switch (err ) {
144
+ error .WriteFailed = > unreachable ,
145
+ else = > | e | return e ,
146
+ };
147
+ }
148
+ const n = limit .minInt (r .end - r .seek );
149
+ r .seek += n ;
150
+ return n ;
151
+ }
152
+
131
153
fn readVec (r : * Reader , data : [][]u8 ) Reader.Error ! usize {
132
154
_ = data ;
133
155
const d : * Decompress = @alignCast (@fieldParentPtr ("reader" , r ));
@@ -140,7 +162,7 @@ fn streamIndirectInner(d: *Decompress) Reader.Error!usize {
140
162
var writer : Writer = .{
141
163
.buffer = r .buffer ,
142
164
.end = r .end ,
143
- .vtable = &.{ .drain = Writer .fixedDrain },
165
+ .vtable = &.{ .drain = Writer .unreachableDrain },
144
166
};
145
167
defer r .end = writer .end ;
146
168
_ = streamFallible (d , & writer , .limited (writer .buffer .len - writer .end )) catch | err | switch (err ) {
@@ -379,30 +401,49 @@ fn streamInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader
379
401
.dynamic_block = > {
380
402
// In larger archives most blocks are usually dynamic, so
381
403
// decompression performance depends on this logic.
382
- while (remaining > 0 ) {
383
- const sym = try d .decodeSymbol (& d .lit_dec );
384
-
385
- switch (sym .kind ) {
386
- .literal = > {
387
- try w .writeBytePreserve (flate .history_len , sym .symbol );
404
+ var sym = try d .decodeSymbol (& d .lit_dec );
405
+ sym : switch (sym .kind ) {
406
+ .literal = > {
407
+ if (remaining != 0 ) {
408
+ @branchHint (.likely );
388
409
remaining -= 1 ;
389
- },
390
- .match = > {
391
- // Decode match backreference <length, distance>
392
- const length = try d .decodeLength (sym .symbol );
393
- const dsm = try d .decodeSymbol (& d .dst_dec );
394
- const distance = try d .decodeDistance (dsm .symbol );
395
- try writeMatch (w , length , distance );
396
- remaining -= length ;
397
- },
398
- .end_of_block = > {
399
- d .state = if (d .final_block ) .protocol_footer else .block_header ;
410
+ try w .writeBytePreserve (flate .history_len , sym .symbol );
411
+ sym = try d .decodeSymbol (& d .lit_dec );
412
+ continue :sym sym .kind ;
413
+ } else {
414
+ d .state = .{ .dynamic_block_literal = sym .symbol };
400
415
return @intFromEnum (limit ) - remaining ;
401
- },
402
- }
416
+ }
417
+ },
418
+ .match = > {
419
+ // Decode match backreference <length, distance>
420
+ const length = try d .decodeLength (sym .symbol );
421
+ continue :sw .{ .dynamic_block_match = length };
422
+ },
423
+ .end_of_block = > {
424
+ d .state = if (d .final_block ) .protocol_footer else .block_header ;
425
+ continue :sw d .state ;
426
+ },
427
+ }
428
+ },
429
+ .dynamic_block_literal = > | symbol | {
430
+ assert (remaining != 0 );
431
+ remaining -= 1 ;
432
+ try w .writeBytePreserve (flate .history_len , symbol );
433
+ continue :sw .dynamic_block ;
434
+ },
435
+ .dynamic_block_match = > | length | {
436
+ if (remaining >= length ) {
437
+ @branchHint (.likely );
438
+ remaining -= length ;
439
+ const dsm = try d .decodeSymbol (& d .dst_dec );
440
+ const distance = try d .decodeDistance (dsm .symbol );
441
+ try writeMatch (w , length , distance );
442
+ continue :sw .dynamic_block ;
443
+ } else {
444
+ d .state = .{ .dynamic_block_match = length };
445
+ return @intFromEnum (limit ) - remaining ;
403
446
}
404
- d .state = .dynamic_block ;
405
- return @intFromEnum (limit ) - remaining ;
406
447
},
407
448
.protocol_footer = > {
408
449
switch (d .container_metadata ) {
@@ -424,7 +465,7 @@ fn streamInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader
424
465
},
425
466
}
426
467
d .state = .end ;
427
- return 0 ;
468
+ return @intFromEnum ( limit ) - remaining ;
428
469
},
429
470
.end = > return error .EndOfStream ,
430
471
}
0 commit comments