<!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 - 036refcount.cc</title>
<meta name="Generator" content="Vim/7.4">
<meta name="plugin-version" content="vim7.4_v2">
<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-size: 12pt; font-family: monospace; color: #eeeeee; background-color: #080808; }
* { font-size: 12pt; font-size: 1em; }
.Constant { color: #00a0a0; }
.cSpecial { color: #008000; }
.traceContains { color: #008000; }
.SalientComment { color: #00ffff; }
.Comment { color: #9090ff; }
.Delimiter { color: #800080; }
.Special { color: #c00000; }
.Identifier { color: #fcb165; }
.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
.Todo { color: #000000; background-color: #ffff00; padding-bottom: 1px; }
-->
</style>
<script type='text/javascript'>
<!--
-->
</script>
</head>
<body>
<pre id='vimCodeElement'>
<span class="Comment">//: Update refcounts when copying addresses.</span>
<span class="Comment">//: The top of the address layer has more on refcounts.</span>
<span class="Delimiter">:(scenario refcounts)</span>
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span>copy <span class="Constant">1000</span>/unsafe
<span class="Constant">2</span>:address:number<span class="Special"> <- </span>copy <span class="Constant">1</span>:address:number
<span class="Constant">1</span>:address:number<span class="Special"> <- </span>copy <span class="Constant">0</span>
<span class="Constant">2</span>:address:number<span class="Special"> <- </span>copy <span class="Constant">0</span>
]
<span class="traceContains">+run: {1: ("address" "number")} <- copy {1000: "literal", "unsafe": ()}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="traceContains">+run: {2: ("address" "number")} <- copy {1: ("address" "number")}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="traceContains">+run: {1: ("address" "number")} <- copy {0: "literal"}</span>
<span class="traceContains">+mem: decrementing refcount of 1000: 2 -> 1</span>
<span class="traceContains">+run: {2: ("address" "number")} <- copy {0: "literal"}</span>
<span class="traceContains">+mem: decrementing refcount of 1000: 1 -> 0</span>
<span class="Delimiter">:(before "End Globals")</span>
<span class="Comment">//: escape hatch for a later layer</span>
<span class="Normal">bool</span> Update_refcounts_in_write_memory = <span class="Constant">true</span><span class="Delimiter">;</span>
<span class="Delimiter">:(before "End write_memory(x) Special-cases")</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>Update_refcounts_in_write_memory<span class="Delimiter">)</span>
update_any_refcounts<span class="Delimiter">(</span>x<span class="Delimiter">,</span> data<span class="Delimiter">);</span>
<span class="Delimiter">:(code)</span>
<span class="Normal">void</span> update_any_refcounts<span class="Delimiter">(</span><span class="Normal">const</span> reagent& canonized_x<span class="Delimiter">,</span> <span class="Normal">const</span> vector<<span class="Normal">double</span>>& data<span class="Delimiter">)</span> <span class="Delimiter">{</span>
increment_any_refcounts<span class="Delimiter">(</span>canonized_x<span class="Delimiter">,</span> data<span class="Delimiter">);</span> <span class="Comment">// increment first so we don't reclaim on x <- copy x</span>
decrement_any_refcounts<span class="Delimiter">(</span>canonized_x<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> increment_any_refcounts<span class="Delimiter">(</span><span class="Normal">const</span> reagent& canonized_x<span class="Delimiter">,</span> <span class="Normal">const</span> vector<<span class="Normal">double</span>>& data<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>is_mu_address<span class="Delimiter">(</span>canonized_x<span class="Delimiter">))</span> <span class="Delimiter">{</span>
assert<span class="Delimiter">(</span>scalar<span class="Delimiter">(</span>data<span class="Delimiter">));</span>
assert<span class="Delimiter">(</span>!canonized_x<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>size<span class="Delimiter">);</span>
increment_refcount<span class="Delimiter">(</span>data<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span>
<span class="Delimiter">}</span>
<span class="Comment">// End Increment Refcounts(canonized_x)</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> increment_refcount<span class="Delimiter">(</span><span class="Normal">int</span> new_address<span class="Delimiter">)</span> <span class="Delimiter">{</span>
assert<span class="Delimiter">(</span>new_address >= <span class="Constant">0</span><span class="Delimiter">);</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>new_address == <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
<span class="Normal">int</span> new_refcount = get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> new_address<span class="Delimiter">);</span>
trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">"mem"</span><span class="Delimiter">)</span> << <span class="Constant">"incrementing refcount of "</span> << new_address << <span class="Constant">": "</span> << new_refcount << <span class="Constant">" -> "</span> << new_refcount+<span class="Constant">1</span> << end<span class="Delimiter">();</span>
put<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> new_address<span class="Delimiter">,</span> new_refcount+<span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> decrement_any_refcounts<span class="Delimiter">(</span><span class="Normal">const</span> reagent& canonized_x<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>is_mu_address<span class="Delimiter">(</span>canonized_x<span class="Delimiter">))</span> <span class="Delimiter">{</span>
assert<span class="Delimiter">(</span>canonized_x<span class="Delimiter">.</span>value<span class="Delimiter">);</span>
assert<span class="Delimiter">(</span>!canonized_x<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>size<span class="Delimiter">);</span>
decrement_refcount<span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> canonized_x<span class="Delimiter">.</span>value<span class="Delimiter">),</span> canonized_x<span class="Delimiter">.</span>type<span class="Delimiter">-></span>right<span class="Delimiter">,</span> payload_size<span class="Delimiter">(</span>canonized_x<span class="Delimiter">));</span>
<span class="Delimiter">}</span>
<span class="Comment">// End Decrement Refcounts(canonized_x)</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> decrement_refcount<span class="Delimiter">(</span><span class="Normal">int</span> old_address<span class="Delimiter">,</span> <span class="Normal">const</span> type_tree* payload_type<span class="Delimiter">,</span> <span class="Normal">int</span> payload_size<span class="Delimiter">)</span> <span class="Delimiter">{</span>
assert<span class="Delimiter">(</span>old_address >= <span class="Constant">0</span><span class="Delimiter">);</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>old_address<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">int</span> old_refcount = get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> old_address<span class="Delimiter">);</span>
trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">"mem"</span><span class="Delimiter">)</span> << <span class="Constant">"decrementing refcount of "</span> << old_address << <span class="Constant">": "</span> << old_refcount << <span class="Constant">" -> "</span> << old_refcount-<span class="Constant">1</span> << end<span class="Delimiter">();</span>
--old_refcount<span class="Delimiter">;</span>
put<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> old_address<span class="Delimiter">,</span> old_refcount<span class="Delimiter">);</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>old_refcount < <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
tb_shutdown<span class="Delimiter">();</span>
cerr << <span class="Constant">"Negative refcount!!! "</span> << old_address << <span class="Constant">' '</span> << old_refcount << <span class="cSpecial">'\n'</span><span class="Delimiter">;</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>Trace_stream<span class="Delimiter">)</span> <span class="Delimiter">{</span>
cerr << <span class="Constant">"Saving trace to last_trace.</span><span class="cSpecial">\n</span><span class="Constant">"</span><span class="Delimiter">;</span>
ofstream fout<span class="Delimiter">(</span><span class="Constant">"last_trace"</span><span class="Delimiter">);</span>
fout << Trace_stream<span class="Delimiter">-></span>readable_contents<span class="Delimiter">(</span><span class="Constant">""</span><span class="Delimiter">);</span>
fout<span class="Delimiter">.</span>close<span class="Delimiter">();</span>
<span class="Delimiter">}</span>
exit<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Comment">// End Decrement Refcount(old_address, payload_type, payload_size)</span>
<span class="Delimiter">}</span>
<span class="Delimiter">}</span>
<span class="Normal">int</span> payload_size<span class="Delimiter">(</span>reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> x<span class="Delimiter">)</span> <span class="Delimiter">{</span>
x<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>pair<string<span class="Delimiter">,</span> string_tree*><span class="Delimiter">(</span><span class="Constant">"lookup"</span><span class="Delimiter">,</span> <span class="Constant">NULL</span><span class="Delimiter">));</span>
lookup_memory_core<span class="Delimiter">(</span>x<span class="Delimiter">);</span>
<span class="Identifier">return</span> size_of<span class="Delimiter">(</span>x<span class="Delimiter">)</span> + <span class="Comment">/*</span><span class="Comment">refcount</span><span class="Comment">*/</span><span class="Constant">1</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Delimiter">:(scenario refcounts_reflexive)</span>
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
<span class="Comment"># idempotent copies leave refcount unchanged</span>
<span class="Constant">1</span>:address:number<span class="Special"> <- </span>copy <span class="Constant">1</span>:address:number
]
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="traceContains">+run: {1: ("address" "number")} <- copy {1: ("address" "number")}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="traceContains">+mem: decrementing refcount of 1000: 2 -> 1</span>
<span class="Delimiter">:(scenario refcounts_call)</span>
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
<span class="Comment"># passing in addresses to recipes increments refcount</span>
foo <span class="Constant">1</span>:address:number
<span class="Comment"># return does NOT yet decrement refcount; memory must be explicitly managed</span>
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
]
def foo [
<span class="Constant">2</span>:address:number<span class="Special"> <- </span>next-ingredient
]
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="traceContains">+run: foo {1: ("address" "number")}</span>
<span class="Comment"># leave ambiguous precisely when the next increment happens; a later layer</span>
<span class="Comment"># will mess with that</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: decrementing refcount of 1000: 2 -> 1</span>
<span class="Comment">//: fix up any instructions that don't follow the usual flow of read_memory</span>
<span class="Comment">//: before the RUN switch, and write_memory after</span>
<span class="Delimiter">:(scenario refcounts_put)</span>
container foo [
<span class="Normal">x</span>:address:number
]
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
<span class="Constant">2</span>:address:foo<span class="Special"> <- </span><span class="Normal">new</span> foo:type
*<span class="Constant">2</span>:address:foo<span class="Special"> <- </span>put *<span class="Constant">2</span>:address:foo<span class="Delimiter">,</span> x:offset<span class="Delimiter">,</span> <span class="Constant">1</span>:address:number
]
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="traceContains">+run: {2: ("address" "foo")} <- new {foo: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1002: 0 -> 1</span>
<span class="traceContains">+run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")}</span>
<span class="Comment"># put increments refcount</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="Delimiter">:(after "Write Memory in PUT in Run")</span>
reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> element = element_type<span class="Delimiter">(</span>base<span class="Delimiter">.</span>type<span class="Delimiter">,</span> offset<span class="Delimiter">);</span>
assert<span class="Delimiter">(</span>!has_property<span class="Delimiter">(</span>element<span class="Delimiter">,</span> <span class="Constant">"lookup"</span><span class="Delimiter">));</span>
element<span class="Delimiter">.</span>set_value<span class="Delimiter">(</span>address<span class="Delimiter">);</span>
update_any_refcounts<span class="Delimiter">(</span>element<span class="Delimiter">,</span> ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">2</span><span class="Delimiter">));</span>
<span class="Delimiter">:(scenario refcounts_put_index)</span>
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
<span class="Constant">2</span>:address:array:address:number<span class="Special"> <- </span><span class="Normal">new</span> <span class="Delimiter">{(</span>address number<span class="Delimiter">)</span>: type<span class="Delimiter">},</span> <span class="Constant">3</span>
*<span class="Constant">2</span>:address:array:address:number<span class="Special"> <- </span>put-index *<span class="Constant">2</span>:address:array:address:number<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">,</span> <span class="Constant">1</span>:address:number
]
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="traceContains">+run: {2: ("address" "array" "address" "number")} <- new {(address number): "type"}, {3: "literal"}</span>
<span class="traceContains">+mem: incrementing refcount of 1002: 0 -> 1</span>
<span class="traceContains">+run: {2: ("address" "array" "address" "number"), "lookup": ()} <- put-index {2: ("address" "array" "address" "number"), "lookup": ()}, {0: "literal"}, {1: ("address" "number")}</span>
<span class="Comment"># put-index increments refcount</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="Delimiter">:(after "Write Memory in PUT_INDEX in Run")</span>
update_any_refcounts<span class="Delimiter">(</span>element<span class="Delimiter">,</span> value<span class="Delimiter">);</span>
<span class="Delimiter">:(scenario refcounts_maybe_convert)</span>
exclusive-container foo [
<span class="Normal">x</span>:number
<span class="Normal">p</span>:address:number
]
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
<span class="Constant">2</span>:foo<span class="Special"> <- </span>merge <span class="Constant">1</span>/p<span class="Delimiter">,</span> <span class="Constant">1</span>:address:number
<span class="Constant">4</span>:address:number<span class="Delimiter">,</span> <span class="Constant">5</span>:boolean<span class="Special"> <- </span>maybe-convert <span class="Constant">2</span>:foo<span class="Delimiter">,</span> <span class="Constant">1</span>:variant/p
]
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="Comment"># merging in an address increments refcount</span>
<span class="traceContains">+run: {2: "foo"} <- merge {1: "literal", "p": ()}, {1: ("address" "number")}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="traceContains">+run: {4: ("address" "number")}, {5: "boolean"} <- maybe-convert {2: "foo"}, {1: "variant", "p": ()}</span>
<span class="Comment"># maybe-convert increments refcount on success</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 2 -> 3</span>
<span class="Delimiter">:(after "Write Memory in Successful MAYBE_CONVERT")</span>
<span class="Comment">// </span><span class="Todo">TODO</span><span class="Comment">: double-check data here as well</span>
vector<<span class="Normal">double</span>> data<span class="Delimiter">;</span>
<span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i < size_of<span class="Delimiter">(</span>product<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span>
data<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> base_address+<span class="Comment">/*</span><span class="Comment">skip tag</span><span class="Comment">*/</span><span class="Constant">1</span>+i<span class="Delimiter">));</span>
update_any_refcounts<span class="Delimiter">(</span>product<span class="Delimiter">,</span> data<span class="Delimiter">);</span>
<span class="SalientComment">//:: manage refcounts in instructions that copy multiple locations at a time</span>
<span class="Delimiter">:(scenario refcounts_copy_nested)</span>
container foo [
<span class="Normal">x</span>:address:number <span class="Comment"># address inside container</span>
]
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
<span class="Constant">2</span>:address:foo<span class="Special"> <- </span><span class="Normal">new</span> foo:type
*<span class="Constant">2</span>:address:foo<span class="Special"> <- </span>put *<span class="Constant">2</span>:address:foo<span class="Delimiter">,</span> x:offset<span class="Delimiter">,</span> <span class="Constant">1</span>:address:number
<span class="Constant">3</span>:foo<span class="Special"> <- </span>copy *<span class="Constant">2</span>:address:foo
]
<span class="traceContains">+transform: compute address offsets for container foo</span>
<span class="traceContains">+transform: checking container foo, element 0</span>
<span class="traceContains">+transform: address at offset 0</span>
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="traceContains">+run: {2: ("address" "foo"), "lookup": ()} <- put {2: ("address" "foo"), "lookup": ()}, {x: "offset"}, {1: ("address" "number")}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="Comment"># copying a container increments refcounts of any contained addresses</span>
<span class="traceContains">+run: {3: "foo"} <- copy {2: ("address" "foo"), "lookup": ()}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 2 -> 3</span>
<span class="Delimiter">:(after "End type_tree Definition")</span>
<span class="Normal">struct</span> address_element_info <span class="Delimiter">{</span>
<span class="Normal">int</span> offset<span class="Delimiter">;</span> <span class="Comment">// where inside a container type (after flattening nested containers!) the address lies</span>
<span class="Normal">const</span> type_tree* payload_type<span class="Delimiter">;</span> <span class="Comment">// all the information we need to compute sizes of items inside an address inside a container. Doesn't need to be a full-scale reagent, since an address inside a container can never be an array, and arrays are the only type that need to know their location to compute their size.</span>
address_element_info<span class="Delimiter">(</span><span class="Normal">int</span> o<span class="Delimiter">,</span> <span class="Normal">const</span> type_tree* p<span class="Delimiter">)</span> <span class="Delimiter">{</span>
offset = o<span class="Delimiter">;</span>
payload_type = p<span class="Delimiter">;</span>
<span class="Delimiter">}</span>
address_element_info<span class="Delimiter">(</span><span class="Normal">const</span> address_element_info& other<span class="Delimiter">)</span> <span class="Delimiter">{</span>
offset = other<span class="Delimiter">.</span>offset<span class="Delimiter">;</span>
payload_type = other<span class="Delimiter">.</span>payload_type ? <span class="Normal">new</span> type_tree<span class="Delimiter">(</span>*other<span class="Delimiter">.</span>payload_type<span class="Delimiter">)</span> : <span class="Constant">NULL</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>
~address_element_info<span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>payload_type<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">delete</span> payload_type<span class="Delimiter">;</span>
payload_type = <span class="Constant">NULL</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Delimiter">}</span>
address_element_info& <span class="Normal">operator</span>=<span class="Delimiter">(</span><span class="Normal">const</span> address_element_info& other<span class="Delimiter">)</span> <span class="Delimiter">{</span>
offset = other<span class="Delimiter">.</span>offset<span class="Delimiter">;</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>payload_type<span class="Delimiter">)</span> <span class="Normal">delete</span> payload_type<span class="Delimiter">;</span>
payload_type = other<span class="Delimiter">.</span>payload_type ? <span class="Normal">new</span> type_tree<span class="Delimiter">(</span>*other<span class="Delimiter">.</span>payload_type<span class="Delimiter">)</span> : <span class="Constant">NULL</span><span class="Delimiter">;</span>
<span class="Identifier">return</span> *<span class="Normal">this</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Delimiter">};</span>
<span class="Comment">// For exclusive containers we might sometimes have an address at some offset</span>
<span class="Comment">// if some other offset has a specific tag. This struct encapsulates such</span>
<span class="Comment">// guards.</span>
<span class="Normal">struct</span> tag_condition_info <span class="Delimiter">{</span>
<span class="Normal">int</span> offset<span class="Delimiter">;</span>
<span class="Normal">int</span> tag<span class="Delimiter">;</span>
tag_condition_info<span class="Delimiter">(</span><span class="Normal">int</span> o<span class="Delimiter">,</span> <span class="Normal">int</span> t<span class="Delimiter">)</span> :offset<span class="Delimiter">(</span>o<span class="Delimiter">),</span> tag<span class="Delimiter">(</span>t<span class="Delimiter">)</span> <span class="Delimiter">{}</span>
<span class="Delimiter">};</span>
<span class="Delimiter">:(before "End container_metadata Fields")</span>
<span class="Comment">// a list of facts of the form:</span>
<span class="Comment">//</span>
<span class="Comment">// IF offset o1 has tag t2 AND offset o2 has tag t2 AND .., THEN</span>
<span class="Comment">// for all address_element_infos:</span>
<span class="Comment">// you need to update refcounts for the address at offset pointing to a payload of type payload_type (just in case we need to abandon something in the process)</span>
map<set<tag_condition_info><span class="Delimiter">,</span> set<address_element_info> > address<span class="Delimiter">;</span>
<span class="Delimiter">:(code)</span>
<span class="Normal">bool</span> <span class="Normal">operator</span><<span class="Delimiter">(</span><span class="Normal">const</span> set<tag_condition_info>& a<span class="Delimiter">,</span> <span class="Normal">const</span> set<tag_condition_info>& b<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>a<span class="Delimiter">.</span>size<span class="Delimiter">()</span> != b<span class="Delimiter">.</span>size<span class="Delimiter">())</span> <span class="Identifier">return</span> a<span class="Delimiter">.</span>size<span class="Delimiter">()</span> < b<span class="Delimiter">.</span>size<span class="Delimiter">();</span>
<span class="Normal">for</span> <span class="Delimiter">(</span>set<tag_condition_info>::const_iterator pa = a<span class="Delimiter">.</span>begin<span class="Delimiter">(),</span> pb = b<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> pa != a<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++pa<span class="Delimiter">,</span> ++pb<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>pa<span class="Delimiter">-></span>offset != pb<span class="Delimiter">-></span>offset<span class="Delimiter">)</span> <span class="Identifier">return</span> pa<span class="Delimiter">-></span>offset < pb<span class="Delimiter">-></span>offset<span class="Delimiter">;</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>pa<span class="Delimiter">-></span>tag != pb<span class="Delimiter">-></span>tag<span class="Delimiter">)</span> <span class="Identifier">return</span> pa<span class="Delimiter">-></span>tag < pb<span class="Delimiter">-></span>tag<span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Comment">// equal</span>
<span class="Delimiter">}</span>
<span class="Normal">bool</span> <span class="Normal">operator</span><<span class="Delimiter">(</span><span class="Normal">const</span> tag_condition_info& a<span class="Delimiter">,</span> <span class="Normal">const</span> tag_condition_info& b<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>a<span class="Delimiter">.</span>offset != b<span class="Delimiter">.</span>offset<span class="Delimiter">)</span> <span class="Identifier">return</span> a<span class="Delimiter">.</span>offset < b<span class="Delimiter">.</span>offset<span class="Delimiter">;</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>a<span class="Delimiter">.</span>tag != b<span class="Delimiter">.</span>tag<span class="Delimiter">)</span> <span class="Identifier">return</span> a<span class="Delimiter">.</span>tag < b<span class="Delimiter">.</span>tag<span class="Delimiter">;</span>
<span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Comment">// equal</span>
<span class="Delimiter">}</span>
<span class="Normal">bool</span> <span class="Normal">operator</span><<span class="Delimiter">(</span><span class="Normal">const</span> set<address_element_info>& a<span class="Delimiter">,</span> <span class="Normal">const</span> set<address_element_info>& b<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>a<span class="Delimiter">.</span>size<span class="Delimiter">()</span> != b<span class="Delimiter">.</span>size<span class="Delimiter">())</span> <span class="Identifier">return</span> a<span class="Delimiter">.</span>size<span class="Delimiter">()</span> < b<span class="Delimiter">.</span>size<span class="Delimiter">();</span>
<span class="Normal">for</span> <span class="Delimiter">(</span>set<address_element_info>::const_iterator pa = a<span class="Delimiter">.</span>begin<span class="Delimiter">(),</span> pb = b<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> pa != a<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++pa<span class="Delimiter">,</span> ++pb<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>pa<span class="Delimiter">-></span>offset != pb<span class="Delimiter">-></span>offset<span class="Delimiter">)</span> <span class="Identifier">return</span> pa<span class="Delimiter">-></span>offset < pb<span class="Delimiter">-></span>offset<span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Comment">// equal</span>
<span class="Delimiter">}</span>
<span class="Normal">bool</span> <span class="Normal">operator</span><<span class="Delimiter">(</span><span class="Normal">const</span> address_element_info& a<span class="Delimiter">,</span> <span class="Normal">const</span> address_element_info& b<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>a<span class="Delimiter">.</span>offset != b<span class="Delimiter">.</span>offset<span class="Delimiter">)</span> <span class="Identifier">return</span> a<span class="Delimiter">.</span>offset < b<span class="Delimiter">.</span>offset<span class="Delimiter">;</span>
<span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span> <span class="Comment">// equal</span>
<span class="Delimiter">}</span>
<span class="Comment">//: populate metadata.address in a separate transform, because it requires</span>
<span class="Comment">//: already knowing the sizes of all types</span>
<span class="Delimiter">:(after "Transform.push_back(compute_container_sizes)")</span>
Transform<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>compute_container_address_offsets<span class="Delimiter">);</span>
<span class="Delimiter">:(code)</span>
<span class="Normal">void</span> compute_container_address_offsets<span class="Delimiter">(</span><span class="Normal">const</span> recipe_ordinal r<span class="Delimiter">)</span> <span class="Delimiter">{</span>
recipe& caller = get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">);</span>
trace<span class="Delimiter">(</span><span class="Constant">9992</span><span class="Delimiter">,</span> <span class="Constant">"transform"</span><span class="Delimiter">)</span> << <span class="Constant">"--- compute address offsets for "</span> << caller<span class="Delimiter">.</span>name << end<span class="Delimiter">();</span>
<span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i < SIZE<span class="Delimiter">(</span>caller<span class="Delimiter">.</span>steps<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
instruction& inst = caller<span class="Delimiter">.</span>steps<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
trace<span class="Delimiter">(</span><span class="Constant">9993</span><span class="Delimiter">,</span> <span class="Constant">"transform"</span><span class="Delimiter">)</span> << <span class="Constant">"- compute address offsets for "</span> << to_string<span class="Delimiter">(</span>inst<span class="Delimiter">)</span> << end<span class="Delimiter">();</span>
<span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i < SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span>
compute_container_address_offsets<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span>
<span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i < SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span>
compute_container_address_offsets<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span>
<span class="Delimiter">}</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> compute_container_address_offsets<span class="Delimiter">(</span>reagent& r<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>is_literal<span class="Delimiter">(</span>r<span class="Delimiter">)</span> || is_dummy<span class="Delimiter">(</span>r<span class="Delimiter">))</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
compute_container_address_offsets<span class="Delimiter">(</span>r<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> r<span class="Delimiter">.</span>type<span class="Delimiter">))</span>
r<span class="Delimiter">.</span>metadata = get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> r<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Comment">// the recursive structure of this function needs to exactly match</span>
<span class="Comment">// compute_container_sizes</span>
<span class="Normal">void</span> compute_container_address_offsets<span class="Delimiter">(</span><span class="Normal">const</span> type_tree* type<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>!type<span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>!type<span class="Delimiter">-></span>atom<span class="Delimiter">)</span> <span class="Delimiter">{</span>
assert<span class="Delimiter">(</span>type<span class="Delimiter">-></span>left<span class="Delimiter">-></span>atom<span class="Delimiter">);</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-></span>left<span class="Delimiter">-></span>name == <span class="Constant">"address"</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
compute_container_address_offsets<span class="Delimiter">(</span>type<span class="Delimiter">-></span>right<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">else</span> <span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-></span>left<span class="Delimiter">-></span>name == <span class="Constant">"array"</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">const</span> type_tree* element_type = type<span class="Delimiter">-></span>right<span class="Delimiter">;</span>
<span class="Comment">// hack: support both array:number:3 and array:address:number</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>!element_type<span class="Delimiter">-></span>atom && element_type<span class="Delimiter">-></span>right && element_type<span class="Delimiter">-></span>right<span class="Delimiter">-></span>atom && is_integer<span class="Delimiter">(</span>element_type<span class="Delimiter">-></span>right<span class="Delimiter">-></span>name<span class="Delimiter">))</span>
element_type = element_type<span class="Delimiter">-></span>left<span class="Delimiter">;</span>
compute_container_address_offsets<span class="Delimiter">(</span>element_type<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Comment">// End compute_container_address_offsets Non-atom Cases</span>
<span class="Delimiter">}</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> root_type<span class="Delimiter">(</span>type<span class="Delimiter">)-></span>value<span class="Delimiter">))</span> <span class="Identifier">return</span><span class="Delimiter">;</span> <span class="Comment">// error raised elsewhere</span>
type_info& info = get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> root_type<span class="Delimiter">(</span>type<span class="Delimiter">)-></span>value<span class="Delimiter">);</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>info<span class="Delimiter">.</span>kind == CONTAINER<span class="Delimiter">)</span> <span class="Delimiter">{</span>
compute_container_address_offsets<span class="Delimiter">(</span>info<span class="Delimiter">,</span> type<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>info<span class="Delimiter">.</span>kind == EXCLUSIVE_CONTAINER<span class="Delimiter">)</span> <span class="Delimiter">{</span>
compute_exclusive_container_address_offsets<span class="Delimiter">(</span>info<span class="Delimiter">,</span> type<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> compute_container_address_offsets<span class="Delimiter">(</span><span class="Normal">const</span> type_info& container_info<span class="Delimiter">,</span> <span class="Normal">const</span> type_tree* full_type<span class="Delimiter">)</span> <span class="Delimiter">{</span>
container_metadata& metadata = get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> full_type<span class="Delimiter">);</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>!metadata<span class="Delimiter">.</span>address<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
trace<span class="Delimiter">(</span><span class="Constant">9994</span><span class="Delimiter">,</span> <span class="Constant">"transform"</span><span class="Delimiter">)</span> << <span class="Constant">"compute address offsets for container "</span> << container_info<span class="Delimiter">.</span>name << end<span class="Delimiter">();</span>
append_addresses<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">,</span> full_type<span class="Delimiter">,</span> metadata<span class="Delimiter">.</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">());</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> compute_exclusive_container_address_offsets<span class="Delimiter">(</span><span class="Normal">const</span> type_info& exclusive_container_info<span class="Delimiter">,</span> <span class="Normal">const</span> type_tree* full_type<span class="Delimiter">)</span> <span class="Delimiter">{</span>
container_metadata& metadata = get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> full_type<span class="Delimiter">);</span>
trace<span class="Delimiter">(</span><span class="Constant">9994</span><span class="Delimiter">,</span> <span class="Constant">"transform"</span><span class="Delimiter">)</span> << <span class="Constant">"compute address offsets for exclusive container "</span> << exclusive_container_info<span class="Delimiter">.</span>name << end<span class="Delimiter">();</span>
<span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> tag = <span class="Constant">0</span><span class="Delimiter">;</span> tag < SIZE<span class="Delimiter">(</span>exclusive_container_info<span class="Delimiter">.</span>elements<span class="Delimiter">);</span> ++tag<span class="Delimiter">)</span> <span class="Delimiter">{</span>
set<tag_condition_info> key<span class="Delimiter">;</span>
key<span class="Delimiter">.</span>insert<span class="Delimiter">(</span>tag_condition_info<span class="Delimiter">(</span><span class="Comment">/*</span><span class="Comment">tag is at offset</span><span class="Comment">*/</span><span class="Constant">0</span><span class="Delimiter">,</span> tag<span class="Delimiter">));</span>
append_addresses<span class="Delimiter">(</span><span class="Comment">/*</span><span class="Comment">skip tag offset</span><span class="Comment">*/</span><span class="Constant">1</span><span class="Delimiter">,</span> variant_type<span class="Delimiter">(</span>full_type<span class="Delimiter">,</span> tag<span class="Delimiter">).</span>type<span class="Delimiter">,</span> metadata<span class="Delimiter">.</span>address<span class="Delimiter">,</span> key<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> append_addresses<span class="Delimiter">(</span><span class="Normal">int</span> base_offset<span class="Delimiter">,</span> <span class="Normal">const</span> type_tree* type<span class="Delimiter">,</span> map<set<tag_condition_info><span class="Delimiter">,</span> set<address_element_info> >& out<span class="Delimiter">,</span> <span class="Normal">const</span> set<tag_condition_info>& key<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>is_mu_address<span class="Delimiter">(</span>type<span class="Delimiter">))</span> <span class="Delimiter">{</span>
get_or_insert<span class="Delimiter">(</span>out<span class="Delimiter">,</span> key<span class="Delimiter">).</span>insert<span class="Delimiter">(</span>address_element_info<span class="Delimiter">(</span>base_offset<span class="Delimiter">,</span> <span class="Normal">new</span> type_tree<span class="Delimiter">(</span>*type<span class="Delimiter">-></span>right<span class="Delimiter">)));</span>
<span class="Identifier">return</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Normal">const</span> type_tree* root = root_type<span class="Delimiter">(</span>type<span class="Delimiter">);</span>
<span class="Normal">const</span> type_info& info = get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> root<span class="Delimiter">-></span>value<span class="Delimiter">);</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>info<span class="Delimiter">.</span>kind == CONTAINER<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> curr_index = <span class="Constant">0</span><span class="Delimiter">,</span> curr_offset = base_offset<span class="Delimiter">;</span> curr_index < SIZE<span class="Delimiter">(</span>info<span class="Delimiter">.</span>elements<span class="Delimiter">);</span> ++curr_index<span class="Delimiter">)</span> <span class="Delimiter">{</span>
trace<span class="Delimiter">(</span><span class="Constant">9993</span><span class="Delimiter">,</span> <span class="Constant">"transform"</span><span class="Delimiter">)</span> << <span class="Constant">"checking container "</span> << root<span class="Delimiter">-></span>name << <span class="Constant">", element "</span> << curr_index << end<span class="Delimiter">();</span>
reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> element = element_type<span class="Delimiter">(</span>type<span class="Delimiter">,</span> curr_index<span class="Delimiter">);</span> <span class="Comment">// not root</span>
<span class="Comment">// Compute Container Address Offset(element)</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>is_mu_address<span class="Delimiter">(</span>element<span class="Delimiter">))</span> <span class="Delimiter">{</span>
trace<span class="Delimiter">(</span><span class="Constant">9993</span><span class="Delimiter">,</span> <span class="Constant">"transform"</span><span class="Delimiter">)</span> << <span class="Constant">"address at offset "</span> << curr_offset << end<span class="Delimiter">();</span>
get_or_insert<span class="Delimiter">(</span>out<span class="Delimiter">,</span> key<span class="Delimiter">).</span>insert<span class="Delimiter">(</span>address_element_info<span class="Delimiter">(</span>curr_offset<span class="Delimiter">,</span> <span class="Normal">new</span> type_tree<span class="Delimiter">(</span>*element<span class="Delimiter">.</span>type<span class="Delimiter">-></span>right<span class="Delimiter">)));</span>
++curr_offset<span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Normal">else</span> <span class="Normal">if</span> <span class="Delimiter">(</span>is_mu_container<span class="Delimiter">(</span>element<span class="Delimiter">))</span> <span class="Delimiter">{</span>
append_addresses<span class="Delimiter">(</span>curr_offset<span class="Delimiter">,</span> element<span class="Delimiter">.</span>type<span class="Delimiter">,</span> out<span class="Delimiter">,</span> key<span class="Delimiter">);</span>
curr_offset += size_of<span class="Delimiter">(</span>element<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">else</span> <span class="Normal">if</span> <span class="Delimiter">(</span>is_mu_exclusive_container<span class="Delimiter">(</span>element<span class="Delimiter">))</span> <span class="Delimiter">{</span>
<span class="Normal">const</span> type_tree* element_root_type = root_type<span class="Delimiter">(</span>element<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
<span class="Normal">const</span> type_info& element_info = get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> element_root_type<span class="Delimiter">-></span>value<span class="Delimiter">);</span>
<span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> tag = <span class="Constant">0</span><span class="Delimiter">;</span> tag < SIZE<span class="Delimiter">(</span>element_info<span class="Delimiter">.</span>elements<span class="Delimiter">);</span> ++tag<span class="Delimiter">)</span> <span class="Delimiter">{</span>
set<tag_condition_info> new_key = key<span class="Delimiter">;</span>
new_key<span class="Delimiter">.</span>insert<span class="Delimiter">(</span>tag_condition_info<span class="Delimiter">(</span>curr_offset<span class="Delimiter">,</span> tag<span class="Delimiter">));</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>out<span class="Delimiter">,</span> new_key<span class="Delimiter">))</span>
append_addresses<span class="Delimiter">(</span>curr_offset+<span class="Comment">/*</span><span class="Comment">skip tag</span><span class="Comment">*/</span><span class="Constant">1</span><span class="Delimiter">,</span> variant_type<span class="Delimiter">(</span>element<span class="Delimiter">.</span>type<span class="Delimiter">,</span> tag<span class="Delimiter">).</span>type<span class="Delimiter">,</span> out<span class="Delimiter">,</span> new_key<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
curr_offset += size_of<span class="Delimiter">(</span>element<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">else</span> <span class="Delimiter">{</span>
<span class="Comment">// non-address primitive</span>
++curr_offset<span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Delimiter">}</span>
<span class="Delimiter">}</span>
<span class="Normal">else</span> <span class="Normal">if</span> <span class="Delimiter">(</span>info<span class="Delimiter">.</span>kind == EXCLUSIVE_CONTAINER<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> tag = <span class="Constant">0</span><span class="Delimiter">;</span> tag < SIZE<span class="Delimiter">(</span>info<span class="Delimiter">.</span>elements<span class="Delimiter">);</span> ++tag<span class="Delimiter">)</span> <span class="Delimiter">{</span>
set<tag_condition_info> new_key = key<span class="Delimiter">;</span>
new_key<span class="Delimiter">.</span>insert<span class="Delimiter">(</span>tag_condition_info<span class="Delimiter">(</span>base_offset<span class="Delimiter">,</span> tag<span class="Delimiter">));</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>out<span class="Delimiter">,</span> new_key<span class="Delimiter">))</span>
append_addresses<span class="Delimiter">(</span>base_offset+<span class="Comment">/*</span><span class="Comment">skip tag</span><span class="Comment">*/</span><span class="Constant">1</span><span class="Delimiter">,</span> variant_type<span class="Delimiter">(</span>type<span class="Delimiter">,</span> tag<span class="Delimiter">).</span>type<span class="Delimiter">,</span> out<span class="Delimiter">,</span> new_key<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Delimiter">}</span>
<span class="Delimiter">}</span>
<span class="Normal">int</span> payload_size<span class="Delimiter">(</span><span class="Normal">const</span> type_tree* type<span class="Delimiter">)</span> <span class="Delimiter">{</span>
assert<span class="Delimiter">(</span>type<span class="Delimiter">-></span>name == <span class="Constant">"address"</span><span class="Delimiter">);</span>
assert<span class="Delimiter">(</span>type<span class="Delimiter">-></span>right<span class="Delimiter">-></span>name != <span class="Constant">"array"</span><span class="Delimiter">);</span>
<span class="Identifier">return</span> size_of<span class="Delimiter">(</span>type<span class="Delimiter">-></span>right<span class="Delimiter">)</span> + <span class="Comment">/*</span><span class="Comment">refcount</span><span class="Comment">*/</span><span class="Constant">1</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Comment">//: for the following unit tests we'll do the work of the transform by hand</span>
<span class="Delimiter">:(before "End Unit Tests")</span>
<span class="Normal">void</span> test_container_address_offsets_empty<span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span class="Normal">int</span> old_size = SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">);</span>
<span class="Comment">// define a container with no addresses</span>
reagent r<span class="Delimiter">(</span><span class="Constant">"x:point"</span><span class="Delimiter">);</span>
compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">);</span> <span class="Comment">// need to first pre-populate the metadata</span>
<span class="Comment">// scan</span>
compute_container_address_offsets<span class="Delimiter">(</span>r<span class="Delimiter">);</span>
<span class="Comment">// global metadata contains just the entry for foo</span>
<span class="Comment">// no entries for non-container types or other junk</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// the reagent we scanned knows it has no addresses</span>
CHECK<span class="Delimiter">(</span>r<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>address<span class="Delimiter">.</span>empty<span class="Delimiter">());</span>
<span class="Comment">// the global table contains an identical entry</span>
CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> r<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
CHECK<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> r<span class="Delimiter">.</span>type<span class="Delimiter">).</span>address<span class="Delimiter">.</span>empty<span class="Delimiter">());</span>
<span class="Comment">// compute_container_address_offsets creates no new entries</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> test_container_address_offsets<span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span class="Normal">int</span> old_size = SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">);</span>
<span class="Comment">// define a container with an address at offset 0 that we have the size for</span>
run<span class="Delimiter">(</span><span class="Constant">"container foo [</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">" x:address:number</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">"]</span><span class="cSpecial">\n</span><span class="Constant">"</span><span class="Delimiter">);</span>
reagent r<span class="Delimiter">(</span><span class="Constant">"x:foo"</span><span class="Delimiter">);</span>
compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">);</span> <span class="Comment">// need to first pre-populate the metadata</span>
<span class="Comment">// scan</span>
compute_container_address_offsets<span class="Delimiter">(</span>r<span class="Delimiter">);</span>
<span class="Comment">// global metadata contains just the entry for foo</span>
<span class="Comment">// no entries for non-container types or other junk</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// the reagent we scanned knows it has an address at offset 0</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>r<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>address<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>r<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">()));</span>
<span class="Normal">const</span> set<address_element_info>& address_offsets = get<span class="Delimiter">(</span>r<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">());</span> <span class="Comment">// unconditional for containers</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>address_offsets<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>offset<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>address_offsets<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>atom<span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>name<span class="Delimiter">,</span> <span class="Constant">"number"</span><span class="Delimiter">);</span>
<span class="Comment">// the global table contains an identical entry</span>
CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> r<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
<span class="Normal">const</span> set<address_element_info>& address_offsets2 = get<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> r<span class="Delimiter">.</span>type<span class="Delimiter">).</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">());</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>offset<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>atom<span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>name<span class="Delimiter">,</span> <span class="Constant">"number"</span><span class="Delimiter">);</span>
<span class="Comment">// compute_container_address_offsets creates no new entries</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> test_container_address_offsets_2<span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span class="Normal">int</span> old_size = SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">);</span>
<span class="Comment">// define a container with an address at offset 1 that we have the size for</span>
run<span class="Delimiter">(</span><span class="Constant">"container foo [</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">" x:number</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">" y:address:number</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">"]</span><span class="cSpecial">\n</span><span class="Constant">"</span><span class="Delimiter">);</span>
reagent r<span class="Delimiter">(</span><span class="Constant">"x:foo"</span><span class="Delimiter">);</span>
compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">);</span> <span class="Comment">// need to first pre-populate the metadata</span>
<span class="Comment">// global metadata contains just the entry for foo</span>
<span class="Comment">// no entries for non-container types or other junk</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// scan</span>
compute_container_address_offsets<span class="Delimiter">(</span>r<span class="Delimiter">);</span>
<span class="Comment">// compute_container_address_offsets creates no new entries</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// the reagent we scanned knows it has an address at offset 1</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>r<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>address<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>r<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">()));</span>
<span class="Normal">const</span> set<address_element_info>& address_offsets = get<span class="Delimiter">(</span>r<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">());</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>address_offsets<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>offset<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span> <span class="Comment">//</span>
CHECK<span class="Delimiter">(</span>address_offsets<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>atom<span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>name<span class="Delimiter">,</span> <span class="Constant">"number"</span><span class="Delimiter">);</span>
<span class="Comment">// the global table contains an identical entry</span>
CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> r<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
<span class="Normal">const</span> set<address_element_info>& address_offsets2 = get<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> r<span class="Delimiter">.</span>type<span class="Delimiter">).</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">());</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>offset<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span> <span class="Comment">//</span>
CHECK<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>atom<span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>name<span class="Delimiter">,</span> <span class="Constant">"number"</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> test_container_address_offsets_nested<span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span class="Normal">int</span> old_size = SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">);</span>
<span class="Comment">// define a container with a nested container containing an address</span>
run<span class="Delimiter">(</span><span class="Constant">"container foo [</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">" x:address:number</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">" y:number</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">"]</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">"container bar [</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">" p:point</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">" f:foo</span><span class="cSpecial">\n</span><span class="Constant">"</span> <span class="Comment">// nested container containing address</span>
<span class="Constant">"]</span><span class="cSpecial">\n</span><span class="Constant">"</span><span class="Delimiter">);</span>
reagent r<span class="Delimiter">(</span><span class="Constant">"x:bar"</span><span class="Delimiter">);</span>
compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">);</span> <span class="Comment">// need to first pre-populate the metadata</span>
<span class="Comment">// global metadata contains entries for bar and included types: point and foo</span>
<span class="Comment">// no entries for non-container types or other junk</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">3</span><span class="Delimiter">);</span>
<span class="Comment">// scan</span>
compute_container_address_offsets<span class="Delimiter">(</span>r<span class="Delimiter">);</span>
<span class="Comment">// the reagent we scanned knows it has an address at offset 2</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>r<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>address<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>r<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">()));</span>
<span class="Normal">const</span> set<address_element_info>& address_offsets = get<span class="Delimiter">(</span>r<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">());</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>address_offsets<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>offset<span class="Delimiter">,</span> <span class="Constant">2</span><span class="Delimiter">);</span> <span class="Comment">//</span>
CHECK<span class="Delimiter">(</span>address_offsets<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>atom<span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>name<span class="Delimiter">,</span> <span class="Constant">"number"</span><span class="Delimiter">);</span>
<span class="Comment">// the global table also knows its address offset</span>
CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> r<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
<span class="Normal">const</span> set<address_element_info>& address_offsets2 = get<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> r<span class="Delimiter">.</span>type<span class="Delimiter">).</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">());</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>offset<span class="Delimiter">,</span> <span class="Constant">2</span><span class="Delimiter">);</span> <span class="Comment">//</span>
CHECK<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>atom<span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>name<span class="Delimiter">,</span> <span class="Constant">"number"</span><span class="Delimiter">);</span>
<span class="Comment">// compute_container_address_offsets creates no new entries</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">3</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> test_container_address_offsets_from_address<span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span class="Normal">int</span> old_size = SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">);</span>
<span class="Comment">// define a container with an address at offset 0</span>
run<span class="Delimiter">(</span><span class="Constant">"container foo [</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">" x:address:number</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">"]</span><span class="cSpecial">\n</span><span class="Constant">"</span><span class="Delimiter">);</span>
reagent r<span class="Delimiter">(</span><span class="Constant">"x:address:foo"</span><span class="Delimiter">);</span>
compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">);</span> <span class="Comment">// need to first pre-populate the metadata</span>
<span class="Comment">// global metadata contains just the entry for foo</span>
<span class="Comment">// no entries for non-container types or other junk</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// scan an address to the container</span>
compute_container_address_offsets<span class="Delimiter">(</span>r<span class="Delimiter">);</span>
<span class="Comment">// compute_container_address_offsets creates no new entries</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// scanning precomputed metadata for the container</span>
reagent container<span class="Delimiter">(</span><span class="Constant">"x:foo"</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
<span class="Normal">const</span> set<address_element_info>& address_offsets2 = get<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">).</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">());</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>offset<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>atom<span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>name<span class="Delimiter">,</span> <span class="Constant">"number"</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> test_container_address_offsets_from_array<span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span class="Normal">int</span> old_size = SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">);</span>
<span class="Comment">// define a container with an address at offset 0</span>
run<span class="Delimiter">(</span><span class="Constant">"container foo [</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">" x:address:number</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">"]</span><span class="cSpecial">\n</span><span class="Constant">"</span><span class="Delimiter">);</span>
reagent r<span class="Delimiter">(</span><span class="Constant">"x:array:foo"</span><span class="Delimiter">);</span>
compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">);</span> <span class="Comment">// need to first pre-populate the metadata</span>
<span class="Comment">// global metadata contains just the entry for foo</span>
<span class="Comment">// no entries for non-container types or other junk</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// scan an array of the container</span>
compute_container_address_offsets<span class="Delimiter">(</span>r<span class="Delimiter">);</span>
<span class="Comment">// compute_container_address_offsets creates no new entries</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// scanning precomputed metadata for the container</span>
reagent container<span class="Delimiter">(</span><span class="Constant">"x:foo"</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
<span class="Normal">const</span> set<address_element_info>& address_offsets2 = get<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">).</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">());</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>offset<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>atom<span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>name<span class="Delimiter">,</span> <span class="Constant">"number"</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> test_container_address_offsets_from_address_to_array<span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span class="Normal">int</span> old_size = SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">);</span>
<span class="Comment">// define a container with an address at offset 0</span>
run<span class="Delimiter">(</span><span class="Constant">"container foo [</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">" x:address:number</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">"]</span><span class="cSpecial">\n</span><span class="Constant">"</span><span class="Delimiter">);</span>
reagent r<span class="Delimiter">(</span><span class="Constant">"x:address:array:foo"</span><span class="Delimiter">);</span>
compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">);</span> <span class="Comment">// need to first pre-populate the metadata</span>
<span class="Comment">// global metadata contains just the entry for foo</span>
<span class="Comment">// no entries for non-container types or other junk</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// scan an address to an array of the container</span>
compute_container_address_offsets<span class="Delimiter">(</span>r<span class="Delimiter">);</span>
<span class="Comment">// compute_container_address_offsets creates no new entries</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// scanning precomputed metadata for the container</span>
reagent container<span class="Delimiter">(</span><span class="Constant">"x:foo"</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
<span class="Normal">const</span> set<address_element_info>& address_offsets2 = get<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">).</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">());</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>offset<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>atom<span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>name<span class="Delimiter">,</span> <span class="Constant">"number"</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> test_container_address_offsets_from_static_array<span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span class="Normal">int</span> old_size = SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">);</span>
<span class="Comment">// define a container with an address at offset 0</span>
run<span class="Delimiter">(</span><span class="Constant">"container foo [</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">" x:address:number</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">"]</span><span class="cSpecial">\n</span><span class="Constant">"</span><span class="Delimiter">);</span>
reagent r<span class="Delimiter">(</span><span class="Constant">"x:array:foo:10"</span><span class="Delimiter">);</span>
compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">);</span> <span class="Comment">// need to first pre-populate the metadata</span>
<span class="Comment">// global metadata contains just the entry for foo</span>
<span class="Comment">// no entries for non-container types or other junk</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// scan a static array of the container</span>
compute_container_address_offsets<span class="Delimiter">(</span>r<span class="Delimiter">);</span>
<span class="Comment">// compute_container_address_offsets creates no new entries</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// scanning precomputed metadata for the container</span>
reagent container<span class="Delimiter">(</span><span class="Constant">"x:foo"</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
<span class="Normal">const</span> set<address_element_info>& address_offsets2 = get<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">).</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">());</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>offset<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>atom<span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>name<span class="Delimiter">,</span> <span class="Constant">"number"</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> test_container_address_offsets_from_address_to_static_array<span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span class="Normal">int</span> old_size = SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">);</span>
<span class="Comment">// define a container with an address at offset 0</span>
run<span class="Delimiter">(</span><span class="Constant">"container foo [</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">" x:address:number</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">"]</span><span class="cSpecial">\n</span><span class="Constant">"</span><span class="Delimiter">);</span>
reagent r<span class="Delimiter">(</span><span class="Constant">"x:address:array:foo:10"</span><span class="Delimiter">);</span>
compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">);</span> <span class="Comment">// need to first pre-populate the metadata</span>
<span class="Comment">// global metadata contains just the entry for foo</span>
<span class="Comment">// no entries for non-container types or other junk</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// scan an address to a static array of the container</span>
compute_container_address_offsets<span class="Delimiter">(</span>r<span class="Delimiter">);</span>
<span class="Comment">// compute_container_address_offsets creates no new entries</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// scanning precomputed metadata for the container</span>
reagent container<span class="Delimiter">(</span><span class="Constant">"x:foo"</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
<span class="Normal">const</span> set<address_element_info>& address_offsets2 = get<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">).</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">());</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>offset<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>atom<span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>name<span class="Delimiter">,</span> <span class="Constant">"number"</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> test_container_address_offsets_from_repeated_address_and_array_types<span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span class="Normal">int</span> old_size = SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">);</span>
<span class="Comment">// define a container with an address at offset 0</span>
run<span class="Delimiter">(</span><span class="Constant">"container foo [</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">" x:address:number</span><span class="cSpecial">\n</span><span class="Constant">"</span>
<span class="Constant">"]</span><span class="cSpecial">\n</span><span class="Constant">"</span><span class="Delimiter">);</span>
<span class="Comment">// scan a deep nest of 'address' and 'array' types modifying a container</span>
reagent r<span class="Delimiter">(</span><span class="Constant">"x:address:array:address:address:array:foo:10"</span><span class="Delimiter">);</span>
compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">);</span> <span class="Comment">// need to first pre-populate the metadata</span>
<span class="Comment">// global metadata contains just the entry for foo</span>
<span class="Comment">// no entries for non-container types or other junk</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
compute_container_address_offsets<span class="Delimiter">(</span>r<span class="Delimiter">);</span>
<span class="Comment">// compute_container_address_offsets creates no new entries</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Comment">// scanning precomputed metadata for the container</span>
reagent container<span class="Delimiter">(</span><span class="Constant">"x:foo"</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
<span class="Normal">const</span> set<address_element_info>& address_offsets2 = get<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">).</span>address<span class="Delimiter">,</span> set<tag_condition_info><span class="Delimiter">());</span>
CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">),</span> <span class="Constant">1</span><span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>offset<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">);</span>
CHECK<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>atom<span class="Delimiter">);</span>
CHECK_EQ<span class="Delimiter">(</span>address_offsets2<span class="Delimiter">.</span>begin<span class="Delimiter">()-></span>payload_type<span class="Delimiter">-></span>name<span class="Delimiter">,</span> <span class="Constant">"number"</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Comment">//: use metadata.address to update refcounts within containers, arrays and</span>
<span class="Comment">//: exclusive containers</span>
<span class="Delimiter">:(before "End Increment Refcounts(canonized_x)")</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>is_mu_container<span class="Delimiter">(</span>canonized_x<span class="Delimiter">)</span> || is_mu_exclusive_container<span class="Delimiter">(</span>canonized_x<span class="Delimiter">))</span> <span class="Delimiter">{</span>
<span class="Normal">const</span> container_metadata& metadata = get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> canonized_x<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
<span class="Normal">for</span> <span class="Delimiter">(</span>map<set<tag_condition_info><span class="Delimiter">,</span> set<address_element_info> >::const_iterator p = metadata<span class="Delimiter">.</span>address<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != metadata<span class="Delimiter">.</span>address<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>!all_match<span class="Delimiter">(</span>data<span class="Delimiter">,</span> p<span class="Delimiter">-></span>first<span class="Delimiter">))</span> <span class="Identifier">continue</span><span class="Delimiter">;</span>
<span class="Normal">for</span> <span class="Delimiter">(</span>set<address_element_info>::const_iterator info = p<span class="Delimiter">-></span>second<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> info != p<span class="Delimiter">-></span>second<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++info<span class="Delimiter">)</span>
increment_refcount<span class="Delimiter">(</span>data<span class="Delimiter">.</span>at<span class="Delimiter">(</span>info<span class="Delimiter">-></span>offset<span class="Delimiter">));</span>
<span class="Delimiter">}</span>
<span class="Delimiter">}</span>
<span class="Delimiter">:(before "End Decrement Refcounts(canonized_x)")</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>is_mu_container<span class="Delimiter">(</span>canonized_x<span class="Delimiter">)</span> || is_mu_exclusive_container<span class="Delimiter">(</span>canonized_x<span class="Delimiter">))</span> <span class="Delimiter">{</span>
trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">"mem"</span><span class="Delimiter">)</span> << <span class="Constant">"need to read old value of '"</span> << to_string<span class="Delimiter">(</span>canonized_x<span class="Delimiter">)</span> << <span class="Constant">"' to figure out what refcounts to decrement"</span> << end<span class="Delimiter">();</span>
<span class="Comment">// read from canonized_x but without canonizing again</span>
<span class="Comment">// todo: inline without running canonize all over again</span>
reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> tmp = canonized_x<span class="Delimiter">;</span>
tmp<span class="Delimiter">.</span>properties<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>pair<string<span class="Delimiter">,</span> string_tree*><span class="Delimiter">(</span><span class="Constant">"raw"</span><span class="Delimiter">,</span> <span class="Constant">NULL</span><span class="Delimiter">));</span>
vector<<span class="Normal">double</span>> data = read_memory<span class="Delimiter">(</span>tmp<span class="Delimiter">);</span>
trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">"mem"</span><span class="Delimiter">)</span> << <span class="Constant">"done reading old value of '"</span> << to_string<span class="Delimiter">(</span>canonized_x<span class="Delimiter">)</span> << <span class="Constant">"'"</span> << end<span class="Delimiter">();</span>
<span class="Normal">const</span> container_metadata& metadata = get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> canonized_x<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
<span class="Normal">for</span> <span class="Delimiter">(</span>map<set<tag_condition_info><span class="Delimiter">,</span> set<address_element_info> >::const_iterator p = metadata<span class="Delimiter">.</span>address<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != metadata<span class="Delimiter">.</span>address<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>!all_match<span class="Delimiter">(</span>data<span class="Delimiter">,</span> p<span class="Delimiter">-></span>first<span class="Delimiter">))</span> <span class="Identifier">continue</span><span class="Delimiter">;</span>
<span class="Normal">for</span> <span class="Delimiter">(</span>set<address_element_info>::const_iterator info = p<span class="Delimiter">-></span>second<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> info != p<span class="Delimiter">-></span>second<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++info<span class="Delimiter">)</span>
decrement_refcount<span class="Delimiter">(</span>get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> canonized_x<span class="Delimiter">.</span>value + info<span class="Delimiter">-></span>offset<span class="Delimiter">),</span> info<span class="Delimiter">-></span>payload_type<span class="Delimiter">,</span> size_of<span class="Delimiter">(</span>info<span class="Delimiter">-></span>payload_type<span class="Delimiter">)</span>+<span class="Comment">/*</span><span class="Comment">refcount</span><span class="Comment">*/</span><span class="Constant">1</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Delimiter">}</span>
<span class="Delimiter">:(code)</span>
<span class="Normal">bool</span> all_match<span class="Delimiter">(</span><span class="Normal">const</span> vector<<span class="Normal">double</span>>& data<span class="Delimiter">,</span> <span class="Normal">const</span> set<tag_condition_info>& conditions<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">for</span> <span class="Delimiter">(</span>set<tag_condition_info>::const_iterator p = conditions<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != conditions<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>data<span class="Delimiter">.</span>at<span class="Delimiter">(</span>p<span class="Delimiter">-></span>offset<span class="Delimiter">)</span> != p<span class="Delimiter">-></span>tag<span class="Delimiter">)</span>
<span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Delimiter">:(scenario refcounts_put_container)</span>
container foo [
<span class="Normal">a</span>:bar <span class="Comment"># contains an address</span>
]
container bar [
<span class="Normal">x</span>:address:number
]
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
<span class="Constant">2</span>:bar<span class="Special"> <- </span>merge <span class="Constant">1</span>:address:number
<span class="Constant">3</span>:address:foo<span class="Special"> <- </span><span class="Normal">new</span> foo:type
*<span class="Constant">3</span>:address:foo<span class="Special"> <- </span>put *<span class="Constant">3</span>:address:foo<span class="Delimiter">,</span> a:offset<span class="Delimiter">,</span> <span class="Constant">2</span>:bar
]
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="traceContains">+run: {2: "bar"} <- merge {1: ("address" "number")}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="traceContains">+run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {a: "offset"}, {2: "bar"}</span>
<span class="Comment"># put increments refcount inside container</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 2 -> 3</span>
<span class="Delimiter">:(scenario refcounts_put_index_array)</span>
container bar [
<span class="Normal">x</span>:address:number
]
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
<span class="Constant">2</span>:bar<span class="Special"> <- </span>merge <span class="Constant">1</span>:address:number
<span class="Constant">3</span>:address:array:bar<span class="Special"> <- </span><span class="Normal">new</span> bar:type<span class="Delimiter">,</span> <span class="Constant">3</span>
*<span class="Constant">3</span>:address:array:bar<span class="Special"> <- </span>put-index *<span class="Constant">3</span>:address:array:bar<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">,</span> <span class="Constant">2</span>:bar
]
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="traceContains">+run: {2: "bar"} <- merge {1: ("address" "number")}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="traceContains">+run: {3: ("address" "array" "bar"), "lookup": ()} <- put-index {3: ("address" "array" "bar"), "lookup": ()}, {0: "literal"}, {2: "bar"}</span>
<span class="Comment"># put-index increments refcount inside container</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 2 -> 3</span>
<span class="Delimiter">:(scenario refcounts_maybe_convert_container)</span>
exclusive-container foo [
<span class="Normal">a</span>:number
<span class="Normal">b</span>:bar <span class="Comment"># contains an address</span>
]
container bar [
<span class="Normal">x</span>:address:number
]
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
<span class="Constant">2</span>:bar<span class="Special"> <- </span>merge <span class="Constant">1</span>:address:number
<span class="Constant">3</span>:foo<span class="Special"> <- </span>merge <span class="Constant">1</span>/b<span class="Delimiter">,</span> <span class="Constant">2</span>:bar
<span class="Constant">5</span>:bar<span class="Delimiter">,</span> <span class="Constant">6</span>:boolean<span class="Special"> <- </span>maybe-convert <span class="Constant">3</span>:foo<span class="Delimiter">,</span> <span class="Constant">1</span>:variant/b
]
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="traceContains">+run: {2: "bar"} <- merge {1: ("address" "number")}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="traceContains">+run: {3: "foo"} <- merge {1: "literal", "b": ()}, {2: "bar"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 2 -> 3</span>
<span class="traceContains">+run: {5: "bar"}, {6: "boolean"} <- maybe-convert {3: "foo"}, {1: "variant", "b": ()}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 3 -> 4</span>
<span class="Delimiter">:(scenario refcounts_copy_doubly_nested)</span>
container foo [
<span class="Normal">a</span>:bar <span class="Comment"># no addresses</span>
<span class="Normal">b</span>:curr <span class="Comment"># contains addresses</span>
]
container bar [
<span class="Normal">x</span>:number
<span class="Normal">y</span>:number
]
container curr [
<span class="Normal">x</span>:number
<span class="Normal">y</span>:address:number <span class="Comment"># address inside container inside container</span>
]
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
<span class="Constant">2</span>:address:curr<span class="Special"> <- </span><span class="Normal">new</span> curr:type
*<span class="Constant">2</span>:address:curr<span class="Special"> <- </span>put *<span class="Constant">2</span>:address:curr<span class="Delimiter">,</span> <span class="Constant">1</span>:offset/y<span class="Delimiter">,</span> <span class="Constant">1</span>:address:number
<span class="Constant">3</span>:address:foo<span class="Special"> <- </span><span class="Normal">new</span> foo:type
*<span class="Constant">3</span>:address:foo<span class="Special"> <- </span>put *<span class="Constant">3</span>:address:foo<span class="Delimiter">,</span> <span class="Constant">1</span>:offset/b<span class="Delimiter">,</span> *<span class="Constant">2</span>:address:curr
<span class="Constant">4</span>:foo<span class="Special"> <- </span>copy *<span class="Constant">3</span>:address:foo
]
<span class="traceContains">+transform: compute address offsets for container foo</span>
<span class="traceContains">+transform: checking container foo, element 1</span>
<span class="traceContains">+transform: address at offset 3</span>
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="Comment"># storing an address in a container updates its refcount</span>
<span class="traceContains">+run: {2: ("address" "curr"), "lookup": ()} <- put {2: ("address" "curr"), "lookup": ()}, {1: "offset", "y": ()}, {1: ("address" "number")}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="Comment"># storing a container in a container updates refcounts of any contained addresses</span>
<span class="traceContains">+run: {3: ("address" "foo"), "lookup": ()} <- put {3: ("address" "foo"), "lookup": ()}, {1: "offset", "b": ()}, {2: ("address" "curr"), "lookup": ()}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 2 -> 3</span>
<span class="Comment"># copying a container containing a container containing an address updates refcount</span>
<span class="traceContains">+run: {4: "foo"} <- copy {3: ("address" "foo"), "lookup": ()}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 3 -> 4</span>
<span class="Delimiter">:(scenario refcounts_copy_exclusive_container_within_container)</span>
container foo [
<span class="Normal">a</span>:number
<span class="Normal">b</span>:bar
]
exclusive-container bar [
<span class="Normal">x</span>:number
<span class="Normal">y</span>:number
<span class="Normal">z</span>:address:number
]
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
<span class="Constant">2</span>:bar<span class="Special"> <- </span>merge <span class="Constant">0</span>/x<span class="Delimiter">,</span> <span class="Constant">34</span>
<span class="Constant">3</span>:foo<span class="Special"> <- </span>merge <span class="Constant">12</span><span class="Delimiter">,</span> <span class="Constant">2</span>:bar
<span class="Constant">5</span>:bar<span class="Special"> <- </span>merge <span class="Constant">1</span>/y<span class="Delimiter">,</span> <span class="Constant">35</span>
<span class="Constant">6</span>:foo<span class="Special"> <- </span>merge <span class="Constant">13</span><span class="Delimiter">,</span> <span class="Constant">5</span>:bar
<span class="Constant">8</span>:bar<span class="Special"> <- </span>merge <span class="Constant">2</span>/z<span class="Delimiter">,</span> <span class="Constant">1</span>:address:number
<span class="Constant">9</span>:foo<span class="Special"> <- </span>merge <span class="Constant">14</span><span class="Delimiter">,</span> <span class="Constant">8</span>:bar
<span class="Constant">11</span>:foo<span class="Special"> <- </span>copy <span class="Constant">9</span>:foo
]
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="Comment"># no change while merging items of other types</span>
<span class="traceContains">+run: {8: "bar"} <- merge {2: "literal", "z": ()}, {1: ("address" "number")}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="traceContains">+run: {9: "foo"} <- merge {14: "literal"}, {8: "bar"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 2 -> 3</span>
<span class="traceContains">+run: {11: "foo"} <- copy {9: "foo"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 3 -> 4</span>
<span class="Delimiter">:(scenario refcounts_copy_container_within_exclusive_container)</span>
exclusive-container foo [
<span class="Normal">a</span>:number
<span class="Normal">b</span>:bar
]
container bar [
<span class="Normal">x</span>:number
<span class="Normal">y</span>:number
<span class="Normal">z</span>:address:number
]
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
<span class="Constant">2</span>:foo<span class="Special"> <- </span>merge <span class="Constant">0</span>/a<span class="Delimiter">,</span> <span class="Constant">34</span>
<span class="Constant">6</span>:foo<span class="Special"> <- </span>merge <span class="Constant">0</span>/a<span class="Delimiter">,</span> <span class="Constant">35</span>
<span class="Constant">10</span>:bar<span class="Special"> <- </span>merge <span class="Constant">2</span>/x<span class="Delimiter">,</span> <span class="Constant">15</span>/y<span class="Delimiter">,</span> <span class="Constant">1</span>:address:number
<span class="Constant">13</span>:foo<span class="Special"> <- </span>merge <span class="Constant">1</span>/b<span class="Delimiter">,</span> <span class="Constant">10</span>:bar
<span class="Constant">17</span>:foo<span class="Special"> <- </span>copy <span class="Constant">13</span>:foo
]
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="Comment"># no change while merging items of other types</span>
<span class="traceContains">+run: {10: "bar"} <- merge {2: "literal", "x": ()}, {15: "literal", "y": ()}, {1: ("address" "number")}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="traceContains">+run: {13: "foo"} <- merge {1: "literal", "b": ()}, {10: "bar"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 2 -> 3</span>
<span class="traceContains">+run: {17: "foo"} <- copy {13: "foo"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 3 -> 4</span>
<span class="Delimiter">:(scenario refcounts_copy_exclusive_container_within_exclusive_container)</span>
exclusive-container foo [
<span class="Normal">a</span>:number
<span class="Normal">b</span>:bar
]
exclusive-container bar [
<span class="Normal">x</span>:number
<span class="Normal">y</span>:address:number
]
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span><span class="Normal">new</span> number:type
<span class="Constant">10</span>:foo<span class="Special"> <- </span>merge <span class="Constant">1</span>/b<span class="Delimiter">,</span> <span class="Constant">1</span>/y<span class="Delimiter">,</span> <span class="Constant">1</span>:address:number
<span class="Constant">20</span>:foo<span class="Special"> <- </span>copy <span class="Constant">10</span>:foo
]
<span class="traceContains">+run: {1: ("address" "number")} <- new {number: "type"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="Comment"># no change while merging items of other types</span>
<span class="traceContains">+run: {10: "foo"} <- merge {1: "literal", "b": ()}, {1: "literal", "y": ()}, {1: ("address" "number")}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="traceContains">+run: {20: "foo"} <- copy {10: "foo"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 2 -> 3</span>
<span class="Delimiter">:(scenario refcounts_copy_array_within_container)</span>
container foo [
<span class="Normal">x</span>:address:array:number
]
def main [
<span class="Constant">1</span>:address:array:number<span class="Special"> <- </span><span class="Normal">new</span> number:type<span class="Delimiter">,</span> <span class="Constant">3</span>
<span class="Constant">2</span>:foo<span class="Special"> <- </span>merge <span class="Constant">1</span>:address:array:number
<span class="Constant">3</span>:address:array:number<span class="Special"> <- </span><span class="Normal">new</span> number:type<span class="Delimiter">,</span> <span class="Constant">5</span>
<span class="Constant">2</span>:foo<span class="Special"> <- </span>merge <span class="Constant">3</span>:address:array:number
]
<span class="traceContains">+run: {1: ("address" "array" "number")} <- new {number: "type"}, {3: "literal"}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 0 -> 1</span>
<span class="traceContains">+run: {2: "foo"} <- merge {1: ("address" "array" "number")}</span>
<span class="traceContains">+mem: incrementing refcount of 1000: 1 -> 2</span>
<span class="traceContains">+run: {2: "foo"} <- merge {3: ("address" "array" "number")}</span>
<span class="traceContains">+mem: decrementing refcount of 1000: 2 -> 1</span>
<span class="Delimiter">:(scenario refcounts_handle_exclusive_containers_with_different_tags)</span>
container foo1 [
<span class="Normal">x</span>:address:number
<span class="Normal">y</span>:number
]
container foo2 [
<span class="Normal">x</span>:number
<span class="Normal">y</span>:address:number
]
exclusive-container bar [
<span class="Normal">a</span>:foo1
<span class="Normal">b</span>:foo2
]
def main [
<span class="Constant">1</span>:address:number<span class="Special"> <- </span>copy <span class="Constant">12000</span>/unsafe <span class="Comment"># pretend allocation</span>
*<span class="Constant">1</span>:address:number<span class="Special"> <- </span>copy <span class="Constant">34</span>
<span class="Constant">2</span>:bar<span class="Special"> <- </span>merge <span class="Constant">0</span>/foo1<span class="Delimiter">,</span> <span class="Constant">1</span>:address:number<span class="Delimiter">,</span> <span class="Constant">97</span>
<span class="Constant">5</span>:address:number<span class="Special"> <- </span>copy <span class="Constant">13000</span>/unsafe <span class="Comment"># pretend allocation</span>
*<span class="Constant">5</span>:address:number<span class="Special"> <- </span>copy <span class="Constant">35</span>
<span class="Constant">6</span>:bar<span class="Special"> <- </span>merge <span class="Constant">1</span>/foo2<span class="Delimiter">,</span> <span class="Constant">98</span><span class="Delimiter">,</span> <span class="Constant">5</span>:address:number
<span class="Constant">2</span>:bar<span class="Special"> <- </span>copy <span class="Constant">6</span>:bar
]
<span class="traceContains">+run: {2: "bar"} <- merge {0: "literal", "foo1": ()}, {1: ("address" "number")}, {97: "literal"}</span>
<span class="traceContains">+mem: incrementing refcount of 12000: 1 -> 2</span>
<span class="traceContains">+run: {6: "bar"} <- merge {1: "literal", "foo2": ()}, {98: "literal"}, {5: ("address" "number")}</span>
<span class="traceContains">+mem: incrementing refcount of 13000: 1 -> 2</span>
<span class="traceContains">+run: {2: "bar"} <- copy {6: "bar"}</span>
<span class="traceContains">+mem: incrementing refcount of 13000: 2 -> 3</span>
<span class="traceContains">+mem: decrementing refcount of 12000: 2 -> 1</span>
<span class="Delimiter">:(code)</span>
<span class="Normal">bool</span> is_mu_container<span class="Delimiter">(</span><span class="Normal">const</span> reagent& r<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Identifier">return</span> is_mu_container<span class="Delimiter">(</span>r<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">bool</span> is_mu_container<span class="Delimiter">(</span><span class="Normal">const</span> type_tree* type<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>!type<span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
<span class="Comment">// End is_mu_container(type) Special-cases</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-></span>value == <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
type_info& info = get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> type<span class="Delimiter">-></span>value<span class="Delimiter">);</span>
<span class="Identifier">return</span> info<span class="Delimiter">.</span>kind == CONTAINER<span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Normal">bool</span> is_mu_exclusive_container<span class="Delimiter">(</span><span class="Normal">const</span> reagent& r<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Identifier">return</span> is_mu_exclusive_container<span class="Delimiter">(</span>r<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
<span class="Normal">bool</span> is_mu_exclusive_container<span class="Delimiter">(</span><span class="Normal">const</span> type_tree* type<span class="Delimiter">)</span> <span class="Delimiter">{</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>!type<span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
<span class="Comment">// End is_mu_exclusive_container(type) Special-cases</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-></span>value == <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
type_info& info = get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> type<span class="Delimiter">-></span>value<span class="Delimiter">);</span>
<span class="Identifier">return</span> info<span class="Delimiter">.</span>kind == EXCLUSIVE_CONTAINER<span class="Delimiter">;</span>
<span class="Delimiter">}</span>
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->