authorgravatar for hwchen@users.noreply.github.comWalther Chen <hwchen@users.noreply.github.com> 2022-12-28 21:44:58-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-12-28 21:44:58-05:00
logff1eff99791483b59a75f1b7279b79c442b815a4
tree3c1e4529e27bedbdaaafab554147f2c0cd8c042d
parent7350f0d9b5aecaf98998bc6591a649d9a7b7091f
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

std: stop using LinearFifo in BufferedReader (#14029)

See also commit 7287c7482a2c694c7c7f56b9f7c1744a7ae7905f where LinearFifo is removed from BufferedWriter Basically, LinearFifo does extra work via copying bytes and increasing an offset.

1 files changed, 112 insertions(+), 9 deletions(-)

lib/std/io/buffered_reader.zig+112-9
......@@ -1,35 +1,39 @@
11const std = @import("../std.zig");
22const io = std.io;
3const mem = std.mem;
34const assert = std.debug.assert;
45const testing = std.testing;
56
67pub fn BufferedReader(comptime buffer_size: usize, comptime ReaderType: type) type {
78 return struct {
89 unbuffered_reader: ReaderType,
9 fifo: FifoType = FifoType.init(),
10 buf: [buffer_size]u8 = undefined,
11 start: usize = 0,
12 end: usize = 0,
1013
1114 pub const Error = ReaderType.Error;
1215 pub const Reader = io.Reader(*Self, Error, read);
1316
1417 const Self = @This();
15 const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
1618
1719 pub fn read(self: *Self, dest: []u8) Error!usize {
1820 var dest_index: usize = 0;
21
1922 while (dest_index < dest.len) {
20 const written = self.fifo.read(dest[dest_index..]);
23 const written = std.math.min(dest.len - dest_index, self.end - self.start);
24 std.mem.copy(u8, dest[dest_index..], self.buf[self.start .. self.start + written]);
2125 if (written == 0) {
22 // fifo empty, fill it
23 const writable = self.fifo.writableSlice(0);
24 assert(writable.len > 0);
25 const n = try self.unbuffered_reader.read(writable);
26 // buf empty, fill it
27 const n = try self.unbuffered_reader.read(self.buf[0..]);
2628 if (n == 0) {
2729 // reading from the unbuffered stream returned nothing
2830 // so we have nothing left to read.
2931 return dest_index;
3032 }
31 self.fifo.update(n);
33 self.start = 0;
34 self.end = n;
3235 }
36 self.start += written;
3337 dest_index += written;
3438 }
3539 return dest.len;
......@@ -45,7 +49,7 @@ pub fn bufferedReader(underlying_stream: anytype) BufferedReader(4096, @TypeOf(u
4549 return .{ .unbuffered_reader = underlying_stream };
4650}
4751
48test "io.BufferedReader" {
52test "io.BufferedReader OneByte" {
4953 const OneByteReadReader = struct {
5054 str: []const u8,
5155 curr: usize,
......@@ -84,3 +88,102 @@ test "io.BufferedReader" {
8488 defer testing.allocator.free(res);
8589 try testing.expectEqualSlices(u8, str, res);
8690}
91
92fn smallBufferedReader(underlying_stream: anytype) BufferedReader(8, @TypeOf(underlying_stream)) {
93 return .{ .unbuffered_reader = underlying_stream };
94}
95test "io.BufferedReader Block" {
96 const BlockReader = struct {
97 block: []const u8,
98 reads_allowed: usize,
99 curr_read: usize,
100
101 const Error = error{NoError};
102 const Self = @This();
103 const Reader = io.Reader(*Self, Error, read);
104
105 fn init(block: []const u8, reads_allowed: usize) Self {
106 return Self{
107 .block = block,
108 .reads_allowed = reads_allowed,
109 .curr_read = 0,
110 };
111 }
112
113 fn read(self: *Self, dest: []u8) Error!usize {
114 if (self.curr_read >= self.reads_allowed) {
115 return 0;
116 }
117 std.debug.assert(dest.len >= self.block.len);
118 std.mem.copy(u8, dest, self.block);
119
120 self.curr_read += 1;
121 return self.block.len;
122 }
123
124 fn reader(self: *Self) Reader {
125 return .{ .context = self };
126 }
127 };
128
129 const block = "0123";
130
131 // len out == block
132 {
133 var block_reader = BlockReader.init(block, 2);
134 var test_buf_reader = BufferedReader(4, BlockReader){ .unbuffered_reader = block_reader };
135 var out_buf: [4]u8 = undefined;
136 _ = try test_buf_reader.read(&out_buf);
137 try testing.expectEqualSlices(u8, &out_buf, block);
138 _ = try test_buf_reader.read(&out_buf);
139 try testing.expectEqualSlices(u8, &out_buf, block);
140 try testing.expectEqual(try test_buf_reader.read(&out_buf), 0);
141 }
142
143 // len out < block
144 {
145 var block_reader = BlockReader.init(block, 2);
146 var test_buf_reader = BufferedReader(4, BlockReader){ .unbuffered_reader = block_reader };
147 var out_buf: [3]u8 = undefined;
148 _ = try test_buf_reader.read(&out_buf);
149 try testing.expectEqualSlices(u8, &out_buf, "012");
150 _ = try test_buf_reader.read(&out_buf);
151 try testing.expectEqualSlices(u8, &out_buf, "301");
152 const n = try test_buf_reader.read(&out_buf);
153 try testing.expectEqualSlices(u8, out_buf[0..n], "23");
154 try testing.expectEqual(try test_buf_reader.read(&out_buf), 0);
155 }
156
157 // len out > block
158 {
159 var block_reader = BlockReader.init(block, 2);
160 var test_buf_reader = BufferedReader(4, BlockReader){ .unbuffered_reader = block_reader };
161 var out_buf: [5]u8 = undefined;
162 _ = try test_buf_reader.read(&out_buf);
163 try testing.expectEqualSlices(u8, &out_buf, "01230");
164 const n = try test_buf_reader.read(&out_buf);
165 try testing.expectEqualSlices(u8, out_buf[0..n], "123");
166 try testing.expectEqual(try test_buf_reader.read(&out_buf), 0);
167 }
168
169 // len out == 0
170 {
171 var block_reader = BlockReader.init(block, 2);
172 var test_buf_reader = BufferedReader(4, BlockReader){ .unbuffered_reader = block_reader };
173 var out_buf: [0]u8 = undefined;
174 _ = try test_buf_reader.read(&out_buf);
175 try testing.expectEqualSlices(u8, &out_buf, "");
176 }
177
178 // len bufreader buf > block
179 {
180 var block_reader = BlockReader.init(block, 2);
181 var test_buf_reader = BufferedReader(5, BlockReader){ .unbuffered_reader = block_reader };
182 var out_buf: [4]u8 = undefined;
183 _ = try test_buf_reader.read(&out_buf);
184 try testing.expectEqualSlices(u8, &out_buf, block);
185 _ = try test_buf_reader.read(&out_buf);
186 try testing.expectEqualSlices(u8, &out_buf, block);
187 try testing.expectEqual(try test_buf_reader.read(&out_buf), 0);
188 }
189}