Last active
June 18, 2021 15:40
-
-
Save SpexGuy/3b0047ad2f0a7d367b3b1d1145399bdf to your computer and use it in GitHub Desktop.
VLA types implemented in user space in Zig
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const std = @import("std"); | |
pub fn VLA(comptime ArrayType: type, comptime ParentStruct: type, comptime fieldName: []u8) type { | |
return struct { | |
const headerSize: usize = comptime std.mem.alignForward(@sizeOf(ParentStruct), @alignOf(ArrayType)); | |
const headerAlign: u29 = comptime std.math.max(@alignOf(ArrayType), @alignOf(ParentStruct)); | |
len: usize, | |
pub fn get(self: *@This()) []ArrayType { | |
const parentStruct = @fieldParentPtr(ParentStruct, fieldName, self); | |
var tailPtr = @ptrToInt(parentStruct) + headerSize; | |
return @intToPtr([*]ArrayType, tailPtr)[0..self.len]; | |
} | |
pub fn getConst(self: *const @This()) []const ArrayType { | |
const parentStruct = @fieldParentPtr(ParentStruct, fieldName, self); | |
var tailPtr = @ptrToInt(parentStruct) + headerSize; | |
return @intToPtr([*]const ArrayType, tailPtr)[0..self.len]; | |
} | |
pub const Mixin = struct { | |
pub fn alloc(allocator: *std.mem.Allocator, len: usize) !*ParentStruct { | |
const size = headerSize + len * @sizeOf(ArrayType); | |
const mem = try allocator.alignedAlloc(u8, headerAlign, size); | |
const parentStruct = @ptrCast(*ParentStruct, mem.ptr); | |
@field(parentStruct, fieldName) = @This(){ .len = len }; | |
return parentStruct; | |
} | |
pub fn free(self: *const ParentStruct, allocator: *std.mem.Allocator) void { | |
const size = headerSize + @field(self, fieldName).len * @sizeOf(ArrayType); | |
const mem = @ptrCast([*]align(headerAlign) const u8, self)[0..size]; | |
allocator.free(mem); | |
} | |
}; | |
}; | |
} | |
pub const StructWithVLA = struct { | |
const VLAType = VLA(u8, @This(), "vla"); | |
next: ?*@This(), | |
vla: VLAType, | |
pub usingnamespace VLAType.Mixin; | |
}; | |
pub fn example(allocator: *std.mem.Allocator) !void { | |
const node0 = try StructWithVLA.alloc(allocator, 5); | |
defer node0.free(allocator); | |
node0.next = null; | |
const node1 = try StructWithVLA.alloc(allocator, 10); | |
defer node1.free(allocator); | |
node1.next = node0; | |
// do things with your nodes | |
var curr = node1; | |
while (curr.next) |next| : (curr = next) { | |
for (curr.vla.get()) |*item, i| { | |
item.* = @truncate(u8, i); | |
} | |
} | |
} | |
test "compile" { | |
_ = example; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment