Bewing cursed stuff... (not sure I'll bother, but I want to see if it works...)

This commit is contained in:
2025-10-11 22:46:13 -04:00
parent d25757da61
commit 983cac0660
4 changed files with 125 additions and 19 deletions

View File

@@ -81,7 +81,7 @@ AllocatorQueryFlag :: enum u64 {
Hint_Per_Frame_Temporary,
Hint_Debug_Support,
}
AllocatorError :: enum byte {
AllocatorError :: enum i32 {
None = 0,
Out_Of_Memory = 1,
Invalid_Pointer = 2,
@@ -121,37 +121,69 @@ AllocatorQueryInfo :: struct {
left: int,
max_alloc: int,
min_alloc: int,
continuity_break: b32,
alignment: i32,
}
AllocatorInfo :: struct {
procedure: AllocatorProc,
_ : struct #raw_union {
procedure: AllocatorProc,
proc_id: AllocatorProcID,
},
data: rawptr,
}
// #assert(size_of(AllocatorQueryInfo) == size_of(AllocatorProc_Out))
// Listing of every single allocator (used on hot-reloadable builds)
AllocatorProcID :: enum uintptr {
FArena,
VArena,
CArena,
Pool,
Slab,
Odin_Arena,
// Odin_VArena,
}
resolve_allocator_proc :: #force_inline proc(procedure: Odin_AllocatorProc) -> AllocatorProc {
when ODIN_DEBUG {
switch (transmute(AllocatorProcID)procedure) {
case .FArena: return nil // farena_allocator_proc
case .VArena: return nil // varena_allocaotr_proc
case .CArena: return nil // carena_allocator_proc
case .Pool: return nil // pool_allocator_proc
case .Slab: return nil // slab_allocator_proc
case .Odin_Arena: return nil // odin_arena_allocator_proc
// case .Odin_VArena: return odin_varena_allocator_proc
}
}
else {
return transmute(AllocatorProc) procedure
}
return nil
}
MEMORY_ALIGNMENT_DEFAULT :: 2 * size_of(rawptr)
allocator_query :: proc(ainfo := context.allocator) -> AllocatorQueryInfo {
assert(ainfo.procedure != nil)
out: AllocatorQueryInfo; (cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Query}, transmute(^AllocatorProc_Out) & out)
out: AllocatorQueryInfo; resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .Query}, transmute(^AllocatorProc_Out) & out)
return out
}
mem_free :: proc(mem: []byte, ainfo := context.allocator) {
assert(ainfo.procedure != nil)
(cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Free, old_allocation = mem}, & {})
resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .Free, old_allocation = mem}, & {})
}
mem_reset :: proc(ainfo := context.allocator) {
assert(ainfo.procedure != nil)
(cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Reset}, &{})
resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .Reset}, &{})
}
mem_rewind :: proc(ainfo := context.allocator, save_point: AllocatorSP) {
assert(ainfo.procedure != nil)
(cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Rewind, save_point = save_point}, & {})
resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .Rewind, save_point = save_point}, & {})
}
mem_save_point :: proc(ainfo := context.allocator) -> AllocatorSP {
assert(ainfo.procedure != nil)
out: AllocatorProc_Out
(cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .SavePoint}, & out)
resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .SavePoint}, & out)
return out.save_point
}
mem_alloc :: proc(size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte {
@@ -163,7 +195,7 @@ mem_alloc :: proc(size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero:
alignment = alignment,
}
output: AllocatorProc_Out
(cast(AllocatorProc)ainfo.procedure)(input, & output)
resolve_allocator_proc(ainfo.procedure)(input, & output)
return output.allocation
}
mem_grow :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte {
@@ -176,7 +208,7 @@ mem_grow :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAU
old_allocation = mem,
}
output: AllocatorProc_Out
(cast(AllocatorProc)ainfo.procedure)(input, & output)
resolve_allocator_proc(ainfo.procedure)(input, & output)
return output.allocation
}
mem_resize :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte {
@@ -189,7 +221,7 @@ mem_resize :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEF
old_allocation = mem,
}
output: AllocatorProc_Out
(cast(AllocatorProc)ainfo.procedure)(input, & output)
resolve_allocator_proc(ainfo.procedure)(input, & output)
return output.allocation
}
mem_shrink :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte {
@@ -202,7 +234,7 @@ mem_shrink :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEF
old_allocation = mem,
}
output: AllocatorProc_Out
(cast(AllocatorProc)ainfo.procedure)(input, & output)
resolve_allocator_proc(ainfo.procedure)(input, & output)
return output.allocation
}
@@ -215,7 +247,7 @@ alloc_type :: proc($Type: typeid, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no
alignment = alignment,
}
output: AllocatorProc_Out
(cast(AllocatorProc)ainfo.procedure)(input, & output)
resolve_allocator_proc(ainfo.procedure)(input, & output)
return transmute(^Type) raw_data(output.allocation)
}
alloc_slice :: proc($SliceType: typeid / []$Type, num : int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []Type {
@@ -227,7 +259,76 @@ alloc_slice :: proc($SliceType: typeid / []$Type, num : int, alignment: int = ME
alignment = alignment,
}
output: AllocatorProc_Out
(cast(AllocatorProc)ainfo.procedure)(input, & output)
resolve_allocator_proc(ainfo.procedure)(input, & output)
return transmute([]Type) slice(raw_data(output.allocation), num)
}
//endregion Allocator Interface
/*
Ideally we wrap all procedures that go to ideomatic odin with the following pattern:
Usually we do the following:
```
import "core:dynlib"
os_lib_load :: dynlib.load_library
```
Instead:
os_lib_load :: #force_inline proc "contextless" (... same signature as load_library, allocator := ...) { return dynlib.load_library(..., odin_ainfo_wrap(allocator)) }
*/
odin_allocator_mode_to_allocator_op :: #force_inline proc "contextless" (mode: Odin_AllocatorMode, size_diff : int) -> AllocatorOp {
switch mode {
case .Alloc: return .Alloc
case .Alloc_Non_Zeroed: return .Alloc_NoZero
case .Free: return .Free
case .Free_All: return .Reset
case .Resize: return size_diff > 0 ? .Grow : .Shrink
case .Resize_Non_Zeroed: return size_diff > 0 ? .Grow_NoZero : .Shrink
case .Query_Features: return .Query
case .Query_Info: return .Query
}
panic_contextless("Impossible path")
}
odin_allocator_wrap_proc :: proc(
allocator_data : rawptr,
mode : Odin_AllocatorMode,
size : int,
alignment : int,
old_memory : rawptr,
old_size : int,
loc := #caller_location
) -> ( data : []byte, alloc_error : Odin_AllocatorError)
{
input := AllocatorProc_In {
data = (transmute(^AllocatorInfo)allocator_data).data,
requested_size = size,
alignment = alignment,
old_allocation = slice(transmute([^]byte)old_memory, old_size),
op = odin_allocator_mode_to_allocator_op(mode, size - old_size),
}
output: AllocatorProc_Out
resolve_allocator_proc((transmute(^Odin_Allocator)allocator_data).procedure)(input, & output)
#partial switch mode {
case .Query_Features:
debug_trap() // TODO(Ed): Finish this...
return nil, nil
case .Query_Info:
info := (^Odin_AllocatorQueryInfo)(old_memory)
if info != nil && info.pointer != nil {
info.size = output.left
info.alignment = cast(int) (transmute(AllocatorQueryInfo)output).alignment
return slice(transmute(^byte)info, size_of(info^) ), nil
}
return nil, nil
}
return output.allocation, cast(Odin_AllocatorError)output.error
}
odin_ainfo_wrap :: #force_inline proc(ainfo := context.allocator) -> Odin_Allocator {
@(thread_local)
cursed_allocator_wrap_ref : Odin_Allocator
cursed_allocator_wrap_ref = {ainfo.procedure, ainfo.data}
return {odin_allocator_wrap_proc, & cursed_allocator_wrap_ref}
}

