Browse Source

Add missing `Allocator_Error` and `@(require_results)` to many procedures

gingerBill 2 years ago
parent
commit
600c97cc0f
6 changed files with 153 additions and 57 deletions
  1. 33 33
      core/mem/alloc.odin
  2. 12 3
      core/mem/allocators.odin
  3. 28 0
      core/mem/mem.odin
  4. 5 1
      core/odin/ast/clone.odin
  5. 67 19
      core/slice/slice.odin
  6. 8 1
      core/slice/sort.odin

+ 33 - 33
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<<runtime.MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> T {
+@(require_results)
+make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (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)

+ 12 - 3
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,

+ 28 - 0
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)

+ 5 - 1
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)^

+ 67 - 19
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)]

+ 8 - 1
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