diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2016-09-17 15:01:51 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2016-09-17 15:01:51 -0700 |
commit | f344b250f6f062a1a1902bf69b23ebf9b565de0e (patch) | |
tree | 199bd32a9aee198d5028b1c21b83d2cf0944b2b6 /html/075channel.mu.html | |
parent | 897ae8c1855f830d8819759ea327d147f28a09bf (diff) | |
download | mu-f344b250f6f062a1a1902bf69b23ebf9b565de0e.tar.gz |
3395
Diffstat (limited to 'html/075channel.mu.html')
-rw-r--r-- | html/075channel.mu.html | 204 |
1 files changed, 102 insertions, 102 deletions
diff --git a/html/075channel.mu.html b/html/075channel.mu.html index 4912015e..a2b049a6 100644 --- a/html/075channel.mu.html +++ b/html/075channel.mu.html @@ -49,9 +49,9 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="muScenario">scenario</span> channel [ run [ <span class="Constant">local-scope</span> - source:address:source:number, sink:address:sink:number<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> + source:&:source:num, sink:&:sink:num<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> sink<span class="Special"> <- </span>write sink, <span class="Constant">34</span> - <span class="Constant">10</span>:number/<span class="Special">raw</span>, <span class="Constant">11</span>:boolean/<span class="Special">raw</span>, source<span class="Special"> <- </span>read source + <span class="Constant">10</span>:num/<span class="Special">raw</span>, <span class="Constant">11</span>:bool/<span class="Special">raw</span>, source<span class="Special"> <- </span>read source ] memory-should-contain [ <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">34</span> @@ -60,34 +60,34 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color ] <span class="muData">container</span> channel:_elem [ - lock:boolean <span class="Comment"># inefficient but simple: serialize all reads as well as writes</span> - first-full:number <span class="Comment"># for write</span> - first-free:number <span class="Comment"># for read</span> + lock:bool <span class="Comment"># inefficient but simple: serialize all reads as well as writes</span> + first-full:num <span class="Comment"># for write</span> + first-free:num <span class="Comment"># for read</span> <span class="Comment"># A circular buffer contains values from index first-full up to (but not</span> <span class="Comment"># including) index first-empty. The reader always modifies it at first-full,</span> <span class="Comment"># while the writer always modifies it at first-empty.</span> - data:address:array:_elem + data:&:@:_elem ] <span class="Comment"># Since channels have two ends, and since it's an error to use either end from</span> <span class="Comment"># multiple routines, let's distinguish the ends.</span> <span class="muData">container</span> source:_elem [ - chan:address:channel:_elem + chan:&:channel:_elem ] <span class="muData">container</span> sink:_elem [ - chan:address:channel:_elem + chan:&:channel:_elem ] -<span class="muRecipe">def</span> new-channel capacity:number<span class="muRecipe"> -> </span>in:address:source:_elem, out:address:sink:_elem [ +<span class="muRecipe">def</span> new-channel capacity:num<span class="muRecipe"> -> </span>in:&:source:_elem, out:&:sink:_elem [ <span class="Constant">local-scope</span> <span class="Constant">load-ingredients</span> - result:address:channel:_elem<span class="Special"> <- </span>new <span class="Delimiter">{</span>(channel _elem): type<span class="Delimiter">}</span> + result:&:channel:_elem<span class="Special"> <- </span>new <span class="Delimiter">{</span>(channel _elem): type<span class="Delimiter">}</span> *result<span class="Special"> <- </span>put *result, <span class="Constant">first-full:offset</span>, <span class="Constant">0</span> *result<span class="Special"> <- </span>put *result, <span class="Constant">first-free:offset</span>, <span class="Constant">0</span> capacity<span class="Special"> <- </span>add capacity, <span class="Constant">1</span> <span class="Comment"># unused slot for 'full?' below</span> - data:address:array:_elem<span class="Special"> <- </span>new <span class="Constant">_elem:type</span>, capacity + data:&:@:_elem<span class="Special"> <- </span>new <span class="Constant">_elem:type</span>, capacity *result<span class="Special"> <- </span>put *result, <span class="Constant">data:offset</span>, data in<span class="Special"> <- </span>new <span class="Delimiter">{</span>(source _elem): type<span class="Delimiter">}</span> *in<span class="Special"> <- </span>put *in, <span class="Constant">chan:offset</span>, result @@ -95,11 +95,11 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color *out<span class="Special"> <- </span>put *out, <span class="Constant">chan:offset</span>, result ] -<span class="muRecipe">def</span> write out:address:sink:_elem, val:_elem<span class="muRecipe"> -> </span>out:address:sink:_elem [ +<span class="muRecipe">def</span> write out:&:sink:_elem, val:_elem<span class="muRecipe"> -> </span>out:&:sink:_elem [ <span class="Constant">local-scope</span> <span class="Constant">load-ingredients</span> assert out, <span class="Constant">[write to null channel]</span> - chan:address:channel:_elem<span class="Special"> <- </span>get *out, <span class="Constant">chan:offset</span> + chan:&:channel:_elem<span class="Special"> <- </span>get *out, <span class="Constant">chan:offset</span> <span class="Constant"> <channel-write-initial></span> <span class="Comment"># block until lock is acquired AND queue has room</span> lock:location<span class="Special"> <- </span>get-location *chan, <span class="Constant">lock:offset</span> @@ -108,7 +108,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="CommentedCode">#? $print [trying to acquire lock for writing], 10/newline</span> wait-for-reset-then-set lock <span class="CommentedCode">#? $print [lock acquired for writing], 10/newline</span> - full?:boolean<span class="Special"> <- </span>channel-full? chan + full?:bool<span class="Special"> <- </span>channel-full? chan <span class="muControl">break-unless</span> full? <span class="CommentedCode">#? $print [but channel is full; relinquishing lock], 10/newline</span> <span class="Comment"># channel is full; relinquish lock and give a reader the opportunity to</span> @@ -121,16 +121,16 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color current-routine-is-unblocked <span class="CommentedCode">#? $print [performing write], 10/newline</span> <span class="Comment"># store a deep copy of val</span> - circular-buffer:address:array:_elem<span class="Special"> <- </span>get *chan, <span class="Constant">data:offset</span> - free:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-free:offset</span> + circular-buffer:&:@:_elem<span class="Special"> <- </span>get *chan, <span class="Constant">data:offset</span> + free:num<span class="Special"> <- </span>get *chan, <span class="Constant">first-free:offset</span> val-copy:_elem<span class="Special"> <- </span>deep-copy val <span class="Comment"># on this instruction rests all Mu's concurrency-safety</span> *circular-buffer<span class="Special"> <- </span>put-index *circular-buffer, free, val-copy <span class="Comment"># mark its slot as filled</span> free<span class="Special"> <- </span>add free, <span class="Constant">1</span> <span class="Delimiter">{</span> <span class="Comment"># wrap free around to 0 if necessary</span> - len:number<span class="Special"> <- </span>length *circular-buffer - at-end?:boolean<span class="Special"> <- </span>greater-or-equal free, len + len:num<span class="Special"> <- </span>length *circular-buffer + at-end?:bool<span class="Special"> <- </span>greater-or-equal free, len <span class="muControl">break-unless</span> at-end? free<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Delimiter">}</span> @@ -140,12 +140,12 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color reset lock ] -<span class="muRecipe">def</span> read in:address:source:_elem<span class="muRecipe"> -> </span>result:_elem, eof?:boolean, in:address:source:_elem [ +<span class="muRecipe">def</span> read in:&:source:_elem<span class="muRecipe"> -> </span>result:_elem, eof?:bool, in:&:source:_elem [ <span class="Constant">local-scope</span> <span class="Constant">load-ingredients</span> assert in, <span class="Constant">[read on null channel]</span> eof?<span class="Special"> <- </span>copy <span class="Constant">0/false</span> <span class="Comment"># default result</span> - chan:address:channel:_elem<span class="Special"> <- </span>get *in, <span class="Constant">chan:offset</span> + chan:&:channel:_elem<span class="Special"> <- </span>get *in, <span class="Constant">chan:offset</span> <span class="Comment"># block until lock is acquired AND queue has data</span> lock:location<span class="Special"> <- </span>get-location *chan, <span class="Constant">lock:offset</span> <span class="CommentedCode">#? $print [read], 10/newline</span> @@ -153,7 +153,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="CommentedCode">#? $print [trying to acquire lock for reading], 10/newline</span> wait-for-reset-then-set lock <span class="CommentedCode">#? $print [lock acquired for reading], 10/newline</span> - empty?:boolean<span class="Special"> <- </span>channel-empty? chan + empty?:bool<span class="Special"> <- </span>channel-empty? chan <span class="muControl">break-unless</span> empty? <span class="CommentedCode">#? $print [but channel is empty; relinquishing lock], 10/newline</span> <span class="Comment"># channel is empty; relinquish lock and give a writer the opportunity to</span> @@ -166,18 +166,18 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="Delimiter">}</span> current-routine-is-unblocked <span class="Comment"># pull result off</span> - full:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-full:offset</span> - circular-buffer:address:array:_elem<span class="Special"> <- </span>get *chan, <span class="Constant">data:offset</span> + full:num<span class="Special"> <- </span>get *chan, <span class="Constant">first-full:offset</span> + circular-buffer:&:@:_elem<span class="Special"> <- </span>get *chan, <span class="Constant">data:offset</span> result<span class="Special"> <- </span>index *circular-buffer, full <span class="Comment"># clear the slot</span> - empty:address:_elem<span class="Special"> <- </span>new <span class="Constant">_elem:type</span> + empty:&:_elem<span class="Special"> <- </span>new <span class="Constant">_elem:type</span> *circular-buffer<span class="Special"> <- </span>put-index *circular-buffer, full, *empty <span class="Comment"># mark its slot as empty</span> full<span class="Special"> <- </span>add full, <span class="Constant">1</span> <span class="Delimiter">{</span> <span class="Comment"># wrap full around to 0 if necessary</span> - len:number<span class="Special"> <- </span>length *circular-buffer - at-end?:boolean<span class="Special"> <- </span>greater-or-equal full, len + len:num<span class="Special"> <- </span>length *circular-buffer + at-end?:bool<span class="Special"> <- </span>greater-or-equal full, len <span class="muControl">break-unless</span> at-end? full<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Delimiter">}</span> @@ -187,12 +187,12 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color reset lock ] -<span class="muRecipe">def</span> clear in:address:source:_elem<span class="muRecipe"> -> </span>in:address:source:_elem [ +<span class="muRecipe">def</span> clear in:&:source:_elem<span class="muRecipe"> -> </span>in:&:source:_elem [ <span class="Constant">local-scope</span> <span class="Constant">load-ingredients</span> - chan:address:channel:_elem<span class="Special"> <- </span>get *in, <span class="Constant">chan:offset</span> + chan:&:channel:_elem<span class="Special"> <- </span>get *in, <span class="Constant">chan:offset</span> <span class="Delimiter">{</span> - empty?:boolean<span class="Special"> <- </span>channel-empty? chan + empty?:bool<span class="Special"> <- </span>channel-empty? chan <span class="muControl">break-if</span> empty? _, _, in<span class="Special"> <- </span>read in <span class="Delimiter">}</span> @@ -201,10 +201,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="muScenario">scenario</span> channel-initialization [ run [ <span class="Constant">local-scope</span> - source:address:source:number<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> - chan:address:channel:number<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> - <span class="Constant">10</span>:number/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-full:offset</span> - <span class="Constant">11</span>:number/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-free:offset</span> + source:&:source:num<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> + chan:&:channel:num<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> + <span class="Constant">10</span>:num/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-full:offset</span> + <span class="Constant">11</span>:num/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-free:offset</span> ] memory-should-contain [ <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># first-full</span> @@ -215,11 +215,11 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="muScenario">scenario</span> channel-write-increments-free [ run [ <span class="Constant">local-scope</span> - _, sink:address:sink:number<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> + _, sink:&:sink:num<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> sink<span class="Special"> <- </span>write sink, <span class="Constant">34</span> - chan:address:channel:number<span class="Special"> <- </span>get *sink, <span class="Constant">chan:offset</span> - <span class="Constant">10</span>:number/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-full:offset</span> - <span class="Constant">11</span>:number/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-free:offset</span> + chan:&:channel:num<span class="Special"> <- </span>get *sink, <span class="Constant">chan:offset</span> + <span class="Constant">10</span>:num/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-full:offset</span> + <span class="Constant">11</span>:num/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-free:offset</span> ] memory-should-contain [ <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># first-full</span> @@ -230,12 +230,12 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="muScenario">scenario</span> channel-read-increments-full [ run [ <span class="Constant">local-scope</span> - source:address:source:number, sink:address:sink:number<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> + source:&:source:num, sink:&:sink:num<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> sink<span class="Special"> <- </span>write sink, <span class="Constant">34</span> _, _, source<span class="Special"> <- </span>read source - chan:address:channel:number<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> - <span class="Constant">10</span>:number/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-full:offset</span> - <span class="Constant">11</span>:number/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-free:offset</span> + chan:&:channel:num<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> + <span class="Constant">10</span>:num/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-full:offset</span> + <span class="Constant">11</span>:num/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-free:offset</span> ] memory-should-contain [ <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># first-full</span> @@ -247,20 +247,20 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color run [ <span class="Constant">local-scope</span> <span class="Comment"># channel with just 1 slot</span> - source:address:source:number, sink:address:sink:number<span class="Special"> <- </span>new-channel <span class="Constant">1/capacity</span> - chan:address:channel:number<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> + source:&:source:num, sink:&:sink:num<span class="Special"> <- </span>new-channel <span class="Constant">1/capacity</span> + chan:&:channel:num<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> <span class="Comment"># write and read a value</span> sink<span class="Special"> <- </span>write sink, <span class="Constant">34</span> _, _, source<span class="Special"> <- </span>read source <span class="Comment"># first-free will now be 1</span> - <span class="Constant">10</span>:number/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-free:offset</span> - <span class="Constant">11</span>:number/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-free:offset</span> + <span class="Constant">10</span>:num/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-free:offset</span> + <span class="Constant">11</span>:num/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-free:offset</span> <span class="Comment"># write second value, verify that first-free wraps</span> sink<span class="Special"> <- </span>write sink, <span class="Constant">34</span> - <span class="Constant">20</span>:number/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-free:offset</span> + <span class="Constant">20</span>:num/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-free:offset</span> <span class="Comment"># read second value, verify that first-full wraps</span> _, _, source<span class="Special"> <- </span>read source - <span class="Constant">30</span>:number/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-full:offset</span> + <span class="Constant">30</span>:num/<span class="Special">raw <- </span>get *chan, <span class="Constant">first-full:offset</span> ] memory-should-contain [ <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># first-free after first write</span> @@ -273,10 +273,10 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="muScenario">scenario</span> channel-new-empty-not-full [ run [ <span class="Constant">local-scope</span> - source:address:source:number<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> - chan:address:channel:number<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> - <span class="Constant">10</span>:boolean/<span class="Special">raw <- </span>channel-empty? chan - <span class="Constant">11</span>:boolean/<span class="Special">raw <- </span>channel-full? chan + source:&:source:num<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> + chan:&:channel:num<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> + <span class="Constant">10</span>:bool/<span class="Special">raw <- </span>channel-empty? chan + <span class="Constant">11</span>:bool/<span class="Special">raw <- </span>channel-full? chan ] memory-should-contain [ <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># empty?</span> @@ -286,11 +286,11 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="muScenario">scenario</span> channel-write-not-empty [ run [ - source:address:source:number, sink:address:sink:number<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> - chan:address:channel:number<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> + source:&:source:num, sink:&:sink:num<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> + chan:&:channel:num<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> sink<span class="Special"> <- </span>write sink, <span class="Constant">34</span> - <span class="Constant">10</span>:boolean/<span class="Special">raw <- </span>channel-empty? chan - <span class="Constant">11</span>:boolean/<span class="Special">raw <- </span>channel-full? chan + <span class="Constant">10</span>:bool/<span class="Special">raw <- </span>channel-empty? chan + <span class="Constant">11</span>:bool/<span class="Special">raw <- </span>channel-full? chan ] memory-should-contain [ <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># empty?</span> @@ -301,11 +301,11 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="muScenario">scenario</span> channel-write-full [ run [ <span class="Constant">local-scope</span> - source:address:source:number, sink:address:sink:number<span class="Special"> <- </span>new-channel <span class="Constant">1/capacity</span> - chan:address:channel:number<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> + source:&:source:num, sink:&:sink:num<span class="Special"> <- </span>new-channel <span class="Constant">1/capacity</span> + chan:&:channel:num<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> sink<span class="Special"> <- </span>write sink, <span class="Constant">34</span> - <span class="Constant">10</span>:boolean/<span class="Special">raw <- </span>channel-empty? chan - <span class="Constant">11</span>:boolean/<span class="Special">raw <- </span>channel-full? chan + <span class="Constant">10</span>:bool/<span class="Special">raw <- </span>channel-empty? chan + <span class="Constant">11</span>:bool/<span class="Special">raw <- </span>channel-full? chan ] memory-should-contain [ <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># empty?</span> @@ -316,12 +316,12 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="muScenario">scenario</span> channel-read-not-full [ run [ <span class="Constant">local-scope</span> - source:address:source:number, sink:address:sink:number<span class="Special"> <- </span>new-channel <span class="Constant">1/capacity</span> - chan:address:channel:number<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> + source:&:source:num, sink:&:sink:num<span class="Special"> <- </span>new-channel <span class="Constant">1/capacity</span> + chan:&:channel:num<span class="Special"> <- </span>get *source, <span class="Constant">chan:offset</span> sink<span class="Special"> <- </span>write sink, <span class="Constant">34</span> _, _, source<span class="Special"> <- </span>read source - <span class="Constant">10</span>:boolean/<span class="Special">raw <- </span>channel-empty? chan - <span class="Constant">11</span>:boolean/<span class="Special">raw <- </span>channel-full? chan + <span class="Constant">10</span>:bool/<span class="Special">raw <- </span>channel-empty? chan + <span class="Constant">11</span>:bool/<span class="Special">raw <- </span>channel-full? chan ] memory-should-contain [ <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># empty?</span> @@ -334,21 +334,21 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="Comment"># every channel comes with a boolean signifying if it's been closed</span> <span class="Comment"># initially this boolean is false</span> <span class="muData">container</span> channel:_elem [ - closed?:boolean + closed?:bool ] <span class="Comment"># a channel can be closed from either the source or the sink</span> <span class="Comment"># both routines can modify the 'closed?' bit, but they can only ever set it, so this is a benign race</span> -<span class="muRecipe">def</span> close x:address:source:_elem<span class="muRecipe"> -> </span>x:address:source:_elem [ +<span class="muRecipe">def</span> close x:&:source:_elem<span class="muRecipe"> -> </span>x:&:source:_elem [ <span class="Constant">local-scope</span> <span class="Constant">load-ingredients</span> - chan:address:channel:_elem<span class="Special"> <- </span>get *x, <span class="Constant">chan:offset</span> + chan:&:channel:_elem<span class="Special"> <- </span>get *x, <span class="Constant">chan:offset</span> *chan<span class="Special"> <- </span>put *chan, <span class="Constant">closed?:offset</span>, <span class="Constant">1/true</span> ] -<span class="muRecipe">def</span> close x:address:sink:_elem<span class="muRecipe"> -> </span>x:address:sink:_elem [ +<span class="muRecipe">def</span> close x:&:sink:_elem<span class="muRecipe"> -> </span>x:&:sink:_elem [ <span class="Constant">local-scope</span> <span class="Constant">load-ingredients</span> - chan:address:channel:_elem<span class="Special"> <- </span>get *x, <span class="Constant">chan:offset</span> + chan:&:channel:_elem<span class="Special"> <- </span>get *x, <span class="Constant">chan:offset</span> *chan<span class="Special"> <- </span>put *chan, <span class="Constant">closed?:offset</span>, <span class="Constant">1/true</span> ] @@ -359,14 +359,14 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="Comment"># future reads continue until the channel empties,</span> <span class="Comment"># then the channel is also closed for reading</span> <span class="muRecipe">after</span> <span class="Constant"><channel-write-initial></span> [ - closed?:boolean<span class="Special"> <- </span>get *chan, <span class="Constant">closed?:offset</span> + closed?:bool<span class="Special"> <- </span>get *chan, <span class="Constant">closed?:offset</span> <span class="muControl">return-if</span> closed? ] <span class="muRecipe">after</span> <span class="Constant"><channel-read-empty></span> [ - closed?:boolean<span class="Special"> <- </span>get *chan, <span class="Constant">closed?:offset</span> + closed?:bool<span class="Special"> <- </span>get *chan, <span class="Constant">closed?:offset</span> <span class="Delimiter">{</span> <span class="muControl">break-unless</span> closed? - empty-result:address:_elem<span class="Special"> <- </span>new <span class="Constant">_elem:type</span> + empty-result:&:_elem<span class="Special"> <- </span>new <span class="Constant">_elem:type</span> current-routine-is-unblocked <span class="muControl">return</span> *empty-result, <span class="Constant">1/true</span> <span class="Delimiter">}</span> @@ -375,64 +375,64 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="SalientComment">## helpers</span> <span class="Comment"># An empty channel has first-empty and first-full both at the same value.</span> -<span class="muRecipe">def</span> channel-empty? chan:address:channel:_elem<span class="muRecipe"> -> </span>result:boolean [ +<span class="muRecipe">def</span> channel-empty? chan:&:channel:_elem<span class="muRecipe"> -> </span>result:bool [ <span class="Constant">local-scope</span> <span class="Constant">load-ingredients</span> <span class="Comment"># return chan.first-full == chan.first-free</span> - full:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-full:offset</span> - free:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-free:offset</span> + full:num<span class="Special"> <- </span>get *chan, <span class="Constant">first-full:offset</span> + free:num<span class="Special"> <- </span>get *chan, <span class="Constant">first-free:offset</span> result<span class="Special"> <- </span>equal full, free ] <span class="Comment"># A full channel has first-empty just before first-full, wasting one slot.</span> <span class="Comment"># (Other alternatives: <a href="https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction)">https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction)</a></span> -<span class="muRecipe">def</span> channel-full? chan:address:channel:_elem<span class="muRecipe"> -> </span>result:boolean [ +<span class="muRecipe">def</span> channel-full? chan:&:channel:_elem<span class="muRecipe"> -> </span>result:bool [ <span class="Constant">local-scope</span> <span class="Constant">load-ingredients</span> <span class="Comment"># tmp = chan.first-free + 1</span> - tmp:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-free:offset</span> + tmp:num<span class="Special"> <- </span>get *chan, <span class="Constant">first-free:offset</span> tmp<span class="Special"> <- </span>add tmp, <span class="Constant">1</span> <span class="Delimiter">{</span> <span class="Comment"># if tmp == chan.capacity, tmp = 0</span> - len:number<span class="Special"> <- </span>capacity chan - at-end?:boolean<span class="Special"> <- </span>greater-or-equal tmp, len + len:num<span class="Special"> <- </span>capacity chan + at-end?:bool<span class="Special"> <- </span>greater-or-equal tmp, len <span class="muControl">break-unless</span> at-end? tmp<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Delimiter">}</span> <span class="Comment"># return chan.first-full == tmp</span> - full:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-full:offset</span> + full:num<span class="Special"> <- </span>get *chan, <span class="Constant">first-full:offset</span> result<span class="Special"> <- </span>equal full, tmp ] -<span class="muRecipe">def</span> capacity chan:address:channel:_elem<span class="muRecipe"> -> </span>result:number [ +<span class="muRecipe">def</span> capacity chan:&:channel:_elem<span class="muRecipe"> -> </span>result:num [ <span class="Constant">local-scope</span> <span class="Constant">load-ingredients</span> - q:address:array:_elem<span class="Special"> <- </span>get *chan, <span class="Constant">data:offset</span> + q:&:@:_elem<span class="Special"> <- </span>get *chan, <span class="Constant">data:offset</span> result<span class="Special"> <- </span>length *q ] <span class="Comment"># helper for channels of characters in particular</span> -<span class="muRecipe">def</span> buffer-lines in:address:source:character, buffered-out:address:sink:character<span class="muRecipe"> -> </span>buffered-out:address:sink:character, in:address:source:character [ +<span class="muRecipe">def</span> buffer-lines in:&:source:char, buffered-out:&:sink:char<span class="muRecipe"> -> </span>buffered-out:&:sink:char, in:&:source:char [ <span class="Constant">local-scope</span> <span class="Constant">load-ingredients</span> <span class="Comment"># repeat forever</span> - eof?:boolean<span class="Special"> <- </span>copy <span class="Constant">0/false</span> + eof?:bool<span class="Special"> <- </span>copy <span class="Constant">0/false</span> <span class="Delimiter">{</span> - line:address:buffer<span class="Special"> <- </span>new-buffer <span class="Constant">30</span> + line:&:buffer<span class="Special"> <- </span>new-buffer <span class="Constant">30</span> <span class="Comment"># read characters from 'in' until newline, copy into line</span> <span class="Delimiter">{</span> <span class="Constant"> +next-character</span> - c:character, eof?:boolean, in<span class="Special"> <- </span>read in + c:char, eof?:bool, in<span class="Special"> <- </span>read in <span class="muControl">break-if</span> eof? <span class="Comment"># drop a character on backspace</span> <span class="Delimiter">{</span> <span class="Comment"># special-case: if it's a backspace</span> - backspace?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">8</span> + backspace?:bool<span class="Special"> <- </span>equal c, <span class="Constant">8</span> <span class="muControl">break-unless</span> backspace? <span class="Comment"># drop previous character</span> <span class="Delimiter">{</span> - buffer-length:number<span class="Special"> <- </span>get *line, <span class="Constant">length:offset</span> - buffer-empty?:boolean<span class="Special"> <- </span>equal buffer-length, <span class="Constant">0</span> + buffer-length:num<span class="Special"> <- </span>get *line, <span class="Constant">length:offset</span> + buffer-empty?:bool<span class="Special"> <- </span>equal buffer-length, <span class="Constant">0</span> <span class="muControl">break-if</span> buffer-empty? buffer-length<span class="Special"> <- </span>subtract buffer-length, <span class="Constant">1</span> *line<span class="Special"> <- </span>put *line, <span class="Constant">length:offset</span>, buffer-length @@ -442,18 +442,18 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="Delimiter">}</span> <span class="Comment"># append anything else</span> line<span class="Special"> <- </span>append line, c - line-done?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + line-done?:bool<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> <span class="muControl">break-if</span> line-done? <span class="muControl">loop</span> <span class="Delimiter">}</span> <span class="Comment"># copy line into 'buffered-out'</span> - i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + i:num<span class="Special"> <- </span>copy <span class="Constant">0</span> line-contents:text<span class="Special"> <- </span>get *line, <span class="Constant">data:offset</span> - max:number<span class="Special"> <- </span>get *line, <span class="Constant">length:offset</span> + max:num<span class="Special"> <- </span>get *line, <span class="Constant">length:offset</span> <span class="Delimiter">{</span> - done?:boolean<span class="Special"> <- </span>greater-or-equal i, max + done?:bool<span class="Special"> <- </span>greater-or-equal i, max <span class="muControl">break-if</span> done? - c:character<span class="Special"> <- </span>index *line-contents, i + c:char<span class="Special"> <- </span>index *line-contents, i buffered-out<span class="Special"> <- </span>write buffered-out, c i<span class="Special"> <- </span>add i, <span class="Constant">1</span> <span class="muControl">loop</span> @@ -470,38 +470,38 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color <span class="muScenario">scenario</span> buffer-lines-blocks-until-newline [ run [ <span class="Constant">local-scope</span> - source:address:source:character, sink:address:sink:character<span class="Special"> <- </span>new-channel <span class="Constant">10/capacity</span> - _, buffered-stdin:address:sink:character/buffered-stdin<span class="Special"> <- </span>new-channel <span class="Constant">10/capacity</span> - buffered-chan:address:channel:character<span class="Special"> <- </span>get *buffered-stdin, <span class="Constant">chan:offset</span> - empty?:boolean<span class="Special"> <- </span>channel-empty? buffered-chan + source:&:source:char, sink:&:sink:char<span class="Special"> <- </span>new-channel <span class="Constant">10/capacity</span> + _, buffered-stdin:&:sink:char/buffered-stdin<span class="Special"> <- </span>new-channel <span class="Constant">10/capacity</span> + buffered-chan:&:channel:char<span class="Special"> <- </span>get *buffered-stdin, <span class="Constant">chan:offset</span> + empty?:bool<span class="Special"> <- </span>channel-empty? buffered-chan assert empty?, <span class="Constant">[ </span> <span class="Constant">F buffer-lines-blocks-until-newline: channel should be empty after init]</span> <span class="Comment"># buffer stdin into buffered-stdin, try to read from buffered-stdin</span> - buffer-routine:number<span class="Special"> <- </span>start-running buffer-lines, source, buffered-stdin + buffer-routine:num<span class="Special"> <- </span>start-running buffer-lines, source, buffered-stdin wait-for-routine-to-block buffer-routine empty?<span class="Special"> <- </span>channel-empty? buffered-chan - assert empty?:boolean, <span class="Constant">[ </span> + assert empty?:bool, <span class="Constant">[ </span> <span class="Constant">F buffer-lines-blocks-until-newline: channel should be empty after buffer-lines bring-up]</span> <span class="Comment"># write 'a'</span> sink<span class="Special"> <- </span>write sink, <span class="Constant">97/a</span> restart buffer-routine wait-for-routine-to-block buffer-routine empty?<span class="Special"> <- </span>channel-empty? buffered-chan - assert empty?:boolean, <span class="Constant">[ </span> + assert empty?:bool, <span class="Constant">[ </span> <span class="Constant">F buffer-lines-blocks-until-newline: channel should be empty after writing 'a']</span> <span class="Comment"># write 'b'</span> sink<span class="Special"> <- </span>write sink, <span class="Constant">98/b</span> restart buffer-routine wait-for-routine-to-block buffer-routine empty?<span class="Special"> <- </span>channel-empty? buffered-chan - assert empty?:boolean, <span class="Constant">[ </span> + assert empty?:bool, <span class="Constant">[ </span> <span class="Constant">F buffer-lines-blocks-until-newline: channel should be empty after writing 'b']</span> <span class="Comment"># write newline</span> sink<span class="Special"> <- </span>write sink, <span class="Constant">10/newline</span> restart buffer-routine wait-for-routine-to-block buffer-routine empty?<span class="Special"> <- </span>channel-empty? buffered-chan - data-emitted?:boolean<span class="Special"> <- </span>not empty? + data-emitted?:bool<span class="Special"> <- </span>not empty? assert data-emitted?, <span class="Constant">[ </span> <span class="Constant">F buffer-lines-blocks-until-newline: channel should contain data after writing newline]</span> trace <span class="Constant">1</span>, <span class="Constant">[test]</span>, <span class="Constant">[reached end]</span> |