hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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 };