mirror of
https://github.com/ganelson/inform.git
synced 2024-07-17 22:44:25 +03:00
1262 lines
148 KiB
HTML
1262 lines
148 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<html>
|
|
<head>
|
|
<title>S/ft2</title>
|
|
<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="../inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
</head>
|
|
<body>
|
|
<nav role="navigation">
|
|
<h1><a href="../webs.html">Sources</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"><b>extensions and kits</b></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="../BasicInformKit/index.html">BasicInformKit</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 'S/bt' generated by 7-->
|
|
<ul class="crumbs"><li><a href="../webs.html">Source</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><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="#SP1">§1. Overview</a></li><li><a href="#SP2">§2. Short Block Format</a></li><li><a href="#SP3">§3. Long Block Access</a></li><li><a href="#SP4">§4. Weak Kind</a></li><li><a href="#SP5">§5. Reference counting</a></li><li><a href="#SP6">§6. Changing Reference Counts</a></li><li><a href="#SP7">§7. Long Block Capacity</a></li><li><a href="#SP8">§8. Long Block Array Access</a></li><li><a href="#SP9">§9. First Zero Entry</a></li><li><a href="#SP10">§10. Mass Copy Entries</a></li><li><a href="#SP11">§11. Mass Copy From Array</a></li><li><a href="#SP12">§12. KOVS Routines</a></li><li><a href="#SP13">§13. Creation</a></li><li><a href="#SP14">§14. Errors</a></li><li><a href="#SP15">§15. Short Block Allocation</a></li><li><a href="#SP16">§16. Block Values On Stack</a></li><li><a href="#SP17">§17. Freeing</a></li><li><a href="#SP18">§18. Quick Copy</a></li><li><a href="#SP19">§19. Short Block Copy</a></li><li><a href="#SP20">§20. Slow Copy</a></li><li><a href="#SP21">§21. Copy</a></li><li><a href="#SP22">§22. Destruction</a></li><li><a href="#SP23">§23. Recycling</a></li><li><a href="#SP24">§24. Mutability</a></li><li><a href="#SP25">§25. Casting</a></li><li><a href="#SP26">§26. Comparison</a></li><li><a href="#SP27">§27. Hashing</a></li><li><a href="#SP28">§28. Serialisation</a></li><li><a href="#SP29">§29. Debugging</a></li><li><a href="#SP30">§30. Printing Memory Addresses</a></li><li><a href="#SP31">§31. Hexadecimal Printing</a></li></ul><hr class="tocbar">
|
|
|
|
<p class="inwebparagraph"><a id="SP1"></a><b>§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="inwebparagraph">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 — "text",
|
|
"list of K", "stored action" and so on — 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="inwebparagraph">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="inwebparagraph">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="inwebparagraph"> let L1 be { 2, 3, 5, 7, 11 };
|
|
let L2 be L1;
|
|
</p>
|
|
|
|
<p class="inwebparagraph">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="inwebparagraph">The rules for customers who want to deal with values like this are much like
|
|
the rules for allocating memory with Flex. Calling <code class="display"><span class="extract">BlkValueCreate</span></code>
|
|
creates a new value, but this must always, and only once, later be disposed
|
|
of using <code class="display"><span class="extract">BlkValueFree</span></code>.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">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="inwebparagraph">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="inwebparagraph">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="inwebparagraph">Finally, note that the I7 compiler also creates block values representing
|
|
constants. For example, the source text
|
|
</p>
|
|
|
|
<p class="inwebparagraph"> let L1 be { 2, 3, 5, 7, 11 };
|
|
</p>
|
|
|
|
<p class="inwebparagraph">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="display">
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">RC_INFINITY</span><span class="plain"> = </span><span class="identifier">MAX_POSITIVE_NUMBER</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP2"></a><b>§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>
|
|
|
|
<p class="inwebparagraph"></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></ul>
|
|
<ul class="items"><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 <code class="display"><span class="extract">BLK_BVBITMAP_LONGBLOCK</span></code> bit is set, a pointer to the long block
|
|
is stored in the second word of the short block.
|
|
</li></ul>
|
|
<ul class="items"><li>(c) Otherwise the short block has length 1 and contains only a pointer to
|
|
the long block.
|
|
</li></ul>
|
|
<pre class="display">
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">BLK_BVBITMAP</span><span class="plain"> = </span><span class="constant">$ff</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">BLK_BVBITMAP_LONGBLOCK</span><span class="plain"> = </span><span class="constant">$10</span><span class="plain">; </span><span class="comment">Word 1 of SB is pointer to LB</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">BLK_BVBITMAP_TEXT</span><span class="plain"> = </span><span class="constant">$20</span><span class="plain">; </span><span class="comment">BV holds a TEXT_TY value</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">BLK_BVBITMAP_CONSTANT</span><span class="plain"> = </span><span class="constant">$40</span><span class="plain">; </span><span class="comment">BV holds a TEXT_TY value</span>
|
|
|
|
<span class="plain">#</span><span class="identifier">IFTRUE</span><span class="plain"> </span><span class="identifier">WORDSIZE</span><span class="plain"> == </span><span class="constant">4</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">BLK_BVBITMAP_LONGBLOCKMASK</span><span class="plain"> = </span><span class="constant">$ffffff10</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">BLK_BVBITMAP_TEXTMASK</span><span class="plain"> = </span><span class="constant">$ffffff20</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">BLK_BVBITMAP_CONSTANTMASK</span><span class="plain"> = </span><span class="constant">$ffffff40</span><span class="plain">;</span>
|
|
<span class="plain">#</span><span class="identifier">IFNOT</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">BLK_BVBITMAP_LONGBLOCKMASK</span><span class="plain"> = </span><span class="constant">$ff10</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">BLK_BVBITMAP_TEXTMASK</span><span class="plain"> = </span><span class="constant">$ff20</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">BLK_BVBITMAP_CONSTANTMASK</span><span class="plain"> = </span><span class="constant">$ff40</span><span class="plain">;</span>
|
|
<span class="plain">#</span><span class="identifier">ENDIF</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP3"></a><b>§3. Long Block Access. </b>Illustrating this:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">o</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">bv</span><span class="plain">) {</span>
|
|
<span class="identifier">o</span><span class="plain"> = </span><span class="identifier">bv</span><span class="plain">-->0;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">o</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> + </span><span class="identifier">WORDSIZE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">o</span><span class="plain"> & </span><span class="identifier">BLK_BVBITMAP</span><span class="plain"> == </span><span class="identifier">o</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">o</span><span class="plain"> & </span><span class="identifier">BLK_BVBITMAP_LONGBLOCK</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain">-->1;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">o</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP4"></a><b>§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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueWeakKind</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">o</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">bv</span><span class="plain">) {</span>
|
|
<span class="identifier">o</span><span class="plain"> = </span><span class="identifier">bv</span><span class="plain">-->0;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">o</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain">-->(</span><span class="identifier">BLK_HEADER_KOV</span><span class="plain">+1);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">o</span><span class="plain"> & </span><span class="identifier">BLK_BVBITMAP</span><span class="plain"> == </span><span class="identifier">o</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">o</span><span class="plain"> & </span><span class="identifier">BLK_BVBITMAP_TEXT</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TEXT_TY</span><span class="plain">;</span>
|
|
<span class="identifier">o</span><span class="plain"> = </span><span class="identifier">bv</span><span class="plain">-->1;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">o</span><span class="plain">--></span><span class="identifier">BLK_HEADER_KOV</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">NIL_TY</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP5"></a><b>§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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueGetRefCountPrimitive</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">long_block</span><span class="plain">;</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">long_block</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">long_block</span><span class="plain">--></span><span class="identifier">BLK_HEADER_RCOUNT</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">RC_INFINITY</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP6"></a><b>§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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueIncRefCountPrimitive</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">long_block</span><span class="plain"> </span><span class="identifier">refc</span><span class="plain">;</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">long_block</span><span class="plain">) {</span>
|
|
<span class="identifier">refc</span><span class="plain"> = </span><span class="identifier">long_block</span><span class="plain">--></span><span class="identifier">BLK_HEADER_RCOUNT</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">refc</span><span class="plain"> < </span><span class="identifier">RC_INFINITY</span><span class="plain">) </span><span class="identifier">long_block</span><span class="plain">--></span><span class="identifier">BLK_HEADER_RCOUNT</span><span class="plain"> = </span><span class="identifier">refc</span><span class="plain"> + </span><span class="constant">1</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">];</span>
|
|
|
|
<span class="plain">[ </span><span class="identifier">BlkValueDecRefCountPrimitive</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">long_block</span><span class="plain"> </span><span class="identifier">refc</span><span class="plain">;</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">long_block</span><span class="plain">) {</span>
|
|
<span class="identifier">refc</span><span class="plain"> = </span><span class="identifier">long_block</span><span class="plain">--></span><span class="identifier">BLK_HEADER_RCOUNT</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">refc</span><span class="plain"> < </span><span class="identifier">RC_INFINITY</span><span class="plain">) {</span>
|
|
<span class="identifier">refc</span><span class="plain">--;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">refc</span><span class="plain"> < </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">BlkValueError</span><span class="plain">(</span><span class="string">"reference count negative"</span><span class="plain">);</span>
|
|
<span class="identifier">long_block</span><span class="plain">--></span><span class="identifier">BLK_HEADER_RCOUNT</span><span class="plain"> = </span><span class="identifier">refc</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">refc</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">RC_INFINITY</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP7"></a><b>§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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueLBCapacity</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">long_block</span><span class="plain"> </span><span class="identifier">array_size_in_bytes</span><span class="plain"> </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> </span><span class="identifier">flags</span><span class="plain">;</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">long_block</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">0</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">array_size_in_bytes</span><span class="plain"> = </span><span class="identifier">FlexTotalSize</span><span class="plain">(</span><span class="identifier">long_block</span><span class="plain">);</span>
|
|
|
|
<span class="identifier">flags</span><span class="plain"> = </span><span class="identifier">long_block</span><span class="plain">-></span><span class="identifier">BLK_HEADER_FLAGS</span><span class="plain">;</span>
|
|
<span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="constant">1</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_16_BIT</span><span class="plain">) </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="constant">2</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_WORD</span><span class="plain">) </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="identifier">WORDSIZE</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">array_size_in_bytes</span><span class="plain"> / </span><span class="identifier">entry_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
|
|
<span class="plain">[ </span><span class="identifier">BlkValueSetLBCapacity</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">new_capacity</span><span class="plain"> </span><span class="identifier">long_block</span><span class="plain"> </span><span class="identifier">flags</span><span class="plain"> </span><span class="identifier">entry_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">bv</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">rfalse</span><span class="plain">;</span>
|
|
<span class="identifier">BlkMakeMutable</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">long_block</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">rfalse</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">flags</span><span class="plain"> = </span><span class="identifier">long_block</span><span class="plain">-></span><span class="identifier">BLK_HEADER_FLAGS</span><span class="plain">;</span>
|
|
<span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="constant">1</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_16_BIT</span><span class="plain">) </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="constant">2</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_WORD</span><span class="plain">) </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="identifier">WORDSIZE</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">FlexResize</span><span class="plain">(</span><span class="identifier">long_block</span><span class="plain">, </span><span class="identifier">new_capacity</span><span class="plain">*</span><span class="identifier">entry_size_in_bytes</span><span class="plain">);</span>
|
|
<span class="reserved">rtrue</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP8"></a><b>§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="inwebparagraph"><code class="display"><span class="extract">BlkValueRead</span></code> takes two compulsory arguments and one optional one. Thus:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">BlkValueRead</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">, </span><span class="identifier">n</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">reads the nth entry in the long block for <code class="display"><span class="extract">bv</span></code>, whereas
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">BlkValueRead</span><span class="plain">(</span><span class="identifier">long_block</span><span class="plain">, </span><span class="identifier">n</span><span class="plain">, </span><span class="reserved">true</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">read it from the given long block directly. <code class="display"><span class="extract">BlkValueWrite</span></code> is similar.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueRead</span><span class="plain"> </span><span class="identifier">from</span><span class="plain"> </span><span class="identifier">pos</span><span class="plain"> </span><span class="identifier">do_not_indirect</span>
|
|
<span class="identifier">long_block</span><span class="plain"> </span><span class="identifier">chunk_size_in_bytes</span><span class="plain"> </span><span class="identifier">header_size_in_bytes</span><span class="plain"> </span><span class="identifier">flags</span><span class="plain"> </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> </span><span class="identifier">seek_byte_position</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">from</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">rfalse</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">do_not_indirect</span><span class="plain">)</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="identifier">from</span><span class="plain">;</span>
|
|
<span class="reserved">else</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">);</span>
|
|
|
|
<span class="identifier">flags</span><span class="plain"> = </span><span class="identifier">long_block</span><span class="plain">-></span><span class="identifier">BLK_HEADER_FLAGS</span><span class="plain">;</span>
|
|
<span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="constant">1</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_16_BIT</span><span class="plain">) </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="constant">2</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_WORD</span><span class="plain">) </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="identifier">WORDSIZE</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_MULTIPLE</span><span class="plain">) </span><span class="identifier">header_size_in_bytes</span><span class="plain"> = </span><span class="identifier">BLK_DATA_MULTI_OFFSET</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">header_size_in_bytes</span><span class="plain"> = </span><span class="identifier">BLK_DATA_OFFSET</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">seek_byte_position</span><span class="plain"> = </span><span class="identifier">pos</span><span class="plain">*</span><span class="identifier">entry_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (: </span><span class="identifier">long_block</span><span class="plain">~=</span><span class="identifier">NULL</span><span class="plain">: </span><span class="identifier">long_block</span><span class="plain">=</span><span class="identifier">long_block</span><span class="plain">--></span><span class="identifier">BLK_NEXT</span><span class="plain">) {</span>
|
|
<span class="identifier">chunk_size_in_bytes</span><span class="plain"> = </span><span class="identifier">FlexSize</span><span class="plain">(</span><span class="identifier">long_block</span><span class="plain">) - </span><span class="identifier">header_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">seek_byte_position</span><span class="plain"> >= </span><span class="constant">0</span><span class="plain">) && (</span><span class="identifier">seek_byte_position</span><span class="plain"><</span><span class="identifier">chunk_size_in_bytes</span><span class="plain">)) {</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="identifier">long_block</span><span class="plain"> + </span><span class="identifier">header_size_in_bytes</span><span class="plain"> + </span><span class="identifier">seek_byte_position</span><span class="plain">;</span>
|
|
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">entry_size_in_bytes</span><span class="plain">) {</span>
|
|
<span class="constant">1</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">long_block</span><span class="plain">->0;</span>
|
|
<span class="constant">2</span><span class="plain">: #</span><span class="identifier">Iftrue</span><span class="plain"> (</span><span class="identifier">WORDSIZE</span><span class="plain"> == </span><span class="constant">2</span><span class="plain">); </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">long_block</span><span class="plain">-->0;</span>
|
|
<span class="plain">#</span><span class="identifier">ifnot</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> (</span><span class="identifier">long_block</span><span class="plain">->0)*256 + (</span><span class="identifier">long_block</span><span class="plain">->1);</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span><span class="plain">;</span>
|
|
<span class="constant">4</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">long_block</span><span class="plain">-->0;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">seek_byte_position</span><span class="plain"> = </span><span class="identifier">seek_byte_position</span><span class="plain"> - </span><span class="identifier">chunk_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">print_ret</span><span class="plain"> </span><span class="string">"*** BlkValueRead: reading from index out of range: "</span><span class="plain">, </span><span class="identifier">pos</span><span class="plain">, </span><span class="string">" in "</span><span class="plain">, </span><span class="identifier">from</span><span class="plain">, </span><span class="string">" ***"</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
|
|
<span class="plain">[ </span><span class="identifier">BlkValueWrite</span><span class="plain"> </span><span class="reserved">to</span><span class="plain"> </span><span class="identifier">pos</span><span class="plain"> </span><span class="identifier">val</span><span class="plain"> </span><span class="identifier">do_not_indirect</span>
|
|
<span class="identifier">long_block</span><span class="plain"> </span><span class="identifier">chunk_size_in_bytes</span><span class="plain"> </span><span class="identifier">header_size_in_bytes</span><span class="plain"> </span><span class="identifier">flags</span><span class="plain"> </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> </span><span class="identifier">seek_byte_position</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="reserved">to</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">rfalse</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">do_not_indirect</span><span class="plain">)</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="reserved">to</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="identifier">BlkMakeMutable</span><span class="plain">(</span><span class="reserved">to</span><span class="plain">);</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="reserved">to</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="identifier">flags</span><span class="plain"> = </span><span class="identifier">long_block</span><span class="plain">-></span><span class="identifier">BLK_HEADER_FLAGS</span><span class="plain">;</span>
|
|
<span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="constant">1</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_16_BIT</span><span class="plain">) </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="constant">2</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_WORD</span><span class="plain">) </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="identifier">WORDSIZE</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_MULTIPLE</span><span class="plain">) </span><span class="identifier">header_size_in_bytes</span><span class="plain"> = </span><span class="identifier">BLK_DATA_MULTI_OFFSET</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">header_size_in_bytes</span><span class="plain"> = </span><span class="identifier">BLK_DATA_OFFSET</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">seek_byte_position</span><span class="plain"> = </span><span class="identifier">pos</span><span class="plain">*</span><span class="identifier">entry_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (:</span><span class="identifier">long_block</span><span class="plain">~=</span><span class="identifier">NULL</span><span class="plain">:</span><span class="identifier">long_block</span><span class="plain">=</span><span class="identifier">long_block</span><span class="plain">--></span><span class="identifier">BLK_NEXT</span><span class="plain">) {</span>
|
|
<span class="identifier">chunk_size_in_bytes</span><span class="plain"> = </span><span class="identifier">FlexSize</span><span class="plain">(</span><span class="identifier">long_block</span><span class="plain">) - </span><span class="identifier">header_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">seek_byte_position</span><span class="plain"> >= </span><span class="constant">0</span><span class="plain">) && (</span><span class="identifier">seek_byte_position</span><span class="plain"><</span><span class="identifier">chunk_size_in_bytes</span><span class="plain">)) {</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="identifier">long_block</span><span class="plain"> + </span><span class="identifier">header_size_in_bytes</span><span class="plain"> + </span><span class="identifier">seek_byte_position</span><span class="plain">;</span>
|
|
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">entry_size_in_bytes</span><span class="plain">) {</span>
|
|
<span class="constant">1</span><span class="plain">: </span><span class="identifier">long_block</span><span class="plain">->0 = </span><span class="identifier">val</span><span class="plain">;</span>
|
|
<span class="constant">2</span><span class="plain">: #</span><span class="identifier">Iftrue</span><span class="plain"> (</span><span class="identifier">WORDSIZE</span><span class="plain"> == </span><span class="constant">2</span><span class="plain">); </span><span class="identifier">long_block</span><span class="plain">-->0 = </span><span class="identifier">val</span><span class="plain">;</span>
|
|
<span class="plain">#</span><span class="identifier">ifnot</span><span class="plain">; </span><span class="identifier">long_block</span><span class="plain">->0 = (</span><span class="identifier">val</span><span class="plain">/256)%256; </span><span class="identifier">long_block</span><span class="plain">->1 = </span><span class="identifier">val</span><span class="plain">%256;</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span><span class="plain">;</span>
|
|
<span class="constant">4</span><span class="plain">: </span><span class="identifier">long_block</span><span class="plain">-->0 = </span><span class="identifier">val</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">seek_byte_position</span><span class="plain"> = </span><span class="identifier">seek_byte_position</span><span class="plain"> - </span><span class="identifier">chunk_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">print_ret</span><span class="plain"> </span><span class="string">"*** BlkValueWrite: writing to index out of range: "</span><span class="plain">, </span><span class="identifier">pos</span><span class="plain">, </span><span class="string">" in "</span><span class="plain">, </span><span class="reserved">to</span><span class="plain">, </span><span class="string">" ***"</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP9"></a><b>§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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueSeekZeroEntry</span><span class="plain"> </span><span class="identifier">from</span>
|
|
<span class="identifier">long_block</span><span class="plain"> </span><span class="identifier">chunk_size_in_bytes</span><span class="plain"> </span><span class="identifier">header_size_in_bytes</span><span class="plain"> </span><span class="identifier">flags</span><span class="plain"> </span><span class="identifier">entry_size_in_bytes</span>
|
|
<span class="identifier">byte_position</span><span class="plain"> </span><span class="identifier">addr</span><span class="plain"> </span><span class="identifier">from_addr</span><span class="plain"> </span><span class="identifier">to_addr</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">from</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> -1;</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="identifier">from</span><span class="plain">);</span>
|
|
|
|
<span class="identifier">flags</span><span class="plain"> = </span><span class="identifier">long_block</span><span class="plain">-></span><span class="identifier">BLK_HEADER_FLAGS</span><span class="plain">;</span>
|
|
<span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="constant">1</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_16_BIT</span><span class="plain">) </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="constant">2</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_WORD</span><span class="plain">) </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="identifier">WORDSIZE</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_MULTIPLE</span><span class="plain">) </span><span class="identifier">header_size_in_bytes</span><span class="plain"> = </span><span class="identifier">BLK_DATA_MULTI_OFFSET</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">header_size_in_bytes</span><span class="plain"> = </span><span class="identifier">BLK_DATA_OFFSET</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">byte_position</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (: </span><span class="identifier">long_block</span><span class="plain">~=</span><span class="identifier">NULL</span><span class="plain">: </span><span class="identifier">long_block</span><span class="plain">=</span><span class="identifier">long_block</span><span class="plain">--></span><span class="identifier">BLK_NEXT</span><span class="plain">) {</span>
|
|
<span class="identifier">chunk_size_in_bytes</span><span class="plain"> = </span><span class="identifier">FlexSize</span><span class="plain">(</span><span class="identifier">long_block</span><span class="plain">) - </span><span class="identifier">header_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="identifier">from_addr</span><span class="plain"> = </span><span class="identifier">long_block</span><span class="plain"> + </span><span class="identifier">header_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="identifier">to_addr</span><span class="plain"> = </span><span class="identifier">from_addr</span><span class="plain"> + </span><span class="identifier">chunk_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">entry_size_in_bytes</span><span class="plain">) {</span>
|
|
<span class="constant">1</span><span class="plain">:</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">addr</span><span class="plain"> = </span><span class="identifier">from_addr</span><span class="plain">: </span><span class="identifier">addr</span><span class="plain"> < </span><span class="identifier">to_addr</span><span class="plain">: </span><span class="identifier">addr</span><span class="plain">++)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">addr</span><span class="plain">->0 == </span><span class="constant">0</span><span class="plain">)</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">byte_position</span><span class="plain"> + </span><span class="identifier">addr</span><span class="plain"> - </span><span class="identifier">from_addr</span><span class="plain">;</span>
|
|
<span class="constant">2</span><span class="plain">:</span>
|
|
<span class="plain">#</span><span class="identifier">iftrue</span><span class="plain"> </span><span class="identifier">WORDSIZE</span><span class="plain"> == </span><span class="constant">2</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">addr</span><span class="plain"> = </span><span class="identifier">from_addr</span><span class="plain">: </span><span class="identifier">addr</span><span class="plain"> < </span><span class="identifier">to_addr</span><span class="plain">: </span><span class="identifier">addr</span><span class="plain">=</span><span class="identifier">addr</span><span class="plain">+2)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">addr</span><span class="plain">-->0 == </span><span class="constant">0</span><span class="plain">)</span>
|
|
<span class="reserved">return</span><span class="plain"> (</span><span class="identifier">byte_position</span><span class="plain"> + </span><span class="identifier">addr</span><span class="plain"> - </span><span class="identifier">from_addr</span><span class="plain">)/2;</span>
|
|
<span class="plain">#</span><span class="identifier">ifnot</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">addr</span><span class="plain"> = </span><span class="identifier">from_addr</span><span class="plain">: </span><span class="identifier">addr</span><span class="plain"> < </span><span class="identifier">to_addr</span><span class="plain">: </span><span class="identifier">addr</span><span class="plain">=</span><span class="identifier">addr</span><span class="plain">+2)</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">addr</span><span class="plain">->0 == </span><span class="constant">0</span><span class="plain">) && (</span><span class="identifier">addr</span><span class="plain">->1 == </span><span class="constant">0</span><span class="plain">))</span>
|
|
<span class="reserved">return</span><span class="plain"> (</span><span class="identifier">byte_position</span><span class="plain"> + </span><span class="identifier">addr</span><span class="plain"> - </span><span class="identifier">from_addr</span><span class="plain">)/2;</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span><span class="plain">;</span>
|
|
<span class="constant">4</span><span class="plain">:</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">addr</span><span class="plain"> = </span><span class="identifier">from_addr</span><span class="plain">: </span><span class="identifier">addr</span><span class="plain"> < </span><span class="identifier">to_addr</span><span class="plain">: </span><span class="identifier">addr</span><span class="plain">=</span><span class="identifier">addr</span><span class="plain">+4)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">addr</span><span class="plain">-->0 == </span><span class="constant">0</span><span class="plain">)</span>
|
|
<span class="reserved">return</span><span class="plain"> (</span><span class="identifier">byte_position</span><span class="plain"> + </span><span class="identifier">addr</span><span class="plain"> - </span><span class="identifier">from_addr</span><span class="plain">)/4;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">byte_position</span><span class="plain"> = </span><span class="identifier">byte_position</span><span class="plain"> + </span><span class="identifier">chunk_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> -1;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP10"></a><b>§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="display">
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">n</span><span class="plain">=0: </span><span class="identifier">n</span><span class="plain"><</span><span class="identifier">no_entries_to_copy</span><span class="plain">: </span><span class="identifier">n</span><span class="plain">++)</span>
|
|
<span class="identifier">BlkValueWrite</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">n</span><span class="plain">, </span><span class="identifier">BlkValueRead</span><span class="plain">(</span><span class="identifier">from_bv</span><span class="plain">, </span><span class="identifier">n</span><span class="plain">));</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">but it's much, much faster, and runs in a reasonably small number of cycles
|
|
given what it needs to do.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueMassCopyEntries</span><span class="plain"> </span><span class="identifier">to_bv</span><span class="plain"> </span><span class="identifier">from_bv</span><span class="plain"> </span><span class="identifier">no_entries_to_copy</span>
|
|
<span class="identifier">from_long_block</span><span class="plain"> </span><span class="identifier">from_addr</span><span class="plain"> </span><span class="identifier">from_bytes_left</span><span class="plain"> </span><span class="identifier">from_header_size_in_bytes</span>
|
|
<span class="identifier">to_long_block</span><span class="plain"> </span><span class="identifier">to_addr</span><span class="plain"> </span><span class="identifier">to_bytes_left</span><span class="plain"> </span><span class="identifier">to_header_size_in_bytes</span>
|
|
<span class="identifier">bytes_to_copy</span><span class="plain"> </span><span class="identifier">flags</span><span class="plain"> </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> </span><span class="identifier">min</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">BlkMakeMutable</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">);</span>
|
|
|
|
<span class="identifier">from_long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="identifier">from_bv</span><span class="plain">);</span>
|
|
<span class="identifier">to_long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">);</span>
|
|
|
|
<span class="identifier">flags</span><span class="plain"> = </span><span class="identifier">from_long_block</span><span class="plain">-></span><span class="identifier">BLK_HEADER_FLAGS</span><span class="plain">;</span>
|
|
<span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="constant">1</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_16_BIT</span><span class="plain">) </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="constant">2</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_WORD</span><span class="plain">) </span><span class="identifier">entry_size_in_bytes</span><span class="plain"> = </span><span class="identifier">WORDSIZE</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">flags</span><span class="plain"> & (</span><span class="identifier">BLK_FLAG_MULTIPLE</span><span class="plain"> + </span><span class="identifier">BLK_FLAG_TRUNCMULT</span><span class="plain">)) &&</span>
|
|
<span class="plain">(</span><span class="identifier">BlkValueSetLBCapacity</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">no_entries_to_copy</span><span class="plain">) == </span><span class="reserved">false</span><span class="plain">))</span>
|
|
<span class="identifier">BlkValueError</span><span class="plain">(</span><span class="string">"copy resizing failed"</span><span class="plain">);</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_MULTIPLE</span><span class="plain">) </span><span class="identifier">from_header_size_in_bytes</span><span class="plain"> = </span><span class="identifier">BLK_DATA_MULTI_OFFSET</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">from_header_size_in_bytes</span><span class="plain"> = </span><span class="identifier">BLK_DATA_OFFSET</span><span class="plain">;</span>
|
|
<span class="identifier">flags</span><span class="plain"> = </span><span class="identifier">to_long_block</span><span class="plain">-></span><span class="identifier">BLK_HEADER_FLAGS</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_MULTIPLE</span><span class="plain">) </span><span class="identifier">to_header_size_in_bytes</span><span class="plain"> = </span><span class="identifier">BLK_DATA_MULTI_OFFSET</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">to_header_size_in_bytes</span><span class="plain"> = </span><span class="identifier">BLK_DATA_OFFSET</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">from_addr</span><span class="plain"> = </span><span class="identifier">from_long_block</span><span class="plain"> + </span><span class="identifier">from_header_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="identifier">from_bytes_left</span><span class="plain"> = </span><span class="identifier">FlexSize</span><span class="plain">(</span><span class="identifier">from_long_block</span><span class="plain">) - </span><span class="identifier">from_header_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="identifier">to_addr</span><span class="plain"> = </span><span class="identifier">to_long_block</span><span class="plain"> + </span><span class="identifier">to_header_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="identifier">to_bytes_left</span><span class="plain"> = </span><span class="identifier">FlexSize</span><span class="plain">(</span><span class="identifier">to_long_block</span><span class="plain">) - </span><span class="identifier">to_header_size_in_bytes</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">bytes_to_copy</span><span class="plain"> = </span><span class="identifier">entry_size_in_bytes</span><span class="plain">*</span><span class="identifier">no_entries_to_copy</span><span class="plain">;</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="reserved">true</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">from_bytes_left</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) {</span>
|
|
<span class="identifier">from_long_block</span><span class="plain"> = </span><span class="identifier">from_long_block</span><span class="plain">--></span><span class="identifier">BLK_NEXT</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">from_long_block</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">BlkValueError</span><span class="plain">(</span><span class="string">"copy destination exhausted"</span><span class="plain">);</span>
|
|
<span class="identifier">from_addr</span><span class="plain"> = </span><span class="identifier">from_long_block</span><span class="plain"> + </span><span class="identifier">from_header_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="identifier">from_bytes_left</span><span class="plain"> = </span><span class="identifier">FlexSize</span><span class="plain">(</span><span class="identifier">from_long_block</span><span class="plain">) - </span><span class="identifier">from_header_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">to_bytes_left</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) {</span>
|
|
<span class="identifier">to_long_block</span><span class="plain"> = </span><span class="identifier">to_long_block</span><span class="plain">--></span><span class="identifier">BLK_NEXT</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">to_long_block</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">BlkValueError</span><span class="plain">(</span><span class="string">"copy source exhausted"</span><span class="plain">);</span>
|
|
<span class="identifier">to_addr</span><span class="plain"> = </span><span class="identifier">to_long_block</span><span class="plain"> + </span><span class="identifier">to_header_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="identifier">to_bytes_left</span><span class="plain"> = </span><span class="identifier">FlexSize</span><span class="plain">(</span><span class="identifier">to_long_block</span><span class="plain">) - </span><span class="identifier">to_header_size_in_bytes</span><span class="plain">;</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="identifier">min</span><span class="plain"> = </span><span class="identifier">from_bytes_left</span><span class="plain">; </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">to_bytes_left</span><span class="plain"> < </span><span class="identifier">min</span><span class="plain">) </span><span class="identifier">min</span><span class="plain"> = </span><span class="identifier">to_bytes_left</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">bytes_to_copy</span><span class="plain"> <= </span><span class="identifier">min</span><span class="plain">) {</span>
|
|
<span class="identifier">Memcpy</span><span class="plain">(</span><span class="identifier">to_addr</span><span class="plain">, </span><span class="identifier">from_addr</span><span class="plain">, </span><span class="identifier">bytes_to_copy</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">Memcpy</span><span class="plain">(</span><span class="identifier">to_addr</span><span class="plain">, </span><span class="identifier">from_addr</span><span class="plain">, </span><span class="identifier">min</span><span class="plain">);</span>
|
|
<span class="identifier">bytes_to_copy</span><span class="plain"> = </span><span class="identifier">bytes_to_copy</span><span class="plain"> - </span><span class="identifier">min</span><span class="plain">;</span>
|
|
<span class="identifier">from_addr</span><span class="plain"> = </span><span class="identifier">from_addr</span><span class="plain"> + </span><span class="identifier">min</span><span class="plain">;</span>
|
|
<span class="identifier">from_bytes_left</span><span class="plain"> = </span><span class="identifier">from_bytes_left</span><span class="plain"> - </span><span class="identifier">min</span><span class="plain">;</span>
|
|
<span class="identifier">to_addr</span><span class="plain"> = </span><span class="identifier">to_addr</span><span class="plain"> + </span><span class="identifier">min</span><span class="plain">;</span>
|
|
<span class="identifier">to_bytes_left</span><span class="plain"> = </span><span class="identifier">to_bytes_left</span><span class="plain"> - </span><span class="identifier">min</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP11"></a><b>§11. Mass Copy From Array. </b>The following is helpful when reading an array of characters into a text:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueMassCopyFromArray</span><span class="plain"> </span><span class="identifier">to_bv</span><span class="plain"> </span><span class="identifier">from_array</span><span class="plain"> </span><span class="identifier">from_entry_size</span><span class="plain"> </span><span class="identifier">no_entries_to_copy</span>
|
|
<span class="identifier">to_long_block</span><span class="plain"> </span><span class="identifier">to_addr</span><span class="plain"> </span><span class="identifier">to_entries_left</span><span class="plain"> </span><span class="identifier">to_header_size</span><span class="plain"> </span><span class="identifier">to_entry_size</span>
|
|
<span class="identifier">flags</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">BlkMakeMutable</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">);</span>
|
|
|
|
<span class="identifier">to_long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">);</span>
|
|
|
|
<span class="identifier">flags</span><span class="plain"> = </span><span class="identifier">to_long_block</span><span class="plain">-></span><span class="identifier">BLK_HEADER_FLAGS</span><span class="plain">;</span>
|
|
<span class="identifier">to_entry_size</span><span class="plain"> = </span><span class="constant">1</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_16_BIT</span><span class="plain">) </span><span class="identifier">to_entry_size</span><span class="plain"> = </span><span class="constant">2</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_WORD</span><span class="plain">) </span><span class="identifier">to_entry_size</span><span class="plain"> = </span><span class="identifier">WORDSIZE</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">flags</span><span class="plain"> & (</span><span class="identifier">BLK_FLAG_MULTIPLE</span><span class="plain"> + </span><span class="identifier">BLK_FLAG_TRUNCMULT</span><span class="plain">)) &&</span>
|
|
<span class="plain">(</span><span class="identifier">BlkValueSetLBCapacity</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">no_entries_to_copy</span><span class="plain">) == </span><span class="reserved">false</span><span class="plain">))</span>
|
|
<span class="identifier">BlkValueError</span><span class="plain">(</span><span class="string">"copy resizing failed"</span><span class="plain">);</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flags</span><span class="plain"> & </span><span class="identifier">BLK_FLAG_MULTIPLE</span><span class="plain">) </span><span class="identifier">to_header_size</span><span class="plain"> = </span><span class="identifier">BLK_DATA_MULTI_OFFSET</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">to_header_size</span><span class="plain"> = </span><span class="identifier">BLK_DATA_OFFSET</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">to_addr</span><span class="plain"> = </span><span class="identifier">to_long_block</span><span class="plain"> + </span><span class="identifier">to_header_size</span><span class="plain">;</span>
|
|
<span class="identifier">to_entries_left</span><span class="plain"> = (</span><span class="identifier">FlexSize</span><span class="plain">(</span><span class="identifier">to_long_block</span><span class="plain">) - </span><span class="identifier">to_header_size</span><span class="plain">)/</span><span class="identifier">to_entry_size</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">no_entries_to_copy</span><span class="plain"> > </span><span class="identifier">to_entries_left</span><span class="plain">) {</span>
|
|
<span class="identifier">Arrcpy</span><span class="plain">(</span><span class="identifier">to_addr</span><span class="plain">, </span><span class="identifier">to_entry_size</span><span class="plain">, </span><span class="identifier">from_array</span><span class="plain">, </span><span class="identifier">from_entry_size</span><span class="plain">, </span><span class="identifier">to_entries_left</span><span class="plain">);</span>
|
|
<span class="identifier">no_entries_to_copy</span><span class="plain"> = </span><span class="identifier">no_entries_to_copy</span><span class="plain"> - </span><span class="identifier">to_entries_left</span><span class="plain">;</span>
|
|
<span class="identifier">from_array</span><span class="plain"> = </span><span class="identifier">from_array</span><span class="plain"> + </span><span class="identifier">to_entries_left</span><span class="plain">*</span><span class="identifier">from_entry_size</span><span class="plain">;</span>
|
|
<span class="identifier">to_long_block</span><span class="plain"> = </span><span class="identifier">to_long_block</span><span class="plain">--></span><span class="identifier">BLK_NEXT</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">to_long_block</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">BlkValueError</span><span class="plain">(</span><span class="string">"copy source exhausted"</span><span class="plain">);</span>
|
|
<span class="identifier">to_addr</span><span class="plain"> = </span><span class="identifier">to_long_block</span><span class="plain"> + </span><span class="identifier">to_header_size</span><span class="plain">;</span>
|
|
<span class="identifier">to_entries_left</span><span class="plain"> = (</span><span class="identifier">FlexSize</span><span class="plain">(</span><span class="identifier">to_long_block</span><span class="plain">) - </span><span class="identifier">to_header_size</span><span class="plain">)/</span><span class="identifier">to_entry_size</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">no_entries_to_copy</span><span class="plain"> > </span><span class="constant">0</span><span class="plain">) {</span>
|
|
<span class="identifier">Arrcpy</span><span class="plain">(</span><span class="identifier">to_addr</span><span class="plain">, </span><span class="identifier">to_entry_size</span><span class="plain">, </span><span class="identifier">from_array</span><span class="plain">, </span><span class="identifier">from_entry_size</span><span class="plain">, </span><span class="identifier">no_entries_to_copy</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP12"></a><b>§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
|
|
<code class="display"><span class="extract">_Support</span></code>: that is, the support function for <code class="display"><span class="extract">TEXT_TY</span></code> is called
|
|
<code class="display"><span class="extract">TEXT_TY_Support</span></code> and so on.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">I7 automatically compiles a function called <code class="display"><span class="extract">KOVSupportFunction</span></code> 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="inwebparagraph">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="display">
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">CREATE_KOVS</span><span class="plain"> = </span><span class="constant">1</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">CAST_KOVS</span><span class="plain"> = </span><span class="constant">2</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">DESTROY_KOVS</span><span class="plain"> = </span><span class="constant">3</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">MAKEMUTABLE_KOVS</span><span class="plain"> = </span><span class="constant">4</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">COPYKIND_KOVS</span><span class="plain"> = </span><span class="constant">5</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">EXTENT_KOVS</span><span class="plain"> = </span><span class="constant">6</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">COPYQUICK_KOVS</span><span class="plain"> = </span><span class="constant">7</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">COPYSB_KOVS</span><span class="plain"> = </span><span class="constant">8</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">KINDDATA_KOVS</span><span class="plain"> = </span><span class="constant">9</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">COPY_KOVS</span><span class="plain"> = </span><span class="constant">10</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">COMPARE_KOVS</span><span class="plain"> = </span><span class="constant">11</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">READ_FILE_KOVS</span><span class="plain"> = </span><span class="constant">12</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">WRITE_FILE_KOVS</span><span class="plain"> = </span><span class="constant">13</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">HASH_KOVS</span><span class="plain"> = </span><span class="constant">14</span><span class="plain">;</span>
|
|
<span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">DEBUG_KOVS</span><span class="plain"> = </span><span class="constant">15</span><span class="plain">;</span>
|
|
|
|
<span class="plain">! </span><span class="reserved">Constant</span><span class="plain"> </span><span class="identifier">BLKVALUE_TRACE</span><span class="plain">; </span><span class="comment">Uncomment this to expose masses of tracery</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP13"></a><b>§13. Creation. </b>To create a block value, call:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">BlkValueCreate</span><span class="plain">(</span><span class="identifier">kind</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">where <code class="display"><span class="extract">K</span></code> is its (strong) kind ID. Optionally, call:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">BlkValueCreate</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">, </span><span class="identifier">short_block</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">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="inwebparagraph">These work by delegating to:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">CREATE_KOVS</span><span class="plain">, </span><span class="identifier">strong_kind</span><span class="plain">, </span><span class="identifier">short_block</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">which returns the address of the short block for the new value.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueCreate</span><span class="plain"> </span><span class="identifier">strong_kind</span><span class="plain"> </span><span class="identifier">short_block</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">kovs</span><span class="plain"> = </span><span class="identifier">KOVSupportFunction</span><span class="plain">(</span><span class="identifier">strong_kind</span><span class="plain">, </span><span class="string">"impossible allocation"</span><span class="plain">);</span>
|
|
<span class="identifier">short_block</span><span class="plain"> = </span><span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">CREATE_KOVS</span><span class="plain">, </span><span class="identifier">strong_kind</span><span class="plain">, </span><span class="identifier">short_block</span><span class="plain">);</span>
|
|
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">BLKVALUE_TRACE</span><span class="plain">; </span><span class="reserved">print</span><span class="plain"> </span><span class="string">"Created: "</span><span class="plain">, (</span><span class="identifier">BlkValueDebug</span><span class="plain">) </span><span class="identifier">short_block</span><span class="plain">, </span><span class="string">"^"</span><span class="plain">; #</span><span class="identifier">endif</span><span class="plain">;</span>
|
|
|
|
<span class="comment">The new value is represented in I6 as the pointer to its short block:</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">short_block</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP14"></a><b>§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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueError</span><span class="plain"> </span><span class="identifier">reason</span><span class="plain">;</span>
|
|
<span class="reserved">print</span><span class="plain"> </span><span class="string">"*** Value handling failed: "</span><span class="plain">, (</span><span class="reserved">string</span><span class="plain">) </span><span class="identifier">reason</span><span class="plain">, </span><span class="string">" ***^"</span><span class="plain">;</span>
|
|
<span class="identifier">RunTimeProblem</span><span class="plain">(</span><span class="identifier">RTP_HEAPERROR</span><span class="plain">);</span>
|
|
<span class="plain">@</span><span class="reserved">quit</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP15"></a><b>§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
|
|
<code class="display"><span class="extract">short_block</span></code> 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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueCreateSB1</span><span class="plain"> </span><span class="identifier">short_block</span><span class="plain"> </span><span class="identifier">val</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">short_block</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">)</span>
|
|
<span class="identifier">short_block</span><span class="plain"> = </span><span class="identifier">FlexAllocate</span><span class="plain">(</span><span class="identifier">WORDSIZE</span><span class="plain">, </span><span class="constant">0</span><span class="plain">, </span><span class="identifier">BLK_FLAG_WORD</span><span class="plain">) + </span><span class="identifier">BLK_DATA_OFFSET</span><span class="plain">;</span>
|
|
<span class="identifier">short_block</span><span class="plain">-->0 = </span><span class="identifier">val</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">short_block</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
|
|
<span class="plain">[ </span><span class="identifier">BlkValueCreateSB2</span><span class="plain"> </span><span class="identifier">short_block</span><span class="plain"> </span><span class="identifier">val1</span><span class="plain"> </span><span class="identifier">val2</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">short_block</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">)</span>
|
|
<span class="identifier">short_block</span><span class="plain"> = </span><span class="identifier">FlexAllocate</span><span class="plain">(2*</span><span class="identifier">WORDSIZE</span><span class="plain">, </span><span class="constant">0</span><span class="plain">, </span><span class="identifier">BLK_FLAG_WORD</span><span class="plain">) + </span><span class="identifier">BLK_DATA_OFFSET</span><span class="plain">;</span>
|
|
<span class="identifier">short_block</span><span class="plain">-->0 = </span><span class="identifier">val1</span><span class="plain">; </span><span class="identifier">short_block</span><span class="plain">-->1 = </span><span class="identifier">val2</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">short_block</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP16"></a><b>§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="inwebparagraph"><code class="display"><span class="extract">BlkValueCreateOnStack</span></code> acts exactly like <code class="display"><span class="extract">BlkValueCreate</span></code>, 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="display">
|
|
<span class="plain">[ </span><span class="identifier">StackFramingInitialise</span><span class="plain">;</span>
|
|
<span class="identifier">I7SFRAME</span><span class="plain"> = </span><span class="identifier">blockv_stack</span><span class="plain"> + </span><span class="identifier">WORDSIZE</span><span class="plain">*</span><span class="identifier">BLOCKV_STACK_SIZE</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
|
|
<span class="plain">[ </span><span class="identifier">StackFrameCreate</span><span class="plain"> </span><span class="identifier">size</span><span class="plain"> </span><span class="identifier">new</span><span class="plain">;</span>
|
|
<span class="identifier">new</span><span class="plain"> = </span><span class="identifier">I7SFRAME</span><span class="plain"> - </span><span class="identifier">WORDSIZE</span><span class="plain">*</span><span class="identifier">size</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">new</span><span class="plain"> < </span><span class="identifier">blockv_stack</span><span class="plain">) { </span><span class="identifier">RunTimeProblem</span><span class="plain">(</span><span class="identifier">RTP_HEAPERROR</span><span class="plain">); @</span><span class="reserved">quit</span><span class="plain">; }</span>
|
|
<span class="identifier">I7SFRAME</span><span class="plain"> = </span><span class="identifier">new</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
|
|
<span class="plain">[ </span><span class="identifier">BlkValueCreateOnStack</span><span class="plain"> </span><span class="identifier">offset</span><span class="plain"> </span><span class="identifier">strong_kind</span><span class="plain">;</span>
|
|
<span class="identifier">BlkValueCreate</span><span class="plain">(</span><span class="identifier">strong_kind</span><span class="plain">, </span><span class="identifier">I7SFRAME</span><span class="plain"> + </span><span class="identifier">WORDSIZE</span><span class="plain">*</span><span class="identifier">offset</span><span class="plain">);</span>
|
|
<span class="plain">];</span>
|
|
|
|
<span class="plain">[ </span><span class="identifier">BlkValueFreeOnStack</span><span class="plain"> </span><span class="identifier">offset</span><span class="plain">;</span>
|
|
<span class="identifier">BlkValueFree</span><span class="plain">(</span><span class="identifier">I7SFRAME</span><span class="plain"> + </span><span class="identifier">WORDSIZE</span><span class="plain">*</span><span class="identifier">offset</span><span class="plain">);</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP17"></a><b>§17. Freeing. </b>As noted above, every value returned by <code class="display"><span class="extract">BlkValueCreate</span></code> must later be
|
|
freed by calling the following routine exactly once:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">BlkValueFree</span><span class="plain">(</span><span class="identifier">value</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">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="inwebparagraph">As noted above, short blocks are sometimes created within Flex blocks on
|
|
the heap, using <code class="display"><span class="extract">FlexAllocate</span></code>; and if this is one of those, we need to free
|
|
the relevant Flex block.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueFree</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain"> </span><span class="identifier">d</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">bv</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
|
|
<span class="comment">Dispose of any data in the long block</span>
|
|
<span class="identifier">kovs</span><span class="plain"> = </span><span class="identifier">KOVSupportFunction</span><span class="plain">(</span><span class="identifier">BlkValueWeakKind</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">), </span><span class="string">"impossible deallocation"</span><span class="plain">);</span>
|
|
<span class="identifier">BlkValueDestroyPrimitive</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">, </span><span class="identifier">kovs</span><span class="plain">);</span>
|
|
|
|
<span class="comment">Free any heap memory occupied by the short block</span>
|
|
<span class="identifier">d</span><span class="plain"> = </span><span class="identifier">bv</span><span class="plain"> - </span><span class="identifier">Flex_Heap</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">d</span><span class="plain"> >= </span><span class="constant">0</span><span class="plain">) && (</span><span class="identifier">d</span><span class="plain"> < </span><span class="identifier">MEMORY_HEAP_SIZE</span><span class="plain"> + </span><span class="constant">16</span><span class="plain">))</span>
|
|
<span class="identifier">FlexFree</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain"> - </span><span class="identifier">BLK_DATA_OFFSET</span><span class="plain">);</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP18"></a><b>§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="inwebparagraph">The support function should respond to:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">COPYSB_KOVS</span><span class="plain">, </span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">from_bv</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">by copying the short blocks alone.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueQuickCopyPrimitive</span><span class="plain"> </span><span class="identifier">to_bv</span><span class="plain"> </span><span class="identifier">from_bv</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">;</span>
|
|
<span class="identifier">BlkValueDestroyPrimitive</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">kovs</span><span class="plain">);</span>
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">COPYSB_KOVS</span><span class="plain">, </span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">from_bv</span><span class="plain">);</span>
|
|
<span class="identifier">BlkValueIncRefCountPrimitive</span><span class="plain">(</span><span class="identifier">from_bv</span><span class="plain">);</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP19"></a><b>§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 <code class="display"><span class="extract">COPYSB_KOVS</span></code> 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 <code class="display"><span class="extract">from_bv</span></code>, it won't be true in <code class="display"><span class="extract">to_bv</span></code>, so we must correct it.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueCopySB1</span><span class="plain"> </span><span class="identifier">to_bv</span><span class="plain"> </span><span class="identifier">from_bv</span><span class="plain">;</span>
|
|
<span class="identifier">to_bv</span><span class="plain">-->0 = </span><span class="identifier">from_bv</span><span class="plain">-->0;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">to_bv</span><span class="plain">-->0 == </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">to_bv</span><span class="plain">-->0 = </span><span class="identifier">from_bv</span><span class="plain"> + </span><span class="identifier">WORDSIZE</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
|
|
<span class="plain">[ </span><span class="identifier">BlkValueCopySB2</span><span class="plain"> </span><span class="identifier">to_bv</span><span class="plain"> </span><span class="identifier">from_bv</span><span class="plain">;</span>
|
|
<span class="identifier">to_bv</span><span class="plain">-->0 = </span><span class="identifier">from_bv</span><span class="plain">-->0;</span>
|
|
<span class="identifier">to_bv</span><span class="plain">-->1 = </span><span class="identifier">from_bv</span><span class="plain">-->1;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">to_bv</span><span class="plain">-->1 == </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">to_bv</span><span class="plain">-->1 = </span><span class="identifier">from_bv</span><span class="plain"> + </span><span class="constant">2</span><span class="plain">*</span><span class="identifier">WORDSIZE</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP20"></a><b>§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="inwebparagraph">We first call:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">KINDDATA_KOVS</span><span class="plain">, </span><span class="identifier">to_bv</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">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="inwebparagraph">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="inwebparagraph">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="display">
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">COPY_KOVS</span><span class="plain">, </span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">from_bv</span><span class="plain">, </span><span class="identifier">k</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">This is where the KOVS should make a proper copy, using <code class="display"><span class="extract">BlkValueCopy</span></code> 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 <code class="display"><span class="extract">k</span></code>
|
|
is the value given us by <code class="display"><span class="extract">KINDDATA_KOVS</span></code>.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueSlowCopyPrimitive</span><span class="plain"> </span><span class="identifier">to_bv</span><span class="plain"> </span><span class="identifier">from_bv</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain"> </span><span class="identifier">recycling</span>
|
|
<span class="identifier">k</span><span class="plain"> </span><span class="identifier">from_long_block</span><span class="plain"> </span><span class="identifier">no_entries_to_copy</span><span class="plain">;</span>
|
|
<span class="identifier">k</span><span class="plain"> = </span><span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">KINDDATA_KOVS</span><span class="plain">, </span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">from_bv</span><span class="plain">);</span>
|
|
|
|
<span class="identifier">from_long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="identifier">from_bv</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">from_long_block</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">recycling</span><span class="plain">) </span><span class="identifier">BlkValueRecyclePrimitive</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">kovs</span><span class="plain">);</span>
|
|
<span class="identifier">no_entries_to_copy</span><span class="plain"> = </span><span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">EXTENT_KOVS</span><span class="plain">, </span><span class="identifier">from_bv</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">no_entries_to_copy</span><span class="plain"> == -1) </span><span class="identifier">no_entries_to_copy</span><span class="plain"> = </span><span class="identifier">BlkValueLBCapacity</span><span class="plain">(</span><span class="identifier">from_bv</span><span class="plain">);</span>
|
|
<span class="identifier">BlkValueMassCopyEntries</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">from_bv</span><span class="plain">, </span><span class="identifier">no_entries_to_copy</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">COPY_KOVS</span><span class="plain">, </span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">from_bv</span><span class="plain">, </span><span class="identifier">k</span><span class="plain">);</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP21"></a><b>§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="display">
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">COPYQUICK_KOVS</span><span class="plain">, </span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">from_bv</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">which should return true if a quick copy is okay, or false if not.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueCopy</span><span class="plain"> </span><span class="identifier">to_bv</span><span class="plain"> </span><span class="identifier">from_bv</span><span class="plain"> </span><span class="identifier">to_kind</span><span class="plain"> </span><span class="identifier">from_kind</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">to_bv</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">BlkValueError</span><span class="plain">(</span><span class="string">"copy to null value"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">from_bv</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">BlkValueError</span><span class="plain">(</span><span class="string">"copy from null value"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">to_bv</span><span class="plain"> == </span><span class="identifier">from_bv</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">BLKVALUE_TRACE</span><span class="plain">;</span>
|
|
<span class="reserved">print</span><span class="plain"> </span><span class="string">"Copy: "</span><span class="plain">, (</span><span class="identifier">BlkValueDebug</span><span class="plain">) </span><span class="identifier">to_bv</span><span class="plain">, </span><span class="string">" to equal "</span><span class="plain">, (</span><span class="identifier">BlkValueDebug</span><span class="plain">) </span><span class="identifier">from_bv</span><span class="plain">, </span><span class="string">"^"</span><span class="plain">;</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">to_kind</span><span class="plain"> = </span><span class="identifier">BlkValueWeakKind</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">);</span>
|
|
<span class="identifier">from_kind</span><span class="plain"> = </span><span class="identifier">BlkValueWeakKind</span><span class="plain">(</span><span class="identifier">from_bv</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">to_kind</span><span class="plain"> ~= </span><span class="identifier">from_kind</span><span class="plain">) </span><span class="identifier">BlkValueError</span><span class="plain">(</span><span class="string">"copy incompatible kinds"</span><span class="plain">);</span>
|
|
|
|
<span class="identifier">kovs</span><span class="plain"> = </span><span class="identifier">KOVSupportFunction</span><span class="plain">(</span><span class="identifier">to_kind</span><span class="plain">, </span><span class="string">"impossible copy"</span><span class="plain">);</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">COPYQUICK_KOVS</span><span class="plain">, </span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">from_bv</span><span class="plain">))</span>
|
|
<span class="identifier">BlkValueQuickCopyPrimitive</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">from_bv</span><span class="plain">, </span><span class="identifier">kovs</span><span class="plain">);</span>
|
|
<span class="reserved">else</span>
|
|
<span class="identifier">BlkValueSlowCopyPrimitive</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">from_bv</span><span class="plain">, </span><span class="identifier">kovs</span><span class="plain">, </span><span class="reserved">true</span><span class="plain">);</span>
|
|
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">to_bv</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
|
|
<span class="plain">[ </span><span class="identifier">BlkValueCopyAZ</span><span class="plain"> </span><span class="identifier">to_bv</span><span class="plain"> </span><span class="identifier">from_bv</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">from_bv</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">BlkValueCopy</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">from_bv</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">to_bv</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP22"></a><b>§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="inwebparagraph">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="display">
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">DESTROY_KOVS</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueDestroyPrimitive</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain"> </span><span class="identifier">long_block</span><span class="plain">;</span>
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">BLKVALUE_TRACE</span><span class="plain">; </span><span class="reserved">print</span><span class="plain"> </span><span class="string">"Destroying "</span><span class="plain">, (</span><span class="identifier">BlkValueDebug</span><span class="plain">) </span><span class="identifier">bv</span><span class="plain">, </span><span class="string">"^"</span><span class="plain">; #</span><span class="identifier">endif</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">BlkValueDecRefCountPrimitive</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">) == </span><span class="constant">0</span><span class="plain">) {</span>
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">DESTROY_KOVS</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">long_block</span><span class="plain">) </span><span class="identifier">FlexFree</span><span class="plain">(</span><span class="identifier">long_block</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP23"></a><b>§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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueRecyclePrimitive</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">;</span>
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">BLKVALUE_TRACE</span><span class="plain">; </span><span class="reserved">print</span><span class="plain"> </span><span class="string">"Recycling "</span><span class="plain">, (</span><span class="identifier">BlkValueDebug</span><span class="plain">) </span><span class="identifier">bv</span><span class="plain">, </span><span class="string">"^"</span><span class="plain">; #</span><span class="identifier">endif</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">BlkValueDecRefCountPrimitive</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">) == </span><span class="constant">0</span><span class="plain">) {</span>
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">DESTROY_KOVS</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="identifier">BlkValueIncRefCountPrimitive</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="identifier">BlkValueCreate</span><span class="plain">(</span><span class="identifier">BlkValueWeakKind</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">), </span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP24"></a><b>§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="inwebparagraph">We offer the KOVS a chance to handle this for us:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">MAKEMUTABLE_KOVS</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkMakeMutable</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">block</span><span class="plain"> </span><span class="identifier">bv_kind</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain"> </span><span class="identifier">sb_size</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">bv</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">BlkValueError</span><span class="plain">(</span><span class="string">"tried to make null block mutable"</span><span class="plain">);</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">BlkValueGetRefCountPrimitive</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">) > </span><span class="constant">1</span><span class="plain">) {</span>
|
|
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">BLKVALUE_TRACE</span><span class="plain">; </span><span class="reserved">print</span><span class="plain"> </span><span class="string">"Make mutable: "</span><span class="plain">, (</span><span class="identifier">BlkValueDebug</span><span class="plain">) </span><span class="identifier">bv</span><span class="plain">, </span><span class="string">"^"</span><span class="plain">; #</span><span class="identifier">endif</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">BlkValueDecRefCountPrimitive</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">);</span>
|
|
|
|
<span class="identifier">bv_kind</span><span class="plain"> = </span><span class="identifier">BlkValueWeakKind</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="identifier">kovs</span><span class="plain"> = </span><span class="identifier">KOVSupportFunction</span><span class="plain">(</span><span class="identifier">bv_kind</span><span class="plain">, </span><span class="string">"impossible mutability"</span><span class="plain">);</span>
|
|
|
|
<span class="identifier">sb_size</span><span class="plain"> = </span><span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">MAKEMUTABLE_KOVS</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">sb_size</span><span class="plain"> > </span><span class="constant">0</span><span class="plain">) {</span>
|
|
<span class="plain">@</span><span class="identifier">push</span><span class="plain"> </span><span class="identifier">I7SFRAME</span><span class="plain">;</span>
|
|
<span class="identifier">StackFrameCreate</span><span class="plain">(</span><span class="identifier">sb_size</span><span class="plain">);</span>
|
|
<span class="identifier">BlkValueCreateOnStack</span><span class="plain">(0, </span><span class="identifier">bv_kind</span><span class="plain">);</span>
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">COPYKIND_KOVS</span><span class="plain">, </span><span class="identifier">I7SFRAME</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="identifier">BlkValueSlowCopyPrimitive</span><span class="plain">(</span><span class="identifier">I7SFRAME</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">, </span><span class="identifier">kovs</span><span class="plain">, </span><span class="reserved">false</span><span class="plain">);</span>
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">COPYSB_KOVS</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">, </span><span class="identifier">I7SFRAME</span><span class="plain">);</span>
|
|
<span class="plain">@</span><span class="identifier">pull</span><span class="plain"> </span><span class="identifier">I7SFRAME</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP25"></a><b>§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="display">
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">CAST_KOVS</span><span class="plain">, </span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">original_kind</span><span class="plain">, </span><span class="identifier">original_value</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">casts from the given value, with the given kind, into the existing block
|
|
value <code class="display"><span class="extract">to_bv</span></code>. 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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueCast</span><span class="plain"> </span><span class="identifier">to_bv</span><span class="plain"> </span><span class="identifier">original_kind</span><span class="plain"> </span><span class="identifier">original_value</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">;</span>
|
|
<span class="identifier">kovs</span><span class="plain"> = </span><span class="identifier">KOVSupportFunction</span><span class="plain">(</span><span class="identifier">BlkValueWeakKind</span><span class="plain">(</span><span class="identifier">to_bv</span><span class="plain">), </span><span class="string">"impossible cast"</span><span class="plain">);</span>
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">CAST_KOVS</span><span class="plain">, </span><span class="identifier">to_bv</span><span class="plain">, </span><span class="identifier">original_kind</span><span class="plain">, </span><span class="identifier">original_value</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">to_bv</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP26"></a><b>§26. Comparison. </b>And it's a similar story with comparison:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">COMPARE_KOVS</span><span class="plain">, </span><span class="identifier">bv_left</span><span class="plain">, </span><span class="identifier">bv_right</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">looks at the data in the two BVs and returns 0 if they are equal, a positive
|
|
number if <code class="display"><span class="extract">bv_right</span></code> is "greater than" <code class="display"><span class="extract">bv_left</span></code>, 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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueCompare</span><span class="plain"> </span><span class="identifier">bv_left</span><span class="plain"> </span><span class="identifier">bv_right</span><span class="plain"> </span><span class="identifier">kind_left</span><span class="plain"> </span><span class="identifier">kind_right</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">bv_left</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) && (</span><span class="identifier">bv_right</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">bv_left</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">1</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">bv_right</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> -1;</span>
|
|
|
|
<span class="identifier">kind_left</span><span class="plain"> = </span><span class="identifier">BlkValueWeakKind</span><span class="plain">(</span><span class="identifier">bv_left</span><span class="plain">);</span>
|
|
<span class="identifier">kind_right</span><span class="plain"> = </span><span class="identifier">BlkValueWeakKind</span><span class="plain">(</span><span class="identifier">bv_right</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">kind_left</span><span class="plain"> ~= </span><span class="identifier">kind_right</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">kind_left</span><span class="plain"> - </span><span class="identifier">kind_right</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">kovs</span><span class="plain"> = </span><span class="identifier">KOVSupportFunction</span><span class="plain">(</span><span class="identifier">kind_left</span><span class="plain">, </span><span class="string">"impossible comparison"</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">COMPARE_KOVS</span><span class="plain">, </span><span class="identifier">bv_left</span><span class="plain">, </span><span class="identifier">bv_right</span><span class="plain">);</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP27"></a><b>§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="inwebparagraph">If the value can be stored in a single word already, it can be its own
|
|
hash code. Otherwise, we ask:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">HASH_KOVS</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">to return one for us. Whatever this does, it must at minimum have the
|
|
property that two equivalent blocks (for which <code class="display"><span class="extract">COMPARE_KOVS</span></code> returns 0)
|
|
produce the same hash value.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">[ </span><span class="identifier">GetHashValue</span><span class="plain"> </span><span class="identifier">kind</span><span class="plain"> </span><span class="identifier">value</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">KOVIsBlockValue</span><span class="plain">(</span><span class="identifier">kind</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">BlkValueHash</span><span class="plain">(</span><span class="identifier">value</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">value</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
|
|
<span class="plain">[ </span><span class="identifier">BlkValueHash</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">bv_kind</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">bv</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="identifier">bv_kind</span><span class="plain"> = </span><span class="identifier">BlkValueWeakKind</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="identifier">kovs</span><span class="plain"> = </span><span class="identifier">KOVSupportFunction</span><span class="plain">(</span><span class="identifier">bv_kind</span><span class="plain">, </span><span class="string">"impossible hashing"</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">HASH_KOVS</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28"></a><b>§28. Serialisation. </b>Some block values can be written to external files (on Glulx): others cannot.
|
|
The following routines abstract that.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">If <code class="display"><span class="extract">ch</span></code> is -1, then:
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">READ_FILE_KOVS</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">, </span><span class="identifier">auxf</span><span class="plain">, </span><span class="identifier">ch</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">returns <code class="display"><span class="extract">true</span></code> or <code class="display"><span class="extract">false</span></code> according to whether it is possible to read data
|
|
from an auxiliary file <code class="display"><span class="extract">auxf</span></code> into the block value <code class="display"><span class="extract">bv</span></code>. If <code class="display"><span class="extract">ch</span></code> is any
|
|
other value, then the routine should do exactly that, taking <code class="display"><span class="extract">ch</span></code> to be the
|
|
first character of the text read from the file which makes up the serialised
|
|
form of the data.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">WRITE_FILE_KOVS</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">)</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">is simpler because, strictly speaking, it doesn't write to a file at all: it
|
|
simply prints a serialised form of the data in <code class="display"><span class="extract">bv</span></code> 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 <code class="display"><span class="extract">WRITE_FILE_KOVS</span></code> should return <code class="display"><span class="extract">true</span></code> or <code class="display"><span class="extract">false</span></code> according to
|
|
whether it was able to write the data.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueReadFromFile</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">auxf</span><span class="plain"> </span><span class="identifier">ch</span><span class="plain"> </span><span class="identifier">bv_kind</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">;</span>
|
|
<span class="identifier">kovs</span><span class="plain"> = </span><span class="identifier">KOVSupportFunction</span><span class="plain">(</span><span class="identifier">bv_kind</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">kovs</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">READ_FILE_KOVS</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">, </span><span class="identifier">auxf</span><span class="plain">, </span><span class="identifier">ch</span><span class="plain">);</span>
|
|
<span class="reserved">rfalse</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
|
|
<span class="plain">[ </span><span class="identifier">BlkValueWriteToFile</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">bv_kind</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">;</span>
|
|
<span class="identifier">kovs</span><span class="plain"> = </span><span class="identifier">KOVSupportFunction</span><span class="plain">(</span><span class="identifier">bv_kind</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">kovs</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">WRITE_FILE_KOVS</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="reserved">rfalse</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP29"></a><b>§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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkValueDebug</span><span class="plain"> </span><span class="identifier">bv</span><span class="plain"> </span><span class="identifier">flag</span><span class="plain"> </span><span class="identifier">refc</span><span class="plain"> </span><span class="identifier">long_block</span><span class="plain"> </span><span class="identifier">kovs</span><span class="plain">;</span>
|
|
<span class="reserved">print</span><span class="plain"> </span><span class="string">"(BV"</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">bv</span><span class="plain">) {</span>
|
|
<span class="identifier">BlkDebugAddress</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">, </span><span class="identifier">flag</span><span class="plain">);</span>
|
|
<span class="identifier">long_block</span><span class="plain"> = </span><span class="identifier">BlkValueGetLongBlock</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">long_block</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">bv</span><span class="plain">-->0 == </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">print</span><span class="plain"> </span><span class="string">"..."</span><span class="plain">; </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">print</span><span class="plain"> </span><span class="string">"-->"</span><span class="plain">;</span>
|
|
<span class="reserved">print</span><span class="plain"> </span><span class="string">"L"</span><span class="plain">; </span><span class="identifier">BlkDebugAddress</span><span class="plain">(</span><span class="identifier">long_block</span><span class="plain">, </span><span class="identifier">flag</span><span class="plain">);</span>
|
|
<span class="reserved">print</span><span class="plain"> </span><span class="string">" 2**"</span><span class="plain">, </span><span class="identifier">long_block</span><span class="plain">-></span><span class="identifier">BLK_HEADER_N</span><span class="plain">;</span>
|
|
<span class="identifier">refc</span><span class="plain"> = </span><span class="identifier">BlkValueGetRefCountPrimitive</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">refc</span><span class="plain"> == </span><span class="identifier">RC_INFINITY</span><span class="plain">) </span><span class="reserved">print</span><span class="plain"> </span><span class="string">" resident"</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> { </span><span class="reserved">print</span><span class="plain"> </span><span class="string">" "</span><span class="plain">, </span><span class="identifier">refc</span><span class="plain">, </span><span class="string">" ref"</span><span class="plain">; </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">refc</span><span class="plain"> ~= </span><span class="constant">1</span><span class="plain">) </span><span class="reserved">print</span><span class="plain"> </span><span class="string">"s"</span><span class="plain">; }</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">kovs</span><span class="plain"> = </span><span class="identifier">KOVSupportFunction</span><span class="plain">(</span><span class="identifier">BlkValueWeakKind</span><span class="plain">(</span><span class="identifier">bv</span><span class="plain">));</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">kovs</span><span class="plain">) </span><span class="identifier">kovs</span><span class="plain">(</span><span class="identifier">DEBUG_KOVS</span><span class="plain">, </span><span class="identifier">bv</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">print</span><span class="plain"> </span><span class="string">")"</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP30"></a><b>§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="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkDebugAddress</span><span class="plain"> </span><span class="identifier">addr</span><span class="plain"> </span><span class="identifier">flag</span><span class="plain"> </span><span class="identifier">d</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">flag</span><span class="plain">) { </span><span class="reserved">print</span><span class="plain"> </span><span class="string">"###"</span><span class="plain">; </span><span class="reserved">return</span><span class="plain">; }</span>
|
|
|
|
<span class="identifier">d</span><span class="plain"> = </span><span class="identifier">addr</span><span class="plain"> - </span><span class="identifier">blockv_stack</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">d</span><span class="plain"> >= </span><span class="constant">0</span><span class="plain">) && (</span><span class="identifier">d</span><span class="plain"> <= </span><span class="identifier">WORDSIZE</span><span class="plain">*</span><span class="identifier">BLOCKV_STACK_SIZE</span><span class="plain">)) {</span>
|
|
<span class="reserved">print</span><span class="plain"> </span><span class="string">"s+"</span><span class="plain">, (</span><span class="identifier">BlkPrintHexadecimal</span><span class="plain">) </span><span class="identifier">d</span><span class="plain">;</span>
|
|
<span class="identifier">d</span><span class="plain"> = </span><span class="identifier">addr</span><span class="plain"> - </span><span class="identifier">I7SFRAME</span><span class="plain">;</span>
|
|
<span class="reserved">print</span><span class="plain"> </span><span class="string">"=f"</span><span class="plain">; </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">d</span><span class="plain"> >= </span><span class="constant">0</span><span class="plain">) </span><span class="reserved">print</span><span class="plain"> </span><span class="string">"+"</span><span class="plain">; </span><span class="reserved">print</span><span class="plain"> </span><span class="identifier">d</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="identifier">d</span><span class="plain"> = </span><span class="identifier">addr</span><span class="plain"> - </span><span class="identifier">Flex_Heap</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">d</span><span class="plain"> >= </span><span class="constant">0</span><span class="plain">) && (</span><span class="identifier">d</span><span class="plain"> < </span><span class="identifier">MEMORY_HEAP_SIZE</span><span class="plain"> + </span><span class="constant">16</span><span class="plain">)) {</span>
|
|
<span class="reserved">print</span><span class="plain"> </span><span class="string">"h+"</span><span class="plain">, (</span><span class="identifier">BlkPrintHexadecimal</span><span class="plain">) </span><span class="identifier">d</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">print</span><span class="plain"> (</span><span class="identifier">BlkPrintHexadecimal</span><span class="plain">) </span><span class="identifier">addr</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP31"></a><b>§31. Hexadecimal Printing. </b></p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">[ </span><span class="identifier">BlkPrintHexadecimal</span><span class="plain"> </span><span class="identifier">v</span><span class="plain">;</span>
|
|
<span class="plain">#</span><span class="identifier">iftrue</span><span class="plain"> </span><span class="identifier">WORDSIZE</span><span class="plain"> == </span><span class="constant">4</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">v</span><span class="plain"> & </span><span class="constant">$ffff0000</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">v</span><span class="plain"> & </span><span class="constant">$ff000000</span><span class="plain">) {</span>
|
|
<span class="identifier">BlkPrintHexDigit</span><span class="plain">(</span><span class="identifier">v</span><span class="plain"> / </span><span class="constant">$10000000</span><span class="plain">);</span>
|
|
<span class="identifier">BlkPrintHexDigit</span><span class="plain">(</span><span class="identifier">v</span><span class="plain"> / </span><span class="constant">$1000000</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">BlkPrintHexDigit</span><span class="plain">(</span><span class="identifier">v</span><span class="plain"> / </span><span class="constant">$100000</span><span class="plain">);</span>
|
|
<span class="identifier">BlkPrintHexDigit</span><span class="plain">(</span><span class="identifier">v</span><span class="plain"> / </span><span class="constant">$10000</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">#</span><span class="identifier">endif</span><span class="plain">;</span>
|
|
<span class="identifier">BlkPrintHexDigit</span><span class="plain">(</span><span class="identifier">v</span><span class="plain"> / </span><span class="constant">$1000</span><span class="plain">);</span>
|
|
<span class="identifier">BlkPrintHexDigit</span><span class="plain">(</span><span class="identifier">v</span><span class="plain"> / </span><span class="constant">$100</span><span class="plain">);</span>
|
|
<span class="identifier">BlkPrintHexDigit</span><span class="plain">(</span><span class="identifier">v</span><span class="plain"> / </span><span class="constant">$10</span><span class="plain">);</span>
|
|
<span class="identifier">BlkPrintHexDigit</span><span class="plain">(</span><span class="identifier">v</span><span class="plain">);</span>
|
|
<span class="plain">];</span>
|
|
|
|
<span class="plain">[ </span><span class="identifier">BlkPrintHexDigit</span><span class="plain"> </span><span class="identifier">v</span><span class="plain">;</span>
|
|
<span class="identifier">v</span><span class="plain"> = </span><span class="identifier">v</span><span class="plain"> & </span><span class="constant">$F</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">v</span><span class="plain"> < </span><span class="constant">10</span><span class="plain">) </span><span class="reserved">print</span><span class="plain"> </span><span class="identifier">v</span><span class="plain">; </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">print</span><span class="plain"> (</span><span class="identifier">char</span><span class="plain">) </span><span class="character">'A'</span><span class="plain"> + </span><span class="identifier">v</span><span class="plain"> - </span><span class="constant">10</span><span class="plain">;</span>
|
|
<span class="plain">];</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<hr class="tocbar">
|
|
<ul class="toc"><li><a href="S-ft2.html">Back to 'Flex Template'</a></li><li><a href="S-tt2.html">Continue with 'Text Template'</a></li></ul><hr class="tocbar">
|
|
<!--End of weave-->
|
|
</main>
|
|
</body>
|
|
</html>
|
|
|