Browse Source

Improve error handling for `resize` and `reserve` procedures

gingerBill 2 years ago
parent
commit
1e17f44991

+ 4 - 8
core/compress/shoco/shoco.odin

@@ -177,12 +177,10 @@ decompress_slice_to_string :: proc(input: []u8, model := DEFAULT_MODEL, allocato
 	max_output_size := decompress_bound(len(input), model)
 	max_output_size := decompress_bound(len(input), model)
 
 
 	buf: [dynamic]u8
 	buf: [dynamic]u8
-	if !resize(&buf, max_output_size) {
-		return "", .Out_Of_Memory
-	}
+	resize(&buf, max_output_size) or_return
 
 
 	length, result := decompress_slice_to_output_buffer(input, buf[:])
 	length, result := decompress_slice_to_output_buffer(input, buf[:])
-	resize(&buf, length)
+	resize(&buf, length) or_return
 	return string(buf[:]), result
 	return string(buf[:]), result
 }
 }
 decompress :: proc{decompress_slice_to_output_buffer, decompress_slice_to_string}
 decompress :: proc{decompress_slice_to_output_buffer, decompress_slice_to_string}
@@ -307,12 +305,10 @@ compress_string :: proc(input: string, model := DEFAULT_MODEL, allocator := cont
 	max_output_size := compress_bound(len(input))
 	max_output_size := compress_bound(len(input))
 
 
 	buf: [dynamic]u8
 	buf: [dynamic]u8
-	if !resize(&buf, max_output_size) {
-		return {}, .Out_Of_Memory
-	}
+	resize(&buf, max_output_size) or_return
 
 
 	length, result := compress_string_to_buffer(input, buf[:])
 	length, result := compress_string_to_buffer(input, buf[:])
-	resize(&buf, length)
+	resize(&buf, length) or_return
 	return buf[:length], result
 	return buf[:length], result
 }
 }
 compress :: proc{compress_string_to_buffer, compress_string}
 compress :: proc{compress_string_to_buffer, compress_string}

+ 5 - 5
core/image/common.odin

@@ -634,7 +634,7 @@ alpha_add_if_missing :: proc(img: ^Image, alpha_key := Alpha_Key{}, allocator :=
 	buf := bytes.Buffer{}
 	buf := bytes.Buffer{}
 
 
 	// Can we allocate the return buffer?
 	// Can we allocate the return buffer?
-	if !resize(&buf.buf, bytes_wanted) {
+	if resize(&buf.buf, bytes_wanted) != nil {
 		delete(buf.buf)
 		delete(buf.buf)
 		return false
 		return false
 	}
 	}
@@ -826,7 +826,7 @@ alpha_drop_if_present :: proc(img: ^Image, options := Options{}, alpha_key := Al
 	buf := bytes.Buffer{}
 	buf := bytes.Buffer{}
 
 
 	// Can we allocate the return buffer?
 	// Can we allocate the return buffer?
-	if !resize(&buf.buf, bytes_wanted) {
+	if resize(&buf.buf, bytes_wanted) != nil {
 		delete(buf.buf)
 		delete(buf.buf)
 		return false
 		return false
 	}
 	}
@@ -1075,7 +1075,7 @@ apply_palette_rgb :: proc(img: ^Image, palette: [256]RGB_Pixel, allocator := con
 	// Can we allocate the return buffer?
 	// Can we allocate the return buffer?
 	buf := bytes.Buffer{}
 	buf := bytes.Buffer{}
 	bytes_wanted := compute_buffer_size(img.width, img.height, 3, 8)
 	bytes_wanted := compute_buffer_size(img.width, img.height, 3, 8)
-	if !resize(&buf.buf, bytes_wanted) {
+	if resize(&buf.buf, bytes_wanted) != nil {
 		delete(buf.buf)
 		delete(buf.buf)
 		return false
 		return false
 	}
 	}
@@ -1112,7 +1112,7 @@ apply_palette_rgba :: proc(img: ^Image, palette: [256]RGBA_Pixel, allocator := c
 	// Can we allocate the return buffer?
 	// Can we allocate the return buffer?
 	buf := bytes.Buffer{}
 	buf := bytes.Buffer{}
 	bytes_wanted := compute_buffer_size(img.width, img.height, 4, 8)
 	bytes_wanted := compute_buffer_size(img.width, img.height, 4, 8)
-	if !resize(&buf.buf, bytes_wanted) {
+	if resize(&buf.buf, bytes_wanted) != nil {
 		delete(buf.buf)
 		delete(buf.buf)
 		return false
 		return false
 	}
 	}
@@ -1147,7 +1147,7 @@ expand_grayscale :: proc(img: ^Image, allocator := context.allocator) -> (ok: bo
 	// Can we allocate the return buffer?
 	// Can we allocate the return buffer?
 	buf := bytes.Buffer{}
 	buf := bytes.Buffer{}
 	bytes_wanted := compute_buffer_size(img.width, img.height, img.channels + 2, img.depth)
 	bytes_wanted := compute_buffer_size(img.width, img.height, img.channels + 2, img.depth)
-	if !resize(&buf.buf, bytes_wanted) {
+	if resize(&buf.buf, bytes_wanted) != nil {
 		delete(buf.buf)
 		delete(buf.buf)
 		return false
 		return false
 	}
 	}

+ 5 - 5
core/image/png/png.odin

@@ -731,7 +731,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 		// We need to create a new image buffer
 		// We need to create a new image buffer
 		dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8)
 		dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8)
 		t := bytes.Buffer{}
 		t := bytes.Buffer{}
-		if !resize(&t.buf, dest_raw_size) {
+		if resize(&t.buf, dest_raw_size) != nil {
 			return {}, .Unable_To_Allocate_Or_Resize
 			return {}, .Unable_To_Allocate_Or_Resize
 		}
 		}
 
 
@@ -812,7 +812,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 		// We need to create a new image buffer
 		// We need to create a new image buffer
 		dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 16)
 		dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 16)
 		t := bytes.Buffer{}
 		t := bytes.Buffer{}
-		if !resize(&t.buf, dest_raw_size) {
+		if resize(&t.buf, dest_raw_size) != nil {
 			return {}, .Unable_To_Allocate_Or_Resize
 			return {}, .Unable_To_Allocate_Or_Resize
 		}
 		}
 
 
@@ -1011,7 +1011,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 		// We need to create a new image buffer
 		// We need to create a new image buffer
 		dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8)
 		dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8)
 		t := bytes.Buffer{}
 		t := bytes.Buffer{}
