153 lines
3.8 KiB
Zig
153 lines
3.8 KiB
Zig
|
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));
|
||
|
}
|
||
|
}
|