2023-05-23 02:08:34 +02:00
|
|
|
const io = @import("./io.zig");
|
|
|
|
|
|
|
|
const math = @import("./math.zig");
|
|
|
|
|
2023-07-10 02:10:56 +02:00
|
|
|
pub const ByteStack = Stack(io.Byte);
|
|
|
|
|
2023-05-28 03:19:46 +02:00
|
|
|
pub fn Stack(comptime Value: type) type {
|
2023-05-23 02:08:34 +02:00
|
|
|
return struct {
|
2023-06-23 00:46:48 +02:00
|
|
|
allocator: io.Allocator,
|
2023-07-10 02:10:56 +02:00
|
|
|
capacity: usize,
|
|
|
|
values: []Value,
|
2023-05-23 02:08:34 +02:00
|
|
|
|
|
|
|
const Self = @This();
|
|
|
|
|
|
|
|
pub fn clear(self: *Self) void {
|
|
|
|
self.values = self.values[0 .. 0];
|
|
|
|
}
|
|
|
|
|
2023-11-12 14:09:30 +01:00
|
|
|
pub fn deinit(self: *Self) void {
|
|
|
|
if (self.capacity == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.allocator.deallocate(self.values.ptr[0 .. self.capacity]);
|
|
|
|
|
|
|
|
self.values = &.{};
|
|
|
|
}
|
|
|
|
|
2023-10-29 22:48:21 +01:00
|
|
|
pub fn drop(self: *Self, count: usize) bool {
|
2023-11-08 00:02:49 +01:00
|
|
|
if (math.checked_sub(self.values.len, count)) |updated_count| {
|
2023-10-29 22:48:21 +01:00
|
|
|
self.values = self.values[0 .. updated_count];
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-06-23 00:46:48 +02:00
|
|
|
pub fn grow(self: *Self, growth_amount: usize) io.AllocationError!void {
|
2023-05-23 02:08:34 +02:00
|
|
|
const grown_capacity = self.capacity + growth_amount;
|
2023-07-10 02:10:56 +02:00
|
|
|
const buffer = try self.allocator.reallocate(null, @sizeOf(Value) * grown_capacity);
|
2023-05-23 02:08:34 +02:00
|
|
|
|
2023-07-10 02:10:56 +02:00
|
|
|
errdefer self.allocator.deallocate(buffer);
|
2023-05-23 02:08:34 +02:00
|
|
|
|
2023-06-02 23:43:53 +02:00
|
|
|
if (self.capacity != 0) {
|
2023-07-10 02:10:56 +02:00
|
|
|
io.copy(buffer, io.bytes_of(self.values));
|
|
|
|
self.allocator.deallocate(self.values.ptr[0 .. self.capacity]);
|
2023-06-02 23:43:53 +02:00
|
|
|
}
|
2023-05-23 02:08:34 +02:00
|
|
|
|
2023-07-10 02:10:56 +02:00
|
|
|
self.values = @as([*]Value, @ptrCast(@alignCast(buffer)))[0 .. self.values.len];
|
2023-05-23 02:08:34 +02:00
|
|
|
self.capacity = grown_capacity;
|
|
|
|
}
|
|
|
|
|
2023-11-12 14:09:30 +01:00
|
|
|
pub fn init(allocator: io.Allocator) Self {
|
2023-07-10 02:10:56 +02:00
|
|
|
return .{
|
|
|
|
.allocator = allocator,
|
|
|
|
.capacity = 0,
|
|
|
|
.values = &.{},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-11-12 14:09:30 +01:00
|
|
|
pub fn is_empty(self: Self) bool {
|
|
|
|
return self.values.len == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn pack(self: *Self) io.AllocationError![]Value {
|
2023-07-19 00:52:56 +02:00
|
|
|
const packed_size = self.values.len;
|
|
|
|
const buffer = try self.allocator.reallocate(null, @sizeOf(Value) * self.values.len);
|
|
|
|
|
|
|
|
io.copy(buffer, io.bytes_of(self.values));
|
|
|
|
|
|
|
|
if (self.capacity != 0) {
|
|
|
|
self.allocator.deallocate(self.values.ptr[0 .. self.capacity]);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.values = @as([*]Value, @ptrCast(@alignCast(buffer)))[0 .. packed_size];
|
|
|
|
self.capacity = packed_size;
|
2023-11-12 14:09:30 +01:00
|
|
|
|
|
|
|
return self.values;
|
2023-07-19 00:52:56 +02:00
|
|
|
}
|
|
|
|
|
2023-07-19 13:19:56 +02:00
|
|
|
pub fn peek(self: Self) ?Value {
|
2023-07-19 00:52:56 +02:00
|
|
|
if (self.values.len == 0) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2023-07-22 00:03:25 +02:00
|
|
|
return self.values[self.values.len - 1];
|
2023-07-19 00:52:56 +02:00
|
|
|
}
|
|
|
|
|
2023-05-28 03:19:46 +02:00
|
|
|
pub fn pop(self: *Self) ?Value {
|
|
|
|
if (self.values.len == 0) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const last_index = self.values.len - 1;
|
|
|
|
|
|
|
|
defer self.values = self.values[0 .. last_index];
|
|
|
|
|
|
|
|
return self.values[last_index];
|
|
|
|
}
|
|
|
|
|
2023-07-22 00:03:25 +02:00
|
|
|
pub fn push_all(self: *Self, values: []const Value) io.AllocationError!void {
|
|
|
|
const new_length = self.values.len + values.len;
|
|
|
|
|
|
|
|
if (new_length > self.capacity) {
|
|
|
|
try self.grow(values.len + values.len);
|
|
|
|
}
|
|
|
|
|
|
|
|
const offset_index = self.values.len;
|
|
|
|
|
|
|
|
self.values = self.values.ptr[0 .. new_length];
|
|
|
|
|
|
|
|
for (0 .. values.len) |index| {
|
|
|
|
self.values[offset_index + index] = values[index];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-23 00:46:48 +02:00
|
|
|
pub fn push_one(self: *Self, value: Value) io.AllocationError!void {
|
2023-05-23 02:08:34 +02:00
|
|
|
if (self.values.len == self.capacity) {
|
2023-07-22 14:57:39 +02:00
|
|
|
try self.grow(@max(1, self.capacity));
|
2023-05-23 02:08:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const offset_index = self.values.len;
|
|
|
|
|
|
|
|
self.values = self.values.ptr[0 .. self.values.len + 1];
|
|
|
|
|
|
|
|
self.values[offset_index] = value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2023-07-22 00:03:25 +02:00
|
|
|
|
|
|
|
pub fn stack_as_writer(self: *ByteStack) io.Writer {
|
|
|
|
return io.Writer.bind(ByteStack, self, write_stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_stack(stack: *ByteStack, bytes: []const io.Byte) ?usize {
|
2023-07-22 15:44:33 +02:00
|
|
|
stack.push_all(bytes) catch return null;
|
|
|
|
|
|
|
|
return bytes.len;
|
2023-07-22 00:03:25 +02:00
|
|
|
}
|