ona/source/coral/arena.zig

117 lines
2.9 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 {
allocator: io.Allocator,
min_region_size: usize,
head_region: ?*Region,
tail_region: ?*Region,
2023-06-02 23:43:53 +02:00
const Region = struct {
next: ?*Region,
count: usize,
capacity: usize,
2023-07-10 02:10:56 +02:00
fn allocate(self: *Region, region_size: usize) []usize {
debug.assert(self.can_allocate(region_size));
2023-06-02 23:43:53 +02:00
const offset = (@sizeOf(Region) / @alignOf(usize)) + self.count;
const allocation = @as([*]usize, @ptrCast(self))[offset .. (offset + region_size)];
self.count += region_size;
return allocation;
2023-06-02 23:43:53 +02:00
}
fn as_raw(self: *Region) []usize {
return @as([*]usize, @ptrCast(self))[0 .. ((@sizeOf(Region) / @alignOf(usize)) + self.capacity)];
}
2023-06-02 23:43:53 +02:00
fn can_allocate(self: Region, region_size: usize) bool {
return (self.count + region_size) <= self.capacity;
}
};
2023-06-02 23:43:53 +02:00
fn allocate_region(self: *Stacking, requested_region_size: usize) io.AllocationError!*Region {
const region_size = @max(requested_region_size, self.min_region_size);
const region = @as(*Region, @ptrCast(@alignCast(try self.allocator.reallocate(null, @alignOf(Region) + (@alignOf(usize) * region_size)))));
2023-06-02 23:43:53 +02:00
region.* = .{
.next = null,
.count = 0,
.capacity = region_size,
};
2023-06-02 23:43:53 +02:00
return region;
2023-06-02 23:43:53 +02:00
}
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
}
2023-11-12 14:09:30 +01:00
pub fn deinit(self: *Stacking) void {
while (self.head_region) |region| {
const next_region = region.next;
2023-06-02 23:43:53 +02:00
self.allocator.deallocate(region.as_raw());
2023-06-23 00:46:48 +02:00
self.head_region = next_region;
2023-07-10 02:10:56 +02:00
}
self.head_region = null;
self.tail_region = null;
2023-07-10 02:10:56 +02:00
}
fn deallocate(_: *Stacking, _: []io.Byte) void {
2023-07-10 02:10:56 +02:00
// TODO: Decide how to implement.
unreachable;
2023-07-10 02:10:56 +02:00
}
2023-11-12 14:09:30 +01:00
pub fn init(allocator: io.Allocator, min_region_size: usize) Stacking {
return Stacking{
.allocator = allocator,
.min_region_size = min_region_size,
.head_region = null,
.tail_region = null,
};
}
fn reallocate(self: *Stacking, _: usize, allocation: ?[]io.Byte, byte_size: usize) io.AllocationError![]io.Byte {
if (allocation) |buffer| {
if (byte_size < buffer.len) {
return buffer[0 .. byte_size];
}
2023-07-10 02:10:56 +02:00
}
const region_size = (byte_size + @sizeOf(usize) - 1) / @sizeOf(usize);
2023-07-10 02:10:56 +02:00
const tail_region = self.tail_region orelse {
const region = try self.allocate_region(region_size);
2023-07-10 02:10:56 +02:00
self.tail_region = region;
self.head_region = self.tail_region;
return @as([*]io.Byte, @ptrCast(region.allocate(region_size)))[0 .. byte_size];
};
2023-07-10 02:10:56 +02:00
if (!tail_region.can_allocate(region_size)) {
const region = try self.allocate_region(region_size);
2023-07-10 02:10:56 +02:00
tail_region.next = region;
self.tail_region = region;
2023-07-10 02:10:56 +02:00
return @as([*]io.Byte, @ptrCast(region.allocate(region_size)))[0 .. byte_size];
2023-06-23 00:46:48 +02:00
}
return @as([*]io.Byte, @ptrCast(tail_region.allocate(region_size)))[0 .. byte_size];
2023-06-23 00:46:48 +02:00
}
2023-06-02 23:43:53 +02:00
};