Improve error handling for resize and reserve procedures

This commit is contained in:
gingerBill
2023-05-22 11:47:36 +01:00
parent 600c97cc0f
commit 1e17f44991
6 changed files with 87 additions and 90 deletions
+69 -68
View File
@@ -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.
*/
@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 {
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
}
@@ -315,18 +314,18 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
@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 {
return 0
return 0, nil
}
when size_of(E) == 0 {
array := (^Raw_Dynamic_Array)(array)
array.len += 1
return 1
return 1, nil
} else {
if cap(array) < len(array)+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 {
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
}
a.len += 1
return 1
return 1, err
}
return 0
return 0, err
}
}
@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 {
return 0
return 0, nil
}
arg_len := len(args)
if arg_len <= 0 {
return 0
return 0, nil
}
when size_of(E) == 0 {
array := (^Raw_Dynamic_Array)(array)
array.len += arg_len
return arg_len
return arg_len, nil
} else {
if cap(array) < len(array)+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)
if arg_len > 0 {
@@ -372,13 +371,13 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
}
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
@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
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
@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 {
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
}
@@ -398,18 +402,18 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
@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 {
return 0
return 0, nil
}
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
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 {
return
}
@@ -417,18 +421,17 @@ inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
m :: 1
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
}
@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 {
return
}
@@ -441,18 +444,17 @@ inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
m := len(args)
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
}
@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 {
return
}
@@ -465,11 +467,10 @@ inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
m := len(arg)
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
}
@@ -478,11 +479,12 @@ inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
@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) {
array[index] = arg
ok = true
} else if resize(array, index+1, loc) {
} else {
resize(array, index+1, loc) or_return
array[index] = arg
ok = true
}
@@ -491,11 +493,12 @@ assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
@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) {
copy(array[index:], args)
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)
ok = true
}
@@ -504,13 +507,14 @@ assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
@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 {
ok = true
} else if index+len(args) < len(array) {
copy(array[index:], args)
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)
ok = true
}
@@ -530,14 +534,14 @@ clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
}
@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 {
return false
return nil
}
a := (^Raw_Dynamic_Array)(array)
if capacity <= a.cap {
return true
return 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)
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.cap = capacity
return true
return nil
}
@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 {
return false
return nil
}
a := (^Raw_Dynamic_Array)(array)
if length <= a.cap {
a.len = max(length, 0)
return true
return 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)
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.len = 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.
*/
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 {
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)
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.len = min(new_cap, a.len)
a.cap = new_cap
return true
return true, nil
}
@builtin