about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-06-18 11:26:04 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-06-18 11:37:21 -0700
commit0ab01e6f00fad00bb2103113c9c90f6c3a042321 (patch)
tree7701c48a4f6c395506197fe87849cbeef71463fa
parent9e86933229e6d6d45f0192a23e618557540d21d9 (diff)
downloadmu-0ab01e6f00fad00bb2103113c9c90f6c3a042321.tar.gz
1594 - removing from start/end of duplex list
This uncovers an issue with this interface to duplex lists: the caller
needs to check the result and invalidate any other pointers if it's null
(i.e. the list is now empty)

We *could* try to encapsulate the list in a header to help the caller
manage header pointers. But heck, let's see if writing tests helps
call-sites stay on the straight and narrow.
-rw-r--r--065duplex_list.mu71
1 files changed, 67 insertions, 4 deletions
diff --git a/065duplex_list.mu b/065duplex_list.mu
index 8334066c..287e460b 100644
--- a/065duplex_list.mu
+++ b/065duplex_list.mu
@@ -213,7 +213,10 @@ scenario inserting-after-start-of-duplex-list [
 
 # l:address:duplex-list <- remove-duplex in:address:duplex-list
 # Removes 'in' from its surrounding list. Returns some valid pointer into the
-# rest of the list. Returns null if and only if list is empty.
+# rest of the list.
+#
+# Returns null if and only if list is empty. Beware: in that case any pointers
+# to the head are now invalid.
 recipe remove-duplex [
   default-space:address:array:location <- new location:type, 30:literal
   in:address:duplex-list <- next-ingredient
@@ -252,6 +255,35 @@ scenario removing-from-duplex-list [
     1:address:duplex-list <- push-duplex 5:literal, 1:address:duplex-list
     2:address:duplex-list <- next-duplex 1:address:duplex-list  # 2 points at second element
     2:address:duplex-list <- remove-duplex 2:address:duplex-list
+    3:boolean <- equal 2:address:duplex-list, 0:literal
+    # check structure like before
+    2:address:duplex-list <- copy 1:address:duplex-list
+    4:number <- first 2:address:duplex-list
+    2:address:duplex-list <- next-duplex 2:address:duplex-list
+    5:number <- first 2:address:duplex-list
+    6:address:duplex-list <- next-duplex 2:address:duplex-list
+    2:address:duplex-list <- prev-duplex 2:address:duplex-list
+    7:number <- first 2:address:duplex-list
+    8:boolean <- equal 1:address:duplex-list, 2:address:duplex-list
+  ]
+  memory-should-contain [
+    3 <- 0  # remove returned non-null
+    4 <- 5  # scanning next, skipping deleted element
+    5 <- 3
+    6 <- 0  # no more elements
+    7 <- 5  # prev of final element
+    8 <- 1  # list back at start
+  ]
+]
+
+scenario removing-from-start-of-duplex-list [
+  run [
+    1:address:duplex-list <- copy 0:literal  # 1 points to head of list
+    1:address:duplex-list <- push-duplex 3:literal, 1:address:duplex-list
+    1:address:duplex-list <- push-duplex 4:literal, 1:address:duplex-list
+    1:address:duplex-list <- push-duplex 5:literal, 1:address:duplex-list
+    # removing from head? return value matters.
+    1:address:duplex-list <- remove-duplex 1:address:duplex-list
     # check structure like before
     2:address:duplex-list <- copy 1:address:duplex-list
     3:number <- first 2:address:duplex-list
@@ -263,14 +295,45 @@ scenario removing-from-duplex-list [
     7:boolean <- equal 1:address:duplex-list, 2:address:duplex-list
   ]
   memory-should-contain [
-    3 <- 5  # scanning next, skipping deleted element
+    3 <- 4  # scanning next, skipping deleted element
     4 <- 3
     5 <- 0  # no more elements
-    6 <- 5  # prev of final element
+    6 <- 4  # prev of final element
     7 <- 1  # list back at start
   ]
 ]
 
+scenario removing-from-end-of-duplex-list [
+  run [
+    1:address:duplex-list <- copy 0:literal  # 1 points to head of list
+    1:address:duplex-list <- push-duplex 3:literal, 1:address:duplex-list
+    1:address:duplex-list <- push-duplex 4:literal, 1:address:duplex-list
+    1:address:duplex-list <- push-duplex 5:literal, 1:address:duplex-list
+    # delete last element
+    2:address:duplex-list <- next-duplex 1:address:duplex-list
+    2:address:duplex-list <- next-duplex 2:address:duplex-list
+    2:address:duplex-list <- remove-duplex 2:address:duplex-list
+    3:boolean <- equal 2:address:duplex-list, 0:literal
+    # check structure like before
+    2:address:duplex-list <- copy 1:address:duplex-list
+    4:number <- first 2:address:duplex-list
+    2:address:duplex-list <- next-duplex 2:address:duplex-list
+    5:number <- first 2:address:duplex-list
+    6:address:duplex-list <- next-duplex 2:address:duplex-list
+    2:address:duplex-list <- prev-duplex 2:address:duplex-list
+    7:number <- first 2:address:duplex-list
+    8:boolean <- equal 1:address:duplex-list, 2:address:duplex-list
+  ]
+  memory-should-contain [
+    3 <- 0  # remove returned non-null
+    4 <- 5  # scanning next, skipping deleted element
+    5 <- 4
+    6 <- 0  # no more elements
+    7 <- 5  # prev of final element
+    8 <- 1  # list back at start
+  ]
+]
+
 scenario removing-from-singleton-list [
   run [
     1:address:duplex-list <- copy 0:literal  # 1 points to singleton list
@@ -280,7 +343,7 @@ scenario removing-from-singleton-list [
     4:address:duplex-list <- get 1:address:duplex-list/deref, prev:offset
   ]
   memory-should-contain [
-    2 <- 0  # list is now empty
+    2 <- 0  # remove returned null
     3 <- 0  # removed node is also detached
     4 <- 0
   ]