129 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Zig
		
	
	
	
	
	
			
		
		
	
	
			129 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Zig
		
	
	
	
	
	
| 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 is_empty(self: Self) bool {
 | |
| 			return self.values.len == 0;
 | |
| 		}
 | |
| 
 | |
| 		pub fn make(allocator: io.Allocator) Self {
 | |
| 			return .{
 | |
| 				.allocator = allocator,
 | |
| 				.capacity = 0,
 | |
| 				.values = &.{},
 | |
| 			};
 | |
| 		}
 | |
| 
 | |
| 		pub fn pack(self: *Self) io.AllocationError!void {
 | |
| 			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;
 | |
| 		}
 | |
| 
 | |
| 		pub fn peek(self: Self) ?Value {
 | |
| 			if (self.values.len == 0) {
 | |
| 				return null;
 | |
| 			}
 | |
| 
 | |
| 			return self.values[self.values.len - 1];
 | |
| 		}
 | |
| 
 | |
| 		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_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];
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		pub fn push_one(self: *Self, value: Value) io.AllocationError!void {
 | |
| 			if (self.values.len == self.capacity) {
 | |
| 				try self.grow(@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;
 | |
| 		}
 | |
| 	};
 | |
| }
 | |
| 
 | |
| 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 {
 | |
| 	stack.push_all(bytes) catch return null;
 | |
| 
 | |
| 	return bytes.len;
 | |
| }
 |