From 4ccf135892a7a89c9eb512fce38305d7f50a427f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 23 Aug 2021 12:35:29 +0100 Subject: [PATCH] Unify `new`/`make` the internal logic between runtime and mem --- core/mem/alloc.odin | 69 ++++++++++++++++++++-------------- core/mem/allocators.odin | 7 ++-- core/runtime/core_builtin.odin | 55 ++++++++++++++++----------- 3 files changed, 79 insertions(+), 52 deletions(-) diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin index cabd51733..4000ab92f 100644 --- a/core/mem/alloc.odin +++ b/core/mem/alloc.odin @@ -207,51 +207,54 @@ delete :: proc{ }; -new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> ^T { +new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) { return new_aligned(T, align_of(T), allocator, loc); } -new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> ^T { - ptr := (^T)(alloc(size_of(T), alignment, allocator, loc)); - if ptr != nil { ptr^ = T{}; } - return ptr; +new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) { + data := alloc_bytes(size_of(T), alignment, allocator, loc) or_return; + t = (^T)(raw_data(data)); + return; } new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> ^T { - ptr := (^T)(alloc(size_of(T), align_of(T), allocator, loc)); - if ptr != nil { ptr^ = data; } - return ptr; + data := alloc_bytes(size_of(T), alignment, allocator, loc) or_return; + t = (^T)(raw_data(data)); + if t != nil { + t^ = data; + } + return; } +DEFAULT_RESERVE_CAPACITY :: 16; -make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> T { +make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (slice: T, err: Allocator_Error) { + runtime.make_slice_error_loc(loc, len); + data := alloc_bytes(size_of(E)*len, alignment, allocator, loc) or_return; + if data == nil && size_of(E) != 0 { + return; + } + slice = transmute(T)Raw_Slice{raw_data(data), len}; + return; +} +make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) { return make_aligned(T, len, align_of(E), allocator, loc); } -make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> T { - runtime.make_slice_error_loc(loc, len); - data := alloc(size_of(E)*len, alignment, allocator, loc); - if data == nil && size_of(E) != 0 { - return nil; - } - zero(data, size_of(E)*len); - s := Raw_Slice{data, len}; - return transmute(T)s; +make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) { + return make_dynamic_array_len_cap(T, 0, DEFAULT_RESERVE_CAPACITY, allocator, loc); } -make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> T { - return make_dynamic_array_len_cap(T, 0, 16, allocator, loc); -} -make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> T { +make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) { return make_dynamic_array_len_cap(T, len, len, allocator, loc); } -make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> T { +make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) { runtime.make_dynamic_array_error_loc(loc, len, cap); - data := alloc(size_of(E)*cap, align_of(E), allocator, loc); - s := Raw_Dynamic_Array{data, len, cap, allocator}; + data := alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return; + s := Raw_Dynamic_Array{raw_data(data), len, cap, allocator}; if data == nil && size_of(E) != 0 { s.len, s.cap = 0, 0; } - zero(data, size_of(E)*len); - return transmute(T)s; + array = transmute(T)s; + return; } -make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 16, allocator := context.allocator, loc := #caller_location) -> T { +make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = DEFAULT_RESERVE_CAPACITY, allocator := context.allocator, loc := #caller_location) -> T { runtime.make_map_expr_error_loc(loc, cap); context.allocator = allocator; @@ -259,6 +262,15 @@ make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 16, allocator := cont reserve_map(&m, cap); return m; } +make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) { + runtime.make_slice_error_loc(loc, len); + data := alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return; + if data == nil && size_of(E) != 0 { + return; + } + mp = cast(T)raw_data(data); + return; +} make :: proc{ make_slice, @@ -266,6 +278,7 @@ make :: proc{ make_dynamic_array_len, make_dynamic_array_len_cap, make_map, + make_multi_pointer, }; diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 21e0fedb5..d497017ad 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -114,12 +114,13 @@ Scratch_Allocator :: struct { leaked_allocations: [dynamic][]byte, } -scratch_allocator_init :: proc(s: ^Scratch_Allocator, size: int, backup_allocator := context.allocator) { - s.data = make_aligned([]byte, size, 2*align_of(rawptr), backup_allocator); +scratch_allocator_init :: proc(s: ^Scratch_Allocator, size: int, backup_allocator := context.allocator) -> Allocator_Error { + s.data = make_aligned([]byte, size, 2*align_of(rawptr), backup_allocator) or_return; s.curr_offset = 0; s.prev_allocation = nil; s.backup_allocator = backup_allocator; s.leaked_allocations.allocator = backup_allocator; + return nil; } scratch_allocator_destroy :: proc(s: ^Scratch_Allocator) { @@ -188,7 +189,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, return ptr, err; } if s.leaked_allocations == nil { - s.leaked_allocations = make([dynamic][]byte, a); + s.leaked_allocations, err = make([dynamic][]byte, a); } append(&s.leaked_allocations, ptr); diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index 0fc72fd69..1cac23cf3 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -170,18 +170,22 @@ delete :: proc{ // return is a pointer to a newly allocated value of that type using the specified allocator, default is context.allocator @builtin new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_second { - ptr, err := mem_alloc(size_of(T), align_of(T), allocator, loc); - return (^T)(ptr), err; + return new_aligned(T, align_of(T), allocator, loc); +} +new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) { + data := mem_alloc_bytes(size_of(T), alignment, allocator, loc) or_return; + t = (^T)(raw_data(data)); + return; } @builtin -new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_second { - ptr, err := mem_alloc(size_of(T), align_of(T), allocator, loc); - res := (^T)(ptr); - if ptr != nil && err != .Out_Of_Memory { - res^ = data; +new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_second { + data := alloc_bytes(size_of(T), alignment, allocator, loc) or_return; + t = (^T)(raw_data(data)); + if t != nil { + t^ = data; } - return res, err; + return; } DEFAULT_RESERVE_CAPACITY :: 16; @@ -196,33 +200,30 @@ make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocat return transmute(T)s, err; } -@builtin +@(builtin) make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { return make_aligned(T, len, align_of(E), allocator, loc); } - -@builtin +@(builtin) make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { return make_dynamic_array_len_cap(T, 0, DEFAULT_RESERVE_CAPACITY, allocator, loc); } - -@builtin +@(builtin) make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { return make_dynamic_array_len_cap(T, len, len, allocator, loc); } - -@builtin -make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second { +@(builtin) +make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_second { make_dynamic_array_error_loc(loc, len, cap); - data, err := mem_alloc(size_of(E)*cap, align_of(E), allocator, loc); - s := Raw_Dynamic_Array{data, len, cap, allocator}; + data := mem_alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return; + s := Raw_Dynamic_Array{raw_data(data), len, cap, allocator}; if data == nil && size_of(E) != 0 { s.len, s.cap = 0, 0; } - return transmute(T)s, err; + array = transmute(T)s; + return; } - -@builtin +@(builtin) make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = DEFAULT_RESERVE_CAPACITY, allocator := context.allocator, loc := #caller_location) -> T { make_map_expr_error_loc(loc, cap); context.allocator = allocator; @@ -231,6 +232,17 @@ make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = DEFAULT_RESERVE_CAPAC reserve_map(&m, cap); return m; } +@(builtin) +make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) #optional_second { + make_slice_error_loc(loc, len); + data := mem_alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return; + if data == nil && size_of(E) != 0 { + return; + } + mp = cast(T)raw_data(data); + return; +} + // The make built-in procedure allocates and initializes a value of type slice, dynamic array, or map (only) // Similar to new, the first argument is a type, not a value. Unlike new, make's return type is the same as the @@ -243,6 +255,7 @@ make :: proc{ make_dynamic_array_len, make_dynamic_array_len_cap, make_map, + make_multi_pointer, };