ona/source/ona/heap.zig

174 lines
4.1 KiB
Zig
Raw Normal View History

const builtin = @import("builtin");
const coral = @import("coral");
const ext = @import("./ext.zig");
const std = @import("std");
2023-07-10 01:10:56 +01:00
const AllocationNode = struct {
trace: std.debug.ConfigurableTrace(2, 4, switch (builtin.mode) {
.Debug, .ReleaseSafe => true,
.ReleaseFast, .ReleaseSmall => false,
}),
next: ?*AllocationNode,
2023-06-04 02:00:31 +00:00
size: usize,
2023-07-10 01:10:56 +01:00
fn alloc(size: usize, return_address: usize) *AllocationNode {
const node = @as(*AllocationNode, @ptrCast(@alignCast(ext.SDL_malloc(@sizeOf(AllocationNode) + size))));
2023-07-10 01:10:56 +01:00
node.* = .{
.size = size,
.next = null,
.trace = .{},
};
2023-07-10 01:10:56 +01:00
node.trace.addAddr(return_address, "");
2023-07-10 01:10:56 +01:00
return node;
}
2023-07-10 01:10:56 +01:00
fn dealloc(self: *AllocationNode) void {
ext.SDL_free(self);
}
2023-07-10 01:10:56 +01:00
fn realloc(self: *AllocationNode, size: usize, return_address: usize) *AllocationNode {
const node = @as(*AllocationNode, @ptrCast(@alignCast(ext.SDL_realloc(self, @sizeOf(AllocationNode) + size))));
2023-07-10 01:10:56 +01:00
node.* = .{
.size = size,
.next = null,
.trace = .{},
};
node.trace.addAddr(return_address, "");
return node;
}
fn owns_userdata(self: *AllocationNode, other_userdata: []const coral.io.Byte) bool {
const self_userdata = self.userdata();
return self_userdata.ptr == other_userdata.ptr and self_userdata.len == other_userdata.len;
}
2023-07-10 01:10:56 +01:00
fn userdata(self: *AllocationNode) []coral.io.Byte {
return @as([*]coral.io.Byte, @ptrFromInt(@intFromPtr(self) + @sizeOf(AllocationNode)))[0 .. self.size];
}
2023-07-10 01:10:56 +01:00
};
const Context = struct {
head: ?*AllocationNode = null,
fn deallocate(self: *Context, allocation: []u8) void {
switch (builtin.mode) {
.Debug, .ReleaseSafe => {
2023-07-10 01:10:56 +01:00
const panic_message = "incorrect allocation address for deallocating";
var current_node = self.head orelse @panic(panic_message);
if (current_node.owns_userdata(allocation)) {
self.head = current_node.next;
2023-07-10 01:10:56 +01:00
return current_node.dealloc();
}
2023-07-10 01:10:56 +01:00
while (true) {
const next_node = current_node.next orelse @panic(panic_message);
2023-07-10 01:10:56 +01:00
if (next_node.owns_userdata(allocation)) {
current_node.next = next_node.next;
2023-07-10 01:10:56 +01:00
return next_node.dealloc();
}
2023-07-10 01:10:56 +01:00
current_node = next_node;
}
},
.ReleaseFast, .ReleaseSmall => {
ext.SDL_free(allocation.ptr);
},
}
}
2023-07-10 01:10:56 +01:00
fn reallocate(self: *Context, return_address: usize, existing_allocation: ?[]u8, size: usize) coral.io.AllocationError![]u8 {
switch (builtin.mode) {
.Debug, .ReleaseSafe => {
2023-07-10 01:10:56 +01:00
if (existing_allocation) |allocation| {
const panic_message = "incorrect allocation address for reallocating";
var current_node = self.head orelse @panic(panic_message);
2023-07-10 01:10:56 +01:00
if (current_node.owns_userdata(allocation)) {
const node = current_node.realloc(size, return_address);
2023-07-10 01:10:56 +01:00
self.head = node;
2023-07-10 01:10:56 +01:00
return node.userdata();
}
2023-07-10 01:10:56 +01:00
while (true) {
const next_node = current_node.next orelse @panic(panic_message);
2023-07-10 01:10:56 +01:00
if (next_node.owns_userdata(allocation)) {
const node = next_node.realloc(size, return_address);
2023-07-10 01:10:56 +01:00
current_node.next = node;
2023-07-10 01:10:56 +01:00
return node.userdata();
}
2023-07-10 01:10:56 +01:00
current_node = next_node;
}
} else {
const node = AllocationNode.alloc(size, return_address);
if (self.head) |head| {
node.next = head;
}
2023-07-10 01:10:56 +01:00
self.head = node;
return node.userdata();
}
},
.ReleaseFast, .ReleaseSmall => {
2023-07-10 01:10:56 +01:00
if (existing_allocation) |allocation | {
return @as([*]u8, ext.SDL_realloc(allocation.ptr, size) orelse {
return error.OutOfMemory;
})[0 .. size];
}
return @as([*]u8, ext.SDL_malloc(size) orelse return error.OutOfMemory)[0 .. size];
},
}
}
};
var context = Context{};
2023-07-10 01:10:56 +01:00
pub const allocator = coral.io.Allocator.bind(Context, &context, .{
.reallocate = Context.reallocate,
.deallocate = Context.deallocate,
});
pub fn trace_leaks() void {
switch (builtin.mode) {
.Debug, .ReleaseSafe => {
2023-07-22 11:03:23 +01:00
var current_node = context.head;
2023-07-22 11:03:23 +01:00
while (current_node) |node| : (current_node = node.next) {
2023-07-22 15:20:31 +01:00
std.debug.print("{d} byte leak at 0x{x} detected", .{
2023-07-22 11:03:23 +01:00
node.size,
@intFromPtr(node) + @sizeOf(AllocationNode),
});
2023-07-22 11:03:23 +01:00
node.trace.dump();
}
},
.ReleaseFast, .ReleaseSmall => {},
}
}