-		if !resize(&t.buf, dest_raw_size) {
+		if resize(&t.buf, dest_raw_size) != nil {
 			return {}, .Unable_To_Allocate_Or_Resize
 			return {}, .Unable_To_Allocate_Or_Resize
 		}
 		}
 
 
@@ -1522,7 +1522,7 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
 	bytes_per_channel := depth == 16 ? 2 : 1
 	bytes_per_channel := depth == 16 ? 2 : 1
 
 
 	num_bytes := compute_buffer_size(width, height, channels, depth == 16 ? 16 : 8)
 	num_bytes := compute_buffer_size(width, height, channels, depth == 16 ? 16 : 8)
-	if !resize(&img.pixels.buf, num_bytes) {
+	if resize(&img.pixels.buf, num_bytes) != nil {
 		return .Unable_To_Allocate_Or_Resize
 		return .Unable_To_Allocate_Or_Resize
 	}
 	}
 
 
@@ -1564,7 +1564,7 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
 			if x > 0 && y > 0 {
 			if x > 0 && y > 0 {
 				temp: bytes.Buffer
 				temp: bytes.Buffer
 				temp_len := compute_buffer_size(x, y, channels, depth == 16 ? 16 : 8)
 				temp_len := compute_buffer_size(x, y, channels, depth == 16 ? 16 : 8)
-				if !resize(&temp.buf, temp_len) {
+				if resize(&temp.buf, temp_len) != nil {
 					return .Unable_To_Allocate_Or_Resize
 					return .Unable_To_Allocate_Or_Resize
 				}
 				}
 
 

+ 2 - 2
core/image/qoi/qoi.odin

@@ -53,7 +53,7 @@ save_to_buffer  :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}
 	// Calculate and allocate maximum size. We'll reclaim space to actually written output at the end.
 	// Calculate and allocate maximum size. We'll reclaim space to actually written output at the end.
 	max_size := pixels * (img.channels + 1) + size_of(image.QOI_Header) + size_of(u64be)
 	max_size := pixels * (img.channels + 1) + size_of(image.QOI_Header) + size_of(u64be)
 
 
-	if !resize(&output.buf, max_size) {
+	if resize(&output.buf, max_size) != nil {
 		return .Unable_To_Allocate_Or_Resize
 		return .Unable_To_Allocate_Or_Resize
 	}
 	}
 
 
@@ -233,7 +233,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 
 
 	bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), img.channels, 8)
 	bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), img.channels, 8)
 
 
