1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-03 07:24:58 +03:00
inform7/docs/BasicInformKit/S-flx.html
2020-05-03 01:20:55 +01:00

710 lines
121 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Flex Template</title>
<link href="../docs-assets/Breadcrumbs.css" rel="stylesheet" rev="stylesheet" type="text/css">
<meta name="viewport" content="width=device-width initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="../docs-assets/Contents.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Progress.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Navigation.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Fonts.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Base.css" rel="stylesheet" rev="stylesheet" type="text/css">
<script>
MathJax = {
tex: {
inlineMath: '$', '$'], ['\\(', '\\)'
},
svg: {
fontCache: 'global'
}
};
</script>
<script type="text/javascript" id="MathJax-script" async
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js">
</script>
<link href="../docs-assets/Colours.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body class="commentary-font">
<nav role="navigation">
<h1><a href="../index.html">
<img src="../docs-src/Figures/Inform.png" height=72">
</a></h1>
<ul><li><a href="../compiler.html">compiler tools</a></li>
<li><a href="../other.html">other tools</a></li>
<li><a href="../extensions.html">extensions and kits</a></li>
<li><a href="../units.html">unit test tools</a></li>
</ul><h2>Extensions</h2><ul>
<li><a href="../basic_inform/index.html">basic_inform</a></li>
<li><a href="../standard_rules/index.html">standard_rules</a></li>
</ul><h2>Kits</h2><ul>
<li><a href="index.html"><span class="selectedlink">BasicInformKit</span></a></li>
<li><a href="../BasicInformExtrasKit/index.html">BasicInformExtrasKit</a></li>
<li><a href="../CommandParserKit/index.html">CommandParserKit</a></li>
<li><a href="../EnglishLanguageKit/index.html">EnglishLanguageKit</a></li>
<li><a href="../WorldModelKit/index.html">WorldModelKit</a></li>
</ul>
</nav>
<main role="main">
<!--Weave of 'Flex Template' generated by Inweb-->
<div class="breadcrumbs">
<ul class="crumbs"><li><a href="../index.html">Home</a></li><li><a href="../extensions.html">Kits</a></li><li><a href="index.html">BasicInformKit</a></li><li><b>Flex Template</b></li></ul></div>
<p class="purpose">To allocate flexible-sized blocks of memory as needed to hold arbitrary-length strings of text, stored actions or other block values.</p>
<ul class="toc"><li><a href="S-flx.html#SP1">&#167;1. Blocks</a></li><li><a href="S-flx.html#SP2">&#167;2. Multiple Blocks</a></li><li><a href="S-flx.html#SP3">&#167;3. The Heap</a></li><li><a href="S-flx.html#SP4">&#167;4. Initialisation</a></li><li><a href="S-flx.html#SP5">&#167;5. Net Free Space</a></li><li><a href="S-flx.html#SP6">&#167;6. Make Space</a></li><li><a href="S-flx.html#SP7">&#167;7. Block Allocation</a></li><li><a href="S-flx.html#SP8">&#167;8. Errors</a></li><li><a href="S-flx.html#SP9">&#167;9. Merging</a></li><li><a href="S-flx.html#SP10">&#167;10. Recutting</a></li><li><a href="S-flx.html#SP11">&#167;11. Deallocation</a></li><li><a href="S-flx.html#SP12">&#167;12. Resizing</a></li><li><a href="S-flx.html#SP13">&#167;13. Block Size</a></li><li><a href="S-flx.html#SP14">&#167;14. Debugging Routines</a></li></ul><hr class="tocbar">
<p class="commentary firstcommentary"><a id="SP1"></a><b>&#167;1. Blocks. </b>The purpose of the Flex routines is to manage flexible-sized "blocks" of
memory for any general-purpose use. The main customer for this service is
the system for creating texts, lists, stored actions, and so on, which
are collectively called "block values" because they store their data in
blocks allocated by Flex. But in this section, we're just managing
arrays of memory, and don't need to know what it's for.
</p>
<p class="commentary">A "block" is a continuous range of \(2^n\) bytes of memory, where \(n\geq 3\)
for a 16-bit VM (i.e., for the Z-machine) and \(n\geq 4\) for a 32-bit VM
(i.e., on Glulx). Internally, a block is divided into a header followed
by a data section.
</p>
<p class="commentary">The header size depends on the word size and the kind of block (see below). It
always begins with a byte specifying \(n\), the binary logarithm of its size,
except that if the top bit is set then we know this isn't a flex-allocated
block, which turns out to be convenient. Thus the largest block representable
is \(2^{127}\) bytes long, but somehow I think we can live with that. The second
byte contains a bitmap of (at present) four flags, whose meanings will be
explained below. The second {\it word} of the block, which might be at byte
offset 2 or 4 from the start of the block depending on the word-size of the
VM, is a number specifying the kind of value (if any) which the block contains
data of.
</p>
<p class="commentary">The header also contains a weak kind ID and a reference count, but the Flex
routines do nothing with either of these except to initialise them; they're
provided for the benefit of the <span class="extract"><span class="extract-syntax">BlockValue</span></span> system.
</p>
<p class="commentary">The data section of a block begins at the byte offset <span class="extract"><span class="extract-syntax">BLK_DATA_OFFSET</span></span>
from the address of the block: but see below for how multiple-blocks
behave differently.
</p>
<p class="commentary">These definitions must not be altered without making matching changes
to the compiler.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax"> = </span><span class="constant-syntax">$$00000001</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_FLAG_16_BIT</span><span class="plain-syntax"> = </span><span class="constant-syntax">$$00000010</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_FLAG_WORD</span><span class="plain-syntax"> = </span><span class="constant-syntax">$$00000100</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_FLAG_RESIDENT</span><span class="plain-syntax"> = </span><span class="constant-syntax">$$00001000</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_FLAG_TRUNCMULT</span><span class="plain-syntax"> = </span><span class="constant-syntax">$$00010000</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">2</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax"> = </span><span class="constant-syntax">3</span><span class="plain-syntax">*</span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
</pre>
<p class="commentary firstcommentary"><a id="SP2"></a><b>&#167;2. Multiple Blocks. </b>Some of the data we want to store will be fixed in size, but some of it will
need to expand or contract. The latter can change unpredictably in size and
might at any point overflow their current storage, so they're stored in a
doubly linked list of blocks. The pointer to such a flexible-length array is
by definition the pointer to the block heading this linked list. For instance,
the data in a text
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="string-syntax">"But now I worship a celestiall Sunne"</span>
</pre>
<p class="commentary">might be stored in a list of blocks like so:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">NULL</span><span class="plain-syntax"> &lt;-- </span><span class="identifier-syntax">BN</span><span class="plain-syntax">: </span><span class="string-syntax">"But now I wor"</span><span class="plain-syntax"> &lt;--&gt; </span><span class="identifier-syntax">BN2</span><span class="plain-syntax">: </span><span class="string-syntax">"ship a celestiall Sunne"</span><span class="plain-syntax"> --&gt; </span><span class="identifier-syntax">NULL</span>
</pre>
<p class="commentary">Note that the unique pointer to <span class="extract"><span class="extract-syntax">BN2</span></span> is the one in the header of the
<span class="extract"><span class="extract-syntax">BN</span></span> block. When we need to grow such a text, we add additional blocks;
if the text should shrink, blocks at the end can at our discretion be
deallocated. If the entire text should be deallocated, then all of the
blocks used for it are deallocated, starting at the back and working
towards the front.
</p>
<p class="commentary">A multiple-block is one whose flags byte contains the <span class="extract"><span class="extract-syntax">BLK_FLAG_MULTIPLE</span></span>.
This information is redundant since it could in principle be deduced from
the kind of value stored in the block, which is recorded in the
<span class="extract"><span class="extract-syntax">--&gt;BLK_HEADER_KOV</span></span> word, but that would be too slow. <span class="extract"><span class="extract-syntax">BLK_FLAG_MULTIPLE</span></span>
can never change for a currently allocated block, just as it can never
change its KOV.
</p>
<p class="commentary">A multiple-block header is longer than that of an ordinary block, because
it contains two extra words: <span class="extract"><span class="extract-syntax">--&gt;BLK_NEXT</span></span> is the next block in the
doubly-linked list of blocks representing the current value, or <span class="extract"><span class="extract-syntax">NULL</span></span>
if this is the end; <span class="extract"><span class="extract-syntax">--&gt;BLK_PREV</span></span> is the previous block, or <span class="extract"><span class="extract-syntax">NULL</span></span> if this
is the beginning. The need to fit these two extra words in means that the
data section is deferred, and so for a multiple-block data begins at the
byte offset <span class="extract"><span class="extract-syntax">BLK_DATA_MULTI_OFFSET</span></span> rather than <span class="extract"><span class="extract-syntax">BLK_DATA_OFFSET</span></span>.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax"> + </span><span class="constant-syntax">2</span><span class="plain-syntax">*</span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> </span><span class="constant-syntax">3</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> </span><span class="constant-syntax">4</span><span class="plain-syntax">;</span>
<span class="comment-syntax">Constant BLKVALUE_TRACE = 1; ! Uncomment this for debugging purposes</span>
</pre>
<p class="commentary firstcommentary"><a id="SP3"></a><b>&#167;3. The Heap. </b>Properly speaking, a "heap" is a specific kind of structure often used for
managing uneven-sized or unpredictably changing data. We use "heap" here in
the looser sense of being an amorphous-sized collection of blocks of memory,
some free, others allocated; our actual representation of free space on the
heap is not a heap structure in computer science terms. (Though this segment
could easily be rewritten to make it so, or to adopt any other scheme which
might be faster.) The heap begins as a contiguous region of memory, but it
need not remain so: on Glulx we use dynamic memory allocation to extend it.
</p>
<p class="commentary">For I7 purposes we don't need a way to represent allocated memory, only
the free memory. A block is free if and only if it has <span class="extract"><span class="extract-syntax">--&gt;BLK_HEADER_KOV</span></span>
equal to 0, which is never a valid kind of value, and also has the multiple
flag set. We do that because we construct the whole collection of free
blocks, at any given time, as a single, multiple-block "value": a doubly
linked list joined by the <span class="extract"><span class="extract-syntax">--&gt;BLK_NEXT</span></span> and <span class="extract"><span class="extract-syntax">&lt;--BLK_PREV</span></span>.
</p>
<p class="commentary">A single block, at the bottom of memory and never moving, never allocated
to anyone, is preserved in order to be the head of this linked list of
free blocks. This is a 16-byte (i.e., \(n=4\)) block, which we format when
the heap is initialised in <span class="extract"><span class="extract-syntax">HeapInitialise()</span></span>. Thus the heap is full
if and only if the <span class="extract"><span class="extract-syntax">--&gt;BLK_NEXT</span></span> of the head-free-block is <span class="extract"><span class="extract-syntax">NULL</span></span>.
</p>
<p class="commentary">So far we have described a somewhat lax regime. After many allocations and
deallocations one could imagine the list of free blocks becoming a very
long list of individually small blocks, which would both make it difficult
to allocate large blocks, and also slow to look through the list. To
ameliorate matters, we maintain the following invariants:
</p>
<ul class="items"><li>(a) In the free blocks list, <span class="extract"><span class="extract-syntax">B--&gt;BLK_NEXT</span></span> is always an address after <span class="extract"><span class="extract-syntax">B</span></span>;
</li><li>(b) For any contiguous run of free space blocks in memory (excluding the
head-free-block), taking up a total of \(T\) bytes, the last block in the run
has size \(2^n\) where \(n\) is the largest integer such that \(2^n\leq T\).
</li></ul>
<p class="commentary">For instance, there can never be two consecutive free blocks of size 128:
they would form a "run" in the sense of rule (b) of size \(T = 256\), and
when \(T\) is a power of two the run must contain a single block. In general,
it's easy to prove that the number of blocks in the run is exactly the
number of 1s when \(T\) is written out as a binary number, and that the
blocks are ordered in memory from small to large (the reverse of the
direction of reading, i.e., rightmost 1 digit first). Maintaining (b)
is a matter of being careful to fragment blocks only from the front when
smaller blocks are needed, and to rejoin from the back when blocks are
freed and added to the free space object.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">Array</span><span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax"> -&gt; (</span><span class="identifier-syntax">MEMORY_HEAP_SIZE</span><span class="plain-syntax"> + </span><span class="constant-syntax">16</span><span class="plain-syntax">); </span><span class="comment-syntax">Plus 16 to allow room for head-free-block</span>
</pre>
<p class="commentary firstcommentary"><a id="SP4"></a><b>&#167;4. Initialisation. </b>To recap: the constant <span class="extract"><span class="extract-syntax">MEMORY_HEAP_SIZE</span></span> has been predefined by the Inform compiler,
and is always itself a power of 2, say \(2^n\). We therefore have \(2^n + 2^4\)
bytes available to us, and we format these as a free space list of two
blocks: the \(2^4\)-sized "head-free-block" described above followed by
a \(2^n\)-sized block exactly containing the whole of the rest of the heap.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">HeapInitialise</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> </span><span class="identifier-syntax">bsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax"> + </span><span class="constant-syntax">16</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = </span><span class="constant-syntax">4</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">MAX_POSITIVE_NUMBER</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">=1: </span><span class="identifier-syntax">bsize</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">MEMORY_HEAP_SIZE</span><span class="plain-syntax">: </span><span class="identifier-syntax">bsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">*2) </span><span class="identifier-syntax">n</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = </span><span class="identifier-syntax">n</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">blk2</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP5"></a><b>&#167;5. Net Free Space. </b>"Net" in the sense of "after deductions for the headers": this is the
actual number of free bytes left on the heap which could be used for data.
Note that it is used to predict whether it is possible to fit something
further in: so there are two answers, depending on whether the something
is multiple-block data (with a larger header and therefore less room for
data) or single-block data (smaller header, more room).
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">HeapNetFreeSpace</span><span class="plain-syntax"> </span><span class="identifier-syntax">multiple</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">: </span><span class="identifier-syntax">txb</span><span class="plain-syntax">~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">: </span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">txb</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> + </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">txb</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">multiple</span><span class="plain-syntax">) </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP6"></a><b>&#167;6. Make Space. </b>The following routine determines if there is enough free space to accommodate
another <span class="extract"><span class="extract-syntax">size</span></span> bytes of data, given that it has to be multiple-block data if
the <span class="extract"><span class="extract-syntax">multiple</span></span> flag is set. If the answer turns out to be "no", we see if
the host virtual machine is able to allocate more for us: if it is, then
we ask for \(2^m\) further bytes, where \(2^m\) is at least <span class="extract"><span class="extract-syntax">size</span></span> plus the
worst-case header storage requirement (16 bytes), and in addition is large
enough to make it worth while allocating. We don't want to bother the VM
by asking for trivial amounts of memory.
</p>
<p class="commentary">This looks to be more memory than is needed, since after all we've asked
for enough that the new data can fit entirely into the new block allocated,
and we might have been able to squeeze some of it into the existing free
space. But it ensures that heap invariant (b) above is preserved, and
besides, running out of memory tends to be something you don't do only once.
</p>
<p class="commentary">(The code below is a refinement on the original, suggested by Jesse McGrew,
which handles non-multiple blocks better.)
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">Constant</span><span class="plain-syntax"> </span><span class="identifier-syntax">SMALLEST_BLK_WORTH_ALLOCATING</span><span class="plain-syntax"> = </span><span class="constant-syntax">12</span><span class="plain-syntax">; </span><span class="comment-syntax">i.e. 2^12 = 4096 bytes</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">HeapMakeSpace</span><span class="plain-syntax"> </span><span class="identifier-syntax">size</span><span class="plain-syntax"> </span><span class="identifier-syntax">multiple</span><span class="plain-syntax"> </span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax"> </span><span class="identifier-syntax">B</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (::) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">multiple</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">HeapNetFreeSpace</span><span class="plain-syntax">(</span><span class="identifier-syntax">multiple</span><span class="plain-syntax">) &gt;= </span><span class="identifier-syntax">size</span><span class="plain-syntax">) </span><span class="reserved-syntax">rtrue</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">HeapLargestFreeBlock</span><span class="plain-syntax">(0) &gt;= </span><span class="identifier-syntax">size</span><span class="plain-syntax">) </span><span class="reserved-syntax">rtrue</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">n</span><span class="plain-syntax">=0: (</span><span class="identifier-syntax">n</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">SMALLEST_BLK_WORTH_ALLOCATING</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">size</span><span class="plain-syntax">): </span><span class="identifier-syntax">n</span><span class="plain-syntax">++)</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax">*2;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">size</span><span class="plain-syntax">+16) </span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax">*2;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax"> = </span><span class="identifier-syntax">VM_AllocateMemory</span><span class="plain-syntax">(</span><span class="identifier-syntax">newblocksize</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">newblock</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = </span><span class="identifier-syntax">n</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">B</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">:</span><span class="identifier-syntax">B</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">:</span><span class="identifier-syntax">B</span><span class="plain-syntax"> = </span><span class="identifier-syntax">B</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">B</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">B</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">B</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">jump</span><span class="plain-syntax"> </span><span class="identifier-syntax">Linked</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newblock</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> .</span><span class="identifier-syntax">Linked</span><span class="plain-syntax">; ;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifdef</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLKVALUE_TRACE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Increasing heap to free space map: "</span><span class="plain-syntax">; </span><span class="identifier-syntax">FlexDebugDecomposition</span><span class="plain-syntax">(</span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">, </span><span class="constant-syntax">0</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">rtrue</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">HeapLargestFreeBlock</span><span class="plain-syntax"> </span><span class="identifier-syntax">multiple</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> </span><span class="identifier-syntax">best</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">best</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">: </span><span class="identifier-syntax">txb</span><span class="plain-syntax">~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">: </span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">txb</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">txb</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">multiple</span><span class="plain-syntax">) </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">asize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">asize</span><span class="plain-syntax"> &gt; </span><span class="identifier-syntax">best</span><span class="plain-syntax">) </span><span class="identifier-syntax">best</span><span class="plain-syntax"> = </span><span class="identifier-syntax">asize</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">best</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">HeapDebug</span><span class="plain-syntax"> </span><span class="identifier-syntax">full</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">full</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Managing a heap of initially "</span><span class="plain-syntax">, </span><span class="identifier-syntax">MEMORY_HEAP_SIZE</span><span class="plain-syntax">+16, </span><span class="string-syntax">" bytes.^"</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="identifier-syntax">HeapNetFreeSpace</span><span class="plain-syntax">(</span><span class="reserved-syntax">false</span><span class="plain-syntax">), </span><span class="string-syntax">" bytes currently free.^"</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Free space decomposition: "</span><span class="plain-syntax">; </span><span class="identifier-syntax">FlexDebugDecomposition</span><span class="plain-syntax">(</span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Free space map: "</span><span class="plain-syntax">; </span><span class="identifier-syntax">FlexDebug</span><span class="plain-syntax">(</span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="identifier-syntax">HeapNetFreeSpace</span><span class="plain-syntax">(</span><span class="reserved-syntax">false</span><span class="plain-syntax">), </span><span class="string-syntax">" of "</span><span class="plain-syntax">, </span><span class="identifier-syntax">MEMORY_HEAP_SIZE</span><span class="plain-syntax">+16, </span><span class="string-syntax">" bytes free.^"</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP7"></a><b>&#167;7. Block Allocation. </b>Now for the Flex routines. Those with names ending in <span class="extract"><span class="extract-syntax">Internal</span></span> are private
and should only be called by other Flex routines. Even the public ones must
be used with care, or memory leaks or crashes will occur.
</p>
<p class="commentary">The routine <span class="extract"><span class="extract-syntax">FlexAllocate(N, K, F)</span></span> allocates a block with room for <span class="extract"><span class="extract-syntax">size</span></span>
net bytes of data, which will have kind of value <span class="extract"><span class="extract-syntax">K</span></span> and with flags <span class="extract"><span class="extract-syntax">F</span></span>. If
the flags include <span class="extract"><span class="extract-syntax">BLK_FLAG_MULTIPLE</span></span>, this may be either a list of blocks
or a single block. It returns either the address of the block or else throws
run-time problem message and returns 0.
</p>
<p class="commentary">If it does succeed and return a nonzero address, then the caller must be
able to guarantee that <span class="extract"><span class="extract-syntax">FlexFree</span></span> will later be called, exactly once, on
this address. In other words, <span class="extract"><span class="extract-syntax">FlexAllocate</span></span> and <span class="extract"><span class="extract-syntax">FlexFree</span></span> behave somewhat
like C's <span class="extract"><span class="extract-syntax">malloc</span></span> and <span class="extract"><span class="extract-syntax">free</span></span> routines, with all the advantages and hazards
that implies.
</p>
<p class="commentary">In allocation, we try to find a block which is as close as possible to the
right size, and we may have to subdivide blocks: see case II below. For
instance, if a block of size \(2^n\) is available and we only need a block of
size \(2^k\) where \(k&lt;n\) then we break it up in memory as a sequence of
blocks of size \(2^k, 2^k, 2^{k+1}, 2^{k+2}, ..., 2^{n-1}\): note that the
sum of these sizes is the \(2^n\) we started with. We then use the first
block of size \(2^k\). To continue the comparison with binary arithmetic,
this is like a subtraction with repeated carries:
$$ 10000000_2 - 00001000_2 = 01111000_2 $$
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexAllocate</span><span class="plain-syntax"> </span><span class="identifier-syntax">size</span><span class="plain-syntax"> </span><span class="identifier-syntax">kov</span><span class="plain-syntax"> </span><span class="identifier-syntax">flags</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> </span><span class="identifier-syntax">m</span><span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">min_m</span><span class="plain-syntax"> </span><span class="identifier-syntax">max_m</span><span class="plain-syntax"> </span><span class="identifier-syntax">smallest_oversized_block</span><span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> </span><span class="identifier-syntax">hsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">head</span><span class="plain-syntax"> </span><span class="identifier-syntax">tail</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">HeapMakeSpace</span><span class="plain-syntax">(</span><span class="identifier-syntax">size</span><span class="plain-syntax">, </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) == </span><span class="reserved-syntax">false</span><span class="plain-syntax">) </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax">(</span><span class="string-syntax">"ran out"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Calculate the header size for a block of this KOV</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) </span><span class="identifier-syntax">hsize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">hsize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Calculate the data size</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax">=0; </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=1: ((</span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">hsize</span><span class="plain-syntax">+</span><span class="identifier-syntax">size</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">n</span><span class="plain-syntax">&lt;3+(</span><span class="identifier-syntax">WORDSIZE</span><span class="plain-syntax">/2))): </span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">*2) </span><span class="identifier-syntax">n</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Seek a free block closest to the correct size, but starting from the</span>
<span class="plain-syntax"> </span><span class="comment-syntax">block after the fixed head-free-block, which we can't touch</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">min_m</span><span class="plain-syntax"> = </span><span class="constant-syntax">10000</span><span class="plain-syntax">; </span><span class="identifier-syntax">max_m</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">free_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">:</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">:</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">m</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Current block the ideal size</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">m</span><span class="plain-syntax"> == </span><span class="identifier-syntax">n</span><span class="plain-syntax">) </span><span class="reserved-syntax">jump</span><span class="plain-syntax"> </span><span class="identifier-syntax">CorrectSizeFound</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Current block too large: find the smallest which is larger than needed</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">m</span><span class="plain-syntax"> &gt; </span><span class="identifier-syntax">n</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">min_m</span><span class="plain-syntax"> &gt; </span><span class="identifier-syntax">m</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">min_m</span><span class="plain-syntax"> = </span><span class="identifier-syntax">m</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">smallest_oversized_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Current block too small: find the largest which is smaller than needed</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">m</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">n</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">max_m</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">m</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">max_m</span><span class="plain-syntax"> = </span><span class="identifier-syntax">m</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">min_m</span><span class="plain-syntax"> == </span><span class="constant-syntax">10000</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Case I: No block is large enough to hold the entire size</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax">(</span><span class="string-syntax">"too fragmented"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Set dsize to the size in bytes if the largest block available</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=1: </span><span class="identifier-syntax">max_m</span><span class="plain-syntax"> &gt; </span><span class="constant-syntax">0</span><span class="plain-syntax">: </span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">*2) </span><span class="identifier-syntax">max_m</span><span class="plain-syntax">--;</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Split as a head (dsize-hsize), which we can be sure fits into one block,</span>
<span class="plain-syntax"> </span><span class="comment-syntax">plus a tail (size-(dsize-hsize), which might be a list of blocks</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">head</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexAllocate</span><span class="plain-syntax">(</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">-</span><span class="identifier-syntax">hsize</span><span class="plain-syntax">, </span><span class="identifier-syntax">kov</span><span class="plain-syntax">, </span><span class="identifier-syntax">flags</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">head</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax">(</span><span class="string-syntax">"for head block not available"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">tail</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexAllocate</span><span class="plain-syntax">(</span><span class="identifier-syntax">size</span><span class="plain-syntax">-(</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">-</span><span class="identifier-syntax">hsize</span><span class="plain-syntax">), </span><span class="identifier-syntax">kov</span><span class="plain-syntax">, </span><span class="identifier-syntax">flags</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">tail</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax">(</span><span class="string-syntax">"for tail block not available"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">head</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">tail</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">tail</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">head</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">head</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Case II: No block is the right size, but some exist which are too big</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Set dsize to the size in bytes of the smallest oversized block</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=1,</span><span class="identifier-syntax">m</span><span class="plain-syntax">=1: </span><span class="identifier-syntax">m</span><span class="plain-syntax">&lt;=</span><span class="identifier-syntax">min_m</span><span class="plain-syntax">: </span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">*2) </span><span class="identifier-syntax">m</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">smallest_oversized_block</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">min_m</span><span class="plain-syntax"> &gt; </span><span class="identifier-syntax">n</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Repeatedly halve free_block at the front until the two smallest</span>
<span class="plain-syntax"> </span><span class="comment-syntax">fragments left are the correct size: then take the frontmost</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">dsize</span><span class="plain-syntax">/2;</span>
<span class="plain-syntax"> </span><span class="comment-syntax">print "Halving size to ", dsize, "^";</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax"> + </span><span class="identifier-syntax">dsize</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">)--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = (</span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">) - </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">secondhalf</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">min_m</span><span class="plain-syntax">--;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Once that is done, free_block points to a block which is exactly the</span>
<span class="plain-syntax"> </span><span class="comment-syntax">right size, so we can fall into...</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Case III: There is a free block which has the correct size.</span>
<span class="plain-syntax"> .</span><span class="identifier-syntax">CorrectSizeFound</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Delete the free block from the double linked list of free blocks: note</span>
<span class="plain-syntax"> </span><span class="comment-syntax">that it cannot be the head of this list, which is fixed</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="comment-syntax">We remove final block, so previous is now final</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">)--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="comment-syntax">We remove a middle block, so join previous to next</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">)--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">)--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">KindAtomic</span><span class="plain-syntax">(</span><span class="identifier-syntax">kov</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">flags</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="comment-syntax">Zero out the data bytes in the memory allocated</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">i</span><span class="plain-syntax">=</span><span class="identifier-syntax">hsize</span><span class="plain-syntax">:</span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">:</span><span class="identifier-syntax">i</span><span class="plain-syntax">++) </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">i</span><span class="plain-syntax">=0;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">free_block</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP8"></a><b>&#167;8. Errors. </b>In the event that <span class="extract"><span class="extract-syntax">FlexAllocate</span></span> returns 0, the caller may not be able
to survive, so the following is provided as a standardised way to halt
the virtual machine.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax"> </span><span class="identifier-syntax">reason</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"*** Memory "</span><span class="plain-syntax">, (</span><span class="reserved-syntax">string</span><span class="plain-syntax">) </span><span class="identifier-syntax">reason</span><span class="plain-syntax">, </span><span class="string-syntax">" ***^"</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">RunTimeProblem</span><span class="plain-syntax">(</span><span class="identifier-syntax">RTP_HEAPERROR</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> @</span><span class="reserved-syntax">quit</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP9"></a><b>&#167;9. Merging. </b>Given a free block <span class="extract"><span class="extract-syntax">block</span></span>, find the maximal contiguous run of free blocks
which contains it, and then call <span class="extract"><span class="extract-syntax">FlexRecutInternal</span></span> to recut it to conform to
invariant (b) above.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexMergeInternal</span><span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax"> </span><span class="identifier-syntax">first</span><span class="plain-syntax"> </span><span class="identifier-syntax">last</span><span class="plain-syntax"> </span><span class="identifier-syntax">pv</span><span class="plain-syntax"> </span><span class="identifier-syntax">nx</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">first</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">; </span><span class="identifier-syntax">last</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">last</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> == </span><span class="identifier-syntax">last</span><span class="plain-syntax">+</span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">last</span><span class="plain-syntax">))</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">last</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">first</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> + </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">first</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">) == </span><span class="identifier-syntax">first</span><span class="plain-syntax">) &amp;&amp;</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">first</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">))</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">first</span><span class="plain-syntax"> = </span><span class="identifier-syntax">first</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">pv</span><span class="plain-syntax"> = </span><span class="identifier-syntax">first</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">nx</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifdef</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLKVALUE_TRACE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Merging: "</span><span class="plain-syntax">; </span><span class="identifier-syntax">FlexDebugDecomposition</span><span class="plain-syntax">(</span><span class="identifier-syntax">pv</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">, </span><span class="identifier-syntax">nx</span><span class="plain-syntax">); </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"^"</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">FlexRecutInternal</span><span class="plain-syntax">(</span><span class="identifier-syntax">first</span><span class="plain-syntax">, </span><span class="identifier-syntax">last</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">ifdef</span><span class="plain-syntax"> </span><span class="identifier-syntax">BLKVALUE_TRACE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">" --&gt; "</span><span class="plain-syntax">; </span><span class="identifier-syntax">FlexDebugDecomposition</span><span class="plain-syntax">(</span><span class="identifier-syntax">pv</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">, </span><span class="identifier-syntax">nx</span><span class="plain-syntax">); </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"^"</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> #</span><span class="identifier-syntax">endif</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP10"></a><b>&#167;10. Recutting. </b>Given a segment of the free block list, containing blocks known to be contiguous
in memory, we recut into a sequence of blocks satisfying invariant (b): we
repeatedly cut the largest \(2^m\)-sized chunk off the back end until it is all
used up.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexRecutInternal</span><span class="plain-syntax"> </span><span class="identifier-syntax">first</span><span class="plain-syntax"> </span><span class="identifier-syntax">last</span><span class="plain-syntax"> </span><span class="identifier-syntax">tsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">backsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">mfrom</span><span class="plain-syntax"> </span><span class="identifier-syntax">mto</span><span class="plain-syntax"> </span><span class="identifier-syntax">bnext</span><span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> </span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">fine_so_far</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">first</span><span class="plain-syntax"> == </span><span class="identifier-syntax">last</span><span class="plain-syntax">) </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">mfrom</span><span class="plain-syntax"> = </span><span class="identifier-syntax">first</span><span class="plain-syntax">; </span><span class="identifier-syntax">mto</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax"> + </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">last</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">bnext</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">fine_so_far</span><span class="plain-syntax"> = </span><span class="reserved-syntax">true</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (:</span><span class="identifier-syntax">mto</span><span class="plain-syntax">&gt;</span><span class="identifier-syntax">mfrom</span><span class="plain-syntax">: </span><span class="identifier-syntax">mto</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mto</span><span class="plain-syntax"> - </span><span class="identifier-syntax">backsize</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">n</span><span class="plain-syntax">=0, </span><span class="identifier-syntax">backsize</span><span class="plain-syntax">=1: </span><span class="identifier-syntax">backsize</span><span class="plain-syntax">*2 &lt;= </span><span class="identifier-syntax">mto</span><span class="plain-syntax">-</span><span class="identifier-syntax">mfrom</span><span class="plain-syntax">: </span><span class="identifier-syntax">n</span><span class="plain-syntax">++) </span><span class="identifier-syntax">backsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">backsize</span><span class="plain-syntax">*2;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">fine_so_far</span><span class="plain-syntax">) &amp;&amp; (</span><span class="identifier-syntax">backsize</span><span class="plain-syntax"> == </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">last</span><span class="plain-syntax">))) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">bnext</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax">; </span><span class="identifier-syntax">last</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">bnext</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">last</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">last</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">bnext</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">continue</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">fine_so_far</span><span class="plain-syntax"> = </span><span class="reserved-syntax">false</span><span class="plain-syntax">; </span><span class="comment-syntax">From this point, "last" is meaningless</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mto</span><span class="plain-syntax"> - </span><span class="identifier-syntax">backsize</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax"> = </span><span class="identifier-syntax">n</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">backend</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">bnext</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bnext</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">bnext</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">backend</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">bnext</span><span class="plain-syntax"> = </span><span class="identifier-syntax">backend</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">fine_so_far</span><span class="plain-syntax">) </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">rtrue</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP11"></a><b>&#167;11. Deallocation. </b>As noted above, <span class="extract"><span class="extract-syntax">FlexFree</span></span> must be called exactly once on each nonzero
pointer returned by <span class="extract"><span class="extract-syntax">FlexAllocate</span></span>.
</p>
<p class="commentary">There are two complications: first, when we free a multiple block we need
to free all of the blocks in the list, starting from the back end and
working forwards to the front &mdash; this is the job of <span class="extract"><span class="extract-syntax">FlexFree</span></span>. Second,
when any given block is freed it has to be put into the free block list
at the correct position to preserve invariant (a): it might either come
after all of the currently free blocks in memory, and have to be added to
the end of the list, or in between two, and have to be inserted mid-list,
but it can't be before all of them because the head-free-block is kept
lowest in memory of all possible blocks. (Note that Glulx can't allocate
memory dynamically which undercuts the ordinary array space created by I6:
I6 arrays fill up memory from the bottom.)
</p>
<p class="commentary">Certain blocks {\it outside} the heap are marked as "resident" in memory,
that is, are indestructible. This enables Inform to compile constant values.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexFree</span><span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax"> </span><span class="identifier-syntax">fromtxb</span><span class="plain-syntax"> </span><span class="identifier-syntax">ptxb</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">block</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">) &amp; </span><span class="identifier-syntax">BLK_FLAG_RESIDENT</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">) &amp; </span><span class="constant-syntax">$80</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax">; </span><span class="comment-syntax">not a flexible block at all</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">) &amp; </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) (</span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">)--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">fromtxb</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (:(</span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">)~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">:</span><span class="identifier-syntax">block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) ;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">block</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">fromtxb</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">ptxb</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax">; </span><span class="identifier-syntax">FlexFreeSingleBlockInternal</span><span class="plain-syntax">(</span><span class="identifier-syntax">block</span><span class="plain-syntax">); </span><span class="identifier-syntax">block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">ptxb</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">FlexFreeSingleBlockInternal</span><span class="plain-syntax">(</span><span class="identifier-syntax">block</span><span class="plain-syntax">);</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexFreeSingleBlockInternal</span><span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax"> </span><span class="identifier-syntax">free</span><span class="plain-syntax"> </span><span class="identifier-syntax">nx</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_RCOUNT</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax"> = </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">free</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Flex_Heap</span><span class="plain-syntax">:</span><span class="identifier-syntax">free</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">:</span><span class="identifier-syntax">free</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">nx</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">nx</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">FlexMergeInternal</span><span class="plain-syntax">(</span><span class="identifier-syntax">block</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">UnsignedCompare</span><span class="plain-syntax">(</span><span class="identifier-syntax">nx</span><span class="plain-syntax">, </span><span class="identifier-syntax">block</span><span class="plain-syntax">) == </span><span class="constant-syntax">1</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">free</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">nx</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">nx</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">FlexMergeInternal</span><span class="plain-syntax">(</span><span class="identifier-syntax">block</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP12"></a><b>&#167;12. Resizing. </b>A block which has been allocated, but not yet freed, can sometimes have
its data capacity changed by <span class="extract"><span class="extract-syntax">FlexResize</span></span>.
</p>
<p class="commentary">When the data being stored stretches or shrinks, we will sometimes need
to change the size of the block(s) containing the data &mdash; though not always:
we might sometimes need to resize a 1052-byte text to a 1204-byte text and
find that we are sitting in a 2048-byte block in any case. We either shed
blocks from the end of the chain, or add new blocks at the end, that being
the simplest thing to do. Sometimes it might mean preserving a not very
efficient block division, but it minimises the churn of blocks being
allocated and freed, which is probably good.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexResize</span><span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax"> </span><span class="identifier-syntax">req</span><span class="plain-syntax"> </span><span class="identifier-syntax">newsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">newblk</span><span class="plain-syntax"> </span><span class="identifier-syntax">kov</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> </span><span class="identifier-syntax">otxb</span><span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">block</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax">(</span><span class="string-syntax">"failed resizing null block"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kov</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">flags</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">flags</span><span class="plain-syntax"> &amp; </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">FlexError</span><span class="plain-syntax">(</span><span class="string-syntax">"failed resizing inextensible block"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">otxb</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newsize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">req</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (:: </span><span class="identifier-syntax">block</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">dsize</span><span class="plain-syntax">=1: </span><span class="identifier-syntax">n</span><span class="plain-syntax">&gt;0: </span><span class="identifier-syntax">n</span><span class="plain-syntax">--) </span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">dsize</span><span class="plain-syntax">*2;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> = </span><span class="identifier-syntax">dsize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newsize</span><span class="plain-syntax"> = </span><span class="identifier-syntax">newsize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">i</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">newsize</span><span class="plain-syntax"> &gt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) </span><span class="reserved-syntax">continue</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newblk</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FlexAllocate</span><span class="plain-syntax">(</span><span class="identifier-syntax">newsize</span><span class="plain-syntax">, </span><span class="identifier-syntax">kov</span><span class="plain-syntax">, </span><span class="identifier-syntax">flags</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">newblk</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">rfalse</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">newblk</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">newblk</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_PREV</span><span class="plain-syntax"> = </span><span class="identifier-syntax">block</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">FlexFree</span><span class="plain-syntax">(</span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">block</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP13"></a><b>&#167;13. Block Size. </b>These two routines are provided for the use of the <span class="extract"><span class="extract-syntax">BlockValue</span></span> routines
only.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax"> </span><span class="identifier-syntax">bsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax">; </span><span class="comment-syntax">Size of an individual block, including header</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">=1: </span><span class="identifier-syntax">n</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">txb</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">: </span><span class="identifier-syntax">bsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">*2) </span><span class="identifier-syntax">n</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">bsize</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexTotalSize</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax"> </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax">; </span><span class="comment-syntax">Combined size of multiple-blocks for a value</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">txb</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_FLAGS</span><span class="plain-syntax">) &amp; </span><span class="identifier-syntax">BLK_FLAG_MULTIPLE</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">txb</span><span class="plain-syntax">) - </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (:</span><span class="identifier-syntax">txb</span><span class="plain-syntax">~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">:</span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">txb</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax"> = </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax"> + </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">txb</span><span class="plain-syntax">) - </span><span class="identifier-syntax">BLK_DATA_MULTI_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<p class="commentary firstcommentary"><a id="SP14"></a><b>&#167;14. Debugging Routines. </b>These two routines are purely for testing the above code.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexDebug</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> </span><span class="identifier-syntax">k</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> </span><span class="identifier-syntax">bsize</span><span class="plain-syntax"> </span><span class="identifier-syntax">tot</span><span class="plain-syntax"> </span><span class="identifier-syntax">dtot</span><span class="plain-syntax"> </span><span class="identifier-syntax">kov</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="string-syntax">"Block never created."</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kov</span><span class="plain-syntax"> = </span><span class="identifier-syntax">txb</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"Block "</span><span class="plain-syntax">, </span><span class="identifier-syntax">txb</span><span class="plain-syntax">, </span><span class="string-syntax">" (kov "</span><span class="plain-syntax">, </span><span class="identifier-syntax">kov</span><span class="plain-syntax">, </span><span class="string-syntax">"): "</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (:</span><span class="identifier-syntax">txb</span><span class="plain-syntax">~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">:</span><span class="identifier-syntax">txb</span><span class="plain-syntax"> = </span><span class="identifier-syntax">txb</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">k</span><span class="plain-syntax">++ == </span><span class="constant-syntax">100</span><span class="plain-syntax">) </span><span class="string-syntax">" ... and so on."</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax"> ~= </span><span class="identifier-syntax">kov</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"*Wrong kov="</span><span class="plain-syntax">, </span><span class="identifier-syntax">txb</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_HEADER_KOV</span><span class="plain-syntax">, </span><span class="string-syntax">"* "</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">n</span><span class="plain-syntax"> = </span><span class="identifier-syntax">txb</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">BLK_HEADER_N</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">=1:</span><span class="identifier-syntax">n</span><span class="plain-syntax">&gt;0:</span><span class="identifier-syntax">n</span><span class="plain-syntax">--) </span><span class="identifier-syntax">bsize</span><span class="plain-syntax">=</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">*2;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> = </span><span class="identifier-syntax">bsize</span><span class="plain-syntax"> - </span><span class="identifier-syntax">BLK_DATA_OFFSET</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">dtot</span><span class="plain-syntax"> = </span><span class="identifier-syntax">dtot</span><span class="plain-syntax">+</span><span class="identifier-syntax">i</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">tot</span><span class="plain-syntax"> = </span><span class="identifier-syntax">tot</span><span class="plain-syntax">+</span><span class="identifier-syntax">bsize</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax">, </span><span class="string-syntax">"("</span><span class="plain-syntax">, </span><span class="identifier-syntax">bsize</span><span class="plain-syntax">, </span><span class="string-syntax">") &gt; "</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="identifier-syntax">dtot</span><span class="plain-syntax">, </span><span class="string-syntax">" data in "</span><span class="plain-syntax">, </span><span class="identifier-syntax">tot</span><span class="plain-syntax">, </span><span class="string-syntax">" bytes^"</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
<span class="plain-syntax">[ </span><span class="identifier-syntax">FlexDebugDecomposition</span><span class="plain-syntax"> </span><span class="identifier-syntax">from</span><span class="plain-syntax"> </span><span class="reserved-syntax">to</span><span class="plain-syntax"> </span><span class="identifier-syntax">txb</span><span class="plain-syntax"> </span><span class="identifier-syntax">pf</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="reserved-syntax">to</span><span class="plain-syntax">==0) </span><span class="reserved-syntax">to</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">from</span><span class="plain-syntax">:((</span><span class="identifier-syntax">txb</span><span class="plain-syntax">~=</span><span class="reserved-syntax">to</span><span class="plain-syntax">) &amp;&amp; (</span><span class="identifier-syntax">txb</span><span class="plain-syntax">~=</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">)):</span><span class="identifier-syntax">txb</span><span class="plain-syntax">=</span><span class="identifier-syntax">txb</span><span class="plain-syntax">--&gt;</span><span class="identifier-syntax">BLK_NEXT</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">pf</span><span class="plain-syntax">) </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"+"</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="identifier-syntax">FlexSize</span><span class="plain-syntax">(</span><span class="identifier-syntax">txb</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">pf</span><span class="plain-syntax"> = </span><span class="reserved-syntax">true</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">print</span><span class="plain-syntax"> </span><span class="string-syntax">"^"</span><span class="plain-syntax">;</span>
<span class="plain-syntax">];</span>
</pre>
<nav role="progress"><div class="progresscontainer">
<ul class="progressbar"><li class="progressprev"><a href="S-rlb.html">&#10094;</a></li><li class="progresssection"><a href="S-dfn.html">dfn</a></li><li class="progresssection"><a href="S-utl.html">utl</a></li><li class="progresssection"><a href="S-gll.html">gll</a></li><li class="progresssection"><a href="S-zmc.html">zmc</a></li><li class="progresssection"><a href="S-prg.html">prg</a></li><li class="progresssection"><a href="S-mth.html">mth</a></li><li class="progresssection"><a href="S-fl.html">fl</a></li><li class="progresssection"><a href="S-srt.html">srt</a></li><li class="progresssection"><a href="S-tbl.html">tbl</a></li><li class="progresssection"><a href="S-mst.html">mst</a></li><li class="progresssection"><a href="S-rlb.html">rlb</a></li><li class="progresscurrent">flx</li><li class="progresssection"><a href="S-blc.html">blc</a></li><li class="progresssection"><a href="S-txt.html">txt</a></li><li class="progresssection"><a href="S-unc.html">unc</a></li><li class="progresssection"><a href="S-chr.html">chr</a></li><li class="progresssection"><a href="S-rgx.html">rgx</a></li><li class="progresssection"><a href="S-lst.html">lst</a></li><li class="progresssection"><a href="S-cmb.html">cmb</a></li><li class="progresssection"><a href="S-rlt.html">rlt</a></li><li class="progresssection"><a href="S-rlt2.html">rlt2</a></li><li class="progresssection"><a href="S-rtp.html">rtp</a></li><li class="progressnext"><a href="S-blc.html">&#10095;</a></li></ul></div>
</nav><!--End of weave-->
</main>
</body>
</html>