std: use LinearFifo to implement io.BufferedInStreamCustom
This commit is contained in:
committed by
Andrew Kelley
parent
662996e4a8
commit
bdff2f43bd
@@ -121,76 +121,37 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
|
||||
|
||||
unbuffered_in_stream: *Stream,
|
||||
|
||||
buffer: [buffer_size]u8,
|
||||
start_index: usize,
|
||||
end_index: usize,
|
||||
const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
|
||||
fifo: FifoType,
|
||||
|
||||
pub fn init(unbuffered_in_stream: *Stream) Self {
|
||||
return Self{
|
||||
.unbuffered_in_stream = unbuffered_in_stream,
|
||||
.buffer = undefined,
|
||||
|
||||
// Initialize these two fields to buffer_size so that
|
||||
// in `readFn` we treat the state as being able to read
|
||||
// more from the unbuffered stream. If we set them to 0
|
||||
// and 0, the code would think we already hit EOF.
|
||||
.start_index = buffer_size,
|
||||
.end_index = buffer_size,
|
||||
|
||||
.fifo = FifoType.init(),
|
||||
.stream = Stream{ .readFn = readFn },
|
||||
};
|
||||
}
|
||||
|
||||
fn readFn(in_stream: *Stream, dest: []u8) !usize {
|
||||
const self = @fieldParentPtr(Self, "stream", in_stream);
|
||||
|
||||
// Hot path for one byte reads
|
||||
if (dest.len == 1 and self.end_index > self.start_index) {
|
||||
dest[0] = self.buffer[self.start_index];
|
||||
self.start_index += 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
var dest_index: usize = 0;
|
||||
while (true) {
|
||||
const dest_space = dest.len - dest_index;
|
||||
if (dest_space == 0) {
|
||||
return dest_index;
|
||||
}
|
||||
const amt_buffered = self.end_index - self.start_index;
|
||||
if (amt_buffered == 0) {
|
||||
assert(self.end_index <= buffer_size);
|
||||
// Make sure the last read actually gave us some data
|
||||
if (self.end_index == 0) {
|
||||
while (dest_index < dest.len) {
|
||||
const written = self.fifo.read(dest[dest_index..]);
|
||||
if (written == 0) {
|
||||
// fifo empty, fill it
|
||||
const writable = self.fifo.writableSlice(0);
|
||||
assert(writable.len > 0);
|
||||
const n = try self.unbuffered_in_stream.read(writable);
|
||||
if (n == 0) {
|
||||
// reading from the unbuffered stream returned nothing
|
||||
// so we have nothing left to read.
|
||||
return dest_index;
|
||||
}
|
||||
// we can read more data from the unbuffered stream
|
||||
if (dest_space < buffer_size) {
|
||||
self.start_index = 0;
|
||||
self.end_index = try self.unbuffered_in_stream.read(self.buffer[0..]);
|
||||
|
||||
// Shortcut
|
||||
if (self.end_index >= dest_space) {
|
||||
mem.copy(u8, dest[dest_index..], self.buffer[0..dest_space]);
|
||||
self.start_index = dest_space;
|
||||
return dest.len;
|
||||
}
|
||||
} else {
|
||||
// asking for so much data that buffering is actually less efficient.
|
||||
// forward the request directly to the unbuffered stream
|
||||
const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]);
|
||||
return dest_index + amt_read;
|
||||
}
|
||||
self.fifo.update(n);
|
||||
}
|
||||
|
||||
const copy_amount = math.min(dest_space, amt_buffered);
|
||||
const copy_end_index = self.start_index + copy_amount;
|
||||
mem.copy(u8, dest[dest_index..], self.buffer[self.start_index..copy_end_index]);
|
||||
self.start_index = copy_end_index;
|
||||
dest_index += copy_amount;
|
||||
dest_index += written;
|
||||
}
|
||||
return dest.len;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user