authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-04-18 19:50:04-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:27-07:00
logcdd05df532511be471adb2006d89175335c0b980
tree11db4d94d72d24afaaab1a6d443c98e18b3f5147
parent00afaa4b1822e9d2c096830e546e96ab4e87f25b

std.io.BufferedReader: don't use a BufferedWriter field

this is way better with readVec and the ability to call `std.io.Reader.buffered`.

7 files changed, 70 insertions(+), 110 deletions(-)

lib/compiler/std-docs.zig+1-2
......@@ -92,10 +92,9 @@ fn accept(context: *Context, connection: std.net.Server.Connection) void {
9292
9393 var recv_buffer: [8000]u8 = undefined;
9494 var send_buffer: [4000]u8 = undefined;
95 var connection_br: std.io.BufferedReader = undefined;
9695 var stream_reader = connection.stream.reader();
97 connection_br.init(stream_reader.interface(), &recv_buffer);
9896 var stream_writer = connection.stream.writer();
97 var connection_br = stream_reader.interface().buffered(&recv_buffer);
9998 var connection_bw = stream_writer.interface().buffered(&send_buffer);
10099 var server = std.http.Server.init(&connection_br, &connection_bw);
101100
lib/compiler/test_runner.zig+1-2
......@@ -71,8 +71,7 @@ fn mainServer() !void {
7171 @disableInstrumentation();
7272 var stdin_reader = std.fs.File.stdin().reader();
7373 var stdout_writer = std.fs.File.stdout().writer();
74 var stdin_buffered_reader: std.io.BufferedReader = undefined;
75 stdin_buffered_reader.init(stdin_reader.interface(), &stdin_buffer);
74 var stdin_buffered_reader = stdin_reader.interface().buffered(&stdin_buffer);
7675 var stdout_buffered_writer = stdout_writer.interface().buffered(&stdout_buffer);
7776 var server = try std.zig.Server.init(.{
7877 .in = &stdin_buffered_reader,
lib/std/debug/SelfInfo.zig+1-1
......@@ -2031,7 +2031,7 @@ pub const VirtualMachine = struct {
20312031
20322032 var prev_row: Row = self.current_row;
20332033 for (&readers, [2]bool{ true, false }) |*reader, is_initial| {
2034 while (reader.seek < reader.storageBuffer().len) {
2034 while (reader.seek < reader.buffer.len) {
20352035 const instruction = try std.debug.Dwarf.call_frame.Instruction.read(reader, addr_size_bytes, endian);
20362036 prev_row = try self.step(allocator, cie, is_initial, instruction);
20372037 if (pc < fde.pc_begin + self.current_row.offset) return prev_row;
lib/std/io/BufferedReader.zig+52-101
......@@ -9,19 +9,12 @@ const Reader = std.io.Reader;
99
1010const BufferedReader = @This();
1111
12/// Number of bytes which have been consumed from `storage`.
13seek: usize,
14storage: BufferedWriter,
1512unbuffered_reader: Reader,
16
17pub fn init(br: *BufferedReader, r: Reader, buffer: []u8) void {
18 br.* = .{
19 .seek = 0,
20 .storage = undefined,
21 .unbuffered_reader = r,
22 };
23 br.storage.initFixed(buffer);
24}
13buffer: []u8,
14/// In `buffer` before this are buffered bytes, after this is `undefined`.
15end: usize,
16/// Number of bytes which have been consumed from `buffer`.
17seek: usize,
2518
2619/// Constructs `br` such that it will read from `buffer` and then end.
2720///
......@@ -29,25 +22,15 @@ pub fn init(br: *BufferedReader, r: Reader, buffer: []u8) void {
2922/// and if they are avoided then `buffer` can be safely used with `@constCast`.
3023pub fn initFixed(br: *BufferedReader, buffer: []u8) void {
3124 br.* = .{
32 .seek = 0,
33 .storage = .{
34 .buffer = buffer,
35 .unbuffered_writer = .failing,
36 },
3725 .unbuffered_reader = .ending,
26 .buffer = buffer,
27 .end = buffer.len,
28 .seek = 0,
3829 };
3930}
4031
41pub fn storageBuffer(br: *BufferedReader) []u8 {
42 const storage = &br.storage;
43 assert(storage.unbuffered_writer.vtable == std.io.Writer.failing.vtable);
44 assert(br.unbuffered_reader.vtable == Reader.ending.vtable);
45 return storage.buffer;
46}
47
4832pub fn bufferContents(br: *BufferedReader) []u8 {
49 const storage = &br.storage;
50 return storage.buffer[br.seek..storage.end];
33 return br.buffer[br.seek..br.end];
5134}
5235
5336/// Although `BufferedReader` can easily satisfy the `Reader` interface, it's
......@@ -65,8 +48,7 @@ pub fn reader(br: *BufferedReader) Reader {
6548
6649fn passthruRead(ctx: ?*anyopaque, bw: *BufferedWriter, limit: Reader.Limit) Reader.RwError!usize {
6750 const br: *BufferedReader = @alignCast(@ptrCast(ctx));
68 const storage = &br.storage;
69 const buffer = storage.buffer[0..storage.end];
51 const buffer = br.buffer[0..br.end];
7052 const buffered = buffer[br.seek..];
7153 const limited = buffered[0..limit.min(buffered.len)];
7254 if (limited.len > 0) {
......@@ -89,7 +71,7 @@ pub fn seekBy(br: *BufferedReader, seek_by: i64) !void {
8971}
9072
9173pub fn seekBackwardBy(br: *BufferedReader, seek_by: u64) !void {
92 if (seek_by > br.storage.end - br.seek) return error.Unseekable; // TODO
74 if (seek_by > br.end - br.seek) return error.Unseekable; // TODO
9375 br.seek += @abs(seek_by);
9476}
9577
......@@ -115,10 +97,9 @@ pub fn seekForwardBy(br: *BufferedReader, seek_by: u64) !void {
11597/// * `tryPeekArray`
11698/// * `toss`
11799pub fn peek(br: *BufferedReader, n: usize) Reader.Error![]u8 {
118 const storage = &br.storage;
119 assert(n <= storage.buffer.len);
100 assert(n <= br.buffer.len);
120101 try br.fill(n);
121 return storage.buffer[br.seek..][0..n];
102 return br.buffer[br.seek..][0..n];
122103}
123104
124105/// Returns all the next buffered bytes from `unbuffered_reader`, after filling
......@@ -137,10 +118,9 @@ pub fn peek(br: *BufferedReader, n: usize) Reader.Error![]u8 {
137118/// * `tryPeekGreedy`
138119/// * `toss`
139120pub fn peekGreedy(br: *BufferedReader, n: usize) Reader.Error![]u8 {
140 const storage = &br.storage;
141 assert(n <= storage.buffer.len);
121 assert(n <= br.buffer.len);
142122 try br.fill(n);
143 return storage.buffer[br.seek..storage.end];
123 return br.buffer[br.seek..br.end];
144124}
145125
146126/// Skips the next `n` bytes from the stream, advancing the seek position. This
......@@ -153,7 +133,7 @@ pub fn peekGreedy(br: *BufferedReader, n: usize) Reader.Error![]u8 {
153133/// * `discard`.
154134pub fn toss(br: *BufferedReader, n: usize) void {
155135 br.seek += n;
156 assert(br.seek <= br.storage.end);
136 assert(br.seek <= br.end);
157137}
158138
159139/// Equivalent to `peek` followed by `toss`.
......@@ -207,15 +187,14 @@ pub fn discard(br: *BufferedReader, n: usize) Reader.Error!void {
207187/// * `toss`
208188/// * `discardRemaining`
209189pub fn discardShort(br: *BufferedReader, n: usize) Reader.ShortError!usize {
210 const storage = &br.storage;
211190 const proposed_seek = br.seek + n;
212 if (proposed_seek <= storage.end) {
191 if (proposed_seek <= br.end) {
213192 @branchHint(.likely);
214193 br.seek = proposed_seek;
215194 return n;
216195 }
217 var remaining = n - (storage.end - br.seek);
218 storage.end = 0;
196 var remaining = n - (br.end - br.seek);
197 br.end = 0;
219198 br.seek = 0;
220199 while (true) {
221200 const discard_len = br.unbuffered_reader.discard(.limited(remaining)) catch |err| switch (err) {
......@@ -230,9 +209,8 @@ pub fn discardShort(br: *BufferedReader, n: usize) Reader.ShortError!usize {
230209/// Reads the stream until the end, ignoring all the data.
231210/// Returns the number of bytes discarded.
232211pub fn discardRemaining(br: *BufferedReader) Reader.ShortError!usize {
233 const storage = &br.storage;
234 const buffered_len = storage.end;
235 storage.end = 0;
212 const buffered_len = br.end;
213 br.end = 0;
236214 return buffered_len + try br.unbuffered_reader.discardRemaining();
237215}
238216
......@@ -247,36 +225,25 @@ pub fn discardRemaining(br: *BufferedReader) Reader.ShortError!usize {
247225/// See also:
248226/// * `peek`
249227pub fn read(br: *BufferedReader, buffer: []u8) Reader.Error!void {
250 const storage = &br.storage;
251 const in_buffer = storage.buffer[0..storage.end];
252 const seek = br.seek;
253 const proposed_seek = seek + in_buffer.len;
254 if (proposed_seek <= in_buffer.len) {
255 @memcpy(buffer, in_buffer[seek..proposed_seek]);
256 br.seek = proposed_seek;
228 const in_buffer = br.buffer[br.seek..br.end];
229 const copy_len = @min(buffer.len, in_buffer.len);
230 @memcpy(buffer[0..copy_len], in_buffer[0..copy_len]);
231 if (copy_len == buffer.len) {
232 br.seek += copy_len;
257233 return;
258234 }
259 @memcpy(buffer[0..in_buffer.len], in_buffer);
260 storage.end = 0;
235 var i: usize = copy_len;
236 br.end = 0;
261237 br.seek = 0;
262 var i: usize = in_buffer.len;
263238 while (true) {
264 // TODO if remaining buffer len is greater than storage len, read directly into buffer
265 const read_len = br.unbuffered_reader.read(storage, .unlimited) catch |err| switch (err) {
266 error.WriteFailed => storage.end,
267 else => |e| return e,
268 };
269 assert(read_len == storage.end);
270 const next_i = i + storage.end;
271 if (next_i >= buffer.len) {
272 const remaining = buffer[i..];
273 @memcpy(remaining, storage.buffer[0..remaining.len]);
274 br.seek = remaining.len;
275 return;
239 const remaining = buffer[i..];
240 const n = try br.unbuffered_reader.readVec(&.{ remaining, br.buffer });
241 if (n < remaining.len) {
242 i += n;
243 continue;
276244 }
277 @memcpy(buffer[i..next_i], storage.buffer[0..storage.end]);
278 storage.end = 0;
279 i = next_i;
245 br.end = n - remaining.len;
246 return;
280247 }
281248}
282249
......@@ -365,8 +332,8 @@ pub const DelimiterExclusiveError = error{
365332pub fn takeDelimiterExclusive(br: *BufferedReader, delimiter: u8) DelimiterExclusiveError![]u8 {
366333 const result = br.peekDelimiterInclusiveUnlessEnd(delimiter) catch |err| switch (err) {
367334 error.EndOfStream => {
368 br.toss(br.storage.end);
369 return br.storage.buffer[0..br.storage.end];
335 br.toss(br.end);
336 return br.buffer[0..br.end];
370337 },
371338 else => |e| return e,
372339 };
......@@ -376,15 +343,14 @@ pub fn takeDelimiterExclusive(br: *BufferedReader, delimiter: u8) DelimiterExclu
376343
377344pub fn peekDelimiterExclusive(br: *BufferedReader, delimiter: u8) DelimiterExclusiveError![]u8 {
378345 const result = br.peekDelimiterInclusiveUnlessEnd(delimiter) catch |err| switch (err) {
379 error.EndOfStream => return br.storage.buffer[0..br.storage.end],
346 error.EndOfStream => return br.buffer[0..br.end],
380347 else => |e| return e,
381348 };
382349 return result[0 .. result.len - 1];
383350}
384351
385352fn peekDelimiterInclusiveUnlessEnd(br: *BufferedReader, delimiter: u8) DelimiterInclusiveError!?[]u8 {
386 const storage = &br.storage;
387 const buffer = storage.buffer[0..storage.end];
353 const buffer = br.buffer[0..br.end];
388354 const seek = br.seek;
389355 if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |end| {
390356 @branchHint(.likely);
......@@ -392,24 +358,15 @@ fn peekDelimiterInclusiveUnlessEnd(br: *BufferedReader, delimiter: u8) Delimiter
392358 }
393359 const remainder = buffer[seek..];
394360 std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
395 var i = remainder.len;
396 storage.end = i;
361 br.end = remainder.len;
397362 br.seek = 0;
398 while (i < storage.buffer.len) {
399 const eos = eos: {
400 const read_len = br.unbuffered_reader.read(storage, .unlimited) catch |err| switch (err) {
401 error.WriteFailed => storage.end - i,
402 error.ReadFailed => return error.ReadFailed,
403 error.EndOfStream => break :eos true,
404 };
405 assert(read_len == storage.end - i);
406 break :eos false;
407 };
408 if (std.mem.indexOfScalarPos(u8, storage.buffer[0..storage.end], i, delimiter)) |end| {
409 return storage.buffer[0 .. end + 1];
363 while (br.end < br.buffer.len) {
364 const n = try br.unbuffered_reader.readVec(&.{br.buffer[br.end..]});
365 const prev_end = br.end;
366 br.end = prev_end + n;
367 if (std.mem.indexOfScalarPos(u8, br.buffer[0..br.end], prev_end, delimiter)) |end| {
368 return br.buffer[0 .. end + 1];
410369 }
411 if (eos) return error.EndOfStream;
412 i = storage.end;
413370 }
414371 return error.StreamTooLong;
415372}
......@@ -494,9 +451,8 @@ pub fn discardDelimiterExclusive(br: *BufferedReader, delimiter: u8) Reader.Shor
494451///
495452/// Asserts buffer capacity is at least `n`.
496453pub fn fill(br: *BufferedReader, n: usize) Reader.Error!void {
497 const storage = &br.storage;
498 assert(n <= storage.buffer.len);
499 const buffer = storage.buffer[0..storage.end];
454 assert(n <= br.buffer.len);
455 const buffer = br.buffer[0..br.end];
500456 const seek = br.seek;
501457 if (seek + n <= buffer.len) {
502458 @branchHint(.likely);
......@@ -504,22 +460,17 @@ pub fn fill(br: *BufferedReader, n: usize) Reader.Error!void {
504460 }
505461 const remainder = buffer[seek..];
506462 std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
507 storage.end = remainder.len;
463 br.end = remainder.len;
508464 br.seek = 0;
509465 while (true) {
510 const read_len = br.unbuffered_reader.read(storage, .unlimited) catch |err| switch (err) {
511 error.WriteFailed => storage.end - remainder.len,
512 else => |e| return e,
513 };
514 assert(storage.end == remainder.len + read_len);
515 if (n <= storage.end) return;
466 br.end += try br.unbuffered_reader.readVec(&.{br.buffer[br.end..]});
467 if (n <= br.end) return;
516468 }
517469}
518470
519471/// Reads 1 byte from the stream or returns `error.EndOfStream`.
520472pub fn takeByte(br: *BufferedReader) Reader.Error!u8 {
521 const storage = &br.storage;
522 const buffer = storage.buffer[0..storage.end];
473 const buffer = br.buffer[0..br.end];
523474 const seek = br.seek;
524475 if (seek >= buffer.len) {
525476 @branchHint(.unlikely);
lib/std/io/BufferedWriter.zig+1-2
......@@ -17,8 +17,7 @@ const testing = std.testing;
1717unbuffered_writer: Writer,
1818/// If this has length zero, the writer is unbuffered, and `flush` is a no-op.
1919buffer: []u8,
20/// Marks the end of `buffer` - before this are buffered bytes, after this is
21/// undefined.
20/// In `buffer` before this are buffered bytes, after this is `undefined`.
2221end: usize = 0,
2322/// Tracks total number of bytes written to this `BufferedWriter`. This value
2423/// only increases. In the case of fixed mode, this value always equals `end`.
lib/std/io/Reader.zig+13
......@@ -197,6 +197,19 @@ pub const ending: Reader = .{
197197 },
198198};
199199
200pub fn unbuffered(r: Reader) std.io.BufferedReader {
201 return buffered(r, &.{});
202}
203
204pub fn buffered(r: Reader, buffer: []u8) std.io.BufferedReader {
205 return .{
206 .unbuffered_reader = r,
207 .seek = 0,
208 .buffer = buffer,
209 .end = 0,
210 };
211}
212
200213fn endingRead(context: ?*anyopaque, bw: *BufferedWriter, limit: Limit) RwError!usize {
201214 _ = context;
202215 _ = bw;
lib/std/process/Child.zig+1-2
......@@ -1012,8 +1012,7 @@ fn writeIntFd(fd: i32, value: ErrInt) !void {
10121012fn readIntFd(fd: i32) !ErrInt {
10131013 var fr = std.fs.File.reader(.{ .handle = fd });
10141014 var buffer: [8]u8 = undefined;
1015 var br: std.io.BufferedReader = undefined;
1016 br.init(fr.interface(), &buffer);
1015 var br = fr.interface().buffered(&buffer);
10171016 return @intCast(br.takeInt(u64, .little) catch return error.SystemResources);
10181017}
10191018