135 lines
3.5 KiB
Text
135 lines
3.5 KiB
Text
make_crash_allocator :: () -> Allocator {
|
|
return .{ proc = crash_allocator_proc };
|
|
}
|
|
|
|
crash_allocator_proc :: (mode: Allocator_Mode, size: s64, old_size: s64, old_memory: *void, allocator_data: *void) -> *void {
|
|
message: string;
|
|
|
|
if mode == {
|
|
case .ALLOCATE;
|
|
message = basic.tprint("Attempt to allocate % byte(s) using the crash allocator!", size);
|
|
case .RESIZE;
|
|
message = basic.tprint("Attempt to resize (from % to % byte(s)) using the crash allocator!", old_size, size);
|
|
case .FREE;
|
|
message = basic.tprint("Attempt to free % byte(s) using the crash allocator!", size);
|
|
}
|
|
|
|
loc := meta.get_stack_trace_caller_location();
|
|
basic.assert(false, message, loc = loc);
|
|
debug_break();
|
|
return null;
|
|
}
|
|
|
|
|
|
Arena :: struct {
|
|
memory: *void;
|
|
memory_size: u64;
|
|
offset: u64;
|
|
}
|
|
|
|
init_arena :: (a: *Arena, memory: *void, size: u64) {
|
|
a.memory = memory;
|
|
a.memory_size = size;
|
|
a.offset = 0;
|
|
}
|
|
|
|
make_arena_allocator :: (arena: *Arena) -> Allocator {
|
|
return .{
|
|
data = arena,
|
|
proc = xx arena_allocator_proc,
|
|
};
|
|
}
|
|
|
|
Extended_Allocator_Mode :: enum {
|
|
using Allocator_Mode;
|
|
|
|
request_memory :: Allocator_Mode.ALLOCATE;
|
|
resize_memory :: Allocator_Mode.RESIZE;
|
|
release_memory :: Allocator_Mode.FREE;
|
|
first_time_used :: Allocator_Mode.STARTUP;
|
|
release_everything :: Allocator_Mode.SHUTDOWN;
|
|
|
|
reset_state;
|
|
save_point; // should return *s64
|
|
restore_save_point; // 'old_size' will be the dereferenced return value of 'save_point'
|
|
}
|
|
|
|
arena_allocator_proc :: (mode: Extended_Allocator_Mode, size: s64, old_size: s64, old_memory: *void, allocator_data: *void) -> *void {
|
|
arena := allocator_data.(*Arena);
|
|
if mode == {
|
|
case .request_memory;
|
|
return arena_alloc(arena, size);
|
|
|
|
case .resize_memory;
|
|
if old_memory == null {
|
|
return arena_alloc(arena, size);
|
|
}
|
|
|
|
if size == 0 {
|
|
return null;
|
|
}
|
|
|
|
if size == old_size {
|
|
return old_memory;
|
|
}
|
|
|
|
new_memory := arena_alloc(arena, size);
|
|
memcpy(new_memory, old_memory, old_size);
|
|
return new_memory;
|
|
|
|
case .save_point;
|
|
return *arena.offset;
|
|
|
|
case .restore_save_point;
|
|
arena.offset = old_size.(u64);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
arena_alloc :: (a: *Arena, count: int, alignment := Default_Align, loc := #caller_location) -> *void {
|
|
basic.assert(a.memory != null, "arena: not initialized", loc = loc);
|
|
basic.assert(power_of_two(alignment));
|
|
|
|
end := a.memory.(*u8) + a.offset;
|
|
ptr := align_forward(end.(int), alignment);
|
|
total_size := (count + ptr.(*u8) - end.(*u8)).(u64);
|
|
|
|
basic.assert(a.offset + total_size <= a.memory_size, "arena: out of memory", loc = loc);
|
|
a.offset += total_size;
|
|
|
|
return ptr.(*void);
|
|
}
|
|
|
|
|
|
#scope_file;
|
|
|
|
basic :: #import "Basic"; // @future
|
|
meta :: #import "jc/meta";
|
|
|
|
|
|
// ----------------------------------------------------------
|
|
// TESTS
|
|
// ----------------------------------------------------------
|
|
|
|
#if RUN_TESTS {
|
|
test :: #import "jc/test";
|
|
|
|
#run {
|
|
test.run("arena:basic", t => {
|
|
memory := request_memory(1 * Kilobyte);
|
|
defer release_memory(memory);
|
|
|
|
arena: Arena;
|
|
init_arena(*arena, memory, 1 * Kilobyte);
|
|
|
|
context.allocator = make_arena_allocator(*arena);
|
|
save_point := allocator_save();
|
|
|
|
i := request_memory(int);
|
|
basic.assert(i != null);
|
|
basic.assert(arena.offset == size_of(int));
|
|
allocator_restore(save_point);
|
|
});
|
|
}
|
|
}
|