-	if !resize(&img.pixels.buf, bytes_needed) {
+	if resize(&img.pixels.buf, bytes_needed) != nil {
 	 	return img, .Unable_To_Allocate_Or_Resize
 	 	return img, .Unable_To_Allocate_Or_Resize
 	}
 	}
 
 

+ 2 - 2
core/image/tga/tga.odin

@@ -57,7 +57,7 @@ save_to_buffer  :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}
 	// Calculate and allocate necessary space.
 	// Calculate and allocate necessary space.
 	necessary := pixels * img.channels + size_of(image.TGA_Header)
 	necessary := pixels * img.channels + size_of(image.TGA_Header)
 
 
-	if !resize(&output.buf, necessary) {
+	if resize(&output.buf, necessary) != nil {
 		return .Unable_To_Allocate_Or_Resize
 		return .Unable_To_Allocate_Or_Resize
 	}
 	}
 
 
@@ -292,7 +292,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 		return img, nil
 		return img, nil
 	}
 	}
 
 
-	if !resize(&img.pixels.buf, dest_channels * img.width * img.height) {
+	if resize(&img.pixels.buf, dest_channels * img.width * img.height) != nil {
 		return img, .Unable_To_Allocate_Or_Resize
 		return img, .Unable_To_Allocate_Or_Resize
 	}
 	}
 
 

+ 69 - 68
core/runtime/core_builtin.odin

@@ -289,10 +289,9 @@ reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) ->
 	Shrinks the capacity of a map down to the current length.
 	Shrinks the capacity of a map down to the current length.
 */
 */
 @builtin
 @builtin
-shrink_map :: proc(m: ^$T/map[$K]$V, loc := #caller_location) -> (did_shrink: bool) {
+shrink_map :: proc(m: ^$T/map[$K]$V, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
 	if m != nil {
 	if m != nil {
-		err := map_shrink_dynamic((^Raw_Map)(m), map_info(T), loc)
-		did_shrink = err == nil
+		return map_shrink_dynamic((^Raw_Map)(m), map_info(T), loc)
 	}
 	}
 	return
 	return
 }
 }
@@ -315,18 +314,18 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
 
 
 
 
 @builtin
 @builtin
-append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> int {
+append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
 	if array == nil {
 	if array == nil {
-		return 0
+		return 0, nil
 	}
 	}
 	when size_of(E) == 0 {
 	when size_of(E) == 0 {
 		array := (^Raw_Dynamic_Array)(array)
 		array := (^Raw_Dynamic_Array)(array)
 		array.len += 1
 		array.len += 1
-		return 1
+		return 1, nil
 	} else {
 	} else {
 		if cap(array) < len(array)+1 {
 		if cap(array) < len(array)+1 {
 			cap := 2 * cap(array) + max(8, 1)
 			cap := 2 * cap(array) + max(8, 1)
-			_ = reserve(array, cap, loc)
+			err = reserve(array, cap, loc) // do not 'or_return' here as it could be a partial success
 		}
 		}
 		if cap(array)-len(array) > 0 {
 		if cap(array)-len(array) > 0 {
 			a := (^Raw_Dynamic_Array)(array)
 			a := (^Raw_Dynamic_Array)(array)
@@ -336,31 +335,31 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) ->
 				data[a.len] = arg
 				data[a.len] = arg
 			}
 			}
 			a.len += 1
 			a.len += 1
-			return 1
+			return 1, err
 		}
 		}
-		return 0
+		return 0, err
 	}
 	}
 }
 }
 
 
 @builtin
 @builtin
-append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> int {
+append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
 	if array == nil {
 	if array == nil {
-		return 0
+		return 0, nil
 	}
 	}
 
 
 	arg_len := len(args)
 	arg_len := len(args)
 	if arg_len <= 0 {
 	if arg_len <= 0 {
-		return 0
+		return 0, nil
 	}
 	}
 
 
 	when size_of(E) == 0 {
 	when size_of(E) == 0 {
 		array := (^Raw_Dynamic_Array)(array)
 		array := (^Raw_Dynamic_Array)(array)
 		array.len += arg_len
 		array.len += arg_len
-		return arg_len
+		return arg_len, nil
 	} else {
 	} else {
 		if cap(array) < len(array)+arg_len {
 		if cap(array) < len(array)+arg_len {
 			cap := 2 * cap(array) + max(8, arg_len)
 			cap := 2 * cap(array) + max(8, arg_len)
-			_ = reserve(array, cap, loc)
+			err = reserve(array, cap, loc)  // do not 'or_return' here as it could be a partial success
 		}
 		}
 		arg_len = min(cap(array)-len(array), arg_len)
 		arg_len = min(cap(array)-len(array), arg_len)
 		if arg_len > 0 {
 		if arg_len > 0 {
@@ -372,13 +371,13 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
 			}
 			}
 			a.len += arg_len
 			a.len += arg_len
 		}
 		}
-		return arg_len
+		return arg_len, err
 	}
 	}
 }
 }
 
 
 // The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
 // The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
 @builtin
 @builtin
