Skip to content

Instantly share code, notes, and snippets.

@SpexGuy
Last active June 18, 2021 15:40
Show Gist options
  • Save SpexGuy/3b0047ad2f0a7d367b3b1d1145399bdf to your computer and use it in GitHub Desktop.
Save SpexGuy/3b0047ad2f0a7d367b3b1d1145399bdf to your computer and use it in GitHub Desktop.
VLA types implemented in user space in Zig
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