ona/src/stack.zig

118 lines
3.5 KiB
Zig
Raw Normal View History

const io = @import("./io.zig");
const std = @import("std");
2022-09-27 21:45:32 +01:00
pub fn Fixed(comptime Element: type) type {
return struct {
2022-09-27 21:45:32 +01:00
filled: usize = 0,
buffer: []Element,
const Self = @This();
///
/// Wraps `self` and returns it in a [io.Writer] value.
///
/// Note that this will raise a compilation error if [Element] is not `u8`.
///
pub fn writer(self: *Self) io.Writer {
if (Element != u8) @compileError("Cannot coerce fixed stack of type " ++
@typeName(Element) ++ " into a Writer");
return io.Writer.wrap(Self, self, struct {
fn write(stack: *Self, buffer: []const u8) usize {
stack.pushAll(buffer) catch |err| switch (err) {
error.Overflow => return 0,
};
return buffer.len;
}
}.write);
}
///
/// Clears all elements from `self`.
///
pub fn clear(self: *Self) void {
self.filled = 0;
}
///
/// Counts and returns the number of pushed elements in `self`.
///
pub fn count(self: Self) usize {
return self.filled;
}
///
/// Attempts to pop the tail-end of `self`, returning the element value or `null` if the
/// stack is empty.
///
pub fn pop(self: *Self) ?Element {
if (self.filled == 0) return null;
self.filled -= 1;
return self.buffer[self.filled];
}
///
2022-09-27 21:45:32 +01:00
/// Attempts to push `element` into `self`, returning a [FixedPushError] if it failed.
///
2022-09-27 21:45:32 +01:00
pub fn push(self: *Self, element: Element) FixedPushError!void {
if (self.filled == self.buffer.len) return error.Overflow;
self.buffer[self.filled] = element;
self.filled += 1;
}
///
2022-09-27 21:45:32 +01:00
/// Attempts to push all of `elements` into `self`, returning a [FixedPushError] if it
/// failed.
///
2022-09-27 21:45:32 +01:00
pub fn pushAll(self: *Self, elements: []const u8) FixedPushError!void {
const filled = (self.filled + elements.len);
if (filled > self.buffer.len) return error.Overflow;
std.mem.copy(u8, self.buffer[self.filled ..], elements);
self.filled = filled;
}
};
}
///
/// Potential errors that may occur while trying to push one or more elements into a stack of a
/// known maximum size.
///
/// [FinitePushError.Overflow] is returned if the stack does not have sufficient capacity to hold a
/// given set of elements.
///
pub const FixedPushError = error {
Overflow,
};
2022-10-03 22:58:33 +01:00
test {
const testing = std.testing;
2022-09-27 21:45:32 +01:00
var buffer = std.mem.zeroes([4]u8);
var stack = Fixed(u8){.buffer = &buffer};
try testing.expectEqual(stack.count(), 0);
try testing.expectEqual(stack.pop(), null);
try stack.push(69);
try testing.expectEqual(stack.count(), 1);
try testing.expectEqual(stack.pop(), 69);
try stack.pushAll(&.{42, 10, 95, 0});
try testing.expectEqual(stack.count(), 4);
try testing.expectError(FixedPushError.Overflow, stack.push(1));
try testing.expectError(FixedPushError.Overflow, stack.pushAll(&.{1, 11, 11}));
stack.clear();
try testing.expectEqual(stack.count(), 0);
const writer = stack.writer();
try testing.expectEqual(writer.write(&.{0, 0, 0, 0}), 4);
try testing.expectEqual(writer.writeByte(0), false);
}