-append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> int {
+append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
 	args := transmute([]E)arg
 	args := transmute([]E)arg
 	return append_elems(array=array, args=args, loc=loc)
 	return append_elems(array=array, args=args, loc=loc)
 }
 }
@@ -386,9 +385,14 @@ append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #ca
 
 
 // The append_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type
 // The append_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type
 @builtin
 @builtin
-append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int) {
+append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
+	n_arg: int
 	for arg in args {
 	for arg in args {
-		n += append(array = array, args = transmute([]E)(arg), loc = loc)
+		n_arg, err = append(array = array, args = transmute([]E)(arg), loc = loc)
+		n += n_arg
+		if err != nil {
+			return
+		}
 	}
 	}
 	return
 	return
 }
 }
@@ -398,18 +402,18 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
 
 
 
 
 @builtin
 @builtin
-append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> int {
+append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
 	if array == nil {
 	if array == nil {
-		return 0
+		return 0, nil
 	}
 	}
 	prev_len := len(array)
 	prev_len := len(array)
-	resize(array, len(array)+1, loc)
-	return len(array)-prev_len
+	resize(array, len(array)+1, loc) or_return
+	return len(array)-prev_len, nil
 }
 }
 
 
 
 
 @builtin
 @builtin
-inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
+inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
 	if array == nil {
 	if array == nil {
 		return
 		return
 	}
 	}
@@ -417,18 +421,17 @@ inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
 	m :: 1
 	m :: 1
 	new_size := n + m
 	new_size := n + m
 
 
-	if resize(array, new_size, loc) {
-		when size_of(E) != 0 {
-			copy(array[index + m:], array[index:])
-			array[index] = arg
-		}
-		ok = true
+	resize(array, new_size, loc) or_return
+	when size_of(E) != 0 {
+		copy(array[index + m:], array[index:])
+		array[index] = arg
 	}
 	}
+	ok = true
 	return
 	return
 }
 }
 
 
 @builtin
 @builtin
-inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
+inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
 	if array == nil {
 	if array == nil {
 		return
 		return
 	}
 	}
@@ -441,18 +444,17 @@ inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
 	m := len(args)
 	m := len(args)
 	new_size := n + m
 	new_size := n + m
 
 
-	if resize(array, new_size, loc) {
-		when size_of(E) != 0 {
-			copy(array[index + m:], array[index:])
-			copy(array[index:], args)
-		}
-		ok = true
+	resize(array, new_size, loc) or_return
+	when size_of(E) != 0 {
+		copy(array[index + m:], array[index:])
+		copy(array[index:], args)
 	}
 	}
+	ok = true
 	return
 	return
 }
 }
 
 
 @builtin
 @builtin
-inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
+inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
 	if array == nil {
 	if array == nil {
 		return
 		return
 	}
 	}
@@ -465,11 +467,10 @@ inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
 	m := len(arg)
 	m := len(arg)
 	new_size := n + m
 	new_size := n + m
 
 
-	if resize(array, new_size, loc) {
-		copy(array[index+m:], array[index:])
-		copy(array[index:], arg)
-		ok = true
-	}
+	resize(array, new_size, loc) or_return
+	copy(array[index+m:], array[index:])
+	copy(array[index:], arg)
+	ok = true
 	return
 	return
 }
 }
 
 
@@ -478,11 +479,12 @@ inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
 
 
 
 
 @builtin
 @builtin
-assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
+assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
 	if index < len(array) {
 	if index < len(array) {
 		array[index] = arg
 		array[index] = arg
 		ok = true
 		ok = true
-	} else if resize(array, index+1, loc) {
+	} else {
+		resize(array, index+1, loc) or_return
 		array[index] = arg
 		array[index] = arg
 		ok = true
 		ok = true
 	}
 	}
@@ -491,11 +493,12 @@ assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
 
 
 
 
 @builtin
 @builtin
-assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
+assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
 	if index+len(args) < len(array) {
 	if index+len(args) < len(array) {
 		copy(array[index:], args)
 		copy(array[index:], args)
 		ok = true
 		ok = true
-	} else if resize(array, index+1+len(args), loc) {
+	} else {
+		resize(array, index+1+len(args), loc) or_return
 		copy(array[index:], args)
 		copy(array[index:], args)
 		ok = true
 		ok = true
 	}
 	}
@@ -504,13 +507,14 @@ assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
 
 
 
 
 @builtin
 @builtin
-assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
+assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
 	if len(args) == 0 {
 	if len(args) == 0 {
 		ok = true
 		ok = true
 	} else if index+len(args) < len(array) {
 	} else if index+len(args) < len(array) {
 		copy(array[index:], args)
 		copy(array[index:], args)
 		ok = true
 		ok = true
-	} else if resize(array, index+1+len(args), loc) {
+	} else {
+		resize(array, index+1+len(args), loc) or_return
 		copy(array[index:], args)
 		copy(array[index:], args)
 		ok = true
 		ok = true
 	}
 	}
@@ -530,14 +534,14 @@ clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
 }
 }
 
 
 @builtin
 @builtin
-reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
+reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
 	if array == nil {
 	if array == nil {
-		return false
+		return nil
 	}
 	}
 	a := (^Raw_Dynamic_Array)(array)
 	a := (^Raw_Dynamic_Array)(array)
 
 
 	if capacity <= a.cap {
 	if capacity <= a.cap {
-		return true
+		return nil
 	}
 	}
 
 
 	if a.allocator.procedure == nil {
 	if a.allocator.procedure == nil {
@@ -549,26 +553,26 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
 	new_size  := capacity * size_of(E)
 	new_size  := capacity * size_of(E)
 	allocator := a.allocator
 	allocator := a.allocator
 
 
-	new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc)
-	if new_data == nil || err != nil {
-		return false
+	new_data := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
+	if new_data == nil && new_size > 0 {
+		return .Out_Of_Memory
 	}
 	}
 
 
 	a.data = raw_data(new_data)
 	a.data = raw_data(new_data)
 	a.cap = capacity
 	a.cap = capacity
-	return true
+	return nil
 }
 }
 
 
 @builtin
 @builtin
-resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
+resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
 	if array == nil {
 	if array == nil {
-		return false
+		return nil
 	}
 	}
 	a := (^Raw_Dynamic_Array)(array)
 	a := (^Raw_Dynamic_Array)(array)
 
 
 	if length <= a.cap {
 	if length <= a.cap {
 		a.len = max(length, 0)
 		a.len = max(length, 0)
-		return true
+		return nil
 	}
 	}
 
 
 	if a.allocator.procedure == nil {
 	if a.allocator.procedure == nil {
@@ -580,15 +584,15 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
 	new_size  := length * size_of(E)
 	new_size  := length * size_of(E)
 	allocator := a.allocator
 	allocator := a.allocator
 
 
-	new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc)
-	if new_data == nil || err != nil {
-		return false
+	new_data := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
+	if new_data == nil && new_size > 0 {
+		return .Out_Of_Memory
 	}
 	}
 
 
 	a.data = raw_data(new_data)
 	a.data = raw_data(new_data)
 	a.len = length
 	a.len = length
 	a.cap = length
 	a.cap = length
-	return true
+	return nil
 }
 }
 
 
 /*
 /*
@@ -600,7 +604,7 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
 
 
 	If `len(array) < new_cap`, then `len(array)` will be left unchanged.
 	If `len(array) < new_cap`, then `len(array)` will be left unchanged.
 */
 */
-shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #caller_location) -> (did_shrink: bool) {
+shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
 	if array == nil {
 	if array == nil {
 		return
 		return
 	}
 	}
@@ -620,15 +624,12 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call
 	old_size := a.cap * size_of(E)
 	old_size := a.cap * size_of(E)
 	new_size := new_cap * size_of(E)
 	new_size := new_cap * size_of(E)
 
 
-	new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), a.allocator, loc)
-	if err != nil {
-		return
-	}
+	new_data := mem_resize(a.data, old_size, new_size, align_of(E), a.allocator, loc) or_return
 
 
 	a.data = raw_data(new_data)
 	a.data = raw_data(new_data)
 	a.len = min(new_cap, a.len)
 	a.len = min(new_cap, a.len)
 	a.cap = new_cap
 	a.cap = new_cap
-	return true
+	return true, nil
 }
 }
 
 
 @builtin
 @builtin