ona/src/coral/stack.zig

275 lines
6.0 KiB
Zig

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));
}
};
}