mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 23:58:50 +00:00
Reorganize package mem
This commit is contained in:
+4
-389
@@ -183,27 +183,13 @@ align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr {
|
||||
return uintptr(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Allocation_Header :: struct {size: int};
|
||||
|
||||
allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) {
|
||||
header.size = size;
|
||||
ptr := cast(^uint)(ptr_offset(header, 1));
|
||||
n := ptr_sub(cast(^uint)data, ptr);
|
||||
|
||||
for i in 0..n-1 {
|
||||
ptr_offset(ptr, i)^ = ~uint(0);
|
||||
}
|
||||
}
|
||||
allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
|
||||
if data == nil do return nil;
|
||||
p := cast(^uint)data;
|
||||
for ptr_offset(p, -1)^ == ~uint(0) do p = ptr_offset(p, -1);
|
||||
return (^Allocation_Header)(ptr_offset(p, -1));
|
||||
context_from_allocator :: proc(a: Allocator) -> type_of(context) {
|
||||
context.allocator = a;
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Fixed_Byte_Buffer :: distinct [dynamic]byte;
|
||||
|
||||
make_fixed_byte_buffer :: proc(backing: []byte) -> Fixed_Byte_Buffer {
|
||||
@@ -218,110 +204,6 @@ make_fixed_byte_buffer :: proc(backing: []byte) -> Fixed_Byte_Buffer {
|
||||
|
||||
|
||||
|
||||
// Custom allocators
|
||||
|
||||
Arena :: struct {
|
||||
backing: Allocator,
|
||||
memory: Fixed_Byte_Buffer,
|
||||
temp_count: int,
|
||||
}
|
||||
|
||||
Arena_Temp_Memory :: struct {
|
||||
arena: ^Arena,
|
||||
original_count: int,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
||||
backing = Allocator{};
|
||||
memory = make_fixed_byte_buffer(data);
|
||||
temp_count = 0;
|
||||
}
|
||||
|
||||
init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
||||
backing = context.allocator;
|
||||
memory = make_fixed_byte_buffer(make([]byte, size));
|
||||
temp_count = 0;
|
||||
}
|
||||
|
||||
|
||||
context_from_allocator :: proc(a: Allocator) -> type_of(context) {
|
||||
context.allocator = a;
|
||||
return context;
|
||||
}
|
||||
|
||||
destroy_arena :: proc(using a: ^Arena) {
|
||||
if backing.procedure != nil {
|
||||
context.allocator = backing;
|
||||
if memory != nil {
|
||||
free(&memory[0]);
|
||||
}
|
||||
memory = nil;
|
||||
}
|
||||
}
|
||||
|
||||
arena_allocator :: proc(arena: ^Arena) -> Allocator {
|
||||
return Allocator{
|
||||
procedure = arena_allocator_proc,
|
||||
data = arena,
|
||||
};
|
||||
}
|
||||
|
||||
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
|
||||
using Allocator_Mode;
|
||||
arena := cast(^Arena)allocator_data;
|
||||
|
||||
|
||||
switch mode {
|
||||
case Alloc:
|
||||
total_size := size + alignment;
|
||||
|
||||
if len(arena.memory) + total_size > cap(arena.memory) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
#no_bounds_check end := &arena.memory[len(arena.memory)];
|
||||
|
||||
ptr := align_forward(end, uintptr(alignment));
|
||||
(^Raw_Slice)(&arena.memory).len += total_size;
|
||||
return zero(ptr, size);
|
||||
|
||||
case Free:
|
||||
// NOTE(bill): Free all at once
|
||||
// Use Arena_Temp_Memory if you want to free a block
|
||||
|
||||
case Free_All:
|
||||
(^Raw_Slice)(&arena.memory).len = 0;
|
||||
|
||||
case Resize:
|
||||
return default_resize_align(old_memory, old_size, size, alignment, arena_allocator(arena));
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
|
||||
tmp: Arena_Temp_Memory;
|
||||
tmp.arena = a;
|
||||
tmp.original_count = len(a.memory);
|
||||
a.temp_count += 1;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
|
||||
assert(len(arena.memory) >= original_count);
|
||||
assert(arena.temp_count > 0);
|
||||
(^Raw_Dynamic_Array)(&arena.memory).len = original_count;
|
||||
arena.temp_count -= 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
align_formula :: proc(size, align: int) -> int {
|
||||
result := size + align-1;
|
||||
return result - result%align;
|
||||
@@ -350,270 +232,3 @@ calc_padding_with_header :: proc(ptr: uintptr, align: uintptr, header_size: int)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Stack_Allocation_Header :: struct {
|
||||
prev_offset: int,
|
||||
padding: int,
|
||||
}
|
||||
|
||||
// Stack is a stack-like allocator which has a strict memory freeing order
|
||||
Stack :: struct {
|
||||
data: []byte,
|
||||
prev_offset: int,
|
||||
curr_offset: int,
|
||||
peak_used: int,
|
||||
}
|
||||
|
||||
init_stack :: proc(s: ^Stack, data: []byte) {
|
||||
s.data = data;
|
||||
s.prev_offset = 0;
|
||||
s.curr_offset = 0;
|
||||
s.peak_used = 0;
|
||||
}
|
||||
|
||||
stack_allocator :: proc(stack: ^Stack) -> Allocator {
|
||||
return Allocator{
|
||||
procedure = stack_allocator_proc,
|
||||
data = stack,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
|
||||
using Allocator_Mode;
|
||||
s := cast(^Stack)allocator_data;
|
||||
|
||||
if s.data == nil {
|
||||
return nil;
|
||||
}
|
||||
|
||||
raw_alloc :: proc(s: ^Stack, size, alignment: int) -> rawptr {
|
||||
curr_addr := uintptr(&s.data[0]) + uintptr(s.curr_offset);
|
||||
padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Stack_Allocation_Header));
|
||||
if s.curr_offset + padding + size > len(s.data) {
|
||||
return nil;
|
||||
}
|
||||
s.prev_offset = s.curr_offset;
|
||||
s.curr_offset += padding;
|
||||
|
||||
next_addr := curr_addr + uintptr(padding);
|
||||
header := (^Stack_Allocation_Header)(next_addr - size_of(Stack_Allocation_Header));
|
||||
header.padding = auto_cast padding;
|
||||
header.prev_offset = auto_cast s.prev_offset;
|
||||
|
||||
s.curr_offset += size;
|
||||
|
||||
s.peak_used = max(s.peak_used, s.curr_offset);
|
||||
|
||||
return zero(rawptr(next_addr), size);
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case Alloc:
|
||||
return raw_alloc(s, size, alignment);
|
||||
case Free:
|
||||
if old_memory == nil {
|
||||
return nil;
|
||||
}
|
||||
start := uintptr(&s.data[0]);
|
||||
end := start + uintptr(len(s.data));
|
||||
curr_addr := uintptr(old_memory);
|
||||
|
||||
if !(start <= curr_addr && curr_addr < end) {
|
||||
panic("Out of bounds memory address passed to stack allocator (free)");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if curr_addr >= start+uintptr(s.curr_offset) {
|
||||
// NOTE(bill): Allow double frees
|
||||
return nil;
|
||||
}
|
||||
|
||||
header := (^Stack_Allocation_Header)(curr_addr - size_of(Stack_Allocation_Header));
|
||||
old_offset := int(curr_addr - uintptr(header.padding) - uintptr(&s.data[0]));
|
||||
|
||||
if old_offset != int(header.prev_offset) {
|
||||
panic("Out of order stack allocator free");
|
||||
return nil;
|
||||
}
|
||||
|
||||
s.curr_offset = int(old_offset);
|
||||
s.prev_offset = int(header.prev_offset);
|
||||
|
||||
|
||||
case Free_All:
|
||||
s.prev_offset = 0;
|
||||
s.curr_offset = 0;
|
||||
|
||||
case Resize:
|
||||
if old_memory == nil {
|
||||
return raw_alloc(s, size, alignment);
|
||||
}
|
||||
if size == 0 {
|
||||
return nil;
|
||||
}
|
||||
|
||||
start := uintptr(&s.data[0]);
|
||||
end := start + uintptr(len(s.data));
|
||||
curr_addr := uintptr(old_memory);
|
||||
if !(start <= curr_addr && curr_addr < end) {
|
||||
panic("Out of bounds memory address passed to stack allocator (resize)");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if curr_addr >= start+uintptr(s.curr_offset) {
|
||||
// NOTE(bill): Allow double frees
|
||||
return nil;
|
||||
}
|
||||
|
||||
if old_size == size {
|
||||
return old_memory;
|
||||
}
|
||||
|
||||
header := (^Stack_Allocation_Header)(curr_addr - size_of(Stack_Allocation_Header));
|
||||
old_offset := int(curr_addr - uintptr(header.padding) - uintptr(&s.data[0]));
|
||||
|
||||
if old_offset != int(header.prev_offset) {
|
||||
ptr := raw_alloc(s, size, alignment);
|
||||
copy(ptr, old_memory, min(old_size, size));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
old_memory_size := uintptr(s.curr_offset) - (curr_addr - start);
|
||||
assert(old_memory_size == uintptr(old_size));
|
||||
|
||||
diff := size - old_size;
|
||||
s.curr_offset += diff; // works for smaller sizes too
|
||||
if diff > 0 {
|
||||
zero(rawptr(curr_addr + uintptr(diff)), diff);
|
||||
}
|
||||
|
||||
return old_memory;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Small_Stack_Allocation_Header :: struct {
|
||||
padding: u8,
|
||||
}
|
||||
|
||||
// Small_Stack is a stack-like allocator which uses the smallest possible header but at the cost of non-strict memory freeing order
|
||||
Small_Stack :: struct {
|
||||
data: []byte,
|
||||
offset: int,
|
||||
peak_used: int,
|
||||
}
|
||||
|
||||
init_small_stack :: proc(s: ^Small_Stack, data: []byte) {
|
||||
s.data = data;
|
||||
s.offset = 0;
|
||||
s.peak_used = 0;
|
||||
}
|
||||
|
||||
small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator {
|
||||
return Allocator{
|
||||
procedure = small_stack_allocator_proc,
|
||||
data = stack,
|
||||
};
|
||||
}
|
||||
|
||||
small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
|
||||
using Allocator_Mode;
|
||||
s := cast(^Small_Stack)allocator_data;
|
||||
|
||||
if s.data == nil {
|
||||
return nil;
|
||||
}
|
||||
|
||||
raw_alloc :: proc(s: ^Small_Stack, size, alignment: int) -> rawptr {
|
||||
curr_addr := uintptr(&s.data[0]) + uintptr(s.offset);
|
||||
padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Small_Stack_Allocation_Header));
|
||||
if s.offset + padding + size > len(s.data) {
|
||||
return nil;
|
||||
}
|
||||
s.offset += padding;
|
||||
|
||||
next_addr := curr_addr + uintptr(padding);
|
||||
header := (^Small_Stack_Allocation_Header)(next_addr - size_of(Small_Stack_Allocation_Header));
|
||||
header.padding = auto_cast padding;
|
||||
|
||||
s.offset += size;
|
||||
|
||||
s.peak_used = max(s.peak_used, s.offset);
|
||||
|
||||
return zero(rawptr(next_addr), size);
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case Alloc:
|
||||
return raw_alloc(s, size, alignment);
|
||||
case Free:
|
||||
if old_memory == nil {
|
||||
return nil;
|
||||
}
|
||||
start := uintptr(&s.data[0]);
|
||||
end := start + uintptr(len(s.data));
|
||||
curr_addr := uintptr(old_memory);
|
||||
|
||||
if !(start <= curr_addr && curr_addr < end) {
|
||||
panic("Out of bounds memory address passed to stack allocator (free)");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if curr_addr >= start+uintptr(s.offset) {
|
||||
// NOTE(bill): Allow double frees
|
||||
return nil;
|
||||
}
|
||||
|
||||
header := (^Small_Stack_Allocation_Header)(curr_addr - size_of(Small_Stack_Allocation_Header));
|
||||
old_offset := int(curr_addr - uintptr(header.padding) - uintptr(&s.data[0]));
|
||||
|
||||
s.offset = int(old_offset);
|
||||
|
||||
case Free_All:
|
||||
s.offset = 0;
|
||||
|
||||
case Resize:
|
||||
if old_memory == nil {
|
||||
return raw_alloc(s, size, alignment);
|
||||
}
|
||||
if size == 0 {
|
||||
return nil;
|
||||
}
|
||||
|
||||
start := uintptr(&s.data[0]);
|
||||
end := start + uintptr(len(s.data));
|
||||
curr_addr := uintptr(old_memory);
|
||||
if !(start <= curr_addr && curr_addr < end) {
|
||||
panic("Out of bounds memory address passed to stack allocator (resize)");
|
||||
return nil;
|
||||
}
|
||||
|
||||
if curr_addr >= start+uintptr(s.offset) {
|
||||
// NOTE(bill): Treat as a double free
|
||||
return nil;
|
||||
}
|
||||
|
||||
if old_size == size {
|
||||
return old_memory;
|
||||
}
|
||||
|
||||
ptr := raw_alloc(s, size, alignment);
|
||||
copy(ptr, old_memory, min(old_size, size));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user