| ... | @@ -121,76 +121,37 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) | ... | @@ -121,76 +121,37 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) |
| 121 | | 121 | |
| 122 | unbuffered_in_stream: *Stream, | 122 | unbuffered_in_stream: *Stream, |
| 123 | | 123 | |
| 124 | buffer: [buffer_size]u8, | 124 | const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size }); |
| 125 | start_index: usize, | 125 | fifo: FifoType, |
| 126 | end_index: usize, | | |
| 127 | | 126 | |
| 128 | pub fn init(unbuffered_in_stream: *Stream) Self { | 127 | pub fn init(unbuffered_in_stream: *Stream) Self { |
| 129 | return Self{ | 128 | return Self{ |
| 130 | .unbuffered_in_stream = unbuffered_in_stream, | 129 | .unbuffered_in_stream = unbuffered_in_stream, |
| 131 | .buffer = undefined, | 130 | .fifo = FifoType.init(), |
| 132 | | | |
| 133 | // Initialize these two fields to buffer_size so that | | |
| 134 | // in `readFn` we treat the state as being able to read | | |
| 135 | // more from the unbuffered stream. If we set them to 0 | | |
| 136 | // and 0, the code would think we already hit EOF. | | |
| 137 | .start_index = buffer_size, | | |
| 138 | .end_index = buffer_size, | | |
| 139 | | | |
| 140 | .stream = Stream{ .readFn = readFn }, | 131 | .stream = Stream{ .readFn = readFn }, |
| 141 | }; | 132 | }; |
| 142 | } | 133 | } |
| 143 | | 134 | |
| 144 | fn readFn(in_stream: *Stream, dest: []u8) !usize { | 135 | fn readFn(in_stream: *Stream, dest: []u8) !usize { |
| 145 | const self = @fieldParentPtr(Self, "stream", in_stream); | 136 | const self = @fieldParentPtr(Self, "stream", in_stream); |
| 146 | | | |
| 147 | // Hot path for one byte reads | | |
| 148 | if (dest.len == 1 and self.end_index > self.start_index) { | | |
| 149 | dest[0] = self.buffer[self.start_index]; | | |
| 150 | self.start_index += 1; | | |
| 151 | return 1; | | |
| 152 | } | | |
| 153 | | | |
| 154 | var dest_index: usize = 0; | 137 | var dest_index: usize = 0; |
| 155 | while (true) { | 138 | while (dest_index < dest.len) { |
| 156 | const dest_space = dest.len - dest_index; | 139 | const written = self.fifo.read(dest[dest_index..]); |
| 157 | if (dest_space == 0) { | 140 | if (written == 0) { |
| 158 | return dest_index; | 141 | // fifo empty, fill it |
| 159 | } | 142 | const writable = self.fifo.writableSlice(0); |
| 160 | const amt_buffered = self.end_index - self.start_index; | 143 | assert(writable.len > 0); |
| 161 | if (amt_buffered == 0) { | 144 | const n = try self.unbuffered_in_stream.read(writable); |
| 162 | assert(self.end_index <= buffer_size); | 145 | if (n == 0) { |
| 163 | // Make sure the last read actually gave us some data | | |
| 164 | if (self.end_index == 0) { | | |
| 165 | // reading from the unbuffered stream returned nothing | 146 | // reading from the unbuffered stream returned nothing |
| 166 | // so we have nothing left to read. | 147 | // so we have nothing left to read. |
| 167 | return dest_index; | 148 | return dest_index; |
| 168 | } | 149 | } |
| 169 | // we can read more data from the unbuffered stream | 150 | self.fifo.update(n); |
| 170 | if (dest_space < buffer_size) { | | |
| 171 | self.start_index = 0; | | |
| 172 | self.end_index = try self.unbuffered_in_stream.read(self.buffer[0..]); | | |
| 173 | | | |
| 174 | // Shortcut | | |
| 175 | if (self.end_index >= dest_space) { | | |
| 176 | mem.copy(u8, dest[dest_index..], self.buffer[0..dest_space]); | | |
| 177 | self.start_index = dest_space; | | |
| 178 | return dest.len; | | |
| 179 | } | | |
| 180 | } else { | | |
| 181 | // asking for so much data that buffering is actually less efficient. | | |
| 182 | // forward the request directly to the unbuffered stream | | |
| 183 | const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]); | | |
| 184 | return dest_index + amt_read; | | |
| 185 | } | | |
| 186 | } | 151 | } |
| 187 | | 152 | dest_index += written; |
| 188 | const copy_amount = math.min(dest_space, amt_buffered); | | |
| 189 | const copy_end_index = self.start_index + copy_amount; | | |
| 190 | mem.copy(u8, dest[dest_index..], self.buffer[self.start_index..copy_end_index]); | | |
| 191 | self.start_index = copy_end_index; | | |
| 192 | dest_index += copy_amount; | | |
| 193 | } | 153 | } |
| | 154 | return dest.len; |
| 194 | } | 155 | } |
| 195 | }; | 156 | }; |
| 196 | } | 157 | } |