ona/src/coral/slices.zig

153 lines
3.8 KiB
Zig
Raw Normal View History

const io = @import("./io.zig");
const std = @import("std");
pub fn ElementPtr(comptime Slice: type) type {
const pointer_info = @typeInfo(Slice).Pointer;
return @Type(.{
.Pointer = .{
.size = .One,
.is_const = pointer_info.is_const,
.is_volatile = pointer_info.is_volatile,
.alignment = pointer_info.alignment,
.address_space = pointer_info.address_space,
.child = pointer_info.child,
.is_allowzero = false,
.sentinel = null,
},
});
}
pub fn Parallel(comptime Type: type) type {
const fields = @typeInfo(Type).Struct.fields;
const alignment = @alignOf(Type);
return struct {
len: usize = 0,
ptrs: [fields.len][*]align (alignment) io.Byte = undefined,
pub fn Element(comptime field: Field) type {
return fields[@intFromEnum(field)].type;
}
pub const Field = std.meta.FieldEnum(Type);
const Self = @This();
const all_fields = std.enums.values(Field);
pub fn ptr(self: Self, comptime field: Field) [*]align (alignment) Element(field) {
return @as([*]align (alignment) Element(field), @ptrCast(self.ptrs[@intFromEnum(field)]));
}
pub fn slice(self: Self, comptime field: Field) []align (alignment) Element(field) {
return self.ptr(field)[0 .. self.len];
}
pub fn slice_all(self: Self, off: usize, len: usize) ?Self {
if (len > self.len or off > len) {
return null;
}
var sliced = Self{.len = len};
inline for (0 .. fields.len) |i| {
sliced.ptrs[i] = @ptrFromInt(@intFromPtr(self.ptrs[i]) + (@sizeOf(Element(all_fields[i])) * off));
}
return sliced;
}
pub fn get(self: Self, comptime field: Field, index: usize) ?Element(field) {
if (index >= self.len) {
return null;
}
return self.ptr(field)[index];
}
pub fn get_ptr(self: Self, comptime field: Field, index: usize) ?*Element(field) {
if (index >= self.len) {
return null;
}
return &self.ptr(field)[index];
}
pub fn set(self: Self, comptime field: Field, index: usize, value: Element(field)) bool {
if (index >= self.len) {
return false;
}
self.slice(field)[index] = value;
return true;
}
pub fn set_all(self: Self, index: usize, value: Type) bool {
if (index >= self.len) {
return false;
}
inline for (0 .. fields.len) |i| {
self.slice(all_fields[i])[index] = @field(value, fields[i].name);
}
return true;
}
};
}
pub fn get(slice: anytype, index: usize) ?@typeInfo(@TypeOf(slice)).Pointer.child {
if (index >= slice.len) {
return null;
}
return slice[index];
}
pub fn get_ptr(slice: anytype, index: usize) ?ElementPtr(@TypeOf(slice)) {
if (index >= slice.len) {
return null;
}
return &slice[index];
}
pub fn parallel_alloc(comptime Element: type, allocator: std.mem.Allocator, n: usize) std.mem.Allocator.Error!Parallel(Element) {
const alignment = @alignOf(Element);
const Slices = Parallel(Element);
var buffers = @as([std.enums.values(Slices.Field).len][]align (alignment) io.Byte, undefined);
var buffers_allocated = @as(usize, 0);
var allocated = Slices{.len = n};
errdefer {
for (0 .. buffers_allocated) |i| {
allocator.free(buffers[i]);
}
}
const fields = @typeInfo(Element).Struct.fields;
inline for (0 .. fields.len) |i| {
buffers[i] = try allocator.alignedAlloc(io.Byte, alignment, @sizeOf(fields[i].type) * n);
buffers_allocated += 1;
allocated.ptrs[i] = buffers[i].ptr;
}
return allocated;
}
pub fn parallel_copy(comptime Element: type, target: Parallel(Element), origin: Parallel(Element)) void {
inline for (comptime std.enums.values(Parallel(Element).Field)) |field| {
@memcpy(target.slice(field), origin.slice(field));
}
}
pub fn parallel_free(comptime Element: type, allocator: std.mem.Allocator, buffers: Parallel(Element)) void {
inline for (comptime std.enums.values(Parallel(Element).Field)) |field| {
allocator.free(buffers.slice(field));
}
}