View File

@@ -21,17 +21,24 @@ import "base:runtime"
import fmt_io "core:fmt"
str_pfmt_out :: fmt_io.printf
str_pfmt_tmp :: fmt_io.tprintf
str_pfmt_tmp :: #force_inline proc(fmt: string, args: ..any, newline := false) -> string { context.temp_allocator = odin_ainfo_wrap(context.temp_allocator); return fmt_io.tprintf(fmt, ..args, newline = newline) }
str_pfmt :: fmt_io.aprintf // Decided to make aprintf the default. (It will always be the default allocator)
str_pfmt_builder :: fmt_io.sbprintf
str_pfmt_buffer :: fmt_io.bprintf
str_pfmt_file_ln :: fmt_io.fprintln
str_tmp_from_any :: fmt_io.tprint
str_tmp_from_any :: fmt_io.tprint
import "core:log"
Default_File_Logger_Opts :: log.Default_File_Logger_Opts
Logger_Full_Timestamp_Opts :: log.Full_Timestamp_Opts
import "core:mem"
Odin_AllocatorMode :: mem.Allocator_Mode
Odin_AllocatorProc :: mem.Allocator_Proc
Odin_Allocator :: mem.Allocator
Odin_AllocatorQueryInfo :: mem.Allocator_Query_Info
Odin_AllocatorError :: mem.Allocator_Error
import core_os "core:os"
FS_Open_Readonly :: core_os.O_RDONLY
FS_Open_Writeonly :: core_os.O_WRONLY

View File

@@ -22,7 +22,7 @@ main :: proc()
{
// TODO(Ed): Change this
host_scratch: mem.Arena; mem.arena_init(& host_scratch, host_memory.host_scratch[:])
context.allocator = mem.arena_allocator(& host_scratch)
context.allocator = mem.arena_allocator(& host_scratch)
context.temp_allocator = context.allocator
thread_memory.index = .Master_Prepper

View File

@@ -48,5 +48,3 @@ Kilo :: 1024
Mega :: Kilo * 1024
Giga :: Mega * 1024
Tera :: Giga * 1024