about summary refs log blame commit diff stats
path: root/html/033exclusive_container.cc.html
blob: b2a351062c25c687b2274e0e5cd7fb2a4715fc5e (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12



                                                                                          
                                             






                                                                                         

                                                                                                 
                        
                             

                                   

                              
                            
                               
                             

















                                                                                                         
                                                                                                         
                                
                                                                                                                                                

                                                                                                               
                                                                                                                                         
                                                             
                                                                                                                  
                                                                                                                                                             
                                                             

                                                                                                                                                             



                                                                                                                                                                                                           


                                                                                                          


                                                                                                                        


                                                                                                                                                                
                                                                                                                                                                                                                 





                                                                             
                                                                                                                                                                

                                                                                                   



                                                                                                                                                                                                                                                                         












                                                                                                               
                                                                                                                                 


                                                        


                                                                                                                  
                                                                                                                                                                                                                                                                                                  




                                                                  


                                                                                                                  
                                                                                                                                                                                                                                                                                                  





                                                                                      
                                                                                                                       
                                                                                         

                                                                                                                                                                                                                        


                                                                                                                                                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                            

                                                                                                                                                     


                                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                                                                                                                    


                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                    


                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            


                                                                                                                                                                                                                                                             
                                                                                         
                                  
                                       
                                                                            
                                  

                                                                                                                                                                                                                            

                                                                       




                                                                                             

          







                                                                          
                                                                                                                                                                                 

                                                                                                                                                                                 



                                                                                                             

          


             


                                                                                                                                                                                       




                                                                 



                                     
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - 033exclusive_container.cc</title>
<meta name="Generator" content="Vim/7.4">
<meta name="plugin-version" content="vim7.4_v1">
<meta name="syntax" content="cpp">
<meta name="settings" content="use_css,pre_wrap,no_foldcolumn,expand_tabs,prevent_copy=">
<meta name="colorscheme" content="minimal">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
body { font-family: monospace; color: #eeeeee; background-color: #080808; }
* { font-size: 1.05em; }
.cSpecial { color: #008000; }
.SalientComment { color: #00ffff; }
.traceContains { color: #008000; }
.Comment { color: #9090ff; }
.Delimiter { color: #a04060; }
.Special { color: #ff6060; }
.Identifier { color: #804000; }
.Constant { color: #00a0a0; }
-->
</style>

<script type='text/javascript'>
<!--

-->
</script>
</head>
<body>
<pre id='vimCodeElement'>
<span class="Comment">//: Exclusive containers contain exactly one of a fixed number of 'variants'</span>
<span class="Comment">//: of different types.</span>
<span class="Comment">//:</span>
<span class="Comment">//: They also implicitly contain a tag describing precisely which variant is</span>
<span class="Comment">//: currently stored in them.</span>

<span class="Delimiter">:(before &quot;End Mu Types Initialization&quot;)</span>
<span class="Comment">//: We'll use this container as a running example, with two number elements.</span>
<span class="Delimiter">{</span>
type_ordinal tmp = Type_ordinal[<span class="Constant">&quot;number-or-point&quot;</span>] = Next_type_ordinal++<span class="Delimiter">;</span>
Type[tmp]<span class="Delimiter">.</span>size = <span class="Constant">2</span><span class="Delimiter">;</span>
Type[tmp]<span class="Delimiter">.</span>kind = exclusive_container<span class="Delimiter">;</span>
Type[tmp]<span class="Delimiter">.</span>name = <span class="Constant">&quot;number-or-point&quot;</span><span class="Delimiter">;</span>
vector&lt;type_ordinal&gt; t1<span class="Delimiter">;</span>
t1<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>number<span class="Delimiter">);</span>
Type[tmp]<span class="Delimiter">.</span>elements<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>t1<span class="Delimiter">);</span>
vector&lt;type_ordinal&gt; t2<span class="Delimiter">;</span>
t2<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>point<span class="Delimiter">);</span>
Type[tmp]<span class="Delimiter">.</span>elements<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>t2<span class="Delimiter">);</span>
Type[tmp]<span class="Delimiter">.</span>element_names<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span><span class="Constant">&quot;i&quot;</span><span class="Delimiter">);</span>
Type[tmp]<span class="Delimiter">.</span>element_names<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span><span class="Constant">&quot;p&quot;</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="Comment">//: Tests in this layer often explicitly setup memory before reading it as an</span>
<span class="Comment">//: array. Don't do this in general. I'm tagging exceptions with /raw to</span>
<span class="Comment">//: avoid warnings.</span>
<span class="Delimiter">:(scenario copy_exclusive_container)</span>
<span class="Comment"># Copying exclusive containers copies all their contents and an extra location for the tag.</span>
recipe main [
  <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">1</span>  <span class="Comment"># 'point' variant</span>
  <span class="Constant">2</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
  <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">4</span>:number-or-point<span class="Special"> &lt;- </span>copy <span class="Constant">1</span>:number-or-point/<span class="Special">raw</span>  <span class="Comment"># unsafe</span>
]
<span class="traceContains">+mem: storing 1 in location 4</span>
<span class="traceContains">+mem: storing 34 in location 5</span>
<span class="traceContains">+mem: storing 35 in location 6</span>

<span class="Delimiter">:(before &quot;End size_of(types) Cases&quot;)</span>
if <span class="Delimiter">(</span>t<span class="Delimiter">.</span>kind == exclusive_container<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Comment">// size of an exclusive container is the size of its largest variant</span>
  <span class="Comment">// (So like containers, it can't contain arrays.)</span>
  long long int result = <span class="Constant">0</span><span class="Delimiter">;</span>
  for <span class="Delimiter">(</span>long long int i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; t<span class="Delimiter">.</span>size<span class="Delimiter">;</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    long long int tmp = size_of<span class="Delimiter">(</span>t<span class="Delimiter">.</span>elements<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span>
    if <span class="Delimiter">(</span>tmp &gt; result<span class="Delimiter">)</span> result = tmp<span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  <span class="Comment">// ...+1 for its tag.</span>
  <span class="Identifier">return</span> result+<span class="Constant">1</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="SalientComment">//:: To access variants of an exclusive container, use 'maybe-convert'.</span>
<span class="Comment">//: It always returns an address (so that you can modify it) or null (to</span>
<span class="Comment">//: signal that the conversion failed (because the container contains a</span>
<span class="Comment">//: different variant).</span>

<span class="Comment">//: 'maybe-convert' requires a literal in ingredient 1. We'll use a synonym</span>
<span class="Comment">//: called 'variant'.</span>
<span class="Delimiter">:(before &quot;End Mu Types Initialization&quot;)</span>
Type_ordinal[<span class="Constant">&quot;variant&quot;</span>] = <span class="Constant">0</span><span class="Delimiter">;</span>

<span class="Delimiter">:(scenario maybe_convert)</span>
recipe main [
  <span class="Constant">12</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">1</span>
  <span class="Constant">13</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">14</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">36</span>
  <span class="Constant">20</span>:address:point<span class="Special"> &lt;- </span>maybe-convert <span class="Constant">12</span>:number-or-point/<span class="Special">raw</span><span class="Delimiter">,</span> <span class="Constant">1</span>:variant  <span class="Comment"># unsafe</span>
]
<span class="traceContains">+mem: storing 13 in location 20</span>

<span class="Delimiter">:(scenario maybe_convert_fail)</span>
recipe main [
  <span class="Constant">12</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">1</span>
  <span class="Constant">13</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">14</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">36</span>
  <span class="Constant">20</span>:address:point<span class="Special"> &lt;- </span>maybe-convert <span class="Constant">12</span>:number-or-point/<span class="Special">raw</span><span class="Delimiter">,</span> <span class="Constant">0</span>:variant  <span class="Comment"># unsafe</span>
]
<span class="traceContains">+mem: storing 0 in location 20</span>

<span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span>
MAYBE_CONVERT<span class="Delimiter">,</span>
<span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span>
Recipe_ordinal[<span class="Constant">&quot;maybe-convert&quot;</span>] = MAYBE_CONVERT<span class="Delimiter">;</span>
<span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span>
case MAYBE_CONVERT: <span class="Delimiter">{</span>
  if <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>ingredients<span class="Delimiter">)</span> != <span class="Constant">2</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
    raise &lt;&lt; current_recipe_name<span class="Delimiter">()</span> &lt;&lt; <span class="Constant">&quot;: 'maybe-convert' expects exactly 2 ingredients in '&quot;</span> &lt;&lt; current_instruction<span class="Delimiter">().</span>to_string<span class="Delimiter">()</span> &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
    <span class="Identifier">break</span><span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  reagent base = canonize<span class="Delimiter">(</span>current_instruction<span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span>
  long long int base_address = base<span class="Delimiter">.</span>value<span class="Delimiter">;</span>
  if <span class="Delimiter">(</span>base_address == <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
    raise &lt;&lt; current_recipe_name<span class="Delimiter">()</span> &lt;&lt; <span class="Constant">&quot;: tried to access location 0 in '&quot;</span> &lt;&lt; current_instruction<span class="Delimiter">().</span>to_string<span class="Delimiter">()</span> &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
    <span class="Identifier">break</span><span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  if <span class="Delimiter">(</span>base<span class="Delimiter">.</span>types<span class="Delimiter">.</span>empty<span class="Delimiter">()</span> || Type[base<span class="Delimiter">.</span>types<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span>]<span class="Delimiter">.</span>kind != exclusive_container<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    raise &lt;&lt; current_recipe_name <span class="Delimiter">()</span> &lt;&lt; <span class="Constant">&quot;: first ingredient of 'maybe-convert' should be an exclusive-container, but got &quot;</span> &lt;&lt; base<span class="Delimiter">.</span>original_string &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span>
    <span class="Identifier">break</span><span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  if <span class="Delimiter">(</span>!is_literal<span class="Delimiter">(</span>current_instruction<span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span>
    raise &lt;&lt; current_recipe_name<span class="Delimiter">()</span> &lt;&lt; <span class="Constant">&quot;: second ingredient of 'maybe-convert' should have type 'variant', but got &quot;</span> &lt;&lt; current_instruction<span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>original_string &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span>
    <span class="Identifier">break</span><span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  long long int tag = current_instruction<span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>value<span class="Delimiter">;</span>
  long long int result<span class="Delimiter">;</span>
  if <span class="Delimiter">(</span>tag == static_cast&lt;long long int&gt;<span class="Delimiter">(</span>Memory[base_address]<span class="Delimiter">))</span> <span class="Delimiter">{</span>
    result = base_address+<span class="Constant">1</span><span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  else <span class="Delimiter">{</span>
    result = <span class="Constant">0</span><span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  products<span class="Delimiter">.</span>resize<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">);</span>
  products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>push_back<span class="Delimiter">(</span>result<span class="Delimiter">);</span>
  <span class="Identifier">break</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="SalientComment">//:: Allow exclusive containers to be defined in mu code.</span>

<span class="Delimiter">:(scenario exclusive_container)</span>
exclusive-container foo [
  x:number
  y:number
]
<span class="traceContains">+parse: reading exclusive-container foo</span>
<span class="traceContains">+parse:   element name: x</span>
<span class="traceContains">+parse:   type: 1</span>
<span class="traceContains">+parse:   element name: y</span>
<span class="traceContains">+parse:   type: 1</span>

<span class="Delimiter">:(before &quot;End Command Handlers&quot;)</span>
else if <span class="Delimiter">(</span>command == <span class="Constant">&quot;exclusive-container&quot;</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
  insert_container<span class="Delimiter">(</span>command<span class="Delimiter">,</span> exclusive_container<span class="Delimiter">,</span> in<span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="SalientComment">//:: To construct exclusive containers out of variant types, use 'merge'.</span>
<span class="Delimiter">:(scenario lift_to_exclusive_container)</span>
exclusive-container foo [
  x:number
  y:number
]

recipe main [
  <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
  <span class="Constant">2</span>:foo<span class="Special"> &lt;- </span>merge <span class="Constant">0</span>/x<span class="Delimiter">,</span> <span class="Constant">1</span>:number
  <span class="Constant">4</span>:foo<span class="Special"> &lt;- </span>merge <span class="Constant">1</span>/x<span class="Delimiter">,</span> <span class="Constant">1</span>:number
]
<span class="traceContains">+mem: storing 0 in location 2</span>
<span class="traceContains">+mem: storing 34 in location 3</span>
<span class="traceContains">+mem: storing 1 in location 4</span>
<span class="traceContains">+mem: storing 34 in location 5</span>
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->
</span> <span class="Comment">//:</span> <span class="Comment">//: But the usual way we write tests seems incomplete. Refactorings tend to</span> <span class="Comment">//: work in the small, but don't help with changes to function boundaries. If</span> <span class="Comment">//: you want to extract a new function you have to manually test-drive it to</span> <span class="Comment">//: create tests for it. If you want to inline a function its tests are no</span> <span class="Comment">//: longer valid. In both cases you end up having to reorganize code as well as</span> <span class="Comment">//: tests, an error-prone activity.</span> <span class="Comment">//:</span> <span class="Comment">//: This file tries to fix this problem by supporting domain-driven testing</span> <span class="Comment">//: We try to focus on the domain of inputs the program should work on. All</span> <span class="Comment">//: tests invoke the program in a single way: by calling run() with different</span> <span class="Comment">//: inputs. The program operates on the input and logs _facts_ it deduces to a</span> <span class="Comment">//: trace:</span> <span class="Comment">//: trace(&quot;label&quot;) &lt;&lt; &quot;fact 1: &quot; &lt;&lt; val;</span> <span class="Comment">//:</span> <span class="Comment">//: The tests check for facts:</span> <span class="Comment">//: :(scenario foo)</span> <span class="Comment">//: 34 # call run() with this input</span> <span class="Comment">//: +label: fact 1: 34 # trace should have logged this at the end</span> <span class="Comment">//: -label: fact 1: 35 # trace should never contain such a line</span> <span class="Comment">//:</span> <span class="Comment">//: Since we never call anything but the run() function directly, we never have</span> <span class="Comment">//: to rewrite the tests when we reorganize the internals of the program. We</span> <span class="Comment">//: just have to make sure our rewrite deduces the same facts about the domain,</span> <span class="Comment">//: and that's something we're going to have to do anyway.</span> <span class="Comment">//:</span> <span class="Comment">//: To avoid the combinatorial explosion of integration tests, we organize the</span> <span class="Comment">//: program into different layers, and each fact is logged to the trace with a</span> <span class="Comment">//: specific label. Individual tests can focus on specific labels. In essence,</span> <span class="Comment">//: validating the facts logged with a specific label is identical to calling</span> <span class="Comment">//: some internal subsystem.</span> <span class="Comment">//:</span> <span class="Comment">//: Traces interact salubriously with layers. Thanks to our ordering</span> <span class="Comment">//: directives, each layer can contain its own tests. They may rely on other</span> <span class="Comment">//: layers, but when a test fails its usually due to breakage in the same</span> <span class="Comment">//: layer. When multiple tests fail, it's usually useful to debug the very</span> <span class="Comment">//: first test to fail. This is in contrast with the traditional approach,</span> <span class="Comment">//: where changes can cause breakages in faraway subsystems, and picking the</span> <span class="Comment">//: right test to debug can be an important skill to pick up.</span> <span class="Comment">//:</span> <span class="Comment">//: To build robust tests, trace facts about your domain rather than details of</span> <span class="Comment">//: how you computed them.</span> <span class="Comment">//:</span> <span class="Comment">//: More details: <a href="http://akkartik.name/blog/tracing-tests">http://akkartik.name/blog/tracing-tests</a></span> <span class="Comment">//:</span> <span class="Comment">//: ---</span> <span class="Comment">//:</span> <span class="Comment">//: Between layers and domain-driven testing, programming starts to look like a</span> <span class="Comment">//: fundamentally different activity. Instead of a) superficial, b) local rules</span> <span class="Comment">//: on c) code [like <a href="http://blog.bbv.ch/2013/06/05/clean-code-cheat-sheet],">http://blog.bbv.ch/2013/06/05/clean-code-cheat-sheet],</a></span> <span class="Comment">//: we allow programmers to engage with the a) deep, b) global structure of the</span> <span class="Comment">//: c) domain. If you can systematically track discontinuities in the domain</span> <span class="Comment">//: you don't care if the code used gotos as long as it passed the tests. If</span> <span class="Comment">//: tests become more robust to run it becomes easier to try out radically</span> <span class="Comment">//: different implementations for the same program. If code is super-easy to</span> <span class="Comment">//: rewrite, it becomes less important what indentation style it uses, or that</span> <span class="Comment">//: the objects are appropriately encapsulated, or that the functions are</span> <span class="Comment">//: referentially transparent.</span> <span class="Comment">//:</span> <span class="Comment">//: Instead of plumbing, programming becomes building and gradually refining a</span> <span class="Comment">//: map of the environment the program must operate under. Whether a program is</span> <span class="Comment">//: 'correct' at a given point in time is a red herring; what matters is</span> <span class="Comment">//: avoiding regression by monotonically nailing down the more 'eventful' parts</span> <span class="Comment">//: of the terrain. It helps readers new and old and rewards curiosity to</span> <span class="Comment">//: organize large programs in self-similar hiearchies of example scenarios</span> <span class="Comment">//: colocated with the code that makes them work.</span> <span class="Comment">//:</span> <span class="Comment">//: &quot;Programming properly should be regarded as an activity by which</span> <span class="Comment">//: programmers form a mental model, rather than as production of a program.&quot;</span> <span class="Comment">//: -- Peter Naur (<a href="http://alistair.cockburn.us/ASD+book+extract%3A+%22Naur,+Ehn,+Musashi%22)">http://alistair.cockburn.us/ASD+book+extract%3A+%22Naur,+Ehn,+Musashi%22)</a></span> <span class="Delimiter">:(before &quot;int main&quot;)</span> <span class="Comment">// End Tracing // hack to ensure most code in this layer comes before anything else</span> <span class="Delimiter">:(before &quot;End Tracing&quot;)</span> bool Hide_warnings = <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Delimiter">:(before &quot;End Setup&quot;)</span> <span class="CommentedCode">//? cerr &lt;&lt; &quot;AAA setup\n&quot;; //? 2</span> Hide_warnings = <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Delimiter">:(before &quot;End Types&quot;)</span> struct trace_line <span class="Delimiter">{</span> int depth<span class="Delimiter">;</span> <span class="Comment">// optional field just to help browse traces later</span> string label<span class="Delimiter">;</span> string contents<span class="Delimiter">;</span> trace_line<span class="Delimiter">(</span>string l<span class="Delimiter">,</span> string c<span class="Delimiter">)</span> :depth<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">),</span> label<span class="Delimiter">(</span>l<span class="Delimiter">),</span> contents<span class="Delimiter">(</span>c<span class="Delimiter">)</span> <span class="Delimiter">{}</span> trace_line<span class="Delimiter">(</span>int d<span class="Delimiter">,</span> string l<span class="Delimiter">,</span> string c<span class="Delimiter">)</span> :depth<span class="Delimiter">(</span>d<span class="Delimiter">),</span> label<span class="Delimiter">(</span>l<span class="Delimiter">),</span> contents<span class="Delimiter">(</span>c<span class="Delimiter">)</span> <span class="Delimiter">{}</span> <span class="Delimiter">};</span> <span class="Delimiter">:(before &quot;End Tracing&quot;)</span> struct trace_stream <span class="Delimiter">{</span> vector&lt;trace_line&gt; past_lines<span class="Delimiter">;</span> <span class="Comment">// accumulator for current line</span> ostringstream* curr_stream<span class="Delimiter">;</span> string curr_layer<span class="Delimiter">;</span> int curr_depth<span class="Delimiter">;</span> string dump_layer<span class="Delimiter">;</span> set&lt;string&gt; collect_layers<span class="Delimiter">;</span> <span class="Comment">// if not empty, ignore all absent layers</span> ofstream null_stream<span class="Delimiter">;</span> <span class="Comment">// never opens a file, so writes silently fail</span> trace_stream<span class="Delimiter">()</span> :curr_stream<span class="Delimiter">(</span><span class="Constant">NULL</span><span class="Delimiter">),</span> curr_depth<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{}</span> ~trace_stream<span class="Delimiter">()</span> <span class="Delimiter">{</span> if <span class="Delimiter">(</span>curr_stream<span class="Delimiter">)</span> delete curr_stream<span class="Delimiter">;</span> <span class="Delimiter">}</span> ostream&amp; stream<span class="Delimiter">(</span>string layer<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Identifier">return</span> stream<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">,</span> layer<span class="Delimiter">);</span> <span class="Delimiter">}</span> ostream&amp; stream<span class="Delimiter">(</span>int depth<span class="Delimiter">,</span> string layer<span class="Delimiter">)</span> <span class="Delimiter">{</span> if <span class="Delimiter">(</span>!is_collecting<span class="Delimiter">(</span>layer<span class="Delimiter">))</span> <span class="Identifier">return</span> null_stream<span class="Delimiter">;</span> curr_stream = new ostringstream<span class="Delimiter">;</span> curr_layer = layer<span class="Delimiter">;</span> curr_depth = depth<span class="Delimiter">;</span> <span class="Identifier">return</span> *curr_stream<span class="Delimiter">;</span> <span class="Delimiter">}</span> bool is_collecting<span class="Delimiter">(</span>const string&amp; layer<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Identifier">return</span> collect_layers<span class="Delimiter">.</span>empty<span class="Delimiter">()</span> || collect_layers<span class="Delimiter">.</span>find<span class="Delimiter">(</span>layer<span class="Delimiter">)</span> != collect_layers<span class="Delimiter">.</span>end<span class="Delimiter">();</span> <span class="Delimiter">}</span> bool is_narrowly_collecting<span class="Delimiter">(</span>const string&amp; layer<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Identifier">return</span> collect_layers<span class="Delimiter">.</span>find<span class="Delimiter">(</span>layer<span class="Delimiter">)</span> != collect_layers<span class="Delimiter">.</span>end<span class="Delimiter">();</span> <span class="Delimiter">}</span> <span class="Comment">// be sure to call this before messing with curr_stream or curr_layer</span> void newline<span class="Delimiter">()</span> <span class="Delimiter">{</span> if <span class="Delimiter">(</span>!curr_stream<span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Delimiter">;</span> string curr_contents = curr_stream<span class="Delimiter">-&gt;</span>str<span class="Delimiter">();</span> if <span class="Delimiter">(</span>curr_contents<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Identifier">return</span><span class="Delimiter">;</span> past_lines<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>trace_line<span class="Delimiter">(</span>curr_depth<span class="Delimiter">,</span> trim<span class="Delimiter">(</span>curr_layer<span class="Delimiter">),</span> curr_contents<span class="Delimiter">));</span> <span class="Comment">// preserve indent in contents</span> if <span class="Delimiter">(</span>curr_layer == dump_layer || curr_layer == <span class="Constant">&quot;dump&quot;</span> || dump_layer == <span class="Constant">&quot;all&quot;</span> || <span class="Delimiter">(</span>!Hide_warnings &amp;&amp; curr_layer == <span class="Constant">&quot;warn&quot;</span><span class="Delimiter">))</span> <span class="CommentedCode">//? if (dump_layer == &quot;all&quot; &amp;&amp; (Current_routine-&gt;id == 3 || curr_layer == &quot;schedule&quot;)) //? 1</span> cerr &lt;&lt; curr_layer &lt;&lt; <span class="Constant">&quot;: &quot;</span> &lt;&lt; curr_contents &lt;&lt; <span class="cSpecial">'\n'</span><span class="Delimiter">;</span> delete curr_stream<span class="Delimiter">;</span> curr_stream = <span class="Constant">NULL</span><span class="Delimiter">;</span> curr_layer<span class="Delimiter">.</span>clear<span class="Delimiter">();</span> curr_depth = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Comment">// Useful for debugging.</span> string readable_contents<span class="Delimiter">(</span>string layer<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Comment">// missing layer = everything</span> ostringstream output<span class="Delimiter">;</span> layer = trim<span class="Delimiter">(</span>layer<span class="Delimiter">);</span> for <span class="Delimiter">(</span>vector&lt;trace_line&gt;::iterator p = past_lines<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != past_lines<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> if <span class="Delimiter">(</span>layer<span class="Delimiter">.</span>empty<span class="Delimiter">()</span> || layer == p<span class="Delimiter">-&gt;</span>label<span class="Delimiter">)</span> <span class="Delimiter">{</span> if <span class="Delimiter">(</span>p<span class="Delimiter">-&gt;</span>depth<span class="Delimiter">)</span> output &lt;&lt; std::setw<span class="Delimiter">(</span><span class="Constant">4</span><span class="Delimiter">)</span> &lt;&lt; p<span class="Delimiter">-&gt;</span>depth &lt;&lt; <span class="Constant">' '</span><span class="Delimiter">;</span> output &lt;&lt; p<span class="Delimiter">-&gt;</span>label &lt;&lt; <span class="Constant">&quot;: &quot;</span> &lt;&lt; p<span class="Delimiter">-&gt;</span>contents &lt;&lt; <span class="cSpecial">'\n'</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Identifier">return</span> output<span class="Delimiter">.</span>str<span class="Delimiter">();</span> <span class="Delimiter">}</span> <span class="Delimiter">};</span> ^L trace_stream* Trace_stream = <span class="Constant">NULL</span><span class="Delimiter">;</span> <span class="Comment">// Top-level helper. IMPORTANT: can't nest.</span> <span class="PreProc">#define trace(</span><span class="Delimiter">...</span><span class="PreProc">) !Trace_stream ? cerr </span><span class="Comment">/*</span><span class="Comment">print nothing</span><span class="Comment">*/</span><span class="PreProc"> : Trace_stream</span><span class="Delimiter">-&gt;</span><span class="PreProc">stream(__VA_ARGS__)</span> <span class="Comment">// Warnings should go straight to cerr by default since calls to trace() have</span> <span class="Comment">// some unfriendly constraints (they delay printing, they can't nest)</span> <span class="PreProc">#define raise ((!Trace_stream || !Hide_warnings) ? (tb_shutdown()</span><span class="Delimiter">,</span><span class="PreProc">cerr) </span><span class="Comment">/*</span><span class="Comment">do print</span><span class="Comment">*/</span><span class="PreProc"> : Trace_stream</span><span class="Delimiter">-&gt;</span><span class="PreProc">stream(</span><span class="Constant">&quot;warn&quot;</span><span class="PreProc">))</span> <span class="Delimiter">:(before &quot;End Types&quot;)</span> struct end <span class="Delimiter">{};</span> <span class="Delimiter">:(before &quot;End Tracing&quot;)</span> ostream&amp; operator&lt;&lt;<span class="Delimiter">(</span>ostream&amp; os<span class="Delimiter">,</span> unused end<span class="Delimiter">)</span> <span class="Delimiter">{</span> if <span class="Delimiter">(</span>Trace_stream<span class="Delimiter">)</span> Trace_stream<span class="Delimiter">-&gt;</span>newline<span class="Delimiter">();</span> <span class="Identifier">return</span> os<span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="PreProc">#define CLEAR_TRACE </span>delete<span class="PreProc"> Trace_stream</span><span class="Delimiter">,</span><span class="PreProc"> Trace_stream = </span>new<span class="PreProc"> trace_stream</span><span class="Delimiter">;</span> <span class="PreProc">#define DUMP(layer) </span>if<span class="PreProc"> (Trace_stream) cerr &lt;&lt; Trace_stream</span><span class="Delimiter">-&gt;</span><span class="PreProc">readable_contents(layer)</span><span class="Delimiter">;</span> <span class="Comment">// All scenarios save their traces in the repo, just like code. This gives</span> <span class="Comment">// future readers more meat when they try to make sense of a new project.</span> static string Trace_dir = <span class="Constant">&quot;.traces/&quot;</span><span class="Delimiter">;</span> string Trace_file<span class="Delimiter">;</span> <span class="Comment">// Trace_stream is a resource, lease_tracer uses RAII to manage it.</span> struct lease_tracer <span class="Delimiter">{</span> lease_tracer<span class="Delimiter">()</span> <span class="Delimiter">{</span> Trace_stream = new trace_stream<span class="Delimiter">;</span> <span class="Delimiter">}</span> ~lease_tracer<span class="Delimiter">()</span> <span class="Delimiter">{</span> <span class="CommentedCode">//? cerr &lt;&lt; &quot;write to file? &quot; &lt;&lt; Trace_file &lt;&lt; &quot;$\n&quot;; //? 2</span> if <span class="Delimiter">(</span>!Trace_file<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Delimiter">{</span> <span class="CommentedCode">//? cerr &lt;&lt; &quot;writing\n&quot;; //? 2</span> ofstream fout<span class="Delimiter">((</span>Trace_dir+Trace_file<span class="Delimiter">).</span>c_str<span class="Delimiter">());</span> fout &lt;&lt; Trace_stream<span class="Delimiter">-&gt;</span>readable_contents<span class="Delimiter">(</span><span class="Constant">&quot;&quot;</span><span class="Delimiter">);</span> fout<span class="Delimiter">.</span>close<span class="Delimiter">();</span> <span class="Delimiter">}</span> delete Trace_stream<span class="Delimiter">,</span> Trace_stream = <span class="Constant">NULL</span><span class="Delimiter">,</span> Trace_file = <span class="Constant">&quot;&quot;</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">};</span> <span class="PreProc">#define START_TRACING_UNTIL_END_OF_SCOPE lease_tracer leased_tracer</span><span class="Delimiter">;</span> <span class="Delimiter">:(before &quot;End Test Setup&quot;)</span> START_TRACING_UNTIL_END_OF_SCOPE <span class="CommentedCode">//? Trace_stream-&gt;dump_layer = &quot;all&quot;; //? 1</span> <span class="PreProc">#define CHECK_TRACE_CONTENTS(</span><span class="Delimiter">...</span><span class="PreProc">) check_trace_contents(__FUNCTION__</span><span class="Delimiter">,</span><span class="PreProc"> </span><span class="Constant">__FILE__</span><span class="Delimiter">,</span><span class="PreProc"> </span><span class="Constant">__LINE__</span><span class="Delimiter">,</span><span class="PreProc"> __VA_ARGS__)</span> <span class="Delimiter">:(before &quot;End Tracing&quot;)</span> bool check_trace_contents<span class="Delimiter">(</span>string FUNCTION<span class="Delimiter">,</span> string FILE<span class="Delimiter">,</span> int LINE<span class="Delimiter">,</span> string expected<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Comment">// missing layer == anywhere</span> vector&lt;string&gt; expected_lines = split<span class="Delimiter">(</span>expected<span class="Delimiter">,</span> <span class="Constant">&quot;^D&quot;</span><span class="Delimiter">);</span> long long int curr_expected_line = <span class="Constant">0</span><span class="Delimiter">;</span> while <span class="Delimiter">(</span>curr_expected_line &lt; SIZE<span class="Delimiter">(</span>expected_lines<span class="Delimiter">)</span> &amp;&amp; expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">).</span>empty<span class="Delimiter">())</span> ++curr_expected_line<span class="Delimiter">;</span> if <span class="Delimiter">(</span>curr_expected_line == SIZE<span class="Delimiter">(</span>expected_lines<span class="Delimiter">))</span> <span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span> string layer<span class="Delimiter">,</span> contents<span class="Delimiter">;</span> split_layer_contents<span class="Delimiter">(</span>expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">),</span> &amp;layer<span class="Delimiter">,</span> &amp;contents<span class="Delimiter">);</span> for <span class="Delimiter">(</span>vector&lt;trace_line&gt;::iterator p = Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="CommentedCode">//? cerr &lt;&lt; &quot;AAA &quot; &lt;&lt; layer &lt;&lt; ' ' &lt;&lt; p-&gt;label &lt;&lt; '\n'; //? 1</span> if <span class="Delimiter">(</span>layer != p<span class="Delimiter">-&gt;</span>label<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> <span class="CommentedCode">//? cerr &lt;&lt; &quot;BBB ^&quot; &lt;&lt; contents &lt;&lt; &quot;$ ^&quot; &lt;&lt; p-&gt;contents &lt;&lt; &quot;$\n&quot;; //? 1</span> if <span class="Delimiter">(</span>contents != trim<span class="Delimiter">(</span>p<span class="Delimiter">-&gt;</span>contents<span class="Delimiter">))</span> <span class="Identifier">continue</span><span class="Delimiter">;</span> <span class="CommentedCode">//? cerr &lt;&lt; &quot;CCC\n&quot;; //? 1</span> ++curr_expected_line<span class="Delimiter">;</span> while <span class="Delimiter">(</span>curr_expected_line &lt; SIZE<span class="Delimiter">(</span>expected_lines<span class="Delimiter">)</span> &amp;&amp; expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">).</span>empty<span class="Delimiter">())</span> ++curr_expected_line<span class="Delimiter">;</span> if <span class="Delimiter">(</span>curr_expected_line == SIZE<span class="Delimiter">(</span>expected_lines<span class="Delimiter">))</span> <span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span> split_layer_contents<span class="Delimiter">(</span>expected_lines<span class="Delimiter">.</span>at<span class="Delimiter">(</span>curr_expected_line<span class="Delimiter">),</span> &amp;layer<span class="Delimiter">,</span> &amp;contents<span class="Delimiter">);</span> <span class="Delimiter">}</span> ++Num_failures<span class="Delimiter">;</span> cerr &lt;&lt; <span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span> &lt;&lt; FUNCTION &lt;&lt; <span class="Constant">&quot;(&quot;</span> &lt;&lt; FILE &lt;&lt; <span class="Constant">&quot;:&quot;</span> &lt;&lt; LINE &lt;&lt; <span class="Constant">&quot;): missing [&quot;</span> &lt;&lt; contents &lt;&lt; <span class="Constant">&quot;] in trace:</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">;</span> DUMP<span class="Delimiter">(</span>layer<span class="Delimiter">);</span> <span class="CommentedCode">//? exit(0); //? 1</span> Passed = <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> void split_layer_contents<span class="Delimiter">(</span>const string&amp; s<span class="Delimiter">,</span> string* layer<span class="Delimiter">,</span> string* contents<span class="Delimiter">)</span> <span class="Delimiter">{</span> static const string delim<span class="Delimiter">(</span><span class="Constant">&quot;: &quot;</span><span class="Delimiter">);</span> size_t pos = s<span class="Delimiter">.</span>find<span class="Delimiter">(</span>delim<span class="Delimiter">);</span> if <span class="Delimiter">(</span>pos == string::npos<span class="Delimiter">)</span> <span class="Delimiter">{</span> *layer = <span class="Constant">&quot;&quot;</span><span class="Delimiter">;</span> *contents = trim<span class="Delimiter">(</span>s<span class="Delimiter">);</span> <span class="Delimiter">}</span> else <span class="Delimiter">{</span> *layer = trim<span class="Delimiter">(</span>s<span class="Delimiter">.</span>substr<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">,</span> pos<span class="Delimiter">));</span> *contents = trim<span class="Delimiter">(</span>s<span class="Delimiter">.</span>substr<span class="Delimiter">(</span>pos+SIZE<span class="Delimiter">(</span>delim<span class="Delimiter">)));</span> <span class="Delimiter">}</span> <span class="Delimiter">}</span> ^L int trace_count<span class="Delimiter">(</span>string layer<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Identifier">return</span> trace_count<span class="Delimiter">(</span>layer<span class="Delimiter">,</span> <span class="Constant">&quot;&quot;</span><span class="Delimiter">);</span> <span class="Delimiter">}</span> int trace_count<span class="Delimiter">(</span>string layer<span class="Delimiter">,</span> string line<span class="Delimiter">)</span> <span class="Delimiter">{</span> long result = <span class="Constant">0</span><span class="Delimiter">;</span> for <span class="Delimiter">(</span>vector&lt;trace_line&gt;::iterator p = Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != Trace_stream<span class="Delimiter">-&gt;</span>past_lines<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span class="Delimiter">{</span> if <span class="Delimiter">(</span>layer == p<span class="Delimiter">-&gt;</span>label<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="CommentedCode">//? cerr &lt;&lt; &quot;a: &quot; &lt;&lt; line &lt;&lt; &quot;$\n&quot;; //? 1</span> <span class="CommentedCode">//? cerr &lt;&lt; &quot;b: &quot; &lt;&lt; trim(p-&gt;contents) &lt;&lt; &quot;$\n&quot;; //? 1</span> if <span class="Delimiter">(</span>line == <span class="Constant">&quot;&quot;</span> || line == trim<span class="Delimiter">(</span>p<span class="Delimiter">-&gt;</span>contents<span class="Delimiter">))</span> ++result<span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">}</span> <span class="Identifier">return</span> result<span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="PreProc">#define CHECK_TRACE_WARNS() CHECK(trace_count(</span><span class="Constant">&quot;warn&quot;</span><span class="PreProc">) &gt; </span><span class="Constant">0</span><span class="PreProc">)</span> <span class="PreProc">#define CHECK_TRACE_DOESNT_WARN() \</span> <span class="PreProc"> </span>if<span class="PreProc"> (trace_count(</span><span class="Constant">&quot;warn&quot;</span><span class="PreProc">) &gt; </span><span class="Constant">0</span><span class="PreProc">) </span><span class="Delimiter">{</span><span class="PreProc"> \</span> <span class="PreProc"> ++Num_failures</span><span class="Delimiter">;</span><span class="PreProc"> \</span> <span class="PreProc"> cerr &lt;&lt; </span><span class="Constant">&quot;</span><span class="cSpecial">\n</span><span class="Constant">F - &quot;</span><span class="PreProc"> &lt;&lt; __FUNCTION__ &lt;&lt; </span><span class="Constant">&quot;(&quot;</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">__FILE__</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">&quot;:&quot;</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">__LINE__</span><span class="PreProc"> &lt;&lt; </span><span class="Constant">&quot;): unexpected warnings</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">;</span><span class="PreProc"> \</span> <span class="PreProc"> DUMP(</span><span class="Constant">&quot;warn&quot;</span><span class="PreProc">)</span><span class="Delimiter">;</span><span class="PreProc"> \</span> <span class="PreProc"> Passed = </span><span class="Constant">false</span><span class="Delimiter">;</span><span class="PreProc"> \</span> <span class="PreProc"> </span><span class="Identifier">return</span><span class="Delimiter">;</span><span class="PreProc"> \</span> <span class="PreProc"> </span><span class="Delimiter">}</span> bool trace_doesnt_contain<span class="Delimiter">(</span>string layer<span class="Delimiter">,</span> string line<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Identifier">return</span> trace_count<span class="Delimiter">(</span>layer<span class="Delimiter">,</span> line<span class="Delimiter">)</span> == <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> bool trace_doesnt_contain<span class="Delimiter">(</span>string expected<span class="Delimiter">)</span> <span class="Delimiter">{</span> vector&lt;string&gt; tmp = split<span class="Delimiter">(</span>expected<span class="Delimiter">,</span> <span class="Constant">&quot;: &quot;</span><span class="Delimiter">);</span> <span class="Identifier">return</span> trace_doesnt_contain<span class="Delimiter">(</span>tmp<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">),</span> tmp<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">));</span> <span class="Delimiter">}</span> <span class="PreProc">#define CHECK_TRACE_DOESNT_CONTAIN(</span><span class="Delimiter">...</span><span class="PreProc">) CHECK(trace_doesnt_contain(__VA_ARGS__))</span> ^L vector&lt;string&gt; split<span class="Delimiter">(</span>string s<span class="Delimiter">,</span> string delim<span class="Delimiter">)</span> <span class="Delimiter">{</span> vector&lt;string&gt; result<span class="Delimiter">;</span> size_t begin=<span class="Constant">0</span><span class="Delimiter">,</span> end=s<span class="Delimiter">.</span>find<span class="Delimiter">(</span>delim<span class="Delimiter">);</span> while <span class="Delimiter">(</span><span class="Constant">true</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> if <span class="Delimiter">(</span>end == string::npos<span class="Delimiter">)</span> <span class="Delimiter">{</span> result<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>string<span class="Delimiter">(</span>s<span class="Delimiter">,</span> begin<span class="Delimiter">,</span> string::npos<span class="Delimiter">));</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> result<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>string<span class="Delimiter">(</span>s<span class="Delimiter">,</span> begin<span class="Delimiter">,</span> end-begin<span class="Delimiter">));</span> begin = SIZE<span class="Delimiter">(</span>end+delim<span class="Delimiter">);</span> end = s<span class="Delimiter">.</span>find<span class="Delimiter">(</span>delim<span class="Delimiter">,</span> begin<span class="Delimiter">);</span> <span class="Delimiter">}</span> <span class="Identifier">return</span> result<span class="Delimiter">;</span> <span class="Delimiter">}</span> string trim<span class="Delimiter">(</span>const string&amp; s<span class="Delimiter">)</span> <span class="Delimiter">{</span> string::const_iterator first = s<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> while <span class="Delimiter">(</span>first != s<span class="Delimiter">.</span>end<span class="Delimiter">()</span> &amp;&amp; isspace<span class="Delimiter">(</span>*first<span class="Delimiter">))</span> ++first<span class="Delimiter">;</span> if <span class="Delimiter">(</span>first == s<span class="Delimiter">.</span>end<span class="Delimiter">())</span> <span class="Identifier">return</span> <span class="Constant">&quot;&quot;</span><span class="Delimiter">;</span> string::const_iterator last = --s<span class="Delimiter">.</span>end<span class="Delimiter">();</span> while <span class="Delimiter">(</span>last != s<span class="Delimiter">.</span>begin<span class="Delimiter">()</span> &amp;&amp; isspace<span class="Delimiter">(</span>*last<span class="Delimiter">))</span> --last<span class="Delimiter">;</span> ++last<span class="Delimiter">;</span> <span class="Identifier">return</span> string<span class="Delimiter">(</span>first<span class="Delimiter">,</span> last<span class="Delimiter">);</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before &quot;End Includes&quot;)</span> <span class="PreProc">#include</span><span class="Constant">&lt;vector&gt;</span> using std::vector<span class="Delimiter">;</span> <span class="PreProc">#include</span><span class="Constant">&lt;list&gt;</span> using std::list<span class="Delimiter">;</span> <span class="PreProc">#include</span><span class="Constant">&lt;map&gt;</span> using std::map<span class="Delimiter">;</span> <span class="PreProc">#include</span><span class="Constant">&lt;set&gt;</span> using std::set<span class="Delimiter">;</span> <span class="PreProc">#include</span><span class="Constant">&lt;algorithm&gt;</span> <span class="PreProc">#include</span><span class="Constant">&lt;iostream&gt;</span> using std::istream<span class="Delimiter">;</span> using std::ostream<span class="Delimiter">;</span> using std::cin<span class="Delimiter">;</span> using std::cout<span class="Delimiter">;</span> using std::cerr<span class="Delimiter">;</span> <span class="PreProc">#include</span><span class="Constant">&lt;iomanip&gt;</span> <span class="PreProc">#include</span><span class="Constant">&lt;sstream&gt;</span> using std::istringstream<span class="Delimiter">;</span> using std::ostringstream<span class="Delimiter">;</span> <span class="PreProc">#include</span><span class="Constant">&lt;fstream&gt;</span> using std::ifstream<span class="Delimiter">;</span> using std::ofstream<span class="Delimiter">;</span> <span class="PreProc">#include</span><span class="Constant">&quot;termbox/termbox.h&quot;</span> <span class="PreProc">#define unused __attribute__((unused))</span> <span class="Delimiter">:(before &quot;End Globals&quot;)</span> <span class="Comment">//: In future layers we'll use the depth field as follows:</span> <span class="Comment">//:</span> <span class="Comment">//: Mu 'applications' will be able to use depths 1-99 as they like.</span> <span class="Comment">//: Depth 100 will be for scheduling (more on that later).</span> const int Scheduling_depth = <span class="Constant">100</span><span class="Delimiter">;</span> <span class="Comment">//: Primitive statements will occupy 101-9998</span> const int Initial_callstack_depth = <span class="Constant">101</span><span class="Delimiter">;</span> const int Max_callstack_depth = <span class="Constant">9998</span><span class="Delimiter">;</span> <span class="Comment">//: (ignore this until the call layer)</span> <span class="Delimiter">:(before &quot;End Globals&quot;)</span> int Callstack_depth = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Delimiter">:(before &quot;End Setup&quot;)</span> Callstack_depth = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Comment">//: Finally, details of primitive mu statements will occupy depth 9999 (more on that later as well)</span> <span class="Delimiter">:(before &quot;End Globals&quot;)</span> const int Primitive_recipe_depth = <span class="Constant">9999</span><span class="Delimiter">;</span> <span class="Comment">//:</span> <span class="Comment">//: This framework should help us hide some details at each level, mixing</span> <span class="Comment">//: static ideas like layers with the dynamic notion of call-stack depth.</span> </pre> </body> </html> <!-- vim: set foldmethod=manual : -->