ona/source/coral/arena.zig

112 lines
2.6 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
2023-07-10 02:10:56 +02:00
const AllocationsList = list.Stack(usize);
2023-06-02 23:43:53 +02:00
const Page = struct {
2023-07-10 02:10:56 +02:00
buffer: []io.Byte,
2023-06-02 23:43:53 +02:00
used: usize,
2023-07-10 02:10:56 +02:00
fn available(self: Page) usize {
2023-06-02 23:43:53 +02:00
return self.buffer.len - self.used;
}
};
2023-07-10 02:10:56 +02:00
const PageList = list.Stack(Page);
2023-06-02 23:43:53 +02:00
fn allocate_page(self: *Stacking, page_size: usize) io.AllocationError!*Page {
2023-07-10 02:10:56 +02:00
var buffer = try self.page_allocator.reallocate(null, page_size);
2023-06-02 23:43:53 +02:00
2023-07-10 02:10:56 +02:00
errdefer self.page_allocator.deallocate(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 {
2023-07-10 02:10:56 +02:00
return io.Allocator.bind(Stacking, self, .{
.deallocate = deallocate,
.reallocate = reallocate,
});
2023-06-02 23:43:53 +02:00
}
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
2023-07-10 02:10:56 +02:00
pub fn free(self: *Stacking) void {
2023-06-23 00:46:48 +02:00
for (self.pages.values) |page| {
2023-07-10 02:10:56 +02:00
self.page_allocator.deallocate(page.buffer);
}
self.pages.free();
self.allocations.free();
}
pub fn deallocate(_: *Stacking, _: []io.Byte) void {
// TODO: Decide how to implement.
}
pub fn reallocate(self: *Stacking, return_address: usize, existing_allocation: ?[]io.Byte, size: usize) io.AllocationError![]io.Byte {
// TODO: Safety-check existing allocation is from allocator or null.
_ = return_address;
const alignment = @as(usize, 4);
const aligned_size = (size + alignment - 1) & ~(alignment - 1);
if (self.pages.values.len == 0) {
2023-07-22 14:57:39 +02:00
const page = try self.allocate_page(@max(self.min_page_size, aligned_size));
2023-07-10 02:10:56 +02:00
page.used = size;
return page.buffer[0 .. size];
}
var page = self.current_page() orelse unreachable;
if (page.available() <= aligned_size) {
2023-07-22 14:57:39 +02:00
page = try self.allocate_page(@max(self.min_page_size, aligned_size));
2023-07-10 02:10:56 +02:00
}
debug.assert(page.available() >= size);
defer page.used += aligned_size;
const reallocation = page.buffer[page.used .. (page.used + size)];
if (existing_allocation) |allocation| {
io.copy(reallocation, allocation);
2023-06-23 00:46:48 +02:00
}
2023-07-10 02:10:56 +02:00
return reallocation;
2023-06-23 00:46:48 +02:00
}
2023-07-10 02:10:56 +02:00
pub fn make(allocator: io.Allocator, min_page_size: usize) Stacking {
2023-06-23 00:46:48 +02:00
return Stacking{
2023-07-10 02:10:56 +02:00
.allocations = AllocationsList.make(allocator),
.pages = PageList.make(allocator),
2023-06-23 00:46:48 +02:00
.page_allocator = allocator,
.min_page_size = min_page_size,
};
}
2023-06-02 23:43:53 +02:00
};