112 lines
2.6 KiB
Zig
112 lines
2.6 KiB
Zig
const debug = @import("./debug.zig");
|
|
|
|
const io = @import("./io.zig");
|
|
|
|
const list = @import("./list.zig");
|
|
|
|
const math = @import("./math.zig");
|
|
|
|
pub const Stacking = struct {
|
|
page_allocator: io.Allocator,
|
|
min_page_size: usize,
|
|
allocations: list.Stack(usize),
|
|
pages: list.Stack(Page),
|
|
|
|
const AllocationsList = list.Stack(usize);
|
|
|
|
const Page = struct {
|
|
buffer: []io.Byte,
|
|
used: usize,
|
|
|
|
fn available(self: Page) usize {
|
|
return self.buffer.len - self.used;
|
|
}
|
|
};
|
|
|
|
const PageList = list.Stack(Page);
|
|
|
|
fn allocate_page(self: *Stacking, page_size: usize) io.AllocationError!*Page {
|
|
var buffer = try self.page_allocator.reallocate(null, page_size);
|
|
|
|
errdefer self.page_allocator.deallocate(buffer);
|
|
|
|
try self.pages.push_one(.{
|
|
.buffer = buffer,
|
|
.used = 0,
|
|
});
|
|
|
|
return (self.current_page() orelse unreachable);
|
|
}
|
|
|
|
pub fn as_allocator(self: *Stacking) io.Allocator {
|
|
return io.Allocator.bind(Stacking, self, .{
|
|
.deallocate = deallocate,
|
|
.reallocate = reallocate,
|
|
});
|
|
}
|
|
|
|
fn current_page(self: Stacking) ?*Page {
|
|
if (self.pages.values.len == 0) {
|
|
return null;
|
|
}
|
|
|
|
return &self.pages.values[self.pages.values.len - 1];
|
|
}
|
|
|
|
pub fn free(self: *Stacking) void {
|
|
for (self.pages.values) |page| {
|
|
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) {
|
|
const page = try self.allocate_page(math.max(self.min_page_size, aligned_size));
|
|
|
|
page.used = size;
|
|
|
|
return page.buffer[0 .. size];
|
|
}
|
|
|
|
var page = self.current_page() orelse unreachable;
|
|
|
|
if (page.available() <= aligned_size) {
|
|
page = try self.allocate_page(math.max(self.min_page_size, aligned_size));
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
return reallocation;
|
|
}
|
|
|
|
pub fn make(allocator: io.Allocator, min_page_size: usize) Stacking {
|
|
return Stacking{
|
|
.allocations = AllocationsList.make(allocator),
|
|
.pages = PageList.make(allocator),
|
|
.page_allocator = allocator,
|
|
.min_page_size = min_page_size,
|
|
};
|
|
}
|
|
};
|