const io = @import("./io.zig"); const math = @import("./math.zig"); pub const ByteStack = Stack(io.Byte); pub fn Stack(comptime Value: type) type { return struct { allocator: io.Allocator, capacity: usize, values: []Value, const Self = @This(); pub fn clear(self: *Self) void { self.values = self.values[0 .. 0]; } pub fn free(self: *Self) void { if (self.capacity == 0) { return; } self.allocator.deallocate(self.values.ptr[0 .. self.capacity]); self.values = &.{}; } pub fn grow(self: *Self, growth_amount: usize) io.AllocationError!void { const grown_capacity = self.capacity + growth_amount; const buffer = try self.allocator.reallocate(null, @sizeOf(Value) * grown_capacity); errdefer self.allocator.deallocate(buffer); if (self.capacity != 0) { io.copy(buffer, io.bytes_of(self.values)); self.allocator.deallocate(self.values.ptr[0 .. self.capacity]); } self.values = @as([*]Value, @ptrCast(@alignCast(buffer)))[0 .. self.values.len]; self.capacity = grown_capacity; } pub fn make(allocator: io.Allocator) Self { return .{ .allocator = allocator, .capacity = 0, .values = &.{}, }; } 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]; } pub fn push_one(self: *Self, value: Value) io.AllocationError!void { if (self.values.len == self.capacity) { try self.grow(math.max(1, self.capacity)); } const offset_index = self.values.len; self.values = self.values.ptr[0 .. self.values.len + 1]; self.values[offset_index] = value; } }; }