fixed: `core.list` implementation. added: test case
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 12 Dec 2023 18:58:29 +0000 (12:58 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 12 Dec 2023 18:58:29 +0000 (12:58 -0600)
core/container/list.onyx
tests/lists_comprehensive [new file with mode: 0644]
tests/lists_comprehensive.onyx [new file with mode: 0644]

index d4aa3bd0311136844002c3aac460c79326e1f9f9..b6ac202de18c39a132e683d8b13e9641feecfa12 100644 (file)
@@ -34,6 +34,19 @@ make :: ($T: type_expr, allocator := context.allocator) -> List(T) {
     return .{ allocator = allocator };
 }
 
+#overload
+__make_overload :: (_: &List($T), allocator := context.allocator) -> List(T) {
+    return #this_package.make(T, allocator);
+}
+
+from_array :: (arr: [] $T) -> List(T) {
+    l: List(T);
+    for& arr {
+        push_end(&l, *it);
+    }
+    return l;
+}
+
 free :: (list: &List) {
     elem := list.first;
     while elem != null {
@@ -48,10 +61,10 @@ push_end :: (list: &List, x: list.Elem_Type) {
     new_elem.data = x;
 
     new_elem.prev = list.last;
-    list.last.next = new_elem;
+    if list.last do list.last.next = new_elem;
     list.last = new_elem;
 
-    if list.first == null do list.first = new_elem;
+    if !list.first do list.first = new_elem;
 }
 
 push_begin :: (list: &List, x: list.Elem_Type) {
@@ -59,10 +72,10 @@ push_begin :: (list: &List, x: list.Elem_Type) {
     new_elem.data = x;
 
     new_elem.next = list.first;
-    list.first.prev = new_elem;
+    if list.first do list.first.prev = new_elem;
     list.first = new_elem;
 
-    if list.last == null do list.last = new_elem;
+    if !list.last do list.last = new_elem;
 }
 
 pop_end :: (list: &List($T), default: T = .{}) -> T {
@@ -70,7 +83,11 @@ pop_end :: (list: &List($T), default: T = .{}) -> T {
 
     end := list.last;
     list.last = list.last.prev;
-    list.last.next = null;
+    if list.last {
+        list.last.next = null;
+    } else {
+        list.first = null;
+    }
 
     defer raw_free(list.allocator, end);
     return end.data;
@@ -81,12 +98,50 @@ pop_begin :: (list: &List($T), default: T = .{}) -> T {
 
     begin := list.first;
     list.first = list.first.next;
-    list.first.prev = null;
+    if list.first {
+        list.first.prev = null;
+    } else {
+        list.last = null;
+    }
 
     defer raw_free(list.allocator, begin);
     return begin.data;
 }
 
+pop_end_opt :: (list: &List($T)) -> ? T {
+    if list.last == null do return .None;
+
+    end := list.last;
+    list.last = list.last.prev;
+    if list.last {
+        list.last.next = null;
+    } else {
+        list.first = null;
+    }
+
+    defer raw_free(list.allocator, end);
+    return end.data;
+}
+
+pop_begin_opt :: (list: &List($T)) -> ? T {
+    if list.last == null do return .None;
+
+    begin := list.first;
+    list.first = list.first.next;
+    if list.first {
+        list.first.prev = null;
+    } else {
+        list.last = null;
+    }
+
+    defer raw_free(list.allocator, begin);
+    return begin.data;
+}
+
+empty :: (list: &List) -> bool {
+    return list.first == null;
+}
+
 count :: (list: &List) -> i32 {
     c := 0;
     elem := list.first;
@@ -131,8 +186,7 @@ fold :: (list: &List($T), init: $R, f: (T, R) -> R) -> R {
     return val;
 }
 
-map :: #match #local {}
-#match map (list: &List($T), f: (T) -> $R) -> List(R) {
+map :: (list: &List($T), f: (T) -> $R) -> List(R) {
     new_list := make(R, allocator=list.allocator);
     elem := list.first;
     while elem != null {
@@ -143,16 +197,6 @@ map :: #match #local {}
     return new_list;
 }
 
-#match map (list: &List($T), f: (&T) -> void) {
-    elem := list.first;
-    while elem != null {
-        f(&elem.data);
-        elem = elem.next;
-    }
-}
-
-
-#match core.iter.as_iter as_iter
 as_iter :: (list: &List) =>
     core.iter.generator(&.{current = list.first}, (ctx) => {
         if ctx.current != null {
@@ -163,4 +207,7 @@ as_iter :: (list: &List) =>
         return .{}, false;
     });
 
+#overload
+core.iter.as_iter :: as_iter
+
 #local allocate_elem :: macro (list: &List($T)) => new(ListElem(T), allocator=list.allocator);
diff --git a/tests/lists_comprehensive b/tests/lists_comprehensive
new file mode 100644 (file)
index 0000000..7f3e16f
--- /dev/null
@@ -0,0 +1,36 @@
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+=================
+Some(0)
+Some(1)
+Some(2)
+Some(3)
+Some(4)
+=================
+5
+6
+7
+8
+9
+=================
+Some(9)
+Some(8)
+Some(7)
+Some(6)
+Some(5)
+=================
+None
+None
+None
+None
+None
+0
+true
diff --git a/tests/lists_comprehensive.onyx b/tests/lists_comprehensive.onyx
new file mode 100644 (file)
index 0000000..3cea203
--- /dev/null
@@ -0,0 +1,36 @@
+use core {*}
+
+main :: () {
+    l := make(list.List(i32));
+
+    for 10 {
+        list.push_end(&l, it);
+    }
+
+    for iter.as_iter(&l) {
+        println(it);
+    }
+
+    println("=================");
+    for 5 {
+        list.pop_begin_opt(&l) |> println();
+    }
+
+    println("=================");
+    for iter.as_iter(&l) {
+        println(it);
+    }
+
+    println("=================");
+    for 5 {
+        list.pop_end_opt(&l) |> println();
+    }
+
+    println("=================");
+    for 5 {
+        list.pop_begin_opt(&l) |> println();
+    }
+
+    println(list.count(&l));
+    println(list.empty(&l));
+}