Skip to content

Commit 66e49d9

Browse files
authored
Merge pull request #24559 from ziglang/zstd
std: rework zstd for new I/O API
2 parents 9e11727 + 733b208 commit 66e49d9

File tree

20 files changed

+2188
-3072
lines changed

20 files changed

+2188
-3072
lines changed

lib/std/Io/DeprecatedReader.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,11 +373,11 @@ pub fn discard(self: Self) anyerror!u64 {
373373
}
374374

375375
/// Helper for bridging to the new `Reader` API while upgrading.
376-
pub fn adaptToNewApi(self: *const Self) Adapter {
376+
pub fn adaptToNewApi(self: *const Self, buffer: []u8) Adapter {
377377
return .{
378378
.derp_reader = self.*,
379379
.new_interface = .{
380-
.buffer = &.{},
380+
.buffer = buffer,
381381
.vtable = &.{ .stream = Adapter.stream },
382382
.seek = 0,
383383
.end = 0,

lib/std/Io/Reader.zig

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,32 @@ pub fn streamExact64(r: *Reader, w: *Writer, n: u64) StreamError!void {
185185
while (remaining != 0) remaining -= try r.stream(w, .limited64(remaining));
186186
}
187187

188+
/// "Pump" exactly `n` bytes from the reader to the writer.
189+
///
190+
/// When draining `w`, ensures that at least `preserve_len` bytes remain
191+
/// buffered.
192+
///
193+
/// Asserts `Writer.buffer` capacity exceeds `preserve_len`.
194+
pub fn streamExactPreserve(r: *Reader, w: *Writer, preserve_len: usize, n: usize) StreamError!void {
195+
if (w.end + n <= w.buffer.len) {
196+
@branchHint(.likely);
197+
return streamExact(r, w, n);
198+
}
199+
// If `n` is large, we can ignore `preserve_len` up to a point.
200+
var remaining = n;
201+
while (remaining > preserve_len) {
202+
assert(remaining != 0);
203+
remaining -= try r.stream(w, .limited(remaining - preserve_len));
204+
if (w.end + remaining <= w.buffer.len) return streamExact(r, w, remaining);
205+
}
206+
// All the next bytes received must be preserved.
207+
if (preserve_len < w.end) {
208+
@memmove(w.buffer[0..preserve_len], w.buffer[w.end - preserve_len ..][0..preserve_len]);
209+
w.end = preserve_len;
210+
}
211+
return streamExact(r, w, remaining);
212+
}
213+
188214
/// "Pump" data from the reader to the writer, handling `error.EndOfStream` as
189215
/// a success case.
190216
///
@@ -240,7 +266,7 @@ pub fn allocRemaining(r: *Reader, gpa: Allocator, limit: Limit) LimitedAllocErro
240266
/// such case, the next byte that would be read will be the first one to exceed
241267
/// `limit`, and all preceeding bytes have been appended to `list`.
242268
///
243-
/// Asserts `buffer` has nonzero capacity.
269+
/// If `limit` is not `Limit.unlimited`, asserts `buffer` has nonzero capacity.
244270
///
245271
/// See also:
246272
/// * `allocRemaining`
@@ -251,7 +277,7 @@ pub fn appendRemaining(
251277
list: *std.ArrayListAlignedUnmanaged(u8, alignment),
252278
limit: Limit,
253279
) LimitedAllocError!void {
254-
assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data.
280+
if (limit != .unlimited) assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data.
255281
const buffer_contents = r.buffer[r.seek..r.end];
256282
const copy_len = limit.minInt(buffer_contents.len);
257283
try list.appendSlice(gpa, r.buffer[0..copy_len]);

lib/std/Io/Writer.zig

Lines changed: 70 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -256,10 +256,10 @@ test "fixed buffer flush" {
256256
try testing.expectEqual(10, buffer[0]);
257257
}
258258

259-
/// Calls `VTable.drain` but hides the last `preserve_length` bytes from the
259+
/// Calls `VTable.drain` but hides the last `preserve_len` bytes from the
260260
/// implementation, keeping them buffered.
261-
pub fn drainPreserve(w: *Writer, preserve_length: usize) Error!void {
262-
const temp_end = w.end -| preserve_length;
261+
pub fn drainPreserve(w: *Writer, preserve_len: usize) Error!void {
262+
const temp_end = w.end -| preserve_len;
263263
const preserved = w.buffer[temp_end..w.end];
264264
w.end = temp_end;
265265
defer w.end += preserved.len;
@@ -310,24 +310,38 @@ pub fn writableSliceGreedy(w: *Writer, minimum_length: usize) Error![]u8 {
310310
}
311311

312312
/// Asserts the provided buffer has total capacity enough for `minimum_length`
313-
/// and `preserve_length` combined.
313+
/// and `preserve_len` combined.
314314
///
315315
/// Does not `advance` the buffer end position.
316316
///
317-
/// When draining the buffer, ensures that at least `preserve_length` bytes
317+
/// When draining the buffer, ensures that at least `preserve_len` bytes
318318
/// remain buffered.
319319
///
320-
/// If `preserve_length` is zero, this is equivalent to `writableSliceGreedy`.
321-
pub fn writableSliceGreedyPreserve(w: *Writer, preserve_length: usize, minimum_length: usize) Error![]u8 {
322-
assert(w.buffer.len >= preserve_length + minimum_length);
320+
/// If `preserve_len` is zero, this is equivalent to `writableSliceGreedy`.
321+
pub fn writableSliceGreedyPreserve(w: *Writer, preserve_len: usize, minimum_length: usize) Error![]u8 {
322+
assert(w.buffer.len >= preserve_len + minimum_length);
323323
while (w.buffer.len - w.end < minimum_length) {
324-
try drainPreserve(w, preserve_length);
324+
try drainPreserve(w, preserve_len);
325325
} else {
326326
@branchHint(.likely);
327327
return w.buffer[w.end..];
328328
}
329329
}
330330

331+
/// Asserts the provided buffer has total capacity enough for `len`.
332+
///
333+
/// Advances the buffer end position by `len`.
334+
///
335+
/// When draining the buffer, ensures that at least `preserve_len` bytes
336+
/// remain buffered.
337+
///
338+
/// If `preserve_len` is zero, this is equivalent to `writableSlice`.
339+
pub fn writableSlicePreserve(w: *Writer, preserve_len: usize, len: usize) Error![]u8 {
340+
const big_slice = try w.writableSliceGreedyPreserve(preserve_len, len);
341+
advance(w, len);
342+
return big_slice[0..len];
343+
}
344+
331345
pub const WritableVectorIterator = struct {
332346
first: []u8,
333347
middle: []const []u8 = &.{},
@@ -523,16 +537,16 @@ pub fn write(w: *Writer, bytes: []const u8) Error!usize {
523537
return w.vtable.drain(w, &.{bytes}, 1);
524538
}
525539

526-
/// Asserts `buffer` capacity exceeds `preserve_length`.
527-
pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Error!usize {
528-
assert(preserve_length <= w.buffer.len);
540+
/// Asserts `buffer` capacity exceeds `preserve_len`.
541+
pub fn writePreserve(w: *Writer, preserve_len: usize, bytes: []const u8) Error!usize {
542+
assert(preserve_len <= w.buffer.len);
529543
if (w.end + bytes.len <= w.buffer.len) {
530544
@branchHint(.likely);
531545
@memcpy(w.buffer[w.end..][0..bytes.len], bytes);
532546
w.end += bytes.len;
533547
return bytes.len;
534548
}
535-
const temp_end = w.end -| preserve_length;
549+
const temp_end = w.end -| preserve_len;
536550
const preserved = w.buffer[temp_end..w.end];
537551
w.end = temp_end;
538552
defer w.end += preserved.len;
@@ -552,13 +566,13 @@ pub fn writeAll(w: *Writer, bytes: []const u8) Error!void {
552566
/// Calls `drain` as many times as necessary such that all of `bytes` are
553567
/// transferred.
554568
///
555-
/// When draining the buffer, ensures that at least `preserve_length` bytes
569+
/// When draining the buffer, ensures that at least `preserve_len` bytes
556570
/// remain buffered.
557571
///
558-
/// Asserts `buffer` capacity exceeds `preserve_length`.
559-
pub fn writeAllPreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Error!void {
572+
/// Asserts `buffer` capacity exceeds `preserve_len`.
573+
pub fn writeAllPreserve(w: *Writer, preserve_len: usize, bytes: []const u8) Error!void {
560574
var index: usize = 0;
561-
while (index < bytes.len) index += try w.writePreserve(preserve_length, bytes[index..]);
575+
while (index < bytes.len) index += try w.writePreserve(preserve_len, bytes[index..]);
562576
}
563577

564578
/// Renders fmt string with args, calling `writer` with slices of bytes.
@@ -761,11 +775,11 @@ pub fn writeByte(w: *Writer, byte: u8) Error!void {
761775
}
762776
}
763777

764-
/// When draining the buffer, ensures that at least `preserve_length` bytes
778+
/// When draining the buffer, ensures that at least `preserve_len` bytes
765779
/// remain buffered.
766-
pub fn writeBytePreserve(w: *Writer, preserve_length: usize, byte: u8) Error!void {
780+
pub fn writeBytePreserve(w: *Writer, preserve_len: usize, byte: u8) Error!void {
767781
while (w.buffer.len - w.end == 0) {
768-
try drainPreserve(w, preserve_length);
782+
try drainPreserve(w, preserve_len);
769783
} else {
770784
@branchHint(.likely);
771785
w.buffer[w.end] = byte;
@@ -788,10 +802,42 @@ test splatByteAll {
788802
try testing.expectEqualStrings("7" ** 45, aw.writer.buffered());
789803
}
790804

805+
pub fn splatBytePreserve(w: *Writer, preserve_len: usize, byte: u8, n: usize) Error!void {
806+
const new_end = w.end + n;
807+
if (new_end <= w.buffer.len) {
808+
@memset(w.buffer[w.end..][0..n], byte);
809+
w.end = new_end;
810+
return;
811+
}
812+
// If `n` is large, we can ignore `preserve_len` up to a point.
813+
var remaining = n;
814+
while (remaining > preserve_len) {
815+
assert(remaining != 0);
816+
remaining -= try splatByte(w, byte, remaining - preserve_len);
817+
if (w.end + remaining <= w.buffer.len) {
818+
@memset(w.buffer[w.end..][0..remaining], byte);
819+
w.end += remaining;
820+
return;
821+
}
822+
}
823+
// All the next bytes received must be preserved.
824+
if (preserve_len < w.end) {
825+
@memmove(w.buffer[0..preserve_len], w.buffer[w.end - preserve_len ..][0..preserve_len]);
826+
w.end = preserve_len;
827+
}
828+
while (remaining > 0) remaining -= try w.splatByte(byte, remaining);
829+
}
830+
791831
/// Writes the same byte many times, allowing short writes.
792832
///
793833
/// Does maximum of one underlying `VTable.drain`.
794834
pub fn splatByte(w: *Writer, byte: u8, n: usize) Error!usize {
835+
if (w.end + n <= w.buffer.len) {
836+
@branchHint(.likely);
837+
@memset(w.buffer[w.end..][0..n], byte);
838+
w.end += n;
839+
return n;
840+
}
795841
return writeSplat(w, &.{&.{byte}}, n);
796842
}
797843

@@ -801,9 +847,10 @@ pub fn splatBytesAll(w: *Writer, bytes: []const u8, splat: usize) Error!void {
801847
var remaining_bytes: usize = bytes.len * splat;
802848
remaining_bytes -= try w.splatBytes(bytes, splat);
803849
while (remaining_bytes > 0) {
804-
const leftover = remaining_bytes % bytes.len;
805-
const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover ..], bytes };
806-
remaining_bytes -= try w.writeSplat(&buffers, splat);
850+
const leftover_splat = remaining_bytes / bytes.len;
851+
const leftover_bytes = remaining_bytes % bytes.len;
852+
const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover_bytes ..], bytes };
853+
remaining_bytes -= try w.writeSplat(&buffers, leftover_splat);
807854
}
808855
}
809856

lib/std/compress.zig

Lines changed: 2 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,19 @@
11
//! Compression algorithms.
22

3-
const std = @import("std.zig");
4-
53
pub const flate = @import("compress/flate.zig");
64
pub const gzip = @import("compress/gzip.zig");
75
pub const zlib = @import("compress/zlib.zig");
86
pub const lzma = @import("compress/lzma.zig");
97
pub const lzma2 = @import("compress/lzma2.zig");
108
pub const xz = @import("compress/xz.zig");
11-
pub const zstd = @import("compress/zstandard.zig");
12-
13-
pub fn HashedReader(ReaderType: type, HasherType: type) type {
14-
return struct {
15-
child_reader: ReaderType,
16-
hasher: HasherType,
17-
18-
pub const Error = ReaderType.Error;
19-
pub const Reader = std.io.GenericReader(*@This(), Error, read);
20-
21-
pub fn read(self: *@This(), buf: []u8) Error!usize {
22-
const amt = try self.child_reader.read(buf);
23-
self.hasher.update(buf[0..amt]);
24-
return amt;
25-
}
26-
27-
pub fn reader(self: *@This()) Reader {
28-
return .{ .context = self };
29-
}
30-
};
31-
}
32-
33-
pub fn hashedReader(
34-
reader: anytype,
35-
hasher: anytype,
36-
) HashedReader(@TypeOf(reader), @TypeOf(hasher)) {
37-
return .{ .child_reader = reader, .hasher = hasher };
38-
}
39-
40-
pub fn HashedWriter(WriterType: type, HasherType: type) type {
41-
return struct {
42-
child_writer: WriterType,
43-
hasher: HasherType,
44-
45-
pub const Error = WriterType.Error;
46-
pub const Writer = std.io.GenericWriter(*@This(), Error, write);
47-
48-
pub fn write(self: *@This(), buf: []const u8) Error!usize {
49-
const amt = try self.child_writer.write(buf);
50-
self.hasher.update(buf[0..amt]);
51-
return amt;
52-
}
53-
54-
pub fn writer(self: *@This()) Writer {
55-
return .{ .context = self };
56-
}
57-
};
58-
}
59-
60-
pub fn hashedWriter(
61-
writer: anytype,
62-
hasher: anytype,
63-
) HashedWriter(@TypeOf(writer), @TypeOf(hasher)) {
64-
return .{ .child_writer = writer, .hasher = hasher };
65-
}
9+
pub const zstd = @import("compress/zstd.zig");
6610

6711
test {
12+
_ = flate;
6813
_ = lzma;
6914
_ = lzma2;
7015
_ = xz;
7116
_ = zstd;
72-
_ = flate;
7317
_ = gzip;
7418
_ = zlib;
7519
}

lib/std/compress/xz.zig

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub fn Decompress(comptime ReaderType: type) type {
4747

4848
var check: Check = undefined;
4949
const hash_a = blk: {
50-
var hasher = std.compress.hashedReader(source, Crc32.init());
50+
var hasher = hashedReader(source, Crc32.init());
5151
try readStreamFlags(hasher.reader(), &check);
5252
break :blk hasher.hasher.final();
5353
};
@@ -80,7 +80,7 @@ pub fn Decompress(comptime ReaderType: type) type {
8080
return r;
8181

8282
const index_size = blk: {
83-
var hasher = std.compress.hashedReader(self.in_reader, Crc32.init());
83+
var hasher = hashedReader(self.in_reader, Crc32.init());
8484
hasher.hasher.update(&[1]u8{0x00});
8585

8686
var counter = std.io.countingReader(hasher.reader());
@@ -115,7 +115,7 @@ pub fn Decompress(comptime ReaderType: type) type {
115115
const hash_a = try self.in_reader.readInt(u32, .little);
116116

117117
const hash_b = blk: {
118-
var hasher = std.compress.hashedReader(self.in_reader, Crc32.init());
118+
var hasher = hashedReader(self.in_reader, Crc32.init());
119119
const hashed_reader = hasher.reader();
120120

121121
const backward_size = (@as(u64, try hashed_reader.readInt(u32, .little)) + 1) * 4;
@@ -140,6 +140,33 @@ pub fn Decompress(comptime ReaderType: type) type {
140140
};
141141
}
142142

143+
pub fn HashedReader(ReaderType: type, HasherType: type) type {
144+
return struct {
145+
child_reader: ReaderType,
146+
hasher: HasherType,
147+
148+
pub const Error = ReaderType.Error;
149+
pub const Reader = std.io.GenericReader(*@This(), Error, read);
150+
151+
pub fn read(self: *@This(), buf: []u8) Error!usize {
152+
const amt = try self.child_reader.read(buf);
153+
self.hasher.update(buf[0..amt]);
154+
return amt;
155+
}
156+
157+
pub fn reader(self: *@This()) Reader {
158+
return .{ .context = self };
159+
}
160+
};
161+
}
162+
163+
pub fn hashedReader(
164+
reader: anytype,
165+
hasher: anytype,
166+
) HashedReader(@TypeOf(reader), @TypeOf(hasher)) {
167+
return .{ .child_reader = reader, .hasher = hasher };
168+
}
169+
143170
test {
144171
_ = @import("xz/test.zig");
145172
}

lib/std/compress/xz/block.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ pub fn Decoder(comptime ReaderType: type) type {
9191

9292
// Block Header
9393
{
94-
var header_hasher = std.compress.hashedReader(block_reader, Crc32.init());
94+
var header_hasher = xz.hashedReader(block_reader, Crc32.init());
9595
const header_reader = header_hasher.reader();
9696

9797
const header_size = @as(u64, try header_reader.readByte()) * 4;

0 commit comments

Comments
 (0)