std: use LinearFifo to implement io.PeekStream

This commit is contained in:
daurnimator 2019-11-11 03:07:57 +11:00 committed by Andrew Kelley
parent bdff2f43bd
commit 38ad7daebb
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
2 changed files with 17 additions and 37 deletions

View File

@ -196,7 +196,7 @@ test "io.BufferedInStream" {
/// Creates a stream which supports 'un-reading' data, so that it can be read again. /// Creates a stream which supports 'un-reading' data, so that it can be read again.
/// This makes look-ahead style parsing much easier. /// This makes look-ahead style parsing much easier.
pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) type { pub fn PeekStream(comptime buffer_type: usize, comptime InStreamError: type) type {
return struct { return struct {
const Self = @This(); const Self = @This();
pub const Error = InStreamError; pub const Error = InStreamError;
@ -207,55 +207,35 @@ pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) typ
// Right now the look-ahead space is statically allocated, but a version with dynamic allocation // Right now the look-ahead space is statically allocated, but a version with dynamic allocation
// is not too difficult to derive from this. // is not too difficult to derive from this.
buffer: [buffer_size]u8, const FifoType = std.fifo.LinearFifo(u8, .{ .Static = buffer_size });
index: usize, fifo: FifoType,
at_end: bool,
pub fn init(base: *Stream) Self { pub fn init(base: *Stream) Self {
return Self{ return .{
.base = base, .base = base,
.buffer = undefined, .fifo = FifoType.init(),
.index = 0,
.at_end = false,
.stream = Stream{ .readFn = readFn }, .stream = Stream{ .readFn = readFn },
}; };
} }
pub fn putBackByte(self: *Self, byte: u8) void { pub fn putBackByte(self: *Self, byte: u8) !void {
self.buffer[self.index] = byte; try self.putBack(@ptrCast([*]const u8, &byte)[0..1]);
self.index += 1;
} }
pub fn putBack(self: *Self, bytes: []const u8) void { pub fn putBack(self: *Self, bytes: []const u8) !void {
var pos = bytes.len; try self.fifo.unget(bytes);
while (pos != 0) {
pos -= 1;
self.putBackByte(bytes[pos]);
}
} }
fn readFn(in_stream: *Stream, dest: []u8) Error!usize { fn readFn(in_stream: *Stream, dest: []u8) Error!usize {
const self = @fieldParentPtr(Self, "stream", in_stream); const self = @fieldParentPtr(Self, "stream", in_stream);
// copy over anything putBack()'d // copy over anything putBack()'d
var pos: usize = 0; var dest_index = self.fifo.read(dest);
while (pos < dest.len and self.index != 0) { if (dest_index == dest.len) return dest_index;
dest[pos] = self.buffer[self.index - 1];
self.index -= 1;
pos += 1;
}
if (pos == dest.len or self.at_end) {
return pos;
}
// ask the backing stream for more // ask the backing stream for more
const left = dest.len - pos; dest_index += try self.base.read(dest[dest_index..]);
const read = try self.base.read(dest[pos..]); return dest_index;
assert(read <= left);
self.at_end = (read < left);
return pos + read;
} }
}; };
} }

View File

@ -97,8 +97,8 @@ test "PeekStream" {
var dest: [4]u8 = undefined; var dest: [4]u8 = undefined;
ps.putBackByte(9); try ps.putBackByte(9);
ps.putBackByte(10); try ps.putBackByte(10);
var read = try ps.stream.read(dest[0..4]); var read = try ps.stream.read(dest[0..4]);
expect(read == 4); expect(read == 4);
@ -114,8 +114,8 @@ test "PeekStream" {
expect(read == 2); expect(read == 2);
expect(mem.eql(u8, dest[0..2], bytes[6..8])); expect(mem.eql(u8, dest[0..2], bytes[6..8]));
ps.putBackByte(11); try ps.putBackByte(11);
ps.putBackByte(12); try ps.putBackByte(12);
read = try ps.stream.read(dest[0..4]); read = try ps.stream.read(dest[0..4]);
expect(read == 2); expect(read == 2);