Skip to content

Instantly share code, notes, and snippets.

@lassade
Created July 17, 2024 19:27
Show Gist options
  • Save lassade/efe889ae14f3f7780d26c2c3679d7bc0 to your computer and use it in GitHub Desktop.
Save lassade/efe889ae14f3f7780d26c2c3679d7bc0 to your computer and use it in GitHub Desktop.
allocates many slices with different sizes with a single allocation
pub fn SlabAllocation(comptime types: []const type) type {
var alignment: usize = 1;
var slices: [types.len]type = undefined;
for (types, 0..) |T, i| {
slices[i] = []T;
alignment = @max(alignment, @alignOf(T));
}
const out_alignment = alignment;
const Slices = std.meta.Tuple(&slices);
return struct {
blob: []align(out_alignment) u8,
slices: Slices,
pub fn deinit(self: *const @This(), allocator: std.mem.Allocator) void {
allocator.free(self.blob);
}
};
}
/// allocates many slices with different sizes with a single allocation, usage:
/// ```
/// const cube_data = try slabAlloc(allocator, &.{ MeshVert, MeshIndex }, .{ 24, 36 });
/// defer cube_data.deinit(allocator);
///
/// const verts = cube_data.slices[0];
/// const indices = cube_data.slices[1];
/// // ...
/// ```
pub fn slabAlloc(allocator: std.mem.Allocator, comptime types: []const type, sizes: anytype) !SlabAllocation(types) {
const info = comptime blk: {
const Data = struct {
size: usize,
index: usize,
alignment: usize,
fn lessThan(context: void, lhs: @This(), rhs: @This()) bool {
_ = context;
return lhs.alignment > rhs.alignment;
}
};
var data: [types.len]Data = undefined;
for (types, 0..) |T, i| {
data[i] = .{ .size = @sizeOf(T), .index = i, .alignment = @alignOf(T) };
}
std.mem.sort(Data, &data, {}, Data.lessThan);
var alignment: usize = 1;
var indexes: [types.len]usize = undefined;
for (data, 0..) |elem, i| {
indexes[i] = elem.index;
alignment = @max(alignment, elem.alignment);
}
break :blk .{ .indexes = indexes, .alignment = alignment };
};
var size: usize = 0;
inline for (types, 0..) |T, i| {
size += sizes[i] * @sizeOf(T);
}
var allocation: SlabAllocation(types) = undefined;
allocation.blob = try allocator.alignedAlloc(u8, @truncate(info.alignment), size);
var offset: usize = 0;
inline for (info.indexes) |i| {
const ptr: [*]types[i] = @ptrCast(@alignCast(allocation.blob.ptr + offset));
allocation.slices[i] = ptr[0..sizes[i]];
offset += @sizeOf(types[i]) * sizes[i];
}
return allocation;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment