1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-05 16:44:21 +03:00
inform7/docs/BasicInformKit/S-blc.html
2021-08-19 08:59:41 +01:00

1167 lines
185 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>BlockValues Template</title>
<link href="../docs-assets/Breadcrumbs.css" rel="stylesheet" rev="stylesheet" type="text/css">
<meta name="viewport" content="width=device-width initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="../docs-assets/Contents.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Progress.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Navigation.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Fonts.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Base.css" rel="stylesheet" rev="stylesheet" type="text/css">
<script>
MathJax = {
tex: {
inlineMath: '$', '$'], ['\\(', '\\)'
},
svg: {
fontCache: 'global'
}
};
</script>
<script type="text/javascript" id="MathJax-script" async
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js">
</script>
<link href="../docs-assets/Colours.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body class="commentary-font">
<nav role="navigation">
<h1><a href="../index.html">
<img src="../docs-assets/Inform.png" height=72">
</a></h1>
<ul><li><a href="../compiler.html">compiler tools</a></li>
<li><a href="../other.html">other tools</a></li>
<li><a href="../extensions.html">extensions and kits</a></li>
<li><a href="../units.html">unit test tools</a></li>
</ul><h2>Extensions</h2><ul>
<li><a href="../basic_inform/index.html">basic_inform</a></li>
<li><a href="../standard_rules/index.html">standard_rules</a></li>
</ul><h2>Kits</h2><ul>
<li><a href="index.html"><span class="selectedlink">BasicInformKit</span></a></li>
<li><a href="../BasicInformExtrasKit/index.html">BasicInformExtrasKit</a></li>
<li><a href="../CommandParserKit/index.html">CommandParserKit</a></li>
<li><a href="../EnglishLanguageKit/index.html">EnglishLanguageKit</a></li>
<li><a href="../WorldModelKit/index.html">WorldModelKit</a></li>
</ul>
</nav>
<main role="main">
<!--Weave of 'BlockValues Template' generated by Inweb-->
<div class="breadcrumbs">
<ul class="crumbs"><li><a href="../index.html">Home</a></li><li><a href="../extensions.html">Kits</a></li><li><a href="index.html">BasicInformKit</a></li><li><b>BlockValues Template</b></li></ul></div>
<p class="purpose">Routines for copying, comparing, creating and destroying block values, and for reading and writing them as if they were arrays.</p>
<ul class="toc"><li><a href="S-blc.html#SP1">&#167;1. Overview</a></li><li><a href="S-blc.html#SP2">&#167;2. Short Block Format</a></li><li><a href="S-blc.html#SP3">&#167;3. Long Block Access</a></li><li><a href="S-blc.html#SP4">&#167;4. Weak Kind</a></li><li><a href="S-blc.html#SP5">&#167;5. Reference counting</a></li><li><a href="S-blc.html#SP6">&#167;6. Changing Reference Counts</a></li><li><a href="S-blc.html#SP7">&#167;7. Long Block Capacity</a></li><li><a href="S-blc.html#SP8">&#167;8. Long Block Array Access</a></li><li><a href="S-blc.html#SP9">&#167;9. First Zero Entry</a></li><li><a href="S-blc.html#SP10">&#167;10. Mass Copy Entries</a></li><li><a href="S-blc.html#SP11">&#167;11. Mass Copy From Array</a></li><li><a href="S-blc.html#SP12">&#167;12. KOVS Routines</a></li><li><a href="S-blc.html#SP13">&#167;13. Creation</a></li><li><a href="S-blc.html#SP14">&#167;14. Errors</a></li><li><a href="S-blc.html#SP15">&#167;15. Short Block Allocation</a></li><li><a href="S-blc.html#SP16">&#167;16. Block Values On Stack</a></li><li><a href="S-blc.html#SP17">&#167;17. Freeing</a></li><li><a href="S-blc.html#SP18">&#167;18. Quick Copy</a></li><li><a href="S-blc.html#SP19">&#167;19. Short Block Copy</a></li><li><a href="S-blc.html#SP20">&#167;20. Slow Copy</a></li><li><a href="S-blc.html#SP21">&#167;21. Copy</a></li><li><a href="S-blc.html#SP22">&#167;22. Destruction</a></li><li><a href="S-blc.html#SP23">&#167;23. Recycling</a></li><li><a href="S-blc.html#SP24">&#167;24. Mutability</a></li><li><a href="S-blc.html#SP25">&#167;25. Casting</a></li><li><a href="S-blc.html#SP26">&#167;26. Comparison</a></li><li><a href="S-blc.html#SP27">&#167;27. Hashing</a></li><li><a href="S-blc.html#SP28">&#167;28. Serialisation</a></li><li><a href="S-blc.html#SP29">&#167;29. Debugging</a></li><li><a href="S-blc.html#SP30">&#167;30. Printing Memory Addresses</a></li><li><a href="S-blc.html#SP31">&#167;31. Hexadecimal Printing</a></li></ul><hr class="tocbar">
<p class="commentary firstcommentary"><a id="SP1" class="paragraph-anchor"></a><b>&#167;1. Overview. </b>Each I7 value is represented at run-time by an I6 word: on the Z-machine,
a 16-bit number, and on Glulx, a 32-bit number. The correspondence between
these numbers and the original values depends on the kind of value: "number"
comes out as a signed twos-complement number, but "time" as an integer
number of minutes since midnight, "rulebook" as the index of the rulebook
in order of creation, and so on.
</p>
<p class="commentary">Even if a 32-bit number is available, this is not enough to represent the
full range of values we might want: consider all the possible hundred-word
essays of text, for instance. So for a whole range of kinds &mdash; "text",
"list of K", "stored action" and so on &mdash; the I6 value at run-time is only
a pointer to what is called a "short block". This is typically only a few
words long, and often only a single word: hence the term "short". It has
no header or other overhead, and its contents depend on the kind of value.
</p>
<p class="commentary">If we know that a given kind of value can be stored in, say, exactly 128
bits, then it's possible simply to store the whole thing in the short block.
More often, though, the data needs to be flexible in size, or needs to
be large. In that case, the short block will include (and sometimes, will
consist only of) a pointer to data stored in a "long block". Unlike the
short block, the long block is a chunk of memory stored using the Flex
system, and thus is genuinely a "block" in the sense of the Flex
documentation.
</p>
<p class="commentary">It's possible to have several different short blocks each pointing to the
same long block of underlying data: for example, the result of the I7 code
</p>
<p class="commentary"> let L1 be { 2, 3, 5, 7, 11 };
let L2 be L1;
</p>
<p class="commentary">is to create L1 and L2 as pointers to two different short blocks, but the
two SBs each point to the same long block, which contains the data for the
list 2, 3, 5, 7, 11. Note that this makes it very fast to copy L1's contents
into L2, because only L2's short block needs to change.
</p>
<p class="commentary">The rules for customers who want to deal with values like this are much like
the rules for allocating memory with Flex. Calling <span class="extract"><span class="extract-syntax">BlkValueCreate</span></span>
creates a new value, but this must always, and only once, later be disposed
of using <span class="extract"><span class="extract-syntax">BlkValueFree</span></span>.
</p>
<p class="commentary">So if the short blocks of L1 and L2 both point to the same long block of
actual data, what happens when only one of them is freed? The answer is that
every long block has a reference count attached, which counts the number of
short blocks pointing to it. In our example, this count is 2. If list L1
is freed, the long block's reference count is decremented to 1, but it
remains in memory, and only L1's short block is given up; when list L2 is
subsequently freed, both its short block and the now unwanted long block
are given up.
</p>
<p class="commentary">The harder case to handle is what happens when L1 and L2 share a long
block containing 2, 3, 5, 7, 11, but when the source text asks to "add 13
to L1". If we simply changed the long block, that would affect L2 as well.
So we must first make L1 "mutable". This means copying the long block
to make a new unique copy with reference count 1; assigning that to L1
in place of the original; and decrementing the reference count of the
original from 2 to 1. L1 and L2 now point to two different long blocks,
so it's safe to modify L1's.
</p>
<p class="commentary">Subtle and beautiful bugs can occur as a result of making a value mutable
at the wrong moment. Beware in particular of reading data out of a long
block, then writing it back again, because the act of writing may force
the value owning the long block to become mutable; this will make a new
copy of the data; but you will be left holding the old copy. Since these
are functionally identical, you may not even notice, but calamities will
occur later because the version of the value you're holding really
belongs to somebody else and may be freed at any point.
</p>
<p class="commentary">Finally, note that the I7 compiler also creates block values representing
constants. For example, the source text
</p>
<p class="commentary"> let L1 be { 2, 3, 5, 7, 11 };
</p>
<p class="commentary">causes a block value representing this list to be stored in memory. The
long block for a constant needs to be immortal, since this memory must
never be freed: it's therefore given a reference count of "infinity".
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">RC_INFINITY</span><span class="plain-syntax"> = </span><span class="identifier-syntax">MAX_POSITIVE_NUMBER</span><span class="plain-syntax">;</span>
</pre>
<p class="commentary firstcommentary"><a id="SP2" class="paragraph-anchor"></a><b>&#167;2. Short Block Format. </b>A short block begins with a word which is usually, but not always, a pointer
to the long block. There are three possibilities:
</p>
<ul class="items"><li>(a) 0 means the short block has length 1 and the long block begins at the
very next word in memory. This makes it more convenient for I7 to compile
BV constants, but isn't otherwise used.
</li><li>(b) 1 to 255 means the short block has length 2 or more. The value is expected
to be a bitmap in bits 4 to 8 together with a nonzero ID in bits 1 to 4.
If the <span class="extract"><span class="extract-syntax">BLK_BVBITMAP_LONGBLOCK</span></span> bit is set, a pointer to the long block
is stored in the second word of the short block.
</li><li>(c) Otherwise the short block has length 1 and contains only a pointer to
the long block.
</li></ul>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_BVBITMAP</span><span class="plain-syntax"> = </span><span class="constant-syntax">$ff</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_BVBITMAP_LONGBLOCK</span><span class="plain-syntax"> = </span><span class="constant-syntax">$10</span><span class="plain-syntax">; </span><span class="comment-syntax">Word 1 of SB is pointer to LB</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_BVBITMAP_TEXT</span><span class="plain-syntax"> = </span><span class="constant-syntax">$20</span><span class="plain-syntax">; </span><span class="comment-syntax">BV holds a TEXT_TY value</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_BVBITMAP_CONSTANT</span><span class="plain-syntax"> = </span><span class="constant-syntax">$40</span><span class="plain-syntax">; </span><span class="comment-syntax">BV holds a TEXT_TY value</span>
<span class="plain-syntax">#</span><span class="identifier-syntax">IFTRUE</span><span class="plain-syntax"> </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax"> == </span><span class="constant-syntax">4</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_BVBITMAP_LONGBLOCKMASK</span><span class="plain-syntax"> = </span><span class="constant-syntax">$ffffff10</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_BVBITMAP_TEXTMASK</span><span class="plain-syntax"> = </span><span class="constant-syntax">$ffffff20</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_BVBITMAP_CONSTANTMASK</span><span class="plain-syntax"> = </span><span class="constant-syntax">$ffffff40</span><span class="plain-syntax">;</span>
<span class="plain-syntax">#</span><span class="identifier-syntax">IFNOT</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_BVBITMAP_LONGBLOCKMASK</span><span class="plain-syntax"> = </span><span class="constant-syntax">$ff10</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_BVBITMAP_TEXTMASK</span><span class="plain-syntax"> = </span><span class="constant-syntax">$ff20</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_BVBITMAP_CONSTANTMASK</span><span class="plain-syntax"> = </span><span class="constant-syntax">$ff40</span><span class="plain-syntax">;</span>
<span class="plain-syntax">#</span><span class="identifier-syntax">ENDIF</span><span class="plain-syntax">;</span>
</pre>
<p class="commentary firstcommentary"><a id="SP3" class="paragraph-anchor"></a><b>&#167;3. Long Block Access. </b>Illustrating this:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">o</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bv</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">o</span><span class="plain-syntax"> = </span><span class="identifier-syntax">bv</span><span class="plain-syntax">--&gt;0;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">o</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> + </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">o</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_BVBITMAP</span><span class="plain-syntax"> == </span><span class="identifier-syntax">o</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">o</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_BVBITMAP_LONGBLOCK</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax">--&gt;1;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">o</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP4" class="paragraph-anchor"></a><b>&#167;4. Weak Kind. </b>This returns the weak kind ID of a block value. Most of the time this
information is stored in the long block, but that poses a problem for BVs
which have no long block: we must use the bitmap instead.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueWeakKind</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">o</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bv</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">o</span><span class="plain-syntax"> = </span><span class="identifier-syntax">bv</span><span class="plain-syntax">--&gt;0;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">o</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax">--&gt;(</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax">+1);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">o</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_BVBITMAP</span><span class="plain-syntax"> == </span><span class="identifier-syntax">o</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">o</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_BVBITMAP_TEXT</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">TEXT_TY</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">o</span><span class="plain-syntax"> = </span><span class="identifier-syntax">bv</span><span class="plain-syntax">--&gt;1;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">o</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">NIL_TY</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP5" class="paragraph-anchor"></a><b>&#167;5. Reference counting. </b>Reference counts lie in a word at a fixed offset from the start of the
long block: doctrinally, any block value with no long block at all (such
as a piece of packed text) has reference count infinity.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueGetRefCountPrimitive</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">RC_INFINITY</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP6" class="paragraph-anchor"></a><b>&#167;6. Changing Reference Counts. </b>When incrementing, infinity's the limit; when decrementing, it never
reduces. Note that the decrement function returns the new reference count,
but the increment function returns nothing. It's only when reference counts
go downwards that we have to worry about whether something happens.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueIncRefCountPrimitive</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">refc</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">refc</span><span class="plain-syntax"> = </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">refc</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">RC_INFINITY</span><span class="plain-syntax">) </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">refc</span><span class="plain-syntax"> + </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueDecRefCountPrimitive</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">refc</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">refc</span><span class="plain-syntax"> = </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">refc</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">RC_INFINITY</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">refc</span><span class="plain-syntax">--;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">refc</span><span class="plain-syntax"> &lt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">BlkValueError</span><span class="plain-syntax">(</span><span class="string-syntax">"reference count negative"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">refc</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">refc</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">RC_INFINITY</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP7" class="paragraph-anchor"></a><b>&#167;7. Long Block Capacity. </b>As we've seen, the long block has some metadata in a header, but otherwise
it's organised as if it were an array, with entries 8, 16 or 32 bits wide.
At any given time, the "capacity" of the LB is the number of entries in
this array: that doesn't mean that the BV is using them all at any given moment.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueLBCapacity</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">array_size_in_bytes</span><span class="plain-syntax"> </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">array_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexTotalSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> = </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_16_BIT</span><span class="plain-syntax">) </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="constant-syntax">2</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_WORD</span><span class="plain-syntax">) </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">array_size_in_bytes</span><span class="plain-syntax"> / </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueSetLBCapacity</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">new_capacity</span><span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bv</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkMakeMutable</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> = </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_16_BIT</span><span class="plain-syntax">) </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="constant-syntax">2</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_WORD</span><span class="plain-syntax">) </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">FlexResize</span><span class="plain-syntax">(</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">, </span><span class="identifier-syntax">new_capacity</span><span class="plain-syntax">*</span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">rtrue</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP8" class="paragraph-anchor"></a><b>&#167;8. Long Block Array Access. </b>Though the customer thinks he's getting an array, in fact the storage in
the LB is not necessarily contiguous, since it can span multiple Flex blocks.
We abstract that with two routines to read and write entries.
</p>
<p class="commentary"><span class="extract"><span class="extract-syntax">BlkValueRead</span></span> takes two compulsory arguments and one optional one. Thus:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueRead</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">n</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">reads the nth entry in the long block for <span class="extract"><span class="extract-syntax">bv</span></span>, whereas
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueRead</span><span class="plain-syntax">(</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">, </span><span class="identifier-syntax">n</span><span class="plain-syntax">, </span><span class="reserved-syntax">true</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">read it from the given long block directly. <span class="extract"><span class="extract-syntax">BlkValueWrite</span></span> is similar.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueRead</span><span class="plain-syntax"> </span><span class="identifier-syntax">from</span><span class="plain-syntax"> </span><span class="identifier-syntax">pos</span><span class="plain-syntax"> </span><span class="identifier-syntax">do_not_indirect</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">chunk_size_in_bytes</span><span class="plain-syntax"> </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> </span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">from</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">do_not_indirect</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="identifier-syntax">from</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> = </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_16_BIT</span><span class="plain-syntax">) </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="constant-syntax">2</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_WORD</span><span class="plain-syntax">) </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax"> = </span><span class="identifier-syntax">pos</span><span class="plain-syntax">*</span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (: </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">: </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">=</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">chunk_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">) - </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax"> &gt;= </span><span class="constant-syntax">0</span><span class="plain-syntax">) &amp;&amp; (</span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">chunk_size_in_bytes</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> + </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax"> + </span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">switch</span><span class="plain-syntax">(</span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="constant-syntax">1</span><span class="plain-syntax">: </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">-&gt;0;</span>
<span class="plain-syntax"> </span><span class="constant-syntax">2</span><span class="plain-syntax">: #</span><span class="identifier-syntax">Iftrue</span><span class="plain-syntax"> (</span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax"> == </span><span class="constant-syntax">2</span><span class="plain-syntax">); </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">--&gt;0;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifnot</span><span class="plain-syntax">; </span><span class="reserved-syntax">return</span><span class="plain-syntax"> (</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">-&gt;0)*256 + (</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">-&gt;1);</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="constant-syntax">4</span><span class="plain-syntax">: </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">--&gt;0;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax"> = </span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax"> - </span><span class="identifier-syntax">chunk_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print_ret</span><span class="plain-syntax"> </span><span class="string-syntax">"*** BlkValueRead: reading from index out of range: "</span><span class="plain-syntax">, </span><span class="identifier-syntax">pos</span><span class="plain-syntax">, </span><span class="string-syntax">" in "</span><span class="plain-syntax">, </span><span class="identifier-syntax">from</span><span class="plain-syntax">, </span><span class="string-syntax">" ***"</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueWrite</span><span class="plain-syntax"> </span><span class="reserved-syntax">to</span><span class="plain-syntax"> </span><span class="identifier-syntax">pos</span><span class="plain-syntax"> </span><span class="identifier-syntax">val</span><span class="plain-syntax"> </span><span class="identifier-syntax">do_not_indirect</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">chunk_size_in_bytes</span><span class="plain-syntax"> </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> </span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="reserved-syntax">to</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">do_not_indirect</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="reserved-syntax">to</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkMakeMutable</span><span class="plain-syntax">(</span><span class="reserved-syntax">to</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="reserved-syntax">to</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> = </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_16_BIT</span><span class="plain-syntax">) </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="constant-syntax">2</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_WORD</span><span class="plain-syntax">) </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax"> = </span><span class="identifier-syntax">pos</span><span class="plain-syntax">*</span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (:</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">:</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">=</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">chunk_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">) - </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax"> &gt;= </span><span class="constant-syntax">0</span><span class="plain-syntax">) &amp;&amp; (</span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">chunk_size_in_bytes</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> + </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax"> + </span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">switch</span><span class="plain-syntax">(</span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="constant-syntax">1</span><span class="plain-syntax">: </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">-&gt;0 = </span><span class="identifier-syntax">val</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="constant-syntax">2</span><span class="plain-syntax">: #</span><span class="identifier-syntax">Iftrue</span><span class="plain-syntax"> (</span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax"> == </span><span class="constant-syntax">2</span><span class="plain-syntax">); </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">--&gt;0 = </span><span class="identifier-syntax">val</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifnot</span><span class="plain-syntax">; </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">-&gt;0 = (</span><span class="identifier-syntax">val</span><span class="plain-syntax">/256)%256; </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">-&gt;1 = </span><span class="identifier-syntax">val</span><span class="plain-syntax">%256;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="constant-syntax">4</span><span class="plain-syntax">: </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">--&gt;0 = </span><span class="identifier-syntax">val</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax"> = </span><span class="identifier-syntax">seek_byte_position</span><span class="plain-syntax"> - </span><span class="identifier-syntax">chunk_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print_ret</span><span class="plain-syntax"> </span><span class="string-syntax">"*** BlkValueWrite: writing to index out of range: "</span><span class="plain-syntax">, </span><span class="identifier-syntax">pos</span><span class="plain-syntax">, </span><span class="string-syntax">" in "</span><span class="plain-syntax">, </span><span class="reserved-syntax">to</span><span class="plain-syntax">, </span><span class="string-syntax">" ***"</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP9" class="paragraph-anchor"></a><b>&#167;9. First Zero Entry. </b>This returns the entry index of the first zero entry in the long block's array,
or -1 if it has no zeros.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueSeekZeroEntry</span><span class="plain-syntax"> </span><span class="identifier-syntax">from</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">chunk_size_in_bytes</span><span class="plain-syntax"> </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> </span><span class="identifier-syntax">entry_size_in_bytes</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">byte_position</span><span class="plain-syntax"> </span><span class="identifier-syntax">addr</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">from</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> -1;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="identifier-syntax">from</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> = </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_16_BIT</span><span class="plain-syntax">) </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="constant-syntax">2</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_WORD</span><span class="plain-syntax">) </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">byte_position</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (: </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">: </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">=</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">chunk_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">) - </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> + </span><span class="identifier-syntax">header_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax"> + </span><span class="identifier-syntax">chunk_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">switch</span><span class="plain-syntax">(</span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="constant-syntax">1</span><span class="plain-syntax">:</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax">: </span><span class="identifier-syntax">addr</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax">: </span><span class="identifier-syntax">addr</span><span class="plain-syntax">++)</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">addr</span><span class="plain-syntax">-&gt;0 == </span><span class="constant-syntax">0</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">byte_position</span><span class="plain-syntax"> + </span><span class="identifier-syntax">addr</span><span class="plain-syntax"> - </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="constant-syntax">2</span><span class="plain-syntax">:</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">iftrue</span><span class="plain-syntax"> </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax"> == </span><span class="constant-syntax">2</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax">: </span><span class="identifier-syntax">addr</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax">: </span><span class="identifier-syntax">addr</span><span class="plain-syntax">=</span><span class="identifier-syntax">addr</span><span class="plain-syntax">+2)</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">addr</span><span class="plain-syntax">--&gt;0 == </span><span class="constant-syntax">0</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> (</span><span class="identifier-syntax">byte_position</span><span class="plain-syntax"> + </span><span class="identifier-syntax">addr</span><span class="plain-syntax"> - </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax">)/2;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifnot</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax">: </span><span class="identifier-syntax">addr</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax">: </span><span class="identifier-syntax">addr</span><span class="plain-syntax">=</span><span class="identifier-syntax">addr</span><span class="plain-syntax">+2)</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">addr</span><span class="plain-syntax">-&gt;0 == </span><span class="constant-syntax">0</span><span class="plain-syntax">) &amp;&amp; (</span><span class="identifier-syntax">addr</span><span class="plain-syntax">-&gt;1 == </span><span class="constant-syntax">0</span><span class="plain-syntax">))</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> (</span><span class="identifier-syntax">byte_position</span><span class="plain-syntax"> + </span><span class="identifier-syntax">addr</span><span class="plain-syntax"> - </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax">)/2;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="constant-syntax">4</span><span class="plain-syntax">:</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax">: </span><span class="identifier-syntax">addr</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax">: </span><span class="identifier-syntax">addr</span><span class="plain-syntax">=</span><span class="identifier-syntax">addr</span><span class="plain-syntax">+4)</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">addr</span><span class="plain-syntax">--&gt;0 == </span><span class="constant-syntax">0</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> (</span><span class="identifier-syntax">byte_position</span><span class="plain-syntax"> + </span><span class="identifier-syntax">addr</span><span class="plain-syntax"> - </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax">)/4;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">byte_position</span><span class="plain-syntax"> = </span><span class="identifier-syntax">byte_position</span><span class="plain-syntax"> + </span><span class="identifier-syntax">chunk_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> -1;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP10" class="paragraph-anchor"></a><b>&#167;10. Mass Copy Entries. </b>This copies a given number of entries from one BV's long block to another;
they must both be of the same word size but can differ in header size.
Functionally, it's identical to
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">n</span><span class="plain-syntax">=0: </span><span class="identifier-syntax">n</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax">: </span><span class="identifier-syntax">n</span><span class="plain-syntax">++)</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueWrite</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">n</span><span class="plain-syntax">, </span><span class="identifier-syntax">BlkValueRead</span><span class="plain-syntax">(</span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">n</span><span class="plain-syntax">));</span>
</pre>
<p class="commentary">but it's much, much faster, and runs in a reasonably small number of cycles
given what it needs to do.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueMassCopyEntries</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">no_entries_to_copy</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">from_long_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_bytes_left</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_header_size_in_bytes</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_bytes_left</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_header_size_in_bytes</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">bytes_to_copy</span><span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> </span><span class="identifier-syntax">min</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkMakeMutable</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">from_long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from_long_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_16_BIT</span><span class="plain-syntax">) </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="constant-syntax">2</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_WORD</span><span class="plain-syntax">) </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; (</span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax"> + </span><span class="identifier-syntax">BLK_FLAG_TRUNCMULT</span><span class="plain-syntax">)) &amp;&amp;</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">BlkValueSetLBCapacity</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax">) == </span><span class="reserved-syntax">false</span><span class="plain-syntax">))</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueError</span><span class="plain-syntax">(</span><span class="string-syntax">"copy resizing failed"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) </span><span class="identifier-syntax">from_header_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_header_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) </span><span class="identifier-syntax">to_header_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_header_size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from_long_block</span><span class="plain-syntax"> + </span><span class="identifier-syntax">from_header_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">from_bytes_left</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">from_long_block</span><span class="plain-syntax">) - </span><span class="identifier-syntax">from_header_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax"> + </span><span class="identifier-syntax">to_header_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_bytes_left</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax">) - </span><span class="identifier-syntax">to_header_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">bytes_to_copy</span><span class="plain-syntax"> = </span><span class="identifier-syntax">entry_size_in_bytes</span><span class="plain-syntax">*</span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="reserved-syntax">true</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">from_bytes_left</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">from_long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from_long_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">from_long_block</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">BlkValueError</span><span class="plain-syntax">(</span><span class="string-syntax">"copy destination exhausted"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from_long_block</span><span class="plain-syntax"> + </span><span class="identifier-syntax">from_header_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">from_bytes_left</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">from_long_block</span><span class="plain-syntax">) - </span><span class="identifier-syntax">from_header_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">to_bytes_left</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">BlkValueError</span><span class="plain-syntax">(</span><span class="string-syntax">"copy source exhausted"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax"> + </span><span class="identifier-syntax">to_header_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_bytes_left</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax">) - </span><span class="identifier-syntax">to_header_size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">min</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from_bytes_left</span><span class="plain-syntax">; </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">to_bytes_left</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">min</span><span class="plain-syntax">) </span><span class="identifier-syntax">min</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to_bytes_left</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bytes_to_copy</span><span class="plain-syntax"> &lt;= </span><span class="identifier-syntax">min</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Memcpy</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_addr</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax">, </span><span class="identifier-syntax">bytes_to_copy</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Memcpy</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_addr</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax">, </span><span class="identifier-syntax">min</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">bytes_to_copy</span><span class="plain-syntax"> = </span><span class="identifier-syntax">bytes_to_copy</span><span class="plain-syntax"> - </span><span class="identifier-syntax">min</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from_addr</span><span class="plain-syntax"> + </span><span class="identifier-syntax">min</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">from_bytes_left</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from_bytes_left</span><span class="plain-syntax"> - </span><span class="identifier-syntax">min</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax"> + </span><span class="identifier-syntax">min</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_bytes_left</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to_bytes_left</span><span class="plain-syntax"> - </span><span class="identifier-syntax">min</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP11" class="paragraph-anchor"></a><b>&#167;11. Mass Copy From Array. </b>The following is helpful when reading an array of characters into a text:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueMassCopyFromArray</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_array</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_entry_size</span><span class="plain-syntax"> </span><span class="identifier-syntax">no_entries_to_copy</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_entries_left</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_header_size</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_entry_size</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkMakeMutable</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_entry_size</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_16_BIT</span><span class="plain-syntax">) </span><span class="identifier-syntax">to_entry_size</span><span class="plain-syntax"> = </span><span class="constant-syntax">2</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_WORD</span><span class="plain-syntax">) </span><span class="identifier-syntax">to_entry_size</span><span class="plain-syntax"> = </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; (</span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax"> + </span><span class="identifier-syntax">BLK_FLAG_TRUNCMULT</span><span class="plain-syntax">)) &amp;&amp;</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">BlkValueSetLBCapacity</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax">) == </span><span class="reserved-syntax">false</span><span class="plain-syntax">))</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueError</span><span class="plain-syntax">(</span><span class="string-syntax">"copy resizing failed"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) </span><span class="identifier-syntax">to_header_size</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_header_size</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax"> + </span><span class="identifier-syntax">to_header_size</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_entries_left</span><span class="plain-syntax"> = (</span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax">) - </span><span class="identifier-syntax">to_header_size</span><span class="plain-syntax">)/</span><span class="identifier-syntax">to_entry_size</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax"> &gt; </span><span class="identifier-syntax">to_entries_left</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Arrcpy</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_addr</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_entry_size</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_array</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_entry_size</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_entries_left</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax"> = </span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax"> - </span><span class="identifier-syntax">to_entries_left</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">from_array</span><span class="plain-syntax"> = </span><span class="identifier-syntax">from_array</span><span class="plain-syntax"> + </span><span class="identifier-syntax">to_entries_left</span><span class="plain-syntax">*</span><span class="identifier-syntax">from_entry_size</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">BlkValueError</span><span class="plain-syntax">(</span><span class="string-syntax">"copy source exhausted"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_addr</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax"> + </span><span class="identifier-syntax">to_header_size</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_entries_left</span><span class="plain-syntax"> = (</span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_long_block</span><span class="plain-syntax">) - </span><span class="identifier-syntax">to_header_size</span><span class="plain-syntax">)/</span><span class="identifier-syntax">to_entry_size</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax"> &gt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Arrcpy</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_addr</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_entry_size</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_array</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_entry_size</span><span class="plain-syntax">, </span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP12" class="paragraph-anchor"></a><b>&#167;12. KOVS Routines. </b>Different kinds of value use different data formats for both their short and
long blocks, so it follows that each kind needs its own routines to carry out
the fundamental operations of creating, destroying, copying and comparing.
This is organised at run-time by giving each kind of block value a "KOVS", a
"kind of value support" routine. These are named systematically by suffixing
<span class="extract"><span class="extract-syntax">_Support</span></span>: that is, the support function for <span class="extract"><span class="extract-syntax">TEXT_TY</span></span> is called
<span class="extract"><span class="extract-syntax">TEXT_TY_Support</span></span> and so on.
</p>
<p class="commentary">I7 automatically compiles a function called <span class="extract"><span class="extract-syntax">KOVSupportFunction</span></span> which returns
the KOVS for a given kind. Note that this depends only on the weak kind, not
the strong one: so "list of numbers" and "list of texts", for example, share a
common KOVS which handles all list support.
</p>
<p class="commentary">The support function can be called with any of the following task constants
as its first argument: it then has a further one to three arguments
depending on the task in hand.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">CAST_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">2</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">DESTROY_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">3</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">MAKEMUTABLE_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">4</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">COPYKIND_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">5</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">EXTENT_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">6</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">COPYQUICK_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">7</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">COPYSB_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">8</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">KINDDATA_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">9</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">COPY_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">10</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">COMPARE_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">11</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">READ_FILE_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">12</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">WRITE_FILE_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">13</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">HASH_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">14</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">DEBUG_KOVS</span><span class="plain-syntax"> = </span><span class="constant-syntax">15</span><span class="plain-syntax">;</span>
<span class="comment-syntax">Constant BLKVALUE_TRACE; ! Uncomment this to expose masses of tracery</span>
</pre>
<p class="commentary firstcommentary"><a id="SP13" class="paragraph-anchor"></a><b>&#167;13. Creation. </b>To create a block value, call:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueCreate</span><span class="plain-syntax">(</span><span class="identifier-syntax">kind</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">where <span class="extract"><span class="extract-syntax">K</span></span> is its (strong) kind ID. Optionally, call:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueCreate</span><span class="plain-syntax">(</span><span class="identifier-syntax">K</span><span class="plain-syntax">, </span><span class="identifier-syntax">short_block</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">to mandate that the short block needs to be located at the given address
outside the heap: but don't do this unless you can guarantee that space of the
necessary length will be available there for as long as the lifetime of
the value; and please note, it really does matter that this address lies
outside the heap, for reasons to be seen below.
</p>
<p class="commentary">These work by delegating to:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">CREATE_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">strong_kind</span><span class="plain-syntax">, </span><span class="identifier-syntax">short_block</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">which returns the address of the short block for the new value.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueCreate</span><span class="plain-syntax"> </span><span class="identifier-syntax">strong_kind</span><span class="plain-syntax"> </span><span class="identifier-syntax">short_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> = </span><span class="identifier-syntax">KOVSupportFunction</span><span class="plain-syntax">(</span><span class="identifier-syntax">strong_kind</span><span class="plain-syntax">, </span><span class="string-syntax">"impossible allocation"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">short_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">CREATE_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">strong_kind</span><span class="plain-syntax">, </span><span class="identifier-syntax">short_block</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifdef</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLKVALUE_TRACE</span><span class="plain-syntax">; </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Created: "</span><span class="plain-syntax">, (</span><span class="identifier-syntax">BlkValueDebug</span><span class="plain-syntax">) </span><span class="identifier-syntax">short_block</span><span class="plain-syntax">, </span><span class="string-syntax">"^"</span><span class="plain-syntax">; #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="comment-syntax">The new value is represented in I6 as the pointer to its short block:</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">short_block</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP14" class="paragraph-anchor"></a><b>&#167;14. Errors. </b>No I7 source text should ever result in a call to this, unless it does
unpleasant things at the I6 level.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueError</span><span class="plain-syntax"> </span><span class="identifier-syntax">reason</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"*** Value handling failed: "</span><span class="plain-syntax">, (</span><span class="reserved-syntax">string</span><span class="plain-syntax">) </span><span class="identifier-syntax">reason</span><span class="plain-syntax">, </span><span class="string-syntax">" ***^"</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">RunTimeProblem</span><span class="plain-syntax">(</span><span class="identifier-syntax">RTP_HEAPERROR</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> @</span><span class="reserved-syntax">quit</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP15" class="paragraph-anchor"></a><b>&#167;15. Short Block Allocation. </b>The first thing a KOVS does when creating a value is to initialise its
short block. The following routines provide for a one-word and a two-word
short block respectively. The KOVS should pass these routines the same
<span class="extract"><span class="extract-syntax">short_block</span></span> value it was called with. As can be seen, if this is zero
then we need to conjure up memory from somewhere: we do this using Flex.
That incurs a fair amount of overhead in time and memory, though. The
SB data is stored in the data portion of the Flex block, which is why
we get its address from by adding the data offset to the block address.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueCreateSB1</span><span class="plain-syntax"> </span><span class="identifier-syntax">short_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">val</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">short_block</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">short_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexAllocate</span><span class="plain-syntax">(</span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">, </span><span class="constant-syntax">0</span><span class="plain-syntax">, </span><span class="identifier-syntax">BLK_FLAG_WORD</span><span class="plain-syntax">) + </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">short_block</span><span class="plain-syntax">--&gt;0 = </span><span class="identifier-syntax">val</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">short_block</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueCreateSB2</span><span class="plain-syntax"> </span><span class="identifier-syntax">short_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">val1</span><span class="plain-syntax"> </span><span class="identifier-syntax">val2</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">short_block</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">short_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexAllocate</span><span class="plain-syntax">(2*</span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">, </span><span class="constant-syntax">0</span><span class="plain-syntax">, </span><span class="identifier-syntax">BLK_FLAG_WORD</span><span class="plain-syntax">) + </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">short_block</span><span class="plain-syntax">--&gt;0 = </span><span class="identifier-syntax">val1</span><span class="plain-syntax">; </span><span class="identifier-syntax">short_block</span><span class="plain-syntax">--&gt;1 = </span><span class="identifier-syntax">val2</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">short_block</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP16" class="paragraph-anchor"></a><b>&#167;16. Block Values On Stack. </b>As noted above, it's wasteful to keep allocating short blocks using Flex.
For the short blocks of block values in local variables, we store them on
a stack instead. This is a top-down stack, so the current stack frame
starts out just after the end of the stack area in memory (and therefore
points to an empty stack frame); it drops down as new frames are created.
</p>
<p class="commentary"><span class="extract"><span class="extract-syntax">BlkValueCreateOnStack</span></span> acts exactly like <span class="extract"><span class="extract-syntax">BlkValueCreate</span></span>, but stores
the short block at the given word offset in the current stack frame.
(I7 compiles calls to these routines when compiling code to manage
local variables.)
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">StackFramingInitialise</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">I7SFRAME</span><span class="plain-syntax"> = </span><span class="identifier-syntax">blockv_stack</span><span class="plain-syntax"> + </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">*</span><span class="identifier-syntax">BLOCKV_STACK_SIZE</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">StackFrameCreate</span><span class="plain-syntax"> </span><span class="identifier-syntax">size</span><span class="plain-syntax"> </span><span class="identifier-syntax">new</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">new</span><span class="plain-syntax"> = </span><span class="identifier-syntax">I7SFRAME</span><span class="plain-syntax"> - </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">*</span><span class="identifier-syntax">size</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">new</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">blockv_stack</span><span class="plain-syntax">) { </span><span class="identifier-syntax">RunTimeProblem</span><span class="plain-syntax">(</span><span class="identifier-syntax">RTP_HEAPERROR</span><span class="plain-syntax">); @</span><span class="reserved-syntax">quit</span><span class="plain-syntax">; }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">I7SFRAME</span><span class="plain-syntax"> = </span><span class="identifier-syntax">new</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueCreateOnStack</span><span class="plain-syntax"> </span><span class="identifier-syntax">offset</span><span class="plain-syntax"> </span><span class="identifier-syntax">strong_kind</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueCreate</span><span class="plain-syntax">(</span><span class="identifier-syntax">strong_kind</span><span class="plain-syntax">, </span><span class="identifier-syntax">I7SFRAME</span><span class="plain-syntax"> + </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">*</span><span class="identifier-syntax">offset</span><span class="plain-syntax">);</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueFreeOnStack</span><span class="plain-syntax"> </span><span class="identifier-syntax">offset</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueFree</span><span class="plain-syntax">(</span><span class="identifier-syntax">I7SFRAME</span><span class="plain-syntax"> + </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">*</span><span class="identifier-syntax">offset</span><span class="plain-syntax">);</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP17" class="paragraph-anchor"></a><b>&#167;17. Freeing. </b>As noted above, every value returned by <span class="extract"><span class="extract-syntax">BlkValueCreate</span></span> must later be
freed by calling the following routine exactly once:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueFree</span><span class="plain-syntax">(</span><span class="identifier-syntax">value</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">In particular, if a block value is stored in any I6 location which is about
to be overwritten with a new value, it's essential to call this in order
properly to dispose of the old value.
</p>
<p class="commentary">As noted above, short blocks are sometimes created within Flex blocks on
the heap, using <span class="extract"><span class="extract-syntax">FlexAllocate</span></span>; and if this is one of those, we need to free
the relevant Flex block.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueFree</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> </span><span class="identifier-syntax">d</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bv</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Dispose of any data in the long block</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> = </span><span class="identifier-syntax">KOVSupportFunction</span><span class="plain-syntax">(</span><span class="identifier-syntax">BlkValueWeakKind</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">), </span><span class="string-syntax">"impossible deallocation"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueDestroyPrimitive</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Free any heap memory occupied by the short block</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">d</span><span class="plain-syntax"> = </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> - </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">d</span><span class="plain-syntax"> &gt;= </span><span class="constant-syntax">0</span><span class="plain-syntax">) &amp;&amp; (</span><span class="identifier-syntax">d</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">MEMORY_HEAP_SIZE</span><span class="plain-syntax"> + </span><span class="constant-syntax">16</span><span class="plain-syntax">))</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">FlexFree</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax"> - </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">);</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP18" class="paragraph-anchor"></a><b>&#167;18. Quick Copy. </b>The basic method of copying block value B into block value A is to destroy the
old contents of A, which are about to be overwritten; then copy the short
block of A into the short block of B, a quick process; and increment the
reference count of B.
</p>
<p class="commentary">The support function should respond to:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">COPYSB_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">by copying the short blocks alone.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueQuickCopyPrimitive</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueDestroyPrimitive</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">COPYSB_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueIncRefCountPrimitive</span><span class="plain-syntax">(</span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP19" class="paragraph-anchor"></a><b>&#167;19. Short Block Copy. </b>In fact, most of the work of copying a short block is standard. If a SB
consists only a single word pointing to the LB, the first routine below
handles all the work needed to handle the <span class="extract"><span class="extract-syntax">COPYSB_KOVS</span></span> task. The
surprising line in this routine is to deal with the convention that a
pointer value of 0 means the LB immediately follows the SB: if that's
true in <span class="extract"><span class="extract-syntax">from_bv</span></span>, it won't be true in <span class="extract"><span class="extract-syntax">to_bv</span></span>, so we must correct it.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueCopySB1</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">--&gt;0 = </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">--&gt;0;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">--&gt;0 == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">--&gt;0 = </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax"> + </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueCopySB2</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">--&gt;0 = </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">--&gt;0;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">--&gt;1 = </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">--&gt;1;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">--&gt;1 == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">--&gt;1 = </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax"> + </span><span class="constant-syntax">2</span><span class="plain-syntax">*</span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP20" class="paragraph-anchor"></a><b>&#167;20. Slow Copy. </b>Why don't we always do this? Consider the case where B is a list of rooms, and
A is a list of objects. If we give A's short block a pointer to the long block
of B, A will suddenly change its kind as well as its contents, because the
strong kind of a list is stored inside the long block. So there are a few
cases where it's not safe to make a quick copy. In any case, sooner or later
you have to duplicate actual data, not just rearrange pointers to it, and
here's where.
</p>
<p class="commentary">We first call:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">KINDDATA_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">which asks for an ID for the kinds stored in the BV: for example, for a
list of rooms it would return the kind ID for "room". We ask for this
because it's information stored in the long block, which is about to be
overwritten.
</p>
<p class="commentary">As with the quick copy, we must now make sure any data currently in the
destination is properly destroyed. We could do so by making the destination
mutable and then destroying its contents, but that would be inefficient,
in that it might create a whole lot of temporary copies and then delete
them again. So if the long block has a high reference count, we decrement
it and then replace the short block (in place) with a fresh one pointing
to empty data; we only destroy the contents if the long block has reference
count 1.
</p>
<p class="commentary">All of which finally means we can scribble over the destination without
spoiling anybody else's day. We resize it to make room for the incoming data;
we copy the raw data of the long block; and finally we:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">COPY_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">k</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">This is where the KOVS should make a proper copy, using <span class="extract"><span class="extract-syntax">BlkValueCopy</span></span> and
thus perhaps recursing, if any of that data contained block values in turn:
as for instance it will if we're copying a list of texts. Note that <span class="extract"><span class="extract-syntax">k</span></span>
is the value given us by <span class="extract"><span class="extract-syntax">KINDDATA_KOVS</span></span>.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueSlowCopyPrimitive</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> </span><span class="identifier-syntax">recycling</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">k</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_long_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">k</span><span class="plain-syntax"> = </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">KINDDATA_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">from_long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">from_long_block</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">recycling</span><span class="plain-syntax">) </span><span class="identifier-syntax">BlkValueRecyclePrimitive</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax"> = </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">EXTENT_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax"> == -1) </span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueLBCapacity</span><span class="plain-syntax">(</span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueMassCopyEntries</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">no_entries_to_copy</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">COPY_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">k</span><span class="plain-syntax">);</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP21" class="paragraph-anchor"></a><b>&#167;21. Copy. </b>As noted above, some copies are quick, and some are slow. We decide by
asking the kind's support function:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">COPYQUICK_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">which should return true if a quick copy is okay, or false if not.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueCopy</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_kind</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_kind</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">BlkValueError</span><span class="plain-syntax">(</span><span class="string-syntax">"copy to null value"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">from_bv</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">BlkValueError</span><span class="plain-syntax">(</span><span class="string-syntax">"copy from null value"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax"> == </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifdef</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLKVALUE_TRACE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Copy: "</span><span class="plain-syntax">, (</span><span class="identifier-syntax">BlkValueDebug</span><span class="plain-syntax">) </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="string-syntax">" to equal "</span><span class="plain-syntax">, (</span><span class="identifier-syntax">BlkValueDebug</span><span class="plain-syntax">) </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">, </span><span class="string-syntax">"^"</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to_kind</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueWeakKind</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">from_kind</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueWeakKind</span><span class="plain-syntax">(</span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">to_kind</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">from_kind</span><span class="plain-syntax">) </span><span class="identifier-syntax">BlkValueError</span><span class="plain-syntax">(</span><span class="string-syntax">"copy incompatible kinds"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> = </span><span class="identifier-syntax">KOVSupportFunction</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_kind</span><span class="plain-syntax">, </span><span class="string-syntax">"impossible copy"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">COPYQUICK_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">))</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueQuickCopyPrimitive</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueSlowCopyPrimitive</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">, </span><span class="reserved-syntax">true</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueCopyAZ</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueCopy</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">from_bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP22" class="paragraph-anchor"></a><b>&#167;22. Destruction. </b>We will also need primitives for two different forms of destruction. This
is something which should happen whenever a block value is thrown away,
not to be used again: either because it's being freed, or because new
contents are being copied into it.
</p>
<p class="commentary">The idea of destruction is that any data stored in the long block should
safely be disposed of. If the reference count of the long block is 2 or
more, there's no problem, because we can simply decrement the count and
let other people worry about the data from now on. But if it's only 1,
then destroying the data is on us. Since we don't know what's in the
long block, we have to ask the KOVS to do this by means of:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">DESTROY_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">Note that all of this frequently causes recursion: destruction leads to
freeing of some of the data, which in turn means that that data must be
destroyed, and so on. So it's essential that block values be well-founded:
a list must not, for example, contain itself.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueDestroyPrimitive</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifdef</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLKVALUE_TRACE</span><span class="plain-syntax">; </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Destroying "</span><span class="plain-syntax">, (</span><span class="identifier-syntax">BlkValueDebug</span><span class="plain-syntax">) </span><span class="identifier-syntax">bv</span><span class="plain-syntax">, </span><span class="string-syntax">"^"</span><span class="plain-syntax">; #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">BlkValueDecRefCountPrimitive</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">) == </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">DESTROY_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">) </span><span class="identifier-syntax">FlexFree</span><span class="plain-syntax">(</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP23" class="paragraph-anchor"></a><b>&#167;23. Recycling. </b>This is like destruction in that it disposes of the value safely, but it
tries to keep the long block for reuse, rather than deallocating it. This
won't work if other people are still using it, so in the case where its
reference count is 2 or more, we simply reduce the count by 1 and then
replace the small block with a new one (at the same address).
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueRecyclePrimitive</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifdef</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLKVALUE_TRACE</span><span class="plain-syntax">; </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Recycling "</span><span class="plain-syntax">, (</span><span class="identifier-syntax">BlkValueDebug</span><span class="plain-syntax">) </span><span class="identifier-syntax">bv</span><span class="plain-syntax">, </span><span class="string-syntax">"^"</span><span class="plain-syntax">; #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">BlkValueDecRefCountPrimitive</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">) == </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">DESTROY_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueIncRefCountPrimitive</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueCreate</span><span class="plain-syntax">(</span><span class="identifier-syntax">BlkValueWeakKind</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">), </span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP24" class="paragraph-anchor"></a><b>&#167;24. Mutability. </b>A block value is by definition mutable if it has a long block with reference
count 1, because then the data in the long block can freely be changed without
corrupting other block values.
</p>
<p class="commentary">We offer the KOVS a chance to handle this for us:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">MAKEMUTABLE_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">should return 0 to say that it has done so, or else return the size of the
short block in words to ask us to handle it. The way we do this is to create
a temporary value to make a safe copy into; it would be unnecessarily slow
to allocate the short block for this safe copy on the heap and then free it
again moments later, so instead we put the short block on the stack, making
a temporary one-value stack frame instead to hold it.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkMakeMutable</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv_kind</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> </span><span class="identifier-syntax">sb_size</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bv</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">BlkValueError</span><span class="plain-syntax">(</span><span class="string-syntax">"tried to make null block mutable"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">BlkValueGetRefCountPrimitive</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">) &gt; </span><span class="constant-syntax">1</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifdef</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLKVALUE_TRACE</span><span class="plain-syntax">; </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Make mutable: "</span><span class="plain-syntax">, (</span><span class="identifier-syntax">BlkValueDebug</span><span class="plain-syntax">) </span><span class="identifier-syntax">bv</span><span class="plain-syntax">, </span><span class="string-syntax">"^"</span><span class="plain-syntax">; #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueDecRefCountPrimitive</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">bv_kind</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueWeakKind</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> = </span><span class="identifier-syntax">KOVSupportFunction</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv_kind</span><span class="plain-syntax">, </span><span class="string-syntax">"impossible mutability"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">sb_size</span><span class="plain-syntax"> = </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">MAKEMUTABLE_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">sb_size</span><span class="plain-syntax"> &gt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> @</span><span class="identifier-syntax">push</span><span class="plain-syntax"> </span><span class="identifier-syntax">I7SFRAME</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">StackFrameCreate</span><span class="plain-syntax">(</span><span class="identifier-syntax">sb_size</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueCreateOnStack</span><span class="plain-syntax">(0, </span><span class="identifier-syntax">bv_kind</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">COPYKIND_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">I7SFRAME</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueSlowCopyPrimitive</span><span class="plain-syntax">(</span><span class="identifier-syntax">I7SFRAME</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">, </span><span class="reserved-syntax">false</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">COPYSB_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">I7SFRAME</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> @</span><span class="identifier-syntax">pull</span><span class="plain-syntax"> </span><span class="identifier-syntax">I7SFRAME</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP25" class="paragraph-anchor"></a><b>&#167;25. Casting. </b>We can also perform an assignment to an already-created block value in the
form of a cast, that is, a conversion of data from one kind to another:
or at least, for some kinds of value we can.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">CAST_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">original_kind</span><span class="plain-syntax">, </span><span class="identifier-syntax">original_value</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">casts from the given value, with the given kind, into the existing block
value <span class="extract"><span class="extract-syntax">to_bv</span></span>. Note that the source value doesn't need to be a BV itself.
This mechanism is used, for example, to cast snippets to text.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueCast</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">original_kind</span><span class="plain-syntax"> </span><span class="identifier-syntax">original_value</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> = </span><span class="identifier-syntax">KOVSupportFunction</span><span class="plain-syntax">(</span><span class="identifier-syntax">BlkValueWeakKind</span><span class="plain-syntax">(</span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">), </span><span class="string-syntax">"impossible cast"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">CAST_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">original_kind</span><span class="plain-syntax">, </span><span class="identifier-syntax">original_value</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">to_bv</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP26" class="paragraph-anchor"></a><b>&#167;26. Comparison. </b>And it's a similar story with comparison:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">COMPARE_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv_left</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv_right</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">looks at the data in the two BVs and returns 0 if they are equal, a positive
number if <span class="extract"><span class="extract-syntax">bv_right</span></span> is "greater than" <span class="extract"><span class="extract-syntax">bv_left</span></span>, and a negative number if
not. The interpretation of "greater than" depends on the kind, but should be
something which the user would find natural.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueCompare</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv_left</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv_right</span><span class="plain-syntax"> </span><span class="identifier-syntax">kind_left</span><span class="plain-syntax"> </span><span class="identifier-syntax">kind_right</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">bv_left</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) &amp;&amp; (</span><span class="identifier-syntax">bv_right</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bv_left</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bv_right</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> -1;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kind_left</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueWeakKind</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv_left</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kind_right</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueWeakKind</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv_right</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">kind_left</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">kind_right</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">kind_left</span><span class="plain-syntax"> - </span><span class="identifier-syntax">kind_right</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> = </span><span class="identifier-syntax">KOVSupportFunction</span><span class="plain-syntax">(</span><span class="identifier-syntax">kind_left</span><span class="plain-syntax">, </span><span class="string-syntax">"impossible comparison"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">COMPARE_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv_left</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv_right</span><span class="plain-syntax">);</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP27" class="paragraph-anchor"></a><b>&#167;27. Hashing. </b>Given a value of any kind, assign it a hash code which fits in a single
virtual machine word, maximizing the chances that two different values
will have different hash codes.
</p>
<p class="commentary">If the value can be stored in a single word already, it can be its own
hash code. Otherwise, we ask:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">HASH_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">to return one for us. Whatever this does, it must at minimum have the
property that two equivalent blocks (for which <span class="extract"><span class="extract-syntax">COMPARE_KOVS</span></span> returns 0)
produce the same hash value.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">GetHashValue</span><span class="plain-syntax"> </span><span class="identifier-syntax">kind</span><span class="plain-syntax"> </span><span class="identifier-syntax">value</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">KOVIsBlockValue</span><span class="plain-syntax">(</span><span class="identifier-syntax">kind</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">BlkValueHash</span><span class="plain-syntax">(</span><span class="identifier-syntax">value</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">value</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueHash</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv_kind</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bv</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">bv_kind</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueWeakKind</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> = </span><span class="identifier-syntax">KOVSupportFunction</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv_kind</span><span class="plain-syntax">, </span><span class="string-syntax">"impossible hashing"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">HASH_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP28" class="paragraph-anchor"></a><b>&#167;28. Serialisation. </b>Some block values can be written to external files (on Glulx): others cannot.
The following routines abstract that.
</p>
<p class="commentary">If <span class="extract"><span class="extract-syntax">ch</span></span> is \(-1\), then:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">READ_FILE_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">auxf</span><span class="plain-syntax">, </span><span class="identifier-syntax">ch</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">returns <span class="extract"><span class="extract-syntax">true</span></span> or <span class="extract"><span class="extract-syntax">false</span></span> according to whether it is possible to read data
from an auxiliary file <span class="extract"><span class="extract-syntax">auxf</span></span> into the block value <span class="extract"><span class="extract-syntax">bv</span></span>. If <span class="extract"><span class="extract-syntax">ch</span></span> is any
other value, then the routine should do exactly that, taking <span class="extract"><span class="extract-syntax">ch</span></span> to be the
first character of the text read from the file which makes up the serialised
form of the data.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">WRITE_FILE_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary">is simpler because, strictly speaking, it doesn't write to a file at all: it
simply prints a serialised form of the data in <span class="extract"><span class="extract-syntax">bv</span></span> to the output stream.
Since it is called only when that output stream has been redirected to an
auxiliary file, and since the serialised form would often be illegible on
screen, it seems reasonable to call it a file input-output function just the
same. The <span class="extract"><span class="extract-syntax">WRITE_FILE_KOVS</span></span> should return <span class="extract"><span class="extract-syntax">true</span></span> or <span class="extract"><span class="extract-syntax">false</span></span> according to
whether it was able to write the data.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueReadFromFile</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">auxf</span><span class="plain-syntax"> </span><span class="identifier-syntax">ch</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv_kind</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> = </span><span class="identifier-syntax">KOVSupportFunction</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv_kind</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">kovs</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">READ_FILE_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">auxf</span><span class="plain-syntax">, </span><span class="identifier-syntax">ch</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueWriteToFile</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv_kind</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> = </span><span class="identifier-syntax">KOVSupportFunction</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv_kind</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">kovs</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">WRITE_FILE_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP29" class="paragraph-anchor"></a><b>&#167;29. Debugging. </b>Surprisingly, the above system of reference-counted double indirection didn't
work first time, so it turned out to be useful to have these routines on hand.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkValueDebug</span><span class="plain-syntax"> </span><span class="identifier-syntax">bv</span><span class="plain-syntax"> </span><span class="identifier-syntax">flag</span><span class="plain-syntax"> </span><span class="identifier-syntax">refc</span><span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"(BV"</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bv</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkDebugAddress</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">, </span><span class="identifier-syntax">flag</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">long_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetLongBlock</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bv</span><span class="plain-syntax">--&gt;0 == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"..."</span><span class="plain-syntax">; </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"--&gt;"</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"L"</span><span class="plain-syntax">; </span><span class="identifier-syntax">BlkDebugAddress</span><span class="plain-syntax">(</span><span class="identifier-syntax">long_block</span><span class="plain-syntax">, </span><span class="identifier-syntax">flag</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">" 2**"</span><span class="plain-syntax">, </span><span class="identifier-syntax">long_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">refc</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BlkValueGetRefCountPrimitive</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">refc</span><span class="plain-syntax"> == </span><span class="identifier-syntax">RC_INFINITY</span><span class="plain-syntax">) </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">" resident"</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> { </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">" "</span><span class="plain-syntax">, </span><span class="identifier-syntax">refc</span><span class="plain-syntax">, </span><span class="string-syntax">" ref"</span><span class="plain-syntax">; </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">refc</span><span class="plain-syntax"> ~= </span><span class="constant-syntax">1</span><span class="plain-syntax">) </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"s"</span><span class="plain-syntax">; }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kovs</span><span class="plain-syntax"> = </span><span class="identifier-syntax">KOVSupportFunction</span><span class="plain-syntax">(</span><span class="identifier-syntax">BlkValueWeakKind</span><span class="plain-syntax">(</span><span class="identifier-syntax">bv</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">kovs</span><span class="plain-syntax">) </span><span class="identifier-syntax">kovs</span><span class="plain-syntax">(</span><span class="identifier-syntax">DEBUG_KOVS</span><span class="plain-syntax">, </span><span class="identifier-syntax">bv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">")"</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP30" class="paragraph-anchor"></a><b>&#167;30. Printing Memory Addresses. </b>The point of the anonymity flag is that, with this set, the output can be
used as the required output in an Inform test case without tiny movements
in memory between builds invalidating this required output.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkDebugAddress</span><span class="plain-syntax"> </span><span class="identifier-syntax">addr</span><span class="plain-syntax"> </span><span class="identifier-syntax">flag</span><span class="plain-syntax"> </span><span class="identifier-syntax">d</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flag</span><span class="plain-syntax">) { </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"###"</span><span class="plain-syntax">; </span><span class="reserved-syntax">return</span><span class="plain-syntax">; }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">d</span><span class="plain-syntax"> = </span><span class="identifier-syntax">addr</span><span class="plain-syntax"> - </span><span class="identifier-syntax">blockv_stack</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">d</span><span class="plain-syntax"> &gt;= </span><span class="constant-syntax">0</span><span class="plain-syntax">) &amp;&amp; (</span><span class="identifier-syntax">d</span><span class="plain-syntax"> &lt;= </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">*</span><span class="identifier-syntax">BLOCKV_STACK_SIZE</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"s+"</span><span class="plain-syntax">, (</span><span class="identifier-syntax">BlkPrintHexadecimal</span><span class="plain-syntax">) </span><span class="identifier-syntax">d</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">d</span><span class="plain-syntax"> = </span><span class="identifier-syntax">addr</span><span class="plain-syntax"> - </span><span class="identifier-syntax">I7SFRAME</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"=f"</span><span class="plain-syntax">; </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">d</span><span class="plain-syntax"> &gt;= </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"+"</span><span class="plain-syntax">; </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="identifier-syntax">d</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">d</span><span class="plain-syntax"> = </span><span class="identifier-syntax">addr</span><span class="plain-syntax"> - </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">d</span><span class="plain-syntax"> &gt;= </span><span class="constant-syntax">0</span><span class="plain-syntax">) &amp;&amp; (</span><span class="identifier-syntax">d</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">MEMORY_HEAP_SIZE</span><span class="plain-syntax"> + </span><span class="constant-syntax">16</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"h+"</span><span class="plain-syntax">, (</span><span class="identifier-syntax">BlkPrintHexadecimal</span><span class="plain-syntax">) </span><span class="identifier-syntax">d</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> (</span><span class="identifier-syntax">BlkPrintHexadecimal</span><span class="plain-syntax">) </span><span class="identifier-syntax">addr</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP31" class="paragraph-anchor"></a><b>&#167;31. Hexadecimal Printing. </b></p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkPrintHexadecimal</span><span class="plain-syntax"> </span><span class="identifier-syntax">v</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">iftrue</span><span class="plain-syntax"> </span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax"> == </span><span class="constant-syntax">4</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">v</span><span class="plain-syntax"> &amp; </span><span class="constant-syntax">$ffff0000</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">v</span><span class="plain-syntax"> &amp; </span><span class="constant-syntax">$ff000000</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkPrintHexDigit</span><span class="plain-syntax">(</span><span class="identifier-syntax">v</span><span class="plain-syntax"> / </span><span class="constant-syntax">$10000000</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkPrintHexDigit</span><span class="plain-syntax">(</span><span class="identifier-syntax">v</span><span class="plain-syntax"> / </span><span class="constant-syntax">$1000000</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkPrintHexDigit</span><span class="plain-syntax">(</span><span class="identifier-syntax">v</span><span class="plain-syntax"> / </span><span class="constant-syntax">$100000</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkPrintHexDigit</span><span class="plain-syntax">(</span><span class="identifier-syntax">v</span><span class="plain-syntax"> / </span><span class="constant-syntax">$10000</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkPrintHexDigit</span><span class="plain-syntax">(</span><span class="identifier-syntax">v</span><span class="plain-syntax"> / </span><span class="constant-syntax">$1000</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkPrintHexDigit</span><span class="plain-syntax">(</span><span class="identifier-syntax">v</span><span class="plain-syntax"> / </span><span class="constant-syntax">$100</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkPrintHexDigit</span><span class="plain-syntax">(</span><span class="identifier-syntax">v</span><span class="plain-syntax"> / </span><span class="constant-syntax">$10</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">BlkPrintHexDigit</span><span class="plain-syntax">(</span><span class="identifier-syntax">v</span><span class="plain-syntax">);</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">BlkPrintHexDigit</span><span class="plain-syntax"> </span><span class="identifier-syntax">v</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">v</span><span class="plain-syntax"> = </span><span class="identifier-syntax">v</span><span class="plain-syntax"> &amp; </span><span class="constant-syntax">$F</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">v</span><span class="plain-syntax"> &lt; </span><span class="constant-syntax">10</span><span class="plain-syntax">) </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="identifier-syntax">v</span><span class="plain-syntax">; </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> (</span><span class="identifier-syntax">char</span><span class="plain-syntax">) </span><span class="character-syntax">'A'</span><span class="plain-syntax"> + </span><span class="identifier-syntax">v</span><span class="plain-syntax"> - </span><span class="constant-syntax">10</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<nav role="progress"><div class="progresscontainer">
<ul class="progressbar"><li class="progressprev"><a href="S-flx.html">&#10094;</a></li><li class="progresssection"><a href="S-dfn.html">dfn</a></li><li class="progresssection"><a href="S-utl.html">utl</a></li><li class="progresssection"><a href="S-gll.html">gll</a></li><li class="progresssection"><a href="S-zmc.html">zmc</a></li><li class="progresssection"><a href="S-prg.html">prg</a></li><li class="progresssection"><a href="S-mth.html">mth</a></li><li class="progresssection"><a href="S-fl.html">fl</a></li><li class="progresssection"><a href="S-srt.html">srt</a></li><li class="progresssection"><a href="S-tbl.html">tbl</a></li><li class="progresssection"><a href="S-mst.html">mst</a></li><li class="progresssection"><a href="S-rlb.html">rlb</a></li><li class="progresssection"><a href="S-flx.html">flx</a></li><li class="progresscurrent">blc</li><li class="progresssection"><a href="S-txt.html">txt</a></li><li class="progresssection"><a href="S-unc.html">unc</a></li><li class="progresssection"><a href="S-chr.html">chr</a></li><li class="progresssection"><a href="S-rgx.html">rgx</a></li><li class="progresssection"><a href="S-lst.html">lst</a></li><li class="progresssection"><a href="S-cmb.html">cmb</a></li><li class="progresssection"><a href="S-rlt.html">rlt</a></li><li class="progresssection"><a href="S-rlt2.html">rlt2</a></li><li class="progresssection"><a href="S-rtp.html">rtp</a></li><li class="progressnext"><a href="S-txt.html">&#10095;</a></li></ul></div>
</nav><!--End of weave-->
</main>
</body>
</html>