Skip to content

Commit 7429568

Browse files
authored
Merge pull request #24614 from ziglang/flate
std.compress.flate: rework decompression and delete compression
2 parents dcc3e6e + a6f7927 commit 7429568

File tree

101 files changed

+3745
-7229
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+3745
-7229
lines changed

lib/std/Io.zig

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -438,8 +438,6 @@ pub fn GenericWriter(
438438
pub const AnyReader = @import("Io/DeprecatedReader.zig");
439439
/// Deprecated in favor of `Writer`.
440440
pub const AnyWriter = @import("Io/DeprecatedWriter.zig");
441-
/// Deprecated in favor of `File.Reader` and `File.Writer`.
442-
pub const SeekableStream = @import("Io/seekable_stream.zig").SeekableStream;
443441
/// Deprecated in favor of `Writer`.
444442
pub const BufferedWriter = @import("Io/buffered_writer.zig").BufferedWriter;
445443
/// Deprecated in favor of `Writer`.
@@ -467,12 +465,6 @@ pub const CountingReader = @import("Io/counting_reader.zig").CountingReader;
467465
/// Deprecated with no replacement; inefficient pattern
468466
pub const countingReader = @import("Io/counting_reader.zig").countingReader;
469467

470-
pub const BitReader = @import("Io/bit_reader.zig").BitReader;
471-
pub const bitReader = @import("Io/bit_reader.zig").bitReader;
472-
473-
pub const BitWriter = @import("Io/bit_writer.zig").BitWriter;
474-
pub const bitWriter = @import("Io/bit_writer.zig").bitWriter;
475-
476468
pub const tty = @import("Io/tty.zig");
477469

478470
/// Deprecated in favor of `Writer.Discarding`.
@@ -948,16 +940,12 @@ pub fn PollFiles(comptime StreamEnum: type) type {
948940

949941
test {
950942
_ = Reader;
951-
_ = Reader.Limited;
952943
_ = Writer;
953-
_ = BitReader;
954-
_ = BitWriter;
955944
_ = BufferedReader;
956945
_ = BufferedWriter;
957946
_ = CountingWriter;
958947
_ = CountingReader;
959948
_ = FixedBufferStream;
960-
_ = SeekableStream;
961949
_ = tty;
962950
_ = @import("Io/test.zig");
963951
}

lib/std/Io/Reader.zig

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,18 @@ pub const VTable = struct {
7474
///
7575
/// `data` may not contain an alias to `Reader.buffer`.
7676
///
77+
/// `data` is mutable because the implementation may to temporarily modify
78+
/// the fields in order to handle partial reads. Implementations must
79+
/// restore the original value before returning.
80+
///
7781
/// Implementations may ignore `data`, writing directly to `Reader.buffer`,
7882
/// modifying `seek` and `end` accordingly, and returning 0 from this
7983
/// function. Implementations are encouraged to take advantage of this if
8084
/// it simplifies the logic.
8185
///
8286
/// The default implementation calls `stream` with either `data[0]` or
8387
/// `Reader.buffer`, whichever is bigger.
84-
readVec: *const fn (r: *Reader, data: []const []u8) Error!usize = defaultReadVec,
88+
readVec: *const fn (r: *Reader, data: [][]u8) Error!usize = defaultReadVec,
8589

8690
/// Ensures `capacity` more data can be buffered without rebasing.
8791
///
@@ -262,8 +266,7 @@ pub fn streamRemaining(r: *Reader, w: *Writer) StreamRemainingError!usize {
262266
/// number of bytes discarded.
263267
pub fn discardRemaining(r: *Reader) ShortError!usize {
264268
var offset: usize = r.end - r.seek;
265-
r.seek = 0;
266-
r.end = 0;
269+
r.seek = r.end;
267270
while (true) {
268271
offset += r.vtable.discard(r, .unlimited) catch |err| switch (err) {
269272
error.EndOfStream => return offset,
@@ -417,7 +420,7 @@ pub fn readVec(r: *Reader, data: [][]u8) Error!usize {
417420
}
418421

419422
/// Writes to `Reader.buffer` or `data`, whichever has larger capacity.
420-
pub fn defaultReadVec(r: *Reader, data: []const []u8) Error!usize {
423+
pub fn defaultReadVec(r: *Reader, data: [][]u8) Error!usize {
421424
assert(r.seek == r.end);
422425
r.seek = 0;
423426
r.end = 0;
@@ -438,23 +441,6 @@ pub fn defaultReadVec(r: *Reader, data: []const []u8) Error!usize {
438441
return 0;
439442
}
440443

441-
/// Always writes to `Reader.buffer` and returns 0.
442-
pub fn indirectReadVec(r: *Reader, data: []const []u8) Error!usize {
443-
_ = data;
444-
assert(r.seek == r.end);
445-
var writer: Writer = .{
446-
.buffer = r.buffer,
447-
.end = r.end,
448-
.vtable = &.{ .drain = Writer.fixedDrain },
449-
};
450-
const limit: Limit = .limited(writer.buffer.len - writer.end);
451-
r.end += r.vtable.stream(r, &writer, limit) catch |err| switch (err) {
452-
error.WriteFailed => unreachable,
453-
else => |e| return e,
454-
};
455-
return 0;
456-
}
457-
458444
pub fn buffered(r: *Reader) []u8 {
459445
return r.buffer[r.seek..r.end];
460446
}
@@ -463,8 +449,8 @@ pub fn bufferedLen(r: *const Reader) usize {
463449
return r.end - r.seek;
464450
}
465451

466-
pub fn hashed(r: *Reader, hasher: anytype) Hashed(@TypeOf(hasher)) {
467-
return .{ .in = r, .hasher = hasher };
452+
pub fn hashed(r: *Reader, hasher: anytype, buffer: []u8) Hashed(@TypeOf(hasher)) {
453+
return .init(r, hasher, buffer);
468454
}
469455

470456
pub fn readVecAll(r: *Reader, data: [][]u8) Error!void {
@@ -539,8 +525,7 @@ pub fn toss(r: *Reader, n: usize) void {
539525

540526
/// Equivalent to `toss(r.bufferedLen())`.
541527
pub fn tossBuffered(r: *Reader) void {
542-
r.seek = 0;
543-
r.end = 0;
528+
r.seek = r.end;
544529
}
545530

546531
/// Equivalent to `peek` followed by `toss`.
@@ -627,8 +612,7 @@ pub fn discardShort(r: *Reader, n: usize) ShortError!usize {
627612
return n;
628613
}
629614
var remaining = n - (r.end - r.seek);
630-
r.end = 0;
631-
r.seek = 0;
615+
r.seek = r.end;
632616
while (true) {
633617
const discard_len = r.vtable.discard(r, .limited(remaining)) catch |err| switch (err) {
634618
error.EndOfStream => return n - remaining,
@@ -1678,7 +1662,7 @@ fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
16781662
return error.EndOfStream;
16791663
}
16801664

1681-
fn endingReadVec(r: *Reader, data: []const []u8) Error!usize {
1665+
fn endingReadVec(r: *Reader, data: [][]u8) Error!usize {
16821666
_ = r;
16831667
_ = data;
16841668
return error.EndOfStream;
@@ -1709,6 +1693,15 @@ fn failingDiscard(r: *Reader, limit: Limit) Error!usize {
17091693
return error.ReadFailed;
17101694
}
17111695

1696+
pub fn adaptToOldInterface(r: *Reader) std.Io.AnyReader {
1697+
return .{ .context = r, .readFn = derpRead };
1698+
}
1699+
1700+
fn derpRead(context: *const anyopaque, buffer: []u8) anyerror!usize {
1701+
const r: *Reader = @constCast(@alignCast(@ptrCast(context)));
1702+
return r.readSliceShort(buffer);
1703+
}
1704+
17121705
test "readAlloc when the backing reader provides one byte at a time" {
17131706
const str = "This is a test";
17141707
var tiny_buffer: [1]u8 = undefined;
@@ -1772,15 +1765,16 @@ pub fn Hashed(comptime Hasher: type) type {
17721765
return struct {
17731766
in: *Reader,
17741767
hasher: Hasher,
1775-
interface: Reader,
1768+
reader: Reader,
17761769

17771770
pub fn init(in: *Reader, hasher: Hasher, buffer: []u8) @This() {
17781771
return .{
17791772
.in = in,
17801773
.hasher = hasher,
1781-
.interface = .{
1774+
.reader = .{
17821775
.vtable = &.{
1783-
.read = @This().read,
1776+
.stream = @This().stream,
1777+
.readVec = @This().readVec,
17841778
.discard = @This().discard,
17851779
},
17861780
.buffer = buffer,
@@ -1790,33 +1784,39 @@ pub fn Hashed(comptime Hasher: type) type {
17901784
};
17911785
}
17921786

1793-
fn read(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1794-
const this: *@This() = @alignCast(@fieldParentPtr("interface", r));
1795-
const data = w.writableVector(limit);
1787+
fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1788+
const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
1789+
const data = limit.slice(try w.writableSliceGreedy(1));
1790+
var vec: [1][]u8 = .{data};
1791+
const n = try this.in.readVec(&vec);
1792+
this.hasher.update(data[0..n]);
1793+
w.advance(n);
1794+
return n;
1795+
}
1796+
1797+
fn readVec(r: *Reader, data: [][]u8) Error!usize {
1798+
const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
17961799
const n = try this.in.readVec(data);
1797-
const result = w.advanceVector(n);
17981800
var remaining: usize = n;
17991801
for (data) |slice| {
18001802
if (remaining < slice.len) {
18011803
this.hasher.update(slice[0..remaining]);
1802-
return result;
1804+
return n;
18031805
} else {
18041806
remaining -= slice.len;
18051807
this.hasher.update(slice);
18061808
}
18071809
}
18081810
assert(remaining == 0);
1809-
return result;
1811+
return n;
18101812
}
18111813

18121814
fn discard(r: *Reader, limit: Limit) Error!usize {
1813-
const this: *@This() = @alignCast(@fieldParentPtr("interface", r));
1814-
var w = this.hasher.writer(&.{});
1815-
const n = this.in.stream(&w, limit) catch |err| switch (err) {
1816-
error.WriteFailed => unreachable,
1817-
else => |e| return e,
1818-
};
1819-
return n;
1815+
const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
1816+
const peeked = limit.slice(try this.in.peekGreedy(1));
1817+
this.hasher.update(peeked);
1818+
this.in.toss(peeked.len);
1819+
return peeked.len;
18201820
}
18211821
};
18221822
}
@@ -1874,3 +1874,7 @@ pub fn writableVectorWsa(
18741874
}
18751875
return .{ i, n };
18761876
}
1877+
1878+
test {
1879+
_ = Limited;
1880+
}

lib/std/Io/Writer.zig

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,7 +2266,7 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
22662266
const pattern = data[data.len - 1];
22672267
const dest = w.buffer[w.end..];
22682268
switch (pattern.len) {
2269-
0 => return w.end,
2269+
0 => return 0,
22702270
1 => {
22712271
assert(splat >= dest.len);
22722272
@memset(dest, pattern[0]);
@@ -2286,6 +2286,13 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
22862286
}
22872287
}
22882288

2289+
pub fn unreachableDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
2290+
_ = w;
2291+
_ = data;
2292+
_ = splat;
2293+
unreachable;
2294+
}
2295+
22892296
/// Provides a `Writer` implementation based on calling `Hasher.update`, sending
22902297
/// all data also to an underlying `Writer`.
22912298
///
@@ -2296,6 +2303,8 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
22962303
/// generic. A better solution will involve creating a writer for each hash
22972304
/// function, where the splat buffer can be tailored to the hash implementation
22982305
/// details.
2306+
///
2307+
/// Contrast with `Hashing` which terminates the stream pipeline.
22992308
pub fn Hashed(comptime Hasher: type) type {
23002309
return struct {
23012310
out: *Writer,
@@ -2341,7 +2350,7 @@ pub fn Hashed(comptime Hasher: type) type {
23412350
this.hasher.update(slice);
23422351
}
23432352
const pattern = data[data.len - 1];
2344-
assert(remaining == splat * pattern.len);
2353+
assert(remaining <= splat * pattern.len);
23452354
switch (pattern.len) {
23462355
0 => {
23472356
assert(remaining == 0);
@@ -2368,6 +2377,52 @@ pub fn Hashed(comptime Hasher: type) type {
23682377
};
23692378
}
23702379

2380+
/// Provides a `Writer` implementation based on calling `Hasher.update`,
2381+
/// discarding all data.
2382+
///
2383+
/// This implementation makes suboptimal buffering decisions due to being
2384+
/// generic. A better solution will involve creating a writer for each hash
2385+
/// function, where the splat buffer can be tailored to the hash implementation
2386+
/// details.
2387+
///
2388+
/// The total number of bytes written is stored in `hasher`.
2389+
///
2390+
/// Contrast with `Hashed` which also passes the data to an underlying stream.
2391+
pub fn Hashing(comptime Hasher: type) type {
2392+
return struct {
2393+
hasher: Hasher,
2394+
writer: Writer,
2395+
2396+
pub fn init(buffer: []u8) @This() {
2397+
return .initHasher(.init(.{}), buffer);
2398+
}
2399+
2400+
pub fn initHasher(hasher: Hasher, buffer: []u8) @This() {
2401+
return .{
2402+
.hasher = hasher,
2403+
.writer = .{
2404+
.buffer = buffer,
2405+
.vtable = &.{ .drain = @This().drain },
2406+
},
2407+
};
2408+
}
2409+
2410+
fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
2411+
const this: *@This() = @alignCast(@fieldParentPtr("writer", w));
2412+
const hasher = &this.hasher;
2413+
hasher.update(w.buffered());
2414+
w.end = 0;
2415+
var n: usize = 0;
2416+
for (data[0 .. data.len - 1]) |slice| {
2417+
hasher.update(slice);
2418+
n += slice.len;
2419+
}
2420+
for (0..splat) |_| hasher.update(data[data.len - 1]);
2421+
return n + splat * data[data.len - 1].len;
2422+
}
2423+
};
2424+
}
2425+
23712426
/// Maintains `Writer` state such that it writes to the unused capacity of an
23722427
/// array list, filling it up completely before making a call through the
23732428
/// vtable, causing a resize. Consequently, the same, optimized, non-generic

0 commit comments

Comments
 (0)