ona/source/coral/arena.zig

103 lines
2.5 KiB
Zig
Raw Normal View History

2023-06-02 23:43:53 +02:00
const debug = @import("./debug.zig");
const io = @import("./io.zig");
const list = @import("./list.zig");
const math = @import("./math.zig");
pub const Stacking = struct {
base_allocator: io.Allocator,
min_page_size: usize,
allocations: list.Stack(usize) = .{},
pages: list.Stack(Page) = .{},
const Page = struct {
buffer: []u8,
used: usize,
const Self = @This();
fn available(self: Self) usize {
return self.buffer.len - self.used;
}
};
pub fn allocate(self: *Stacking, allocation_size: usize) io.AllocationError![]u8 {
const alignment = @as(usize, 4);
const aligned_allocation_size = (allocation_size + alignment - 1) & ~(alignment - 1);
if (self.pages.values.len == 0) {
const page = try self.allocate_page(math.max(self.min_page_size, aligned_allocation_size));
page.used = allocation_size;
return page.buffer[0 .. allocation_size];
}
var page = self.current_page() orelse unreachable;
if (page.available() <= aligned_allocation_size) {
page = try self.allocate_page(math.max(self.min_page_size, aligned_allocation_size));
}
debug.assert(page.available() >= allocation_size);
defer page.used += aligned_allocation_size;
return page.buffer[page.used .. (page.used + allocation_size)];
}
fn allocate_page(self: *Stacking, page_size: usize) io.AllocationError!*Page {
var buffer = try io.allocate_many(self.base_allocator, page_size, u8);
2023-06-02 23:43:53 +02:00
errdefer io.deallocate(self.base_allocator, buffer);
try self.pages.push_one(self.base_allocator, .{
.buffer = buffer,
.used = 0,
});
return (self.current_page() orelse unreachable);
}
pub fn as_allocator(self: *Stacking) io.Allocator {
return io.Allocator.bind(Stacking, self, struct {
fn reallocate(stacking: *Stacking, options: io.AllocationOptions) ?[]u8 {
const allocation = options.allocation orelse {
return stacking.allocate(options.size) catch null;
};
if (allocation.len == 0) {
return null;
}
const reallocation = stacking.allocate(allocation.len) catch {
return null;
};
io.copy(reallocation, allocation);
return reallocation;
}
}.reallocate);
}
pub fn clear_allocations(self: *Stacking) void {
for (self.pages.values) |page| {
io.deallocate(self.base_allocator, page.buffer);
}
self.pages.deinit(self.base_allocator);
self.allocations.deinit(self.base_allocator);
}
fn current_page(self: Stacking) ?*Page {
if (self.pages.values.len == 0) {
return null;
}
return &self.pages.values[self.pages.values.len - 1];
}
};