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 @@...@@ -1,35 +1,39 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const io = std.io;2const io = std.io;
3const mem = std.mem;
3const assert = std.debug.assert;4const assert = std.debug.assert;
4const testing = std.testing;5const testing = std.testing;
56
6pub fn BufferedReader(comptime buffer_size: usize, comptime ReaderType: type) type {7pub fn BufferedReader(comptime buffer_size: usize, comptime ReaderType: type) type {
7 return struct {8 return struct {
8 unbuffered_reader: ReaderType,9 unbuffered_reader: ReaderType,
9 fifo: FifoType = FifoType.init(),10 buf: [buffer_size]u8 = undefined,
11 start: usize = 0,
12 end: usize = 0,
1013
11 pub const Error = ReaderType.Error;14 pub const Error = ReaderType.Error;
12 pub const Reader = io.Reader(*Self, Error, read);15 pub const Reader = io.Reader(*Self, Error, read);
1316
14 const Self = @This();17 const Self = @This();
15 const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
1618
17 pub fn read(self: *Self, dest: []u8) Error!usize {19 pub fn read(self: *Self, dest: []u8) Error!usize {
18 var dest_index: usize = 0;20 var dest_index: usize = 0;
21
19 while (dest_index < dest.len) {22 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]);
21 if (written == 0) {25 if (written == 0) {
22 // fifo empty, fill it26 // buf empty, fill it
23 const writable = self.fifo.writableSlice(0);27 const n = try self.unbuffered_reader.read(self.buf[0..]);
24 assert(writable.len > 0);
25 const n = try self.unbuffered_reader.read(writable);
26 if (n == 0) {28 if (n == 0) {
27 // reading from the unbuffered stream returned nothing29 // reading from the unbuffered stream returned nothing
28 // so we have nothing left to read.30 // so we have nothing left to read.
29 return dest_index;31 return dest_index;
30 }32 }
31 self.fifo.update(n);33 self.start = 0;
34 self.end = n;
32 }35 }
36 self.start += written;
33 dest_index += written;37 dest_index += written;
34 }38 }
35 return dest.len;39 return dest.len;
...@@ -45,7 +49,7 @@ pub fn bufferedReader(underlying_stream: anytype) BufferedReader(4096, @TypeOf(u...@@ -45,7 +49,7 @@ pub fn bufferedReader(underlying_stream: anytype) BufferedReader(4096, @TypeOf(u
45 return .{ .unbuffered_reader = underlying_stream };49 return .{ .unbuffered_reader = underlying_stream };
46}50}
4751
48test "io.BufferedReader" {52test "io.BufferedReader OneByte" {
49 const OneByteReadReader = struct {53 const OneByteReadReader = struct {
50 str: []const u8,54 str: []const u8,
51 curr: usize,55 curr: usize,
...@@ -84,3 +88,102 @@ test "io.BufferedReader" {...@@ -84,3 +88,102 @@ test "io.BufferedReader" {
84 defer testing.allocator.free(res);88 defer testing.allocator.free(res);
85 try testing.expectEqualSlices(u8, str, res);89 try testing.expectEqualSlices(u8, str, res);
86}90}
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}