about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2014-11-07 14:09:59 -0800
committerKartik K. Agaram <vc@akkartik.com>2014-11-07 14:09:59 -0800
commit66741bc8ef82776b480713fcfc298f315bfa6530 (patch)
treea6396d2574894eb5d1679b85fe8b9fc69dce9e84
parent0a52288c41f6f9a65ac3a598fec30a0804353845 (diff)
downloadmu-66741bc8ef82776b480713fcfc298f315bfa6530.tar.gz
258 - new channel helpers: empty? and full?
-rw-r--r--mu.arc30
-rw-r--r--mu.arc.t92
2 files changed, 118 insertions, 4 deletions
diff --git a/mu.arc b/mu.arc
index d9e96210..ba5b39d3 100644
--- a/mu.arc
+++ b/mu.arc
@@ -602,6 +602,7 @@
 
 (def sizeof (type)
   (trace "sizeof" type)
+  (assert types*.type "sizeof: no such type @type")
   (if (~or types*.type!record types*.type!array)
         types*.type!size
       types*.type!record
@@ -715,6 +716,7 @@
           (if (in op 'get 'get-address)
             (with (basetype  (typeinfo args.0)
                    field  (v args.1))
+              (assert basetype "no such type @args.0")
               (trace "cn0" "field-access " field)
               ; todo: need to rename args.0 as well?
               (when (pos 'deref (metadata args.0))
@@ -889,6 +891,34 @@
   ((watch boolean-address deref) <- copy (t literal))
   (reply (result tagged-value) (chan channel)))
 
+; An empty channel has first-empty and first-full both at the same value.
+; A full channel has first-empty just before first-full, wasting one slot.
+; (Other alternatives: https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction)
+
+(init-fn empty?
+  ((default-scope scope-address) <- new (scope literal) (30 literal))
+  ((chan channel) <- arg)
+  ((full integer) <- get (chan channel) (first-full offset))
+  ((free integer) <- get (chan channel) (first-free offset))
+  ((result boolean) <- eq (full integer) (free integer))
+  (reply (result boolean)))
+
+(init-fn full?
+  ((default-scope scope-address) <- new (scope literal) (30 literal))
+  ((chan channel) <- arg)
+  ((full integer) <- get (chan channel) (first-full offset))
+  ((curr integer) <- get (chan channel) (first-free offset))
+  ((q tagged-value-array-address) <- get (chan channel) (circular-buffer offset))
+  ((qlen integer) <- len (q tagged-value-array-address deref))
+  ((curr integer) <- add (curr integer) (1 literal))
+  { begin
+    ((remaining? boolean) <- lt (curr integer) (qlen integer))
+    (break-if (remaining? boolean))
+    ((curr integer) <- copy (0 literal))
+  }
+  ((result boolean) <- eq (full integer) (curr integer))
+  (reply (result boolean)))
+
 ; drop all traces while processing above functions
 (on-init
   (= traces* (queue)))
diff --git a/mu.arc.t b/mu.arc.t
index 41513a33..1c18eeeb 100644
--- a/mu.arc.t
+++ b/mu.arc.t
@@ -147,6 +147,7 @@
 ; look for it. Everything outside 'add-fns' is just test-harness details.
 
 (reset)
+;? (set dump-trace*)
 (new-trace "literal")
 (add-fns
   '((main
@@ -1937,11 +1938,94 @@
         (~is 0 memory*.5))
   (prn "F - 'read' can wrap pointer back to start"))
 
-; An empty channel has first-empty and first-full both at the same value.
-; A full channel has first-empty just before first-full, wasting one slot.
-; (Other alternatives: https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction)
+(reset)
+(new-trace "channel-new-empty-not-full")
+(add-fns
+  '((main
+      ((1 channel-address) <- new-channel (3 literal))
+      ((2 boolean) <- empty? (1 channel-address deref))
+      ((3 boolean) <- full? (1 channel-address deref)))))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(if (or (~is t memory*.2)
+        (~is nil memory*.3))
+  (prn "F - a new channel is always empty, never full"))
 
-; TODO
+(reset)
+(new-trace "channel-write-not-empty")
+(add-fns
+  '((main
+      ((1 channel-address) <- new-channel (3 literal))
+      ((2 integer-address) <- new (integer literal))
+      ((2 integer-address deref) <- copy (34 literal))
+      ((3 tagged-value-address) <- new-tagged-value (integer-address literal) (2 integer-address))
+      ((1 channel-address deref) <- write (1 channel-address deref) (3 tagged-value-address deref))
+      ((4 boolean) <- empty? (1 channel-address deref))
+      ((5 boolean) <- full? (1 channel-address deref)))))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(if (or (~is nil memory*.4)
+        (~is nil memory*.5))
+  (prn "F - a channel after writing is never empty"))
+
+(reset)
+(new-trace "channel-write-full")
+(add-fns
+  '((main
+      ((1 channel-address) <- new-channel (2 literal))
+      ((2 integer-address) <- new (integer literal))
+      ((2 integer-address deref) <- copy (34 literal))
+      ((3 tagged-value-address) <- new-tagged-value (integer-address literal) (2 integer-address))
+      ((1 channel-address deref) <- write (1 channel-address deref) (3 tagged-value-address deref))
+      ((4 boolean) <- empty? (1 channel-address deref))
+      ((5 boolean) <- full? (1 channel-address deref)))))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(if (or (~is nil memory*.4)
+        (~is t memory*.5))
+  (prn "F - a channel after writing may be full"))
+
+(reset)
+(new-trace "channel-read-not-full")
+(add-fns
+  '((main
+      ((1 channel-address) <- new-channel (3 literal))
+      ((2 integer-address) <- new (integer literal))
+      ((2 integer-address deref) <- copy (34 literal))
+      ((3 tagged-value-address) <- new-tagged-value (integer-address literal) (2 integer-address))
+      ((1 channel-address deref) <- write (1 channel-address deref) (3 tagged-value-address deref))
+      ((1 channel-address deref) <- write (1 channel-address deref) (3 tagged-value-address deref))
+      (_ (1 channel-address deref) <- read (1 channel-address deref))
+      ((4 boolean) <- empty? (1 channel-address deref))
+      ((5 boolean) <- full? (1 channel-address deref)))))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(if (or (~is nil memory*.4)
+        (~is nil memory*.5))
+  (prn "F - a channel after reading is never full"))
+
+(reset)
+(new-trace "channel-read-empty")
+(add-fns
+  '((main
+      ((1 channel-address) <- new-channel (3 literal))
+      ((2 integer-address) <- new (integer literal))
+      ((2 integer-address deref) <- copy (34 literal))
+      ((3 tagged-value-address) <- new-tagged-value (integer-address literal) (2 integer-address))
+      ((1 channel-address deref) <- write (1 channel-address deref) (3 tagged-value-address deref))
+      (_ (1 channel-address deref) <- read (1 channel-address deref))
+      ((4 boolean) <- empty? (1 channel-address deref))
+      ((5 boolean) <- full? (1 channel-address deref)))))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(if (or (~is t memory*.4)
+        (~is nil memory*.5))
+  (prn "F - a channel after reading may be empty"))
 
 ; We'd like to block routines when they write to a full channel or read from
 ; an empty channel.