mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Add array::zip and Related Macros (#2370)
* zip / zip_into * Deprecate `add_array` in favour of `push_all` on lists. * Add support for generic lists for zip. --------- Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
This commit is contained in:
@@ -7,6 +7,6 @@ macro foo(x) => *x = 1;
|
||||
|
||||
fn int main()
|
||||
{
|
||||
foo(0); // #error: Expected a pointer
|
||||
foo(0); // #error: x must be
|
||||
return 0;
|
||||
}
|
||||
@@ -7,7 +7,7 @@ alias PtrList = ElasticArray{void*, 10};
|
||||
fn void delete_contains_index()
|
||||
{
|
||||
IntList test;
|
||||
test.add_array({ 1, 2 });
|
||||
test.push_all({ 1, 2 });
|
||||
assert(test.contains(1));
|
||||
assert(test.contains(2));
|
||||
assert(!test.contains(0));
|
||||
@@ -36,7 +36,7 @@ fn void delete_contains_index()
|
||||
fn void compact()
|
||||
{
|
||||
PtrList test;
|
||||
test.add_array({ null, &test });
|
||||
test.push_all({ null, &test });
|
||||
assert(test.compact_count() == 1);
|
||||
test.push(null);
|
||||
assert(test.compact_count() == 1);
|
||||
@@ -50,7 +50,7 @@ fn void reverse()
|
||||
{
|
||||
IntList test;
|
||||
test.reverse();
|
||||
test.add_array({ 1, 2 });
|
||||
test.push_all({ 1, 2 });
|
||||
test.push(3);
|
||||
assert(test.array_view() == (int[]) { 1, 2, 3});
|
||||
test.reverse();
|
||||
@@ -66,13 +66,13 @@ fn void remove_if()
|
||||
IntList test;
|
||||
usz removed;
|
||||
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.remove_if(&filter);
|
||||
assert(removed == 3);
|
||||
assert(test.array_view() == (int[]){1, 2});
|
||||
|
||||
test.clear();
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.remove_if(&select);
|
||||
assert(removed == 2);
|
||||
assert(test.array_view() == (int[]){11, 10, 20});
|
||||
@@ -84,13 +84,13 @@ fn void remove_using_test()
|
||||
IntList test;
|
||||
usz removed;
|
||||
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.remove_using_test(fn bool(i, ctx) => *i >= *(int*)ctx, &&10);
|
||||
assert(removed == 3);
|
||||
assert(test.array_view() == (int[]){1, 2});
|
||||
|
||||
test.clear();
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.remove_using_test(fn bool(i, ctx) => *i < *(int*)ctx, &&10);
|
||||
assert(removed == 2);
|
||||
assert(test.array_view() == (int[]){11, 10, 20});
|
||||
@@ -101,13 +101,13 @@ fn void retain_if()
|
||||
IntList test;
|
||||
usz removed;
|
||||
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.retain_if(&select);
|
||||
assert(removed == 3);
|
||||
assert(test.array_view() == (int[]){1, 2});
|
||||
|
||||
test.clear();
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.retain_if(&filter);
|
||||
assert(removed == 2);
|
||||
assert(test.array_view() == (int[]){11, 10, 20});
|
||||
@@ -118,13 +118,13 @@ fn void retain_using_test()
|
||||
IntList test;
|
||||
usz removed;
|
||||
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.remove_using_test(fn bool(i, ctx) => *i >= *(int*)ctx, &&10);
|
||||
assert(removed == 3);
|
||||
assert(test.array_view() == (int[]){1, 2});
|
||||
|
||||
test.clear();
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.remove_using_test(fn bool(i, ctx) => *i < *(int*)ctx, &&10);
|
||||
assert(removed == 2);
|
||||
assert(test.array_view() == (int[]){11, 10, 20});
|
||||
|
||||
@@ -25,7 +25,7 @@ fn void remove_at()
|
||||
IntList test;
|
||||
test.init(mem);
|
||||
defer test.free();
|
||||
test.add_array({ 1, 2, 3, 4 });
|
||||
test.push_all({ 1, 2, 3, 4 });
|
||||
test::eq(test.array_view(), (int[]){ 1, 2, 3, 4 });
|
||||
test.remove_at(0);
|
||||
test::eq(test.array_view(), (int[]){ 2, 3, 4 });
|
||||
@@ -41,7 +41,7 @@ fn void delete_contains_index()
|
||||
{
|
||||
IntList test;
|
||||
|
||||
test.add_array({ 1, 2 });
|
||||
test.push_all({ 1, 2 });
|
||||
assert(test.contains(1));
|
||||
assert(test.contains(2));
|
||||
assert(!test.contains(0));
|
||||
@@ -70,7 +70,7 @@ fn void delete_contains_index()
|
||||
fn void compact()
|
||||
{
|
||||
PtrList test;
|
||||
test.add_array({ null, &test });
|
||||
test.push_all({ null, &test });
|
||||
assert(test.compact_count() == 1);
|
||||
test.push(null);
|
||||
assert(test.compact_count() == 1);
|
||||
@@ -85,7 +85,7 @@ fn void reverse()
|
||||
IntList test;
|
||||
|
||||
test.reverse();
|
||||
test.add_array({ 1, 2 });
|
||||
test.push_all({ 1, 2 });
|
||||
test.push(3);
|
||||
assert(test.array_view() == { 1, 2, 3});
|
||||
test.reverse();
|
||||
@@ -101,13 +101,13 @@ fn void remove_if()
|
||||
IntList test;
|
||||
usz removed;
|
||||
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.remove_if(&filter);
|
||||
assert(removed == 3);
|
||||
assert(test.array_view() == {1, 2});
|
||||
|
||||
test.clear();
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.remove_if(&select);
|
||||
assert(removed == 2);
|
||||
assert(test.array_view() == {11, 10, 20});
|
||||
@@ -135,13 +135,13 @@ fn void remove_using_test()
|
||||
IntList test;
|
||||
usz removed;
|
||||
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.remove_using_test(fn bool(i, ctx) => *i >= *(int*)ctx, &&10);
|
||||
assert(removed == 3);
|
||||
assert(test.array_view() == {1, 2});
|
||||
|
||||
test.clear();
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.remove_using_test(fn bool(i, ctx) => *i < *(int*)ctx, &&10);
|
||||
assert(removed == 2);
|
||||
assert(test.array_view() == {11, 10, 20});
|
||||
@@ -152,13 +152,13 @@ fn void retain_if()
|
||||
IntList test;
|
||||
usz removed;
|
||||
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.retain_if(&select);
|
||||
assert(removed == 3);
|
||||
assert(test.array_view() == {1, 2});
|
||||
|
||||
test.clear();
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.retain_if(&filter);
|
||||
assert(removed == 2);
|
||||
assert(test.array_view() == {11, 10, 20});
|
||||
@@ -169,13 +169,13 @@ fn void retain_using_test()
|
||||
IntList test;
|
||||
usz removed;
|
||||
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.remove_using_test(fn bool(i, ctx) => *i >= *(int*)ctx, &&10);
|
||||
assert(removed == 3);
|
||||
assert(test.array_view() == {1, 2});
|
||||
|
||||
test.clear();
|
||||
test.add_array({ 1, 11, 2, 10, 20 });
|
||||
test.push_all({ 1, 11, 2, 10, 20 });
|
||||
removed = test.remove_using_test(fn bool(i, ctx) => *i < *(int*)ctx, &&10);
|
||||
assert(removed == 2);
|
||||
assert(test.array_view() == {11, 10, 20});
|
||||
|
||||
@@ -1,19 +1,47 @@
|
||||
module arraytests @test;
|
||||
module array_test;
|
||||
import std::io;
|
||||
|
||||
struct TestStructZip (Printable)
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
}
|
||||
|
||||
fn TestStructZip TestStructZip.mult(self, TestStructZip other) @operator(*)
|
||||
{
|
||||
self.a *= other.a;
|
||||
self.b *= other.b;
|
||||
return self;
|
||||
}
|
||||
|
||||
fn bool TestStructZip.eq(self, TestStructZip other) @operator(==)
|
||||
{
|
||||
return self.a == other.a && self.b == other.b;
|
||||
}
|
||||
|
||||
fn usz? TestStructZip.to_format(&self, Formatter* f) @dynamic
|
||||
{
|
||||
return f.printf("{ %d, %d }", self.a, self.b);
|
||||
}
|
||||
|
||||
module array_test @test;
|
||||
import std::collections::pair, std::collections::list;
|
||||
|
||||
|
||||
fn void contains()
|
||||
{
|
||||
int[3] a = { 1, 2, 3 };
|
||||
assert(array::contains(a, 2) == true);
|
||||
assert(array::contains(a, 15) == false);
|
||||
assert(array::contains(a, 2));
|
||||
assert(!array::contains(a, 15));
|
||||
}
|
||||
|
||||
fn void find()
|
||||
{
|
||||
int[3] a = { 1, 2, 3 };
|
||||
assert(array::index_of(a, 2)!! == 1);
|
||||
assert(array::index_of(a, 1)!! == 0);
|
||||
assert(array::index_of(a, 3)!! == 2);
|
||||
assert(@catch(array::index_of(a, 4)) == NOT_FOUND);
|
||||
test::eq(array::index_of(a, 2)!!, 1);
|
||||
test::eq(array::index_of(a, 1)!!, 0);
|
||||
test::eq(array::index_of(a, 3)!!, 2);
|
||||
test::@error(array::index_of(a, 4), NOT_FOUND);
|
||||
}
|
||||
|
||||
fn void find_subarray()
|
||||
@@ -35,5 +63,194 @@ fn void concat()
|
||||
free(array::concat(mem, a[:0], (int[2]) { 1, 2 }));
|
||||
int[] c = array::concat(mem, a[1..2], a);
|
||||
defer free(c);
|
||||
assert (c == (int[]){ 2, 3, 1, 2, 3 });
|
||||
assert(c == (int[]){ 2, 3, 1, 2, 3 });
|
||||
}
|
||||
|
||||
|
||||
fn void zip() => @pool()
|
||||
{
|
||||
char[] left = "abcde";
|
||||
long[] right = { -1, 0x8000, 0 };
|
||||
|
||||
Pair{char, long}[] expected = { {'a', -1}, {'b', 0x8000}, {'c', 0} };
|
||||
|
||||
Pair{char, long}[] zipped = array::@tzip(left, right);
|
||||
|
||||
test::eq(zipped.len, 3);
|
||||
foreach (i, c : zipped) assert(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
fn void zip_list() => @pool()
|
||||
{
|
||||
char[] left = "abcde";
|
||||
List{long} l;
|
||||
l.push(-1);
|
||||
l.push(0x8000);
|
||||
l.push(0);
|
||||
|
||||
Pair{char, long}[] expected = { {'a', -1}, {'b', 0x8000}, {'c', 0} };
|
||||
|
||||
Pair{char, long}[] zipped = array::@tzip(left, l);
|
||||
|
||||
test::eq(zipped.len, 3);
|
||||
foreach (i, c : zipped) assert(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
fn void zip_fill_with_default() => @pool()
|
||||
{
|
||||
char[] left = "abcde";
|
||||
long[] right = { -1, 0x8000, 0 };
|
||||
|
||||
Pair{char, long}[] expected = { {'a', -1}, {'b', 0x8000}, {'c', 0}, {'d', 0}, {'e', 0} };
|
||||
|
||||
Pair{char, long}[] zipped = array::@tzip(left, right, fill_with: 0);
|
||||
|
||||
test::eq(zipped.len, 5);
|
||||
foreach (i, c : zipped) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
fn void zip_fill_with_char() => @pool()
|
||||
{
|
||||
char[] left = "abcde";
|
||||
long[] right = { -1, 0x8000, 0 };
|
||||
|
||||
Pair{char, long}[] expected = { {'a', -1}, {'b', 0x8000}, {'c', 0}, {'d', 0x40}, {'e', 0x40} };
|
||||
|
||||
Pair{char, long}[] zipped = array::@tzip(left, right, fill_with: 0x40);
|
||||
|
||||
test::eq(zipped.len, 5);
|
||||
foreach (i, c : zipped) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
fn void zip_fill_with_string() => @pool()
|
||||
{
|
||||
String[] left = { "abcde", "123456" };
|
||||
long[] right = { -1, 0x8000, 20, 30, 40 };
|
||||
|
||||
Pair{String, long}[] expected = { {"abcde", -1}, {"123456", 0x8000}, {"aaa", 20}, {"aaa", 30}, {"aaa", 40} };
|
||||
|
||||
Pair{String, long}[] zipped = array::@tzip(left, right, fill_with: "aaa");
|
||||
|
||||
test::eq(zipped.len, 5);
|
||||
foreach (i, c : zipped) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
fn void zip_fill_with_struct() => @pool()
|
||||
{
|
||||
String[] left = { "abcde", "123456", "zzz" };
|
||||
TestStructZip[] right = { {1, 2} };
|
||||
|
||||
Pair{String, TestStructZip}[] expected = { {"abcde", {1, 2}}, {"123456", {100, 200}}, {"zzz", {100, 200}} };
|
||||
|
||||
Pair{String, TestStructZip}[] zipped = array::@tzip(left, right, fill_with: (TestStructZip){100, 200});
|
||||
|
||||
test::eq(zipped.len, 3);
|
||||
foreach (i, c : zipped) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
fn void zip_with() => @pool()
|
||||
{
|
||||
char[] left = "abcde";
|
||||
char[4] right = { 0x05, 0x04, 0x03, 0x00 };
|
||||
|
||||
char[] expected = "fffd";
|
||||
|
||||
char[] zipped = array::@tzip(left, right, fn char (char a, char b) => a + b);
|
||||
|
||||
test::eq(zipped.len, 4);
|
||||
foreach (i, c : zipped) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
fn void zip_with_fill_with_default() => @pool()
|
||||
{
|
||||
char[] left = "abcde";
|
||||
char[] right = { 0x05, 0x04 };
|
||||
|
||||
char[] expected = "ffcde";
|
||||
|
||||
char[] zipped = array::@tzip(left, right, fn char (char a, char b) => a + b, 0);
|
||||
|
||||
test::eq(zipped.len, 5);
|
||||
foreach (i, c : zipped) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
fn void zip_with_fill_with_char() => @pool()
|
||||
{
|
||||
char[] left = "abcde";
|
||||
char[] right = { 0x05, 0x04 };
|
||||
|
||||
char[] expected = "ffghi";
|
||||
|
||||
char[] zipped = array::@tzip(left, right, fn char (char a, char b) => a + b, 0x04);
|
||||
|
||||
test::eq(zipped.len, 5);
|
||||
foreach (i, c : zipped) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
fn void zip_with_fill_with_pointers() => @pool()
|
||||
{
|
||||
ZString field = "0123456789abcdefghijklmnopqrstuvwxyz-_=!";
|
||||
|
||||
char*[] left = { &field[3], &field[1] };
|
||||
char[] right = { 0x05, 0x04, 0x0A, 0x10, 0x11 };
|
||||
|
||||
char[] expected = "85agh";
|
||||
|
||||
char[] zipped = array::@tzip(left, right, fn char (char* a, char b) => a[b], &field[0]);
|
||||
|
||||
test::eq(zipped.len, 5);
|
||||
foreach (i, c : zipped) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
fn void zip_with_fill_with_string() => @pool()
|
||||
{
|
||||
String[] left = { "Hello", "World", "Foo", "Bazzy" };
|
||||
String[] right = { " there", "!" };
|
||||
|
||||
String[] expected = { "Hello there", "World!", "FooBar", "BazzyBar" };
|
||||
|
||||
String[] zipped = array::@tzip(left, right, fn String (String a, String b) => a.tconcat(b), "Bar");
|
||||
|
||||
test::eq(zipped.len, 4);
|
||||
foreach (i, c : zipped) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
fn void zip_with_fill_with_struct() => @pool()
|
||||
{
|
||||
TestStructZip[] left = { {1, 2}, {300, 400} };
|
||||
TestStructZip[] right = { {-1, -1} };
|
||||
|
||||
TestStructZip[] expected = { {-1, -2}, {600, 1200} };
|
||||
|
||||
TestStructZip[] zipped = array::@tzip(left, right, fn TestStructZip (TestStructZip a, TestStructZip b) => a * b, (TestStructZip){2, 3});
|
||||
|
||||
test::eq(zipped.len, 2);
|
||||
foreach (i, c : zipped) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
fn void zip_into()
|
||||
{
|
||||
char[] left = { '1', '2', '3', '4' };
|
||||
String[6] right = { "one", "two", "three", "four", "five", "six" };
|
||||
|
||||
char[] expected = { '4', '5', '8', '8' };
|
||||
|
||||
array::@zip_into(left, right, fn (a, b) => a + (char)b.len);
|
||||
|
||||
test::eq(left.len, 4);
|
||||
foreach (i, c : left) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
fn void zip_into_list() => @pool()
|
||||
{
|
||||
List{char} l;
|
||||
l.push_all({ '1', '2', '3', '4' });
|
||||
String[6] right = { "one", "two", "three", "four", "five", "six" };
|
||||
|
||||
char[] expected = { '4', '5', '8', '8' };
|
||||
|
||||
array::@zip_into(l, right, fn (a, b) => a + (char)b.len);
|
||||
|
||||
test::eq(l.len(), 4);
|
||||
foreach (i, c : l) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ alias CountingSortTestList = List{int};
|
||||
fn void countingsort_list()
|
||||
{
|
||||
CountingSortTestList list;
|
||||
list.add_array({ 2, 1, 3});
|
||||
list.push_all({ 2, 1, 3});
|
||||
sort::countingsort(list, &sort::key_int_value);
|
||||
assert(check::int_ascending_sort(list.array_view()));
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ alias InsertionSortTestList = List{int};
|
||||
fn void insertionsort_list()
|
||||
{
|
||||
InsertionSortTestList list;
|
||||
list.add_array({ 2, 1, 3});
|
||||
list.push_all({ 2, 1, 3});
|
||||
sort::insertionsort(list, &sort::cmp_int_value);
|
||||
assert(check::int_ascending_sort(list.array_view()));
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ alias List = List{int};
|
||||
fn void quicksort_list()
|
||||
{
|
||||
List list;
|
||||
list.add_array({ 2, 1, 3});
|
||||
list.push_all({ 2, 1, 3});
|
||||
sort::quicksort(list, &sort::cmp_int_value);
|
||||
assert(check::int_sort(list.array_view()));
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ fn void sorted()
|
||||
// with list
|
||||
List{int} list;
|
||||
list.tinit();
|
||||
list.add_array(tc.input);
|
||||
list.push_all(tc.input);
|
||||
|
||||
got = is_sorted(list);
|
||||
assert(got == tc.want, "list: %s, got: %s, want: %s",
|
||||
|
||||
Reference in New Issue
Block a user