ona/source/coral/arena.zig

112 lines
2.7 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 {
2023-06-23 00:46:48 +02:00
page_allocator: io.Allocator,
2023-06-02 23:43:53 +02:00
min_page_size: usize,
2023-06-23 00:46:48 +02:00
allocations: list.Stack(usize),
pages: list.Stack(Page),
2023-06-02 23:43:53 +02:00
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 {
2023-06-23 00:46:48 +02:00
var buffer = try io.allocate_many(self.page_allocator, page_size, u8);
2023-06-02 23:43:53 +02:00
2023-06-23 00:46:48 +02:00
errdefer io.deallocate(self.page_allocator, buffer);
2023-06-02 23:43:53 +02:00
2023-06-23 00:46:48 +02:00
try self.pages.push_one(.{
2023-06-02 23:43:53 +02:00
.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);
}
fn current_page(self: Stacking) ?*Page {
if (self.pages.values.len == 0) {
return null;
}
return &self.pages.values[self.pages.values.len - 1];
}
2023-06-23 00:46:48 +02:00
pub fn deinit(self: *Stacking) void {
for (self.pages.values) |page| {
io.deallocate(self.page_allocator, page.buffer);
}
self.pages.deinit();
self.allocations.deinit();
}
pub fn init(allocator: io.Allocator, min_page_size: usize) io.AllocationError!Stacking {
return Stacking{
.page_allocator = allocator,
.allocations = .{.allocator = allocator},
.pages = .{.allocator = allocator},
.min_page_size = min_page_size,
};
}
2023-06-02 23:43:53 +02:00
};