Created
July 17, 2024 19:27
-
-
Save lassade/efe889ae14f3f7780d26c2c3679d7bc0 to your computer and use it in GitHub Desktop.
allocates many slices with different sizes with a single allocation
This file contains hidden or 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
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