From 600c97cc0f2a9c4c5e1ccf098c95f892c35ff78a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 22 May 2023 11:26:22 +0100 Subject: [PATCH] Add missing `Allocator_Error` and `@(require_results)` to many procedures --- core/mem/alloc.odin | 66 +++++++++++++++--------------- core/mem/allocators.odin | 15 +++++-- core/mem/mem.odin | 28 +++++++++++++ core/odin/ast/clone.odin | 6 ++- core/slice/slice.odin | 86 +++++++++++++++++++++++++++++++--------- core/slice/sort.odin | 9 ++++- 6 files changed, 153 insertions(+), 57 deletions(-) diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin index c7a21dcd4..93d120c67 100644 --- a/core/mem/alloc.odin +++ b/core/mem/alloc.odin @@ -60,15 +60,18 @@ DEFAULT_PAGE_SIZE :: 16 * 1024 when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 else 4 * 1024 -alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { - data, _ := runtime.mem_alloc(size, alignment, allocator, loc) - return raw_data(data) +@(require_results) +alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) { + data, err := runtime.mem_alloc(size, alignment, allocator, loc) + return raw_data(data), err } +@(require_results) alloc_bytes :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { return runtime.mem_alloc(size, alignment, allocator, loc) } +@(require_results) alloc_bytes_non_zeroed :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { return runtime.mem_alloc_non_zeroed(size, alignment, allocator, loc) } @@ -93,15 +96,18 @@ free_all :: proc(allocator := context.allocator, loc := #caller_location) -> All return runtime.mem_free_all(allocator, loc) } -resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { - data, _ := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc) - return raw_data(data) +@(require_results) +resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) { + data, err := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc) + return raw_data(data), err } +@(require_results) resize_bytes :: proc(old_data: []byte, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { return runtime.mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc) } +@(require_results) query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) { if allocator.procedure != nil { allocator.procedure(allocator.data, .Query_Features, 0, 0, &set, 0, loc) @@ -110,6 +116,7 @@ query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: A return nil } +@(require_results) query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_location) -> (props: Allocator_Query_Info) { props.pointer = pointer if allocator.procedure != nil { @@ -146,14 +153,17 @@ delete :: proc{ } +@(require_results) new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) { return new_aligned(T, align_of(T), allocator, loc) } +@(require_results) 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 } +@(require_results) new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) { backing := alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return t = (^T)(raw_data(backing)) @@ -164,6 +174,7 @@ new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_locat return nil, .Out_Of_Memory } +@(require_results) 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 @@ -173,15 +184,19 @@ make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocat slice = transmute(T)Raw_Slice{raw_data(data), len} return } +@(require_results) 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) } +@(require_results) 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, 16, allocator, loc) } +@(require_results) 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) } +@(require_results) 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_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return @@ -192,14 +207,15 @@ make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #a array = transmute(T)s return } -make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 1< T { +@(require_results) +make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 1< (m: T, err: Allocator_Error) { runtime.make_map_expr_error_loc(loc, cap) context.allocator = allocator - m: T - reserve_map(&m, cap, loc) - return m + err = reserve_map(&m, cap, loc) + return } +@(require_results) 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 @@ -220,30 +236,14 @@ make :: proc{ } - -default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> rawptr { - if old_memory == nil { - return alloc(new_size, alignment, allocator, loc) - } - - if new_size == 0 { - free(old_memory, allocator, loc) - return nil - } - - if new_size == old_size { - return old_memory - } - - new_memory := alloc(new_size, alignment, allocator, loc) - if new_memory == nil { - return nil - } - - copy(new_memory, old_memory, min(old_size, new_size)) - free(old_memory, allocator, loc) - return new_memory +@(require_results) +default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> (res: rawptr, err: Allocator_Error) { + data: []byte + data, err = default_resize_bytes_align(([^]byte)(old_memory)[:old_size], new_size, alignment, allocator, loc) + res = raw_data(data) + return } +@(require_results) default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { old_memory := raw_data(old_data) old_size := len(old_data) diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 66da12959..8c19f1788 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -46,6 +46,7 @@ init_arena :: proc(a: ^Arena, data: []byte) { a.temp_count = 0 } +@(require_results) arena_allocator :: proc(arena: ^Arena) -> Allocator { return Allocator{ procedure = arena_allocator_proc, @@ -100,6 +101,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, return nil, nil } +@(require_results) begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory { tmp: Arena_Temp_Memory tmp.arena = a @@ -286,6 +288,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, return nil, nil } +@(require_results) scratch_allocator :: proc(allocator: ^Scratch_Allocator) -> Allocator { return Allocator{ procedure = scratch_allocator_proc, @@ -325,6 +328,7 @@ init_stack :: proc(s: ^Stack, data: []byte) { s.peak_used = 0 } +@(require_results) stack_allocator :: proc(stack: ^Stack) -> Allocator { return Allocator{ procedure = stack_allocator_proc, @@ -490,6 +494,7 @@ init_small_stack :: proc(s: ^Small_Stack, data: []byte) { s.peak_used = 0 } +@(require_results) small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator { return Allocator{ procedure = small_stack_allocator_proc, @@ -673,6 +678,7 @@ dynamic_pool_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode } +@(require_results) dynamic_pool_allocator :: proc(pool: ^Dynamic_Pool) -> Allocator { return Allocator{ procedure = dynamic_pool_allocator_proc, @@ -705,12 +711,13 @@ dynamic_pool_destroy :: proc(using pool: ^Dynamic_Pool) { } -dynamic_pool_alloc :: proc(pool: ^Dynamic_Pool, bytes: int) -> rawptr { +@(require_results) +dynamic_pool_alloc :: proc(pool: ^Dynamic_Pool, bytes: int) -> (rawptr, Allocator_Error) { data, err := dynamic_pool_alloc_bytes(pool, bytes) - assert(err == nil) - return raw_data(data) + return raw_data(data), err } +@(require_results) dynamic_pool_alloc_bytes :: proc(using pool: ^Dynamic_Pool, bytes: int) -> ([]byte, Allocator_Error) { cycle_new_block :: proc(using pool: ^Dynamic_Pool) -> (err: Allocator_Error) { if block_allocator.procedure == nil { @@ -836,6 +843,7 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, return nil, nil } +@(require_results) panic_allocator :: proc() -> Allocator { return Allocator{ procedure = panic_allocator_proc, @@ -885,6 +893,7 @@ tracking_allocator_clear :: proc(t: ^Tracking_Allocator) { } +@(require_results) tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator { return Allocator{ data = data, diff --git a/core/mem/mem.odin b/core/mem/mem.odin index bc77ca287..a06579d71 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -53,14 +53,17 @@ compare :: proc "contextless" (a, b: []byte) -> int { return res } +@(require_results) compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int #no_bounds_check { return runtime.memory_compare(a, b, n) } +@(require_results) check_zero :: proc(data: []byte) -> bool { return check_zero_ptr(raw_data(data), len(data)) } +@(require_results) check_zero_ptr :: proc(ptr: rawptr, len: int) -> bool { switch { case len <= 0: @@ -101,11 +104,13 @@ check_zero_ptr :: proc(ptr: rawptr, len: int) -> bool { return true } +@(require_results) simple_equal :: proc "contextless" (a, b: $T) -> bool where intrinsics.type_is_simple_compare(T) { a, b := a, b return compare_byte_ptrs((^byte)(&a), (^byte)(&b), size_of(T)) == 0 } +@(require_results) compare_ptrs :: proc "contextless" (a, b: rawptr, n: int) -> int { return compare_byte_ptrs((^byte)(a), (^byte)(b), n) } @@ -113,20 +118,24 @@ compare_ptrs :: proc "contextless" (a, b: rawptr, n: int) -> int { ptr_offset :: intrinsics.ptr_offset ptr_sub :: intrinsics.ptr_sub +@(require_results) slice_ptr :: proc "contextless" (ptr: ^$T, len: int) -> []T { return ([^]T)(ptr)[:len] } +@(require_results) byte_slice :: #force_inline proc "contextless" (data: rawptr, #any_int len: int) -> []byte { return ([^]u8)(data)[:max(len, 0)] } +@(require_results) slice_to_bytes :: proc "contextless" (slice: $E/[]$T) -> []byte { s := transmute(Raw_Slice)slice s.len *= size_of(T) return transmute([]byte)s } +@(require_results) slice_data_cast :: proc "contextless" ($T: typeid/[]$A, slice: $S/[]$B) -> T { when size_of(A) == 0 || size_of(B) == 0 { return nil @@ -137,11 +146,13 @@ slice_data_cast :: proc "contextless" ($T: typeid/[]$A, slice: $S/[]$B) -> T { } } +@(require_results) slice_to_components :: proc "contextless" (slice: $E/[]$T) -> (data: ^T, len: int) { s := transmute(Raw_Slice)slice return (^T)(s.data), s.len } +@(require_results) buffer_from_slice :: proc "contextless" (backing: $T/[]$E) -> [dynamic]E { return transmute([dynamic]E)Raw_Dynamic_Array{ data = raw_data(backing), @@ -154,10 +165,12 @@ buffer_from_slice :: proc "contextless" (backing: $T/[]$E) -> [dynamic]E { } } +@(require_results) ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []byte { return transmute([]byte)Raw_Slice{ptr, len*size_of(T)} } +@(require_results) any_to_bytes :: proc "contextless" (val: any) -> []byte { ti := type_info_of(val.id) size := ti != nil ? ti.size : 0 @@ -165,6 +178,7 @@ any_to_bytes :: proc "contextless" (val: any) -> []byte { } +@(require_results) is_power_of_two :: proc "contextless" (x: uintptr) -> bool { if x <= 0 { return false @@ -172,10 +186,12 @@ is_power_of_two :: proc "contextless" (x: uintptr) -> bool { return (x & (x-1)) == 0 } +@(require_results) align_forward :: proc(ptr: rawptr, align: uintptr) -> rawptr { return rawptr(align_forward_uintptr(uintptr(ptr), align)) } +@(require_results) align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr { assert(is_power_of_two(align)) @@ -187,33 +203,41 @@ align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr { return p } +@(require_results) align_forward_int :: proc(ptr, align: int) -> int { return int(align_forward_uintptr(uintptr(ptr), uintptr(align))) } +@(require_results) align_forward_uint :: proc(ptr, align: uint) -> uint { return uint(align_forward_uintptr(uintptr(ptr), uintptr(align))) } +@(require_results) align_backward :: proc(ptr: rawptr, align: uintptr) -> rawptr { return rawptr(align_backward_uintptr(uintptr(ptr), align)) } +@(require_results) align_backward_uintptr :: proc(ptr, align: uintptr) -> uintptr { return align_forward_uintptr(ptr - align + 1, align) } +@(require_results) align_backward_int :: proc(ptr, align: int) -> int { return int(align_backward_uintptr(uintptr(ptr), uintptr(align))) } +@(require_results) align_backward_uint :: proc(ptr, align: uint) -> uint { return uint(align_backward_uintptr(uintptr(ptr), uintptr(align))) } +@(require_results) context_from_allocator :: proc(a: Allocator) -> type_of(context) { context.allocator = a return context } +@(require_results) reinterpret_copy :: proc "contextless" ($T: typeid, ptr: rawptr) -> (value: T) { copy(&value, ptr, size_of(T)) return @@ -222,6 +246,7 @@ reinterpret_copy :: proc "contextless" ($T: typeid, ptr: rawptr) -> (value: T) { Fixed_Byte_Buffer :: distinct [dynamic]byte +@(require_results) make_fixed_byte_buffer :: proc "contextless" (backing: []byte) -> Fixed_Byte_Buffer { s := transmute(Raw_Slice)backing d: Raw_Dynamic_Array @@ -237,11 +262,13 @@ make_fixed_byte_buffer :: proc "contextless" (backing: []byte) -> Fixed_Byte_Buf +@(require_results) align_formula :: proc "contextless" (size, align: int) -> int { result := size + align-1 return result - result%align } +@(require_results) calc_padding_with_header :: proc "contextless" (ptr: uintptr, align: uintptr, header_size: int) -> int { p, a := ptr, align modulo := p & (a-1) @@ -267,6 +294,7 @@ calc_padding_with_header :: proc "contextless" (ptr: uintptr, align: uintptr, he +@(require_results, deprecated="prefer 'slice.clone'") clone_slice :: proc(slice: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> (new_slice: T) { new_slice, _ = make(T, len(slice), allocator, loc) runtime.copy(new_slice, slice) diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index 5ec6bc335..b8c0b8087 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -82,7 +82,11 @@ clone_node :: proc(node: ^Node) -> ^Node { panic("Cannot clone this node type") } - res := cast(^Node)mem.alloc(size, align) + res := cast(^Node)(mem.alloc(size, align) or_else nil) + if res == nil { + // allocation failure + return nil + } src: rawptr = node if node.derived != nil { src = (^rawptr)(&node.derived)^ diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 84da242e2..a8f70e333 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -13,6 +13,7 @@ _ :: mem /* Turn a pointer and a length into a slice. */ +@(require_results) from_ptr :: proc "contextless" (ptr: ^$T, count: int) -> []T { return ([^]T)(ptr)[:count] } @@ -20,6 +21,7 @@ from_ptr :: proc "contextless" (ptr: ^$T, count: int) -> []T { /* Turn a pointer and a length into a byte slice. */ +@(require_results) bytes_from_ptr :: proc "contextless" (ptr: rawptr, byte_count: int) -> []byte { return ([^]byte)(ptr)[:byte_count] } @@ -29,6 +31,7 @@ bytes_from_ptr :: proc "contextless" (ptr: rawptr, byte_count: int) -> []byte { See `slice.reinterpret` to go the other way. */ +@(require_results) to_bytes :: proc "contextless" (s: []$T) -> []byte { return ([^]byte)(raw_data(s))[:len(s) * size_of(T)] } @@ -51,10 +54,15 @@ to_bytes :: proc "contextless" (s: []$T) -> []byte { assert(len(large_items) == 1) // only enough bytes to make 1 x i64; two would need at least 8 bytes. ``` */ +@(require_results) reinterpret :: proc "contextless" ($T: typeid/[]$U, s: []$V) -> []U { - bytes := to_bytes(s) - n := len(bytes) / size_of(U) - return ([^]U)(raw_data(bytes))[:n] + when size_of(U) == 0 || size_of(B) == 0 { + return nil + } else { + bytes := to_bytes(s) + n := len(bytes) / size_of(U) + return ([^]U)(raw_data(bytes))[:n] + } } @@ -82,11 +90,13 @@ reverse :: proc(array: $T/[]$E) { } +@(require_results) contains :: proc(array: $T/[]$E, value: E) -> bool where intrinsics.type_is_comparable(E) { _, found := linear_search(array, value) return found } +@(require_results) linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) where intrinsics.type_is_comparable(T) #no_bounds_check { for x, i in array { @@ -97,6 +107,7 @@ linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) return -1, false } +@(require_results) linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, found: bool) #no_bounds_check { for x, i in array { if f(x) { @@ -106,6 +117,7 @@ linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, f return -1, false } +@(require_results) binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) where intrinsics.type_is_ordered(T) #no_bounds_check { @@ -146,6 +158,7 @@ binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) } +@(require_results) equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) { if len(a) != len(b) { return false @@ -162,6 +175,7 @@ equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) { } } +@(require_results) simple_equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_simple_compare(E) { if len(a) != len(b) { return false @@ -176,6 +190,7 @@ simple_equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_simple_comp slice.prefix_length([]u8{1, 2, 3, 4}, []u8{1, 2, 3}) -> 3 slice.prefix_length([]u8{1, 2, 3, 4}, []u8{2, 3, 4}) -> 0 */ +@(require_results) prefix_length :: proc(a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_comparable(E) { _len := builtin.min(len(a), len(b)) @@ -185,6 +200,7 @@ prefix_length :: proc(a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_compar return } +@(require_results) has_prefix :: proc(array: $T/[]$E, needle: E) -> bool where intrinsics.type_is_comparable(E) { n := len(needle) if len(array) >= n { @@ -194,6 +210,7 @@ has_prefix :: proc(array: $T/[]$E, needle: E) -> bool where intrinsics.type_is_c } +@(require_results) has_suffix :: proc(array: $T/[]$E, needle: E) -> bool where intrinsics.type_is_comparable(E) { array := array m, n := len(array), len(needle) @@ -232,7 +249,8 @@ swap_with_slice :: proc(a, b: $T/[]$E, loc := #caller_location) { ptr_swap_non_overlapping(raw_data(a), raw_data(b), len(a)*size_of(E)) } -concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T) { +@(require_results) +concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T, err: mem.Allocator_Error) #optional_allocator_error { if len(a) == 0 { return } @@ -240,7 +258,7 @@ concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T) { for s in a { n += len(s) } - res = make(T, n, allocator) + res = make(T, n, allocator) or_return i := 0 for s in a { i += copy(res[i:], s) @@ -249,22 +267,24 @@ concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T) { } // copies a slice into a new slice -clone :: proc(a: $T/[]$E, allocator := context.allocator) -> []E { - d := make([]E, len(a), allocator) +@(require_results) +clone :: proc(a: $T/[]$E, allocator := context.allocator) -> ([]E, mem.Allocator_Error) #optional_allocator_error { + d, err := make([]E, len(a), allocator) copy(d[:], a) - return d + return d, err } // copies slice into a new dynamic array -clone_to_dynamic :: proc(a: $T/[]$E, allocator := context.allocator) -> [dynamic]E { - d := make([dynamic]E, len(a), allocator) +clone_to_dynamic :: proc(a: $T/[]$E, allocator := context.allocator) -> ([dynamic]E, mem.Allocator_Error) #optional_allocator_error { + d, err := make([dynamic]E, len(a), allocator) copy(d[:], a) - return d + return d, err } to_dynamic :: clone_to_dynamic // Converts slice into a dynamic array without cloning or allocating memory +@(require_results) into_dynamic :: proc(a: $T/[]$E) -> [dynamic]E { s := transmute(mem.Raw_Slice)a d := mem.Raw_Dynamic_Array{ @@ -277,43 +297,51 @@ into_dynamic :: proc(a: $T/[]$E) -> [dynamic]E { } +@(require_results) length :: proc(a: $T/[]$E) -> int { return len(a) } +@(require_results) is_empty :: proc(a: $T/[]$E) -> bool { return len(a) == 0 } - +@(require_results) split_at :: proc(array: $T/[]$E, index: int) -> (a, b: T) { return array[:index], array[index:] } +@(require_results) split_first :: proc(array: $T/[]$E) -> (first: E, rest: T) { return array[0], array[1:] } +@(require_results) split_last :: proc(array: $T/[]$E) -> (rest: T, last: E) { n := len(array)-1 return array[:n], array[n] } +@(require_results) first :: proc(array: $T/[]$E) -> E { return array[0] } +@(require_results) last :: proc(array: $T/[]$E) -> E { return array[len(array)-1] } +@(require_results) first_ptr :: proc(array: $T/[]$E) -> ^E { if len(array) != 0 { return &array[0] } return nil } +@(require_results) last_ptr :: proc(array: $T/[]$E) -> ^E { if len(array) != 0 { return &array[len(array)-1] @@ -321,6 +349,7 @@ last_ptr :: proc(array: $T/[]$E) -> ^E { return nil } +@(require_results) get :: proc(array: $T/[]$E, index: int) -> (value: E, ok: bool) { if uint(index) < len(array) { value = array[index] @@ -328,6 +357,7 @@ get :: proc(array: $T/[]$E, index: int) -> (value: E, ok: bool) { } return } +@(require_results) get_ptr :: proc(array: $T/[]$E, index: int) -> (value: ^E, ok: bool) { if uint(index) < len(array) { value = &array[index] @@ -336,19 +366,22 @@ get_ptr :: proc(array: $T/[]$E, index: int) -> (value: ^E, ok: bool) { return } +@(require_results) as_ptr :: proc(array: $T/[]$E) -> [^]E { return raw_data(array) } -mapper :: proc(s: $S/[]$U, f: proc(U) -> $V, allocator := context.allocator) -> []V { - r := make([]V, len(s), allocator) +@(require_results) +mapper :: proc(s: $S/[]$U, f: proc(U) -> $V, allocator := context.allocator) -> (r: []V, err: mem.Allocator_Error) #optional_allocator_error { + r = make([]V, len(s), allocator) or_return for v, i in s { r[i] = f(v) } - return r + return } +@(require_results) reduce :: proc(s: $S/[]$U, initializer: $V, f: proc(V, U) -> V) -> V { r := initializer for v in s { @@ -357,6 +390,7 @@ reduce :: proc(s: $S/[]$U, initializer: $V, f: proc(V, U) -> V) -> V { return r } +@(require_results) filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -> S { r := make([dynamic]U, 0, 0, allocator) for v in s { @@ -367,10 +401,11 @@ filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) - return r[:] } -scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := context.allocator) -> []V { - if len(s) == 0 { return {} } +@(require_results) +scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := context.allocator) -> (res: []V, err: mem.Allocator_Error) #optional_allocator_error { + if len(s) == 0 { return } - res := make([]V, len(s), allocator) + res = make([]V, len(s), allocator) or_return p := as_ptr(s) q := as_ptr(res) r := initializer @@ -382,10 +417,11 @@ scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := c q = q[1:] } - return res + return } +@(require_results) min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok { if len(s) != 0 { res = s[0] @@ -396,6 +432,7 @@ min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T } return } +@(require_results) max :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok { if len(s) != 0 { res = s[0] @@ -407,6 +444,7 @@ max :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T return } +@(require_results) min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_ordered(T) { if len(s) != 0 { min, max = s[0], s[0] @@ -419,6 +457,7 @@ min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_ return } +@(require_results) any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { for v in s { if v == value { @@ -428,6 +467,7 @@ any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable return false } +@(require_results) none_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { for v in s { if v == value { @@ -437,6 +477,7 @@ none_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparabl return true } +@(require_results) all_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { if len(s) == 0 { return false @@ -450,6 +491,7 @@ all_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable } +@(require_results) any_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool { for v in s { if f(v) { @@ -459,6 +501,7 @@ any_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool { return false } +@(require_results) none_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool { for v in s { if f(v) { @@ -468,6 +511,7 @@ none_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool { return true } +@(require_results) all_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool { if len(s) == 0 { return false @@ -481,6 +525,7 @@ all_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool { } +@(require_results) count :: proc(s: $S/[]$T, value: T) -> (n: int) where intrinsics.type_is_comparable(T) { for v in s { if v == value { @@ -490,6 +535,7 @@ count :: proc(s: $S/[]$T, value: T) -> (n: int) where intrinsics.type_is_compara return } +@(require_results) count_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> (n: int) { for v in s { if f(v) { @@ -500,6 +546,7 @@ count_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> (n: int) { } +@(require_results) dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool) where intrinsics.type_is_numeric(T) { if len(a) != len(b) { @@ -513,6 +560,7 @@ dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool) // Convert a pointer to an enumerated array to a slice of the element type +@(require_results) enumerated_array :: proc(ptr: ^$T) -> []intrinsics.type_elem_type(T) where intrinsics.type_is_enumerated_array(T) { return ([^]intrinsics.type_elem_type(T))(ptr)[:len(T)] diff --git a/core/slice/sort.odin b/core/slice/sort.odin index b146e03c3..515eddcc3 100644 --- a/core/slice/sort.odin +++ b/core/slice/sort.odin @@ -6,6 +6,7 @@ Ordering :: enum { Greater = +1, } +@(require_results) cmp :: proc(a, b: $E) -> Ordering where ORD(E) { switch { case a < b: @@ -16,6 +17,7 @@ cmp :: proc(a, b: $E) -> Ordering where ORD(E) { return .Equal } +@(require_results) cmp_proc :: proc($E: typeid) -> (proc(E, E) -> Ordering) where ORD(E) { return proc(a, b: E) -> Ordering { switch { @@ -144,6 +146,7 @@ stable_sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) { } } +@(require_results) is_sorted :: proc(array: $T/[]$E) -> bool where ORD(E) { for i := len(array)-1; i > 0; i -= 1 { if array[i] < array[i-1] { @@ -153,6 +156,7 @@ is_sorted :: proc(array: $T/[]$E) -> bool where ORD(E) { return true } +@(require_results) is_sorted_by :: proc(array: $T/[]$E, less: proc(i, j: E) -> bool) -> bool { for i := len(array)-1; i > 0; i -= 1 { if less(array[i], array[i-1]) { @@ -163,6 +167,8 @@ is_sorted_by :: proc(array: $T/[]$E, less: proc(i, j: E) -> bool) -> bool { } is_sorted_by_cmp :: is_sorted_cmp + +@(require_results) is_sorted_cmp :: proc(array: $T/[]$E, cmp: proc(i, j: E) -> Ordering) -> bool { for i := len(array)-1; i > 0; i -= 1 { if cmp(array[i], array[i-1]) == .Less { @@ -215,6 +221,7 @@ reverse_sort_by_key :: proc(data: $T/[]$E, key: proc(E) -> $K) where ORD(K) { }) } +@(require_results) is_sorted_by_key :: proc(array: $T/[]$E, key: proc(E) -> $K) -> bool where ORD(K) { for i := len(array)-1; i > 0; i -= 1 { if key(array[i]) < key(array[i-1]) { @@ -224,7 +231,7 @@ is_sorted_by_key :: proc(array: $T/[]$E, key: proc(E) -> $K) -> bool where ORD(K return true } -@(private) +@(private, require_results) _max_depth :: proc(n: int) -> (depth: int) { // 2*ceil(log2(n+1)) for i := n; i > 0; i >>= 1 { depth += 1