const io = @import("./io.zig"); const scalars = @import("./scalars.zig"); const slices = @import("./slices.zig"); const std = @import("std"); pub fn Sequential(comptime Value: type) type { return struct { allocator: std.mem.Allocator, values: []Value = &.{}, cap: usize = 0, const Self = @This(); pub fn clear(self: *Self) void { self.values = self.values[0 .. 0]; } pub fn deinit(self: *Self) void { if (self.cap == 0) { return; } self.allocator.free(self.values.ptr[0 .. self.cap]); self.* = undefined; } pub fn grow(self: *Self, additional: usize) std.mem.Allocator.Error!void { if (additional == 0) { return; } const grown_capacity = self.cap + additional; const buffer = try self.allocator.alloc(Value, grown_capacity); errdefer self.allocator.deallocate(buffer); if (self.cap != 0) { @memcpy(buffer[0 .. self.values.len], self.values); self.allocator.free(self.values.ptr[0 .. self.cap]); } self.values = @as([*]Value, @ptrCast(@alignCast(buffer)))[0 .. self.values.len]; self.cap = grown_capacity; } pub fn is_empty(self: Self) bool { return self.values.len == 0; } pub fn get(self: Self) ?Value { if (self.get_ptr()) |value| { return value.*; } return null; } pub fn get_ptr(self: Self) ?*Value { if (self.values.len == 0) { return null; } return &self.values[self.values.len - 1]; } pub fn len(self: Self) usize { return self.values.len; } pub fn pop(self: *Self) bool { if (self.values.len == 0) { return false; } self.values = self.values[0 .. self.values.len - 1]; return true; } pub fn pop_many(self: *Self, n: usize) bool { const new_length = scalars.sub(self.values.len, n) orelse { return false; }; self.values = self.values[0 .. new_length]; return true; } pub fn push(self: *Self, value: Value) bool { if (self.values.len == self.cap) { return false; } const offset_index = self.values.len; self.values = self.values.ptr[0 .. self.values.len + 1]; self.values[offset_index] = value; return true; } pub fn push_all(self: *Self, values: []const Value) bool { const new_length = self.values.len + values.len; if (new_length > self.cap) { return false; } 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]; } return true; } pub fn push_grow(self: *Self, value: Value) std.mem.Allocator.Error!void { if (self.values.len == self.cap) { try self.grow(@max(1, self.cap)); } const offset_index = self.values.len; self.values = self.values.ptr[0 .. self.values.len + 1]; self.values[offset_index] = value; } pub fn push_many(self: *Self, n: usize, value: Value) std.mem.Allocator.Error!void { const new_length = self.values.len + n; if (new_length > self.cap) { return false; } const offset_index = self.values.len; self.values = self.values.ptr[0 .. new_length]; for (0 .. n) |index| { self.values[offset_index + index] = value; } return true; } pub fn resize(self: *Self, size: usize, default_value: Value) std.mem.Allocator.Error!void { if (self.cap == size) { return; } const values = try self.allocator.alloc(Value, size); for (0 .. @min(values.len, self.values.len)) |i| { values[i] = self.values[i]; } if (values.len > self.values.len) { for (self.values.len .. values.len) |i| { values[i] = default_value; } } self.values = values[0 .. values.len]; self.cap = values.len; } pub fn to_allocation(self: *Self, size: usize, default_value: Value) std.mem.Allocator.Error![]Value { defer { self.values = &.{}; self.cap = 0; } const allocation = try self.allocator.realloc(self.values.ptr[0 .. self.cap], size); for (allocation[@min(self.values.len, size) .. size]) |*value| { value.* = default_value; } return allocation; } pub const writer = switch (Value) { io.Byte => struct { fn writer(self: *Self) io.Writer { return io.Writer.bind(Self, self, write); } fn write(self: *Self, buffer: []const io.Byte) io.Error!usize { self.push_all(buffer) catch return error.UnavailableResource; return buffer.len; } }.writer, else => @compileError("only `Stack(Byte)` has a `reader()` method"), }; }; } pub fn Parallel(comptime Value: type) type { const Slices = slices.Parallel(Value); const alignment = @alignOf(Value); return struct { allocator: std.mem.Allocator, values: Slices = .{}, cap: usize = 0, pub const Field = std.meta.FieldEnum(Value); const Self = @This(); pub fn clear(self: *Self) void { self.values = self.values.slice_all(0, 0); } pub fn deinit(self: *Self) void { var capacity_slice = self.values; capacity_slice.len = self.cap; slices.parallel_free(Value, self.allocator, capacity_slice); self.* = undefined; } pub fn get_ptr(self: Self, comptime field: Slices.Field) ?*align (alignment) Slices.Element(field) { if (self.len() == 0) { return null; } return &self.slices.field_slice(field)[self.len() - 1]; } pub fn grow(self: *Self, additional: usize) std.mem.Allocator.Error!void { const grown_capacity = self.cap + additional; const buffer = try slices.parallel_alloc(Value, self.allocator, grown_capacity); if (self.cap != 0) { slices.parallel_copy(Value, buffer.slice_all(0, self.values.len).?, self.values); slices.parallel_free(Value, self.allocator, self.values.slice_all(0, self.cap).?); } self.cap = grown_capacity; self.values = buffer.slice_all(0, self.values.len).?; } pub fn len(self: Self) usize { return self.values.len; } pub fn push_grow(self: *Self, value: Value) std.mem.Allocator.Error!void { if (self.len() == self.cap) { try self.grow(@max(1, self.cap)); } const tail_index = self.values.len; self.values.len += 1; std.debug.assert(self.values.set_all(tail_index, value)); } }; }