void.ha (4489B)
1 // License: MPL-2.0 2 // (c) 2021 Drew DeVault <sir@cmpwn.com> 3 use rt; 4 use types; 5 6 // Appends an item, or multiple items, to a slice, reallocating if necessary. 7 export fn appendto(sl: *[]void, itemsz: size, items: const *void...) void = { 8 const repr = sl: *types::slice; 9 insertinto(sl, itemsz, repr.length, items...); 10 }; 11 12 @test fn appendto() void = { 13 let input: []int = []; 14 let num = 1337; 15 appendto(&input: *[]void, size(int), &num, &num); 16 assert(len(input) == 2 && input[0] == 1337 && input[1] == 1337); 17 num = 7331; 18 appendto(&input: *[]void, size(int), &num); 19 assert(len(input) == 3 && input[0] == 1337 && input[1] == 1337 20 && input[2] == 7331); 21 free(input); 22 }; 23 24 // Appends an item, or multiple items, to a slice. Aborts if the slice's 25 // capacity isn't large enough to fit the items. 26 export fn static_appendto( 27 sl: *[]void, 28 itemsz: size, 29 items: const *void... 30 ) void = { 31 const repr = sl: *types::slice; 32 static_insertinto(sl, itemsz, repr.length, items...); 33 }; 34 35 // Inserts an item, or multiple items, to a slice, in O(n) time, reallocating if 36 // necessary. 37 export fn insertinto( 38 sl: *[]void, 39 itemsz: size, 40 idx: size, 41 items: const *void... 42 ) void = { 43 if (len(items) == 0) { 44 return; 45 }; 46 let sl = sl: *types::slice; 47 sl.length += len(items); 48 rt::ensure(sl, itemsz); 49 let data = sl.data: *[*]u8; 50 rt::memmove(&data[(idx + len(items)) * itemsz], &data[idx * itemsz], 51 (sl.length - len(items) - idx) * itemsz); 52 for (let i = 0z; i < len(items); i += 1) { 53 rt::memcpy(&data[(idx + i) * itemsz], items[i], itemsz); 54 }; 55 }; 56 57 @test fn insertinto() void = { 58 let input: []int = alloc([1, 3], 2); 59 let num = 2; 60 insertinto(&input: *[]void, size(int), 1, &num, &num); 61 assert(len(input) == 4 && input[0] == 1 && input[1] == 2 62 && input[2] == 2 && input[3] == 3); 63 free(input); 64 }; 65 66 // Inserts an item, or multiple items, into a slice, in O(n) time. Aborts if the 67 // slice's capacity isn't large enough to fit the items. 68 export fn static_insertinto( 69 sl: *[]void, 70 itemsz: size, 71 idx: size, 72 items: const *void... 73 ) void = { 74 if (len(items) == 0) { 75 return; 76 }; 77 let sl = sl: *types::slice; 78 sl.length += len(items); 79 assert(sl.length <= sl.capacity, 80 "static insert/append exceeds slice capacity"); 81 let data = sl.data: *[*]u8; 82 rt::memmove(&data[(idx + len(items)) * itemsz], &data[idx * itemsz], 83 (sl.length - len(items) - idx) * itemsz); 84 for (let i = 0z; i < len(items); i += 1) { 85 rt::memcpy(&data[(idx + i) * itemsz], items[i], itemsz); 86 }; 87 }; 88 89 // Deletes a range of items from a slice, in O(n) time. The slice may be 90 // reallocated. Reallocation will never fail. 91 export fn deletefrom(sl: *[]void, itemsz: size, start: size, end: size) void = { 92 static_deletefrom(sl, itemsz, start, end); 93 let sl = sl: *types::slice; 94 if (sl.length <= sl.capacity / 2) { 95 // TODO: switch to using alloc() once it's possible to handle 96 // copy allocation errors 97 match (rt::realloc(sl.data, sl.length * itemsz)) { 98 case null => void; 99 case let p: *void => 100 sl.data = p; 101 sl.capacity = sl.length; 102 }; 103 }; 104 }; 105 106 @test fn deletefrom() void = { 107 let input: []int = alloc([1, 2, 3, 4, 5], 5); 108 deletefrom(&input: *[]void, size(int), 1, 1); 109 assert(len(input) == 5); 110 deletefrom(&input: *[]void, size(int), 1, 3); 111 assert(len(input) == 3 && input[0] == 1 && input[1] == 4 112 && input[2] == 5); 113 free(input); 114 }; 115 116 // Deletes a range of items from a slice, in O(n) time, without freeing memory. 117 export fn static_deletefrom( 118 sl: *[]void, 119 itemsz: size, 120 start: size, 121 end: size, 122 ) void = { 123 assert(start <= end); 124 assert(itemsz != 0); 125 if (start == end) { 126 return; 127 }; 128 let sl = sl: *types::slice; 129 let data = sl.data: *[*]u8; 130 rt::memmove(&data[start * itemsz], &data[end * itemsz], 131 (sl.length - end) * itemsz); 132 sl.length -= end - start; 133 }; 134 135 // Swaps two elements of a slice. 136 export fn swap(sl: []void, itemsz: size, a: size, b: size) void = { 137 assert(a < len(sl) && b < len(sl)); 138 let sl = sl: *[*]u8; 139 let a = &sl[a * itemsz]: *[*]u8, b = &sl[b * itemsz]: *[*]u8; 140 for (let i = 0z; i < itemsz; i += 1) { 141 let c = a[i]; 142 a[i] = b[i]; 143 b[i] = c; 144 }; 145 }; 146 147 @test fn swap() void = { 148 let x: []int = [1, 2, 3]; 149 swap(x: []void, size(int), 0, 2); 150 assert(x[0] == 3 && x[2] == 1); 151 }; 152 153 // Returns a pointer to the nth item of a slice. 154 export fn index(sl: []void, itemsz: size, n: size) *void = { 155 assert(n < len(sl)); 156 let ba = sl: *[*]u8; 157 return &ba[n * itemsz]; 158 }; 159 160 @test fn index() void = { 161 let x: []int = [1, 2, 3]; 162 let ptr = index(x, size(int), 1): *int; 163 assert(*ptr == 2); 164 };