mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
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:
@@ -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)
|
||||
{
|
||||
|
||||
38
benchmarks/stdlib/collections/linkedlist.c3
Normal file
38
benchmarks/stdlib/collections/linkedlist.c3
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user