Bewing cursed stuff... (not sure I'll bother, but I want to see if it works...)
This commit is contained in:
@@ -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}
|
||||
}
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user