Add LinkedList Operators and Update Tests (#2438)

* Add LinkedList Operators and Update Tests
* add linkedlist printing and `@new` macros (single-line init and pool-capable)
* add linkedlist node and reg iterator; comparisons w/ ==
* Fix benchmarks. Drop random access to the linked list using []. Only return a direct array view.

---------

Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
This commit is contained in:
Zack Puhl
2025-09-06 05:57:21 -04:00
committed by GitHub
parent 79c0c8e082
commit 078d9dc0b7
9 changed files with 407 additions and 186 deletions

View File

@@ -107,7 +107,8 @@ fn void hash_speeds_of_many_random_values() => @pool()
foreach (&v : vwideints) *v = (uint128)random::next(&rand, uint.max);
char[48][] zstrs = allocator::new_array(tmem, char[48], $arrsz)[:$arrsz];
String[$arrsz] strs;
String[] strs = mem::temp_array(String, $arrsz);
foreach (x, &v : zstrs)
{
foreach (&c : (*v)[:random::next(&rand, 48)]) *c = (char)random::next(&rand, char.max);
@@ -195,7 +196,7 @@ fn void random_access_string_keys() => @pool()
v.tinit();
usz pseudo_checksum = 0;
String[5_000] saved;
String[] saved = mem::temp_array(String, 5_000);
for (usz i = 0; i < saved.len; ++i)
{

View File

@@ -0,0 +1,38 @@
module linkedlist_benchmarks;
import std::collections::linkedlist;
LinkedList{int} long_list;
const HAY = 2;
const NEEDLE = 1000;
fn void bench_setup() @init
{
set_benchmark_warmup_iterations(3);
set_benchmark_max_iterations(4096);
int[*] haystack = { [0..999] = HAY };
long_list = linkedlist::@new{int}(mem, haystack[..]);
long_list.push(NEEDLE);
long_list.push_all(haystack[..]);
}
// ==============================================================================================
module linkedlist_benchmarks @benchmark;
String die_str = "Failed to find the value `1`. Is something broken?";
fn void foreach_iterator()
{
foreach (v : long_list.array_view()) if (v == NEEDLE) return;
runtime::@kill_benchmark(die_str);
}
fn void foreach_r_iterator()
{
foreach_r (v : long_list.array_view()) if (v == NEEDLE) return;
runtime::@kill_benchmark(die_str);
}

View File

@@ -19,7 +19,7 @@ macro void trim_bench($trim_str, String $target = WHITESPACE_TARGET) => @pool()
$switch:
$case $typeof($trim_str) == String:
s1 = s2.trim($trim_str);
$case $typeof($$trim_str) == AsciiCharset:
$case $typeof($trim_str) == AsciiCharset:
s1 = s2.trim_charset($trim_str);
$default: $error "Unable to determine the right String `trim` operation to use.";
$endswitch

View File

@@ -2,10 +2,11 @@
// Use of self source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::collections::linkedlist{Type};
import std::io;
const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type);
struct Node @private
struct Node
{
Node* next;
Node* prev;
@@ -20,6 +21,29 @@ struct LinkedList
Node* _last;
}
fn usz? LinkedList.to_format(&self, Formatter* f) @dynamic
{
usz len = f.print("{ ")!;
for (Node* node = self._first; node != null; node.next)
{
len += f.printf(node.next ? "%s, " : "s", node.value)!;
}
return len + f.print(" }");
}
macro LinkedList @new(Allocator allocator, Type[] #default_values = {})
{
LinkedList new_list;
new_list.init(allocator);
new_list.push_all(#default_values);
return new_list;
}
macro LinkedList @tnew(Type[] #default_values = {})
{
return @new(tmem, #default_values);
}
<*
@param [&inout] allocator : "The allocator to use, defaults to the heap allocator"
@return "the initialized list"
@@ -68,6 +92,11 @@ fn void LinkedList.push_front(&self, Type value)
self.size++;
}
fn void LinkedList.push_front_all(&self, Type[] value)
{
foreach_r (v : value) self.push_front(v);
}
fn void LinkedList.push(&self, Type value)
{
Node *last = self._last;
@@ -85,6 +114,11 @@ fn void LinkedList.push(&self, Type value)
self.size++;
}
fn void LinkedList.push_all(&self, Type[] value)
{
foreach (v : value) self.push(v);
}
fn Type? LinkedList.peek(&self) => self.first() @inline;
fn Type? LinkedList.peek_last(&self) => self.last() @inline;
@@ -133,6 +167,7 @@ macro Node* LinkedList.node_at_index(&self, usz index)
while (index--) node = node.next;
return node;
}
<*
@require index < self.size
*>
@@ -141,6 +176,14 @@ fn Type LinkedList.get(&self, usz index)
return self.node_at_index(index).value;
}
<*
@require index < self.size
*>
fn Type* LinkedList.get_ref(&self, usz index)
{
return &self.node_at_index(index).value;
}
<*
@require index < self.size
*>
@@ -149,6 +192,26 @@ fn void LinkedList.set(&self, usz index, Type element)
self.node_at_index(index).value = element;
}
fn usz? LinkedList.index_of(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
{
for (Node* node = self._first, usz i = 0; node != null; node = node.next, ++i)
{
if (node.value == t) return i;
}
return NOT_FOUND?;
}
fn usz? LinkedList.rindex_of(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
{
for (Node* node = self._last, usz i = self.size - 1; node != null; node = node.prev, --i)
{
if (node.value == t) return i;
if (i == 0) break;
}
return NOT_FOUND?;
}
<*
@require index < self.size
*>
@@ -334,3 +397,69 @@ fn void LinkedList.unlink(&self, Node* x) @private
self.free_node(x);
self.size--;
}
macro bool LinkedList.eq(&self, other) @operator(==) @if(ELEMENT_IS_EQUATABLE)
{
Node* node1 = self._first;
Node* node2 = other._first;
while (true)
{
if (!node1) return node2 == null;
if (!node2) return false;
if (node1.value != node2.value) return false;
node1 = node1.next;
node2 = node2.next;
}
return true;
}
fn LinkedListArrayView LinkedList.array_view(&self)
{
return { .list = self, .current_node = self._first };
}
struct LinkedListArrayView
{
LinkedList* list;
Node* current_node;
usz current_index;
}
fn usz LinkedListArrayView.len(&self) @operator(len) => self.list.size;
<*
@require index < self.list.size
*>
fn Type LinkedListArrayView.get(&self, usz index) @operator([])
{
return *self.get_ref(index);
}
<*
@require index < self.list.size
*>
fn Type* LinkedListArrayView.get_ref(&self, usz index) @operator(&[])
{
if (index == self.list.size - 1)
{
self.current_node = self.list._last;
self.current_index = index;
}
while (self.current_index != index)
{
switch
{
case index < self.current_index: // reverse iteration
self.current_node = self.current_node.prev;
self.current_index--;
case index > self.current_index:
self.current_node = self.current_node.next;
self.current_index++;
}
}
return &self.current_node.value;
}

View File

@@ -387,7 +387,6 @@ macro bool @all(array, #predicate)
@require @is_valid_list(left) &&& @is_valid_list(right) : "Left and right sides must be integer indexable"
@require @is_valid_operation(left, right, ...#operation) : "The operator must take two parameters matching the elements of the left and right side"
@require @is_valid_fill(left, right, ...fill_with) : "The specified fill value does not match either the left or the right array's underlying type."
*>
macro @zip(Allocator allocator, left, right, #operation = ..., fill_with = ...) @nodiscard
{
@@ -460,7 +459,6 @@ macro @zip(Allocator allocator, left, right, #operation = ..., fill_with = ...)
@require @is_valid_list(left) &&& @is_valid_list(right) : "Left and right sides must be integer indexable"
@require @is_valid_operation(left, right, ...#operation) : "The operator must take two parameters matching the elements of the left and right side"
@require @is_valid_fill(left, right, ...fill_with) : "The specified fill value does not match either the left or the right array's underlying type."
*>
macro @tzip(left, right, #operation = ..., fill_with = ...) @nodiscard
{

View File

@@ -56,6 +56,7 @@ long cycle_stop @local;
DString benchmark_log @local;
bool benchmark_warming @local;
uint this_iteration @local;
bool benchmark_stop @local;
macro @start_benchmark()
{
@@ -69,6 +70,12 @@ macro @end_benchmark()
cycle_stop = $$sysclock();
}
macro @kill_benchmark(String format, ...)
{
@log_benchmark(format, $vasplat);
benchmark_stop = true;
}
macro @log_benchmark(msg, args...) => @pool()
{
if (benchmark_warming) return;
@@ -133,6 +140,7 @@ fn bool run_benchmarks(BenchmarkUnit[] benchmarks)
@start_benchmark(); // can be overridden by calls inside the unit's func
unit.func() @inline;
if (benchmark_stop) return false;
if (benchmark_nano_seconds == (NanoDuration){}) @end_benchmark(); // only mark when it wasn't already by the unit.func

View File

@@ -17,6 +17,8 @@
- Added generic `InterfaceList` to store a list of values that implement a specific interface
- Added `path::home_directory`, `path::documents_directory`, `path::videos_directory`, `path::pictures_directory`, `path::desktop_directory`, `path::screenshots_directory`,
`path::public_share_directory`, `path::templates_directory`, `path::saved_games_directory`, `path::music_directory`, `path::downloads_directory`.
- Add `LinkedList` array_view to support `[]` and `foreach`/`foreach_r`. #2438
- Make `LinkedList` printable and add `==` operator. #2438
## 0.7.5 Change list

View File

@@ -6,242 +6,251 @@ alias IntList = LinkedList{int};
fn void test_is_initialized()
{
IntList test;
assert(!test.is_initialized());
test::@check(!test.is_initialized());
test.init(mem);
assert(test.is_initialized());
test::@check(test.is_initialized());
test.free();
}
fn void test_push_front()
fn void test_push_front() => @pool()
{
IntList list;
defer list.free();
IntList list = linkedlist::@tnew{int}();
list.push_front(23);
assert(list.len() == 1);
assert(list.first()!! == 23);
assert(list.last()!! == 23);
test::eq(list.len(), 1);
test::eq(list.first()!!, 23);
test::eq(list.last()!!, 23);
list.push_front(55);
assert(list.len() == 2);
assert(list.last()!! == 23);
assert(list.first()!! == 55);
test::eq(list.len(), 2);
test::eq(list.last()!!, 23);
test::eq(list.first()!!, 55);
}
fn void test_push()
fn void test_push() => @pool()
{
IntList list;
defer list.free();
IntList list = linkedlist::@tnew{int}();
list.push(23);
assert(list.len() == 1);
assert(list.first()!! == 23);
assert(list.last()!! == 23);
test::eq(list.len(), 1);
test::eq(list.first()!!, 23);
test::eq(list.last()!!, 23);
list.push(55);
assert(list.len() == 2);
assert(list.last()!! == 55);
assert(list.first()!! == 23);
test::eq(list.len(), 2);
test::eq(list.last()!!, 55);
test::eq(list.first()!!, 23);
}
fn void test_get()
fn void test_get() => @pool()
{
IntList list;
defer list.free();
list.push(23);
list.push(55);
list.push(-3);
assert(list.get(2) == -3);
assert(list.get(1) == 55);
assert(list.get(0) == 23);
IntList list = linkedlist::@tnew{int}({ 23, 55, -3 });
test::eq(list.get(2), -3);
test::eq(list.get(1), 55);
test::eq(list.get(0), 23);
test::eq(list.array_view()[0], 23);
}
fn void test_insert()
fn void test_insert() => @pool()
{
IntList list;
defer list.free();
list.push(-3);
list.push(55);
list.push(23);
IntList list = linkedlist::@tnew{int}({ -3, 55, 23 });
list.insert_at(0, 1);
list.insert_at(2, 11);
list.insert_at(4, 111);
list.insert_at(6, 1111);
assert(list.get(0) == 1);
assert(list.get(1) == -3);
assert(list.get(2) == 11);
assert(list.get(3) == 55);
assert(list.get(4) == 111);
assert(list.get(5) == 23);
assert(list.get(6) == 1111);
test::eq(list.get(0), 1);
test::eq(list.get(1), -3);
test::eq(list.get(2), 11);
test::eq(list.get(3), 55);
test::eq(list.get(4), 111);
test::eq(list.get(5), 23);
test::eq(list.get(6), 1111);
}
fn void test_set()
fn void test_set() => @pool()
{
IntList list;
defer list.free();
list.push(-3);
list.push(55);
list.push(23);
IntList list = linkedlist::@tnew{int}({ -3, 55, 23 });
for (int i = 0; i < 3; i++) list.set(i, list.get(i) + 1);
assert(list.get(0) == -2);
assert(list.get(1) == 56);
assert(list.get(2) == 24);
test::eq(list.get(0), -2);
test::eq(list.get(1), 56);
test::eq(list.get(2), 24);
}
fn void test_remove_at()
fn void test_remove_at() => @pool()
{
IntList list;
defer list.free();
IntList list = linkedlist::@tnew{int}();
for (int i = 0; i < 10; i++) list.push(i);
list.remove_at(0);
list.remove_at(1);
list.remove_at(7);
list.remove_at(5);
assert(list.get(0) == 1);
assert(list.get(1) == 3);
assert(list.get(5) == 8);
assert(list.get(4) == 6);
test::eq(list.get(0), 1);
test::eq(list.get(1), 3);
test::eq(list.get(5), 8);
test::eq(list.get(4), 6);
}
fn void test_remove()
fn void test_remove() => @pool()
{
IntList list;
defer list.free();
IntList list = linkedlist::@tnew{int}();
list.push(2);
for (int i = 0; i < 10; i++) list.push(5);
list.push(2);
list.remove(5);
assert(list.len() == 2);
test::eq(list.len(), 2);
}
fn void test_remove_first_match()
fn void test_remove_first_match() // no @pool
{
IntList list;
defer list.free();
list.push(23);
list.push(55);
list.push(-3);
assert(list.remove_first_match(23));
assert(list.pop()!! == -3);
assert(list.pop()!! == 55);
assert(!list.len());
defer list.free(); // left this to ensure .free() remains valid and functional
list.push_all({ 23, 55, -3 });
test::@check(list.remove_first_match(23));
test::eq(list.pop()!!, -3);
test::eq(list.pop()!!, 55);
test::@check(!list.len());
list.push(23);
list.push(55);
list.push(-3);
assert(list.remove_first_match(55));
assert(list.pop()!! == -3);
assert(list.pop()!! == 23);
assert(!list.len());
list.push_all({ 23, 55, -3 });
test::@check(list.remove_first_match(55));
test::eq(list.pop()!!, -3);
test::eq(list.pop()!!, 23);
test::@check(!list.len());
list.push(23);
list.push(55);
list.push(-3);
assert(list.remove_first_match(-3));
assert(list.pop()!! == 55);
assert(list.pop()!! == 23);
assert(!list.len());
list.push_all({ 23, 55, -3 });
test::@check(list.remove_first_match(-3));
test::eq(list.pop()!!, 55);
test::eq(list.pop()!!, 23);
test::@check(!list.len());
}
fn void test_remove_last_match()
fn void test_remove_last_match() => @pool()
{
IntList list;
defer list.free();
list.push(23);
list.push(55);
list.push(-3);
assert(list.remove_last_match(23));
assert(list.pop()!! == -3);
assert(list.pop()!! == 55);
assert(!list.len());
IntList list = linkedlist::@tnew{int}({ 23, 55, -3 });
test::@check(list.remove_last_match(23));
test::eq(list.pop()!!, -3);
test::eq(list.pop()!!, 55);
test::@check(!list.len());
list.push(23);
list.push(55);
list.push(-3);
assert(list.remove_last_match(55));
assert(list.pop()!! == -3);
assert(list.pop()!! == 23);
assert(!list.len());
list.push_all({ 23, 55, -3 });
test::@check(list.remove_last_match(55));
test::eq(list.pop()!!, -3);
test::eq(list.pop()!!, 23);
test::@check(!list.len());
list.push(23);
list.push(55);
list.push(-3);
assert(list.remove_last_match(-3));
assert(list.pop()!! == 55);
assert(list.pop()!! == 23);
assert(!list.len());
list.push_all({ 23, 55, -3 });
test::@check(list.remove_last_match(-3));
test::eq(list.pop()!!, 55);
test::eq(list.pop()!!, 23);
test::@check(!list.len());
}
fn void test_pop()
fn void test_pop() => @pool()
{
IntList list;
defer list.free();
list.push(23);
IntList list = linkedlist::@tnew{int}({ 23, 55, -3 });
test::eq(list.len(), 3);
test::eq(list.first()!!, 23);
test::eq(list.last()!!, -3);
test::eq(list.pop()!!, -3);
test::eq(list.len(), 2);
test::eq(list.first()!!, 23);
test::eq(list.last()!!, 55);
test::eq(list.pop()!!, 55);
test::eq(list.first()!!, 23);
test::eq(list.last()!!, 23);
test::eq(list.pop()!!, 23);
test::eq(list.len(), 0);
test::@check(@catch(list.pop()));
test::eq(list.len(), 0);
list.push(55);
list.push(-3);
assert(list.len() == 3);
assert(list.first()!! == 23);
assert(list.last()!! == -3);
assert(list.pop()!! == -3);
assert(list.len() == 2);
assert(list.first()!! == 23);
assert(list.last()!! == 55);
assert(list.pop()!! == 55);
assert(list.first()!! == 23);
assert(list.last()!! == 23);
assert(list.pop()!! == 23);
assert(list.len() == 0);
assert(@catch(list.pop()));
assert(list.len() == 0);
list.push(55);
assert(list.len() == 1);
test::eq(list.len(), 1);
}
fn void test_remove_last()
fn void test_remove_last() => @pool()
{
IntList list;
defer list.free();
list.push(23);
IntList list = linkedlist::@tnew{int}({ 23, 55, -3 });
test::eq(list.len(), 3);
test::eq(list.first()!!, 23);
test::eq(list.last()!!, -3);
test::@check(@ok(list.remove_last()));
test::eq(list.len(), 2);
test::eq(list.first()!!, 23);
test::eq(list.last()!!, 55);
test::@check(@ok(list.remove_last()));
test::eq(list.first()!!, 23);
test::eq(list.last()!!, 23);
test::@check(@ok(list.remove_last()));
test::eq(list.len(), 0);
test::@check(@catch(list.pop()));
test::eq(list.len(), 0);
list.push(55);
list.push(-3);
assert(list.len() == 3);
assert(list.first()!! == 23);
assert(list.last()!! == -3);
assert(@ok(list.remove_last()));
assert(list.len() == 2);
assert(list.first()!! == 23);
assert(list.last()!! == 55);
assert(@ok(list.remove_last()));
assert(list.first()!! == 23);
assert(list.last()!! == 23);
assert(@ok(list.remove_last()));
assert(list.len() == 0);
assert(@catch(list.pop()));
assert(list.len() == 0);
list.push(55);
assert(list.len() == 1);
test::eq(list.len(), 1);
}
fn void test_remove_first()
fn void test_remove_first() => @pool()
{
IntList list;
defer list.free();
list.push(23);
IntList list = linkedlist::@tnew{int}({ 23, 55, -3 });
test::eq(list.len(), 3);
test::eq(list.first()!!, 23);
test::eq(list.last()!!, -3);
test::@check(@ok(list.remove_first()));
test::eq(list.len(), 2);
test::eq(list.last()!!, -3);
test::eq(list.first()!!, 55);
test::@check(@ok(list.remove_first()));
test::eq(list.last()!!, -3);
test::eq(list.first()!!, -3);
test::@check(@ok(list.remove_first()));
test::eq(list.len(), 0);
test::@check(@catch(list.remove_first()));
test::eq(list.len(), 0);
list.push(55);
list.push(-3);
assert(list.len() == 3);
assert(list.first()!! == 23);
assert(list.last()!! == -3);
assert(@ok(list.remove_first()));
assert(list.len() == 2);
assert(list.last()!! == -3);
assert(list.first()!! == 55);
assert(@ok(list.remove_first()));
assert(list.last()!! == -3);
assert(list.first()!! == -3);
assert(@ok(list.remove_first()));
assert(list.len() == 0);
assert(@catch(list.remove_first()));
assert(list.len() == 0);
list.push(55);
assert(list.len() == 1);
test::eq(list.len(), 1);
}
fn void test_push_all_ordering() => @pool()
{
IntList l = linkedlist::@tnew{int}({ 23, 45, 66 });
test::eq(l.array_view()[0], 23);
test::eq(l.array_view()[1], 45);
test::eq(l.array_view()[2], 66);
IntList l2 = linkedlist::@tnew{int}({ 23, 45, 66 });
l2.push_front_all({ 3, 6 });
test::eq(l2.array_view()[0], 3);
test::eq(l2.array_view()[1], 6);
test::eq(l2.array_view()[2], 23);
test::eq(l2.array_view()[3], 45);
test::eq(l2.array_view()[4], 66);
}
fn void test_index_of() => @pool()
{
IntList list = linkedlist::@tnew{int}({ 23, 55, 55, -3 });
test::@error(list.index_of(20), NOT_FOUND);
test::eq(list.index_of(55)!!, 1);
test::eq(list.rindex_of(55)!!, 2);
}
fn void test_operators() => @pool()
{
IntList list = linkedlist::@tnew{int}({ 17, 109, 2, 8 });
foreach (i, &e : list.array_view()) *e += 2;
test::eq(list.array_view()[0], 19);
test::eq(list.array_view()[1], 111);
test::eq(list.array_view()[2], 4);
test::eq(list.array_view()[3], 10);
}
fn void test_iterator_set() => @pool()
{
IntList list = linkedlist::@tnew{int}({ 17, 109, 2, 8 });
IntList expected = linkedlist::@tnew{int}({1, 2, 3, 4});
foreach (int i, &v : list.array_view()) *v = i + 1;
test::eq(list, expected);
}
fn void test_iterator_reverse_set() => @pool()
{
IntList list = linkedlist::@tnew{int}({ 17, 109, 2, 8 });
IntList pushed = linkedlist::@tnew{int}();
IntList expected = linkedlist::@tnew{int}({8, 2, 109, 17});
foreach_r (int i, v : list.array_view()) pushed.push(v);
test::eq(pushed, expected);
}

View File

@@ -32,7 +32,7 @@ fn usz? ArrTestStruct.to_format(&self, Formatter* f) @dynamic
}
module array_test @test;
import std::collections::pair, std::collections::list;
import std::collections;
fn void contains()
@@ -86,6 +86,10 @@ fn void reduce() => @pool()
List {String} l;
l.push_all({ "abc", "adef", "ghi", "a12345" });
test::eq(array::@reduce(l, (usz)0, fn (acc, e, u) => acc + e.len + u), 0 + (3 + 0) + (4 + 1) + (3 + 2) + (6 + 3));
LinkedList {String} ll;
ll.push_all({ "abc", "adef", "ghi", "a12345" });
test::eq(array::@reduce(ll.array_view(), (usz)0, fn (acc, e, u) => acc + e.len + u), 0 + (3 + 0) + (4 + 1) + (3 + 2) + (6 + 3));
}
fn void sum()
@@ -127,6 +131,10 @@ fn void indices_of() => @pool()
List {String} l;
l.push_all({ "abc", "adef", "ghi", "a12345" });
test::eq(array::@tindices_of(l, fn (e, u) => e.len <= 3), (usz[]){0, 2});
LinkedList {String} ll;
ll.push_all({ "abc", "adef", "ghi", "a12345" });
test::eq(array::@tindices_of(ll.array_view(), fn (e, u) => e.len <= 3), (usz[]){0, 2});
}
fn void filter() => @pool()
@@ -143,6 +151,10 @@ fn void filter() => @pool()
List {String} l;
l.push_all({ "abc", "adef", "ghi", "a12345" });
test::eq(array::@tfilter(l, fn (e, u) => e.len <= 3), (String[]){ "abc", "ghi" });
LinkedList {String} ll;
ll.push_all({ "abc", "adef", "ghi", "a12345" });
test::eq(array::@tfilter(ll.array_view(), fn (e, u) => e.len <= 3), (String[]){ "abc", "ghi" });
}
fn void any_true() => @pool()
@@ -159,6 +171,11 @@ fn void any_true() => @pool()
l.push_all({ "abc", "adef", "ghi", "a12345" });
test::@check(array::@any(l, fn (e, u) => e.len > 5));
test::@check(!array::@any(l, fn (e, u) => e == "hi"));
LinkedList {String} ll;
ll.push_all({ "abc", "adef", "ghi", "a12345" });
test::@check(array::@any(ll.array_view(), fn (e, u) => e.len > 5));
test::@check(!array::@any(ll.array_view(), fn (e, u) => e == "hi"));
}
fn void all_true() => @pool()
@@ -175,6 +192,11 @@ fn void all_true() => @pool()
l.push_all({ "abc", "adef", "ghi", "a12345" });
test::@check(array::@all(l, fn (e, u) => e.len > 1));
test::@check(!array::@all(l, fn (e, u) => e.len > 3));
LinkedList {String} ll;
ll.push_all({ "abc", "adef", "ghi", "a12345" });
test::@check(array::@all(ll.array_view(), fn (e, u) => e.len > 1));
test::@check(!array::@all(ll.array_view(), fn (e, u) => e.len > 3));
}
@@ -365,3 +387,17 @@ fn void zip_into_list() => @pool()
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]);
}
fn void zip_into_linked_list() => @pool()
{
LinkedList{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.array_view(), right, fn (a, b) => a + (char)b.len);
test::eq(l.len(), 4);
foreach (i, c : l.array_view()) test::@check(c == expected[i], "Mismatch on index %d: %s (actual) != %s (expected)", i, c, expected[i]);
}