2024-05-29 19:27:02 +01:00
|
|
|
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 {
|
2024-06-20 21:54:00 +01:00
|
|
|
if (additional == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-05-29 19:27:02 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-06-20 21:54:00 +01:00
|
|
|
pub fn push(self: *Self, value: Value) bool {
|
2024-05-29 19:27:02 +01:00
|
|
|
if (self.values.len == self.cap) {
|
2024-06-20 21:54:00 +01:00
|
|
|
return false;
|
2024-05-29 19:27:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const offset_index = self.values.len;
|
|
|
|
|
|
|
|
self.values = self.values.ptr[0 .. self.values.len + 1];
|
|
|
|
|
|
|
|
self.values[offset_index] = value;
|
2024-06-20 21:54:00 +01:00
|
|
|
|
|
|
|
return true;
|
2024-05-29 19:27:02 +01:00
|
|
|
}
|
|
|
|
|
2024-06-20 21:54:00 +01:00
|
|
|
pub fn push_all(self: *Self, values: []const Value) bool {
|
2024-05-29 19:27:02 +01:00
|
|
|
const new_length = self.values.len + values.len;
|
|
|
|
|
|
|
|
if (new_length > self.cap) {
|
2024-06-20 21:54:00 +01:00
|
|
|
return false;
|
2024-05-29 19:27:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
2024-06-20 21:54:00 +01:00
|
|
|
|
|
|
|
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;
|
2024-05-29 19:27:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2024-06-20 21:54:00 +01:00
|
|
|
return false;
|
2024-05-29 19:27:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const offset_index = self.values.len;
|
|
|
|
|
|
|
|
self.values = self.values.ptr[0 .. new_length];
|
|
|
|
|
|
|
|
for (0 .. n) |index| {
|
|
|
|
self.values[offset_index + index] = value;
|
|
|
|
}
|
2024-06-20 21:54:00 +01:00
|
|
|
|
|
|
|
return true;
|
2024-05-29 19:27:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-06-20 21:54:00 +01:00
|
|
|
pub fn push_grow(self: *Self, value: Value) std.mem.Allocator.Error!void {
|
2024-05-29 19:27:02 +01:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|