inweb-bootstrap/docs/foundation-module/2-mmr.html
2020-05-02 23:50:23 +01:00

1118 lines
194 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Memory</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>
function togglePopup(material_id) {
var popup = document.getElementById(material_id);
popup.classList.toggle("show");
}
</script>
<link href="../docs-assets/Popups.css" rel="stylesheet" rev="stylesheet" type="text/css">
<script>
MathJax = {
tex: {
inlineMath: '$', '$'], ['\\(', '\\)'
},
svg: {
fontCache: 'global'
}
};
</script>
<script type="text/javascript" id="MathJax-script" async
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js">
</script>
<link href="../docs-assets/Colours.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body class="commentary-font">
<nav role="navigation">
<h1><a href="../index.html">
<img src="../docs-assets/Octagram.png" width=72 height=72">
</a></h1>
<ul><li><a href="../inweb/index.html">inweb</a></li>
</ul><h2>Foundation Module</h2><ul>
<li><a href="index.html"><span class="selectedlink">foundation</span></a></li>
<li><a href="../foundation-test/index.html">foundation-test</a></li>
</ul><h2>Example Webs</h2><ul>
<li><a href="../goldbach/index.html">goldbach</a></li>
<li><a href="../twinprimes/twinprimes.html">twinprimes</a></li>
<li><a href="../eastertide/index.html">eastertide</a></li>
</ul><h2>Repository</h2><ul>
<li><a href="https://github.com/ganelson/inweb"><img src="../docs-assets/github.png" height=18> github</a></li>
</ul><h2>Related Projects</h2><ul>
<li><a href="../../../inform/docs/index.html">inform</a></li>
<li><a href="../../../intest/docs/index.html">intest</a></li>
</ul>
</nav>
<main role="main">
<!--Weave of 'Memory' generated by Inweb-->
<div class="breadcrumbs">
<ul class="crumbs"><li><a href="../index.html">Home</a></li><li><a href="index.html">foundation</a></li><li><a href="index.html#2">Chapter 2: Memory, Streams and Collections</a></li><li><b>Memory</b></li></ul></div>
<p class="purpose">To allocate memory suitable for the dynamic creation of objects of different sizes, placing some larger objects automatically into doubly linked lists and assigning each a unique allocation ID number.</p>
<ul class="toc"><li><a href="2-mmr.html#SP1">&#167;1. Memory manager</a></li><li><a href="2-mmr.html#SP6">&#167;6. Architecture</a></li><li><a href="2-mmr.html#SP7">&#167;7. Level 1: memory blocks</a></li><li><a href="2-mmr.html#SP13">&#167;13. Level 2: memory frames and integrity checking</a></li><li><a href="2-mmr.html#SP17">&#167;17. Level 3: managing linked lists of allocated objects</a></li><li><a href="2-mmr.html#SP19">&#167;19. Allocator functions created by macros</a></li><li><a href="2-mmr.html#SP21">&#167;21. Expanding many macros</a></li><li><a href="2-mmr.html#SP22">&#167;22. Simple memory allocations</a></li><li><a href="2-mmr.html#SP28">&#167;28. Text storage</a></li><li><a href="2-mmr.html#SP32">&#167;32. Memory usage report</a></li><li><a href="2-mmr.html#SP36">&#167;36. Run-time pointer type checking</a></li></ul><hr class="tocbar">
<p class="commentary firstcommentary"><a id="SP1"></a><b>&#167;1. Memory manager. </b>This allocates memory as needed to store the numerous "objects" of different
sizes, all C structures. There's no garbage collection because nothing is ever
destroyed. Each type has its own doubly-linked list, and in each type the
objects created are given unique IDs (within that type) counting upwards
from 0. These IDs will be unique across all threads.
</p>
<p class="commentary firstcommentary"><a id="SP2"></a><b>&#167;2. </b>Before going much further, we will need to anticipate what the memory
manager wants. An "object" is a copy in memory of a C <span class="extract"><span class="extract-syntax">struct</span></span>; thus,
a plain <span class="extract"><span class="extract-syntax">int</span></span> is not an object. The memory manager can only deal with
a given type of <span class="extract"><span class="extract-syntax">struct</span></span> if it contains three special elements, and we
define those using a macro. Thus, if the user wants to allocate larger
structures of type <span class="extract"><span class="extract-syntax">thingummy</span></span>, then it needs to be defined like so:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="identifier-syntax">thingummy</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">whatsit</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">text_stream</span><span class="plain-syntax"> *</span><span class="identifier-syntax">doobrey</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> ...</span>
<span class="plain-syntax"> </span><span class="constant-syntax">MEMORY_MANAGEMENT</span>
<span class="plain-syntax"> }</span>
</pre>
<p class="commentary">The caveat about "larger structures" is that smaller objects can instead be
stored in arrays, to reduce memory and speed overheads. Their structure
declarations do not include the following macro; they do not have unique
IDs; and they cannot be iterated over.
</p>
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="constant-syntax">MEMORY_MANAGEMENT</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">allocation_id</span><span class="plain-syntax">; </span><span class="comment-syntax"> Numbered from 0 upwards in creation order</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next_structure</span><span class="plain-syntax">; </span><span class="comment-syntax"> Next object in double-linked list</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax">; </span><span class="comment-syntax"> Previous object in double-linked list</span>
</pre>
<p class="commentary firstcommentary"><a id="SP3"></a><b>&#167;3. </b>It is also necessary to define a constant in the following enumeration
family: for <span class="extract"><span class="extract-syntax">thingummy</span></span>, it would be <span class="extract"><span class="extract-syntax">thingummy_MT</span></span>. Had it been a smaller
object, it would have been <span class="extract"><span class="extract-syntax">thingummy_array_MT</span></span> instead.
</p>
<p class="commentary">There is no significance to the order in which structures are registered
with the memory system. The ones here are those needed by Foundation.
</p>
<pre class="definitions code-font"><span class="definition-keyword">enum</span> <span class="constant-syntax">filename_MT</span><span class="plain-syntax"> </span><span class="identifier-syntax">from</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">pathname_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">string_storage_area_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">scan_directory_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_datum_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_volume_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_chapter_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_page_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_image_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">HTML_file_state_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">HTML_tag_array_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">text_stream_array_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">command_line_switch_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">dictionary_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">dict_entry_array_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">debugging_aspect_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">linked_list_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">linked_list_item_array_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">match_avinue_array_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">match_trie_array_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">method_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">method_set_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">ebook_mark_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">semantic_version_number_holder_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">semver_range_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">web_md_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">chapter_md_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">section_md_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">web_bibliographic_datum_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">module_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">module_search_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">heterogeneous_tree_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">tree_type_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">tree_node_MT</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">tree_node_type_MT</span>
</pre>
<p class="commentary firstcommentary"><a id="SP4"></a><b>&#167;4. </b>For each type of object to be allocated, a single structure of the
following design is maintained. Types which are allocated individually,
like world objects, have <span class="extract"><span class="extract-syntax">no_allocated_together</span></span> set to 1, and the doubly
linked list is of the objects themselves. For types allocated in small
arrays (typically of 100 objects at a time), <span class="extract"><span class="extract-syntax">no_allocated_together</span></span> is set
to the number of objects in each completed array (so, typically 100) and
the doubly linked list is of the arrays.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">allocation_status_structure</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="comment-syntax"> actually needed for allocation purposes:</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">objects_allocated</span><span class="plain-syntax">; </span><span class="comment-syntax"> total number of objects (or arrays) ever allocated</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">first_in_memory</span><span class="plain-syntax">; </span><span class="comment-syntax"> head of doubly linked list</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">last_in_memory</span><span class="plain-syntax">; </span><span class="comment-syntax"> tail of doubly linked list</span>
<span class="plain-syntax"> </span><span class="comment-syntax"> used only to provide statistics for the debugging log:</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">name_of_type</span><span class="plain-syntax">; </span><span class="comment-syntax"> e.g., </span><span class="extract"><span class="extract-syntax">"lexicon_entry_MT"</span></span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">bytes_allocated</span><span class="plain-syntax">; </span><span class="comment-syntax"> total allocation for this type of object, not counting overhead</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">objects_count</span><span class="plain-syntax">; </span><span class="comment-syntax"> total number currently in existence (i.e., undeleted)</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">no_allocated_together</span><span class="plain-syntax">; </span><span class="comment-syntax"> number of objects in each array of this type of object</span>
<span class="plain-syntax">} </span><span class="reserved-syntax">allocation_status_structure</span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>The structure allocation_status_structure is private to this section.</li></ul>
<p class="commentary firstcommentary"><a id="SP5"></a><b>&#167;5. </b>The memory allocator itself needs some memory, but only a fixed-size and
fairly small array of the structures defined above. The allocator can safely
begin as soon as this is initialised.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">allocation_status_structure</span><span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</span><span class="plain-syntax">];</span>
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::start</span><button class="popup" onclick="togglePopup('usagePopup1')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup1">Usage of <span class="code-font"><span class="function-syntax">Memory::start</span></span>:<br/>Foundation Module - <a href="1-fm.html#SP8">&#167;8</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">first_in_memory</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">last_in_memory</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_count</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">name_of_type</span><span class="plain-syntax"> = </span><span class="string-syntax">"unused"</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP22" class="function-link"><span class="function-syntax">Memory::name_fundamental_reasons</span></a><span class="plain-syntax">();</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP6"></a><b>&#167;6. Architecture. </b>The memory manager is built in three levels, with its interface to the user
being entirely at level 3 (except that when it shuts down it calls a level 1
routine to free everything). Each level uses the one below it.
</p>
<ul class="items"><li>(3) Managing linked lists of large objects, within which objects can be
created at any point, and from which objects can be deleted; and providing
a way to create new small objects of any given type.
</li><li>(2) Allocating some thousands of memory frames, each holding one large object
or an array of small objects.
</li><li>(1) Allocating and freeing a few dozen large blocks of contiguous memory.
</li></ul>
<p class="commentary firstcommentary"><a id="SP7"></a><b>&#167;7. Level 1: memory blocks. </b>Memory is allocated in blocks within which objects are allocated as
needed. The "safety margin" is the number of spare bytes left blank at the
end of each object: this is done because we want to be paranoid about
compilers on different architectures aligning structures to different
boundaries (multiples of 4, 8, 16, etc.). Each block also ends with a
firebreak of zeroes, which ought never to be touched: we want to minimise the
chance of a mistake causing a memory exception which crashes the compiler,
because if that happens it will be difficult to recover the circumstances from
the debugging log.
</p>
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="constant-syntax">SAFETY_MARGIN</span><span class="plain-syntax"> </span><span class="constant-syntax">128</span>
<span class="definition-keyword">define</span> <span class="constant-syntax">BLANK_END_SIZE</span><span class="plain-syntax"> </span><span class="constant-syntax">256</span>
</pre>
<p class="commentary firstcommentary"><a id="SP8"></a><b>&#167;8. </b>At present <span class="extract"><span class="extract-syntax">MEMORY_GRANULARITY</span></span> is 800K. This is the quantity of memory
allocated by each individual <span class="extract"><span class="extract-syntax">malloc</span></span> call.
</p>
<p class="commentary">After <span class="extract"><span class="extract-syntax">MAX_BLOCKS_ALLOWED</span></span> blocks, we throw in the towel: we must have
fallen into an endless loop which creates endless new objects somewhere.
(If this ever happens, it would be a bug: the point of this mechanism is to
be able to recover. Without this safety measure, OS X in particular would
grind slowly to a halt, never refusing a <span class="extract"><span class="extract-syntax">malloc</span></span>, until the user was
unable to get the GUI responsive enough to kill the process.)
</p>
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="constant-syntax">MAX_BLOCKS_ALLOWED</span><span class="plain-syntax"> </span><span class="constant-syntax">15000</span>
<span class="definition-keyword">define</span> <span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax"> </span><span class="constant-syntax">100</span><span class="plain-syntax">*1024*8 </span><span class="comment-syntax"> which must be divisible by 1024</span>
</pre>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">no_blocks_allocated</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total_objects_allocated</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">; </span><span class="comment-syntax"> a potentially larger number, used only for the debugging log</span>
</pre>
<p class="commentary firstcommentary"><a id="SP9"></a><b>&#167;9. </b>Memory blocks are stored in a linked list, and we keep track of the
size of the current block: that is, the block at the tail of the list.
Each memory block consists of a header structure, followed by <span class="extract"><span class="extract-syntax">SAFETY_MARGIN</span></span>
null bytes, followed by actual data.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">block_number</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">the_memory</span><span class="plain-syntax">;</span>
<span class="plain-syntax">} </span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>The structure memblock_header is accessed in 2/trs, 4/taa and here.</li></ul>
<p class="commentary firstcommentary"><a id="SP10"></a><b>&#167;10. </b></p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> *</span><span class="identifier-syntax">first_memblock_header</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">; </span><span class="comment-syntax"> head of list of memory blocks</span>
<span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> *</span><span class="identifier-syntax">current_memblock_header</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">; </span><span class="comment-syntax"> tail of list of memory blocks</span>
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">used_in_current_memblock</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">; </span><span class="comment-syntax"> number of bytes so far used in the tail memory block</span>
</pre>
<p class="commentary firstcommentary"><a id="SP11"></a><b>&#167;11. </b>The actual allocation and deallocation is performed by the following
pair of routines.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::allocate_another_block</span><button class="popup" onclick="togglePopup('usagePopup2')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup2">Usage of <span class="code-font"><span class="function-syntax">Memory::allocate_another_block</span></span>:<br/><a href="2-mmr.html#SP16_1">&#167;16.1</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">cp</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> *</span><span class="identifier-syntax">mh</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP11_1" class="named-paragraph-link"><span class="named-paragraph">Allocate and zero out a block of memory, making cp point to it</span><span class="named-paragraph-number">11.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">mh</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">cp</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">used_in_current_memblock</span><span class="plain-syntax"> = </span><span class="reserved-syntax">sizeof</span><span class="plain-syntax">(</span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax">) + </span><span class="constant-syntax">SAFETY_MARGIN</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">mh</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">the_memory</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) (</span><span class="identifier-syntax">cp</span><span class="plain-syntax"> + </span><span class="identifier-syntax">used_in_current_memblock</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP11_2" class="named-paragraph-link"><span class="named-paragraph">Add new block to the tail of the list of memory blocks</span><span class="named-paragraph-number">11.2</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP11_1"></a><b>&#167;11.1. </b>Note that <span class="extract"><span class="extract-syntax">cp</span></span> and <span class="extract"><span class="extract-syntax">mh</span></span> are set to the same value: they merely have different
pointer types as far as the C compiler is concerned.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Allocate and zero out a block of memory, making cp point to it</span><span class="named-paragraph-number">11.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">int</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">no_blocks_allocated</span><span class="plain-syntax">++ &gt;= </span><span class="constant-syntax">MAX_BLOCKS_ALLOWED</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><a href="3-em.html#SP2" class="function-link"><span class="function-syntax">Errors::fatal</span></a><span class="plain-syntax">(</span>
<span class="plain-syntax"> </span><span class="string-syntax">"the memory manager has halted inweb, which seems to be generating "</span>
<span class="plain-syntax"> </span><span class="string-syntax">"endless structures. Presumably it is trapped in a loop"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP15" class="function-link"><span class="function-syntax">Memory::check_memory_integrity</span></a><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">cp</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *) (</span><a href="2-mmr.html#SP35" class="function-link"><span class="function-syntax">Memory::paranoid_calloc</span></a><span class="plain-syntax">(</span><span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax">, </span><span class="constant-syntax">1</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">cp</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) </span><a href="3-em.html#SP2" class="function-link"><span class="function-syntax">Errors::fatal</span></a><span class="plain-syntax">(</span><span class="string-syntax">"Run out of memory: malloc failed"</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">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) </span><span class="identifier-syntax">cp</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">] = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP11">&#167;11</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP11_2"></a><b>&#167;11.2. </b>As can be seen, memory block numbers count upwards from 0 in order of
their allocation.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Add new block to the tail of the list of memory blocks</span><span class="named-paragraph-number">11.2</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">current_memblock_header</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">mh</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">block_number</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">first_memblock_header</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mh</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">mh</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">block_number</span><span class="plain-syntax"> = </span><span class="identifier-syntax">current_memblock_header</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">block_number</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">current_memblock_header</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">next</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mh</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">current_memblock_header</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mh</span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP11">&#167;11</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP12"></a><b>&#167;12. </b>Freeing all this memory again is just a matter of freeing each block
in turn, but of course being careful to avoid following links in a just-freed
block.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::free</span><button class="popup" onclick="togglePopup('usagePopup3')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup3">Usage of <span class="code-font"><span class="function-syntax">Memory::free</span></span>:<br/>Foundation Module - <a href="1-fm.html#SP9">&#167;9</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP30" class="function-link"><span class="function-syntax">Memory::free_ssas</span></a><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">memblock_header</span><span class="plain-syntax"> *</span><span class="identifier-syntax">mh</span><span class="plain-syntax"> = </span><span class="identifier-syntax">first_memblock_header</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">mh</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">memblock_header</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next_mh</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mh</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">next</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">p</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">mh</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free</span><span class="plain-syntax">(</span><span class="identifier-syntax">p</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">mh</span><span class="plain-syntax"> = </span><span class="identifier-syntax">next_mh</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. Level 2: memory frames and integrity checking. </b>Within these extensive blocks of contiguous memory, we place the actual
objects in between "memory frames", which are only used at present to police
the integrity of memory: again, finding obscure and irritating memory-corruption
bugs is more important to us than saving bytes. Each memory frame wraps either
a single large object, or a single array of small objects.
</p>
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="constant-syntax">INTEGRITY_NUMBER</span><span class="plain-syntax"> </span><span class="constant-syntax">0x12345678</span><span class="plain-syntax"> </span><span class="comment-syntax"> a value unlikely to be in memory just by chance</span>
</pre>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">integrity_check</span><span class="plain-syntax">; </span><span class="comment-syntax"> this should always contain the </span><span class="extract"><span class="extract-syntax">INTEGRITY_NUMBER</span></span>
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next_frame</span><span class="plain-syntax">; </span><span class="comment-syntax"> next frame in the list of memory frames</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">; </span><span class="comment-syntax"> type of object stored in this frame</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">allocation_id</span><span class="plain-syntax">; </span><span class="comment-syntax"> allocation ID number of object stored in this frame</span>
<span class="plain-syntax">} </span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>The structure memory_frame is private to this section.</li></ul>
<p class="commentary firstcommentary"><a id="SP14"></a><b>&#167;14. </b>There is a single linked list of all the memory frames, perhaps of about
10000 entries in length, beginning here. (These frames live in different memory
blocks, but we don't need to worry about that.)
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *</span><span class="identifier-syntax">first_memory_frame</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">; </span><span class="comment-syntax"> earliest memory frame ever allocated</span>
<span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *</span><span class="identifier-syntax">last_memory_frame</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">; </span><span class="comment-syntax"> most recent memory frame allocated</span>
</pre>
<p class="commentary firstcommentary"><a id="SP15"></a><b>&#167;15. </b>If the integrity numbers of every frame are still intact, then it is pretty
unlikely that any bug has caused memory to overwrite one frame into another.
<span class="extract"><span class="extract-syntax">Memory::check_memory_integrity</span></span> might on very large runs be run often, if we didn't
prevent this: since the number of calls would be roughly proportional to
memory usage, we would implicitly have an \(O(n^2)\) running time in the
amount of storage \(n\) allocated.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">calls_to_cmi</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::check_memory_integrity</span><button class="popup" onclick="togglePopup('usagePopup4')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup4">Usage of <span class="code-font"><span class="function-syntax">Memory::check_memory_integrity</span></span>:<br/><a href="2-mmr.html#SP11_1">&#167;11.1</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">c</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *</span><span class="identifier-syntax">mf</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">c</span><span class="plain-syntax"> = </span><span class="identifier-syntax">calls_to_cmi</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">c</span><span class="plain-syntax">&lt;10) || (</span><span class="identifier-syntax">c</span><span class="plain-syntax"> == </span><span class="constant-syntax">100</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">c</span><span class="plain-syntax"> == </span><span class="constant-syntax">1000</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">c</span><span class="plain-syntax"> == </span><span class="constant-syntax">10000</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">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">c</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">, </span><span class="identifier-syntax">mf</span><span class="plain-syntax"> = </span><span class="identifier-syntax">first_memory_frame</span><span class="plain-syntax">; </span><span class="identifier-syntax">mf</span><span class="plain-syntax">; </span><span class="identifier-syntax">c</span><span class="plain-syntax">++, </span><span class="identifier-syntax">mf</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mf</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">next_frame</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">mf</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">integrity_check</span><span class="plain-syntax"> != </span><span class="constant-syntax">INTEGRITY_NUMBER</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><a href="3-em.html#SP2" class="function-link"><span class="function-syntax">Errors::fatal</span></a><span class="plain-syntax">(</span><span class="string-syntax">"Memory manager failed integrity check"</span><span class="plain-syntax">);</span>
<span class="plain-syntax">}</span>
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::debug_memory_frames</span><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">from</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">to</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">c</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *</span><span class="identifier-syntax">mf</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">c</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">, </span><span class="identifier-syntax">mf</span><span class="plain-syntax"> = </span><span class="identifier-syntax">first_memory_frame</span><span class="plain-syntax">; (</span><span class="identifier-syntax">mf</span><span class="plain-syntax">) &amp;&amp; (</span><span class="identifier-syntax">c</span><span class="plain-syntax"> &lt;= </span><span class="identifier-syntax">to</span><span class="plain-syntax">); </span><span class="identifier-syntax">c</span><span class="plain-syntax">++, </span><span class="identifier-syntax">mf</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mf</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">next_frame</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">c</span><span class="plain-syntax"> &gt;= </span><span class="identifier-syntax">from</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">desc</span><span class="plain-syntax"> = </span><span class="string-syntax">"corrupt"</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">mf</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">integrity_check</span><span class="plain-syntax"> == </span><span class="constant-syntax">INTEGRITY_NUMBER</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">desc</span><span class="plain-syntax"> = </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mf</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">name_of_type</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP16"></a><b>&#167;16. </b>We have seen how memory is allocated in large blocks, and that a linked
list of memory frames will live inside those blocks; we have seen how the
list is checked for integrity; but we not seen how it is built. Every
memory frame is created by the following function:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::allocate</span><button class="popup" onclick="togglePopup('usagePopup5')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup5">Usage of <span class="code-font"><span class="function-syntax">Memory::allocate</span></span>:<br/><a href="2-mmr.html#SP19">&#167;19</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">extent</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">cp</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *</span><span class="identifier-syntax">mf</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">bytes_free_in_current_memblock</span><span class="plain-syntax">, </span><span class="identifier-syntax">extent_without_overheads</span><span class="plain-syntax"> = </span><span class="identifier-syntax">extent</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">extent</span><span class="plain-syntax"> += </span><span class="reserved-syntax">sizeof</span><span class="plain-syntax">(</span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax">); </span><span class="comment-syntax"> each allocation is preceded by a memory frame</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">extent</span><span class="plain-syntax"> += </span><span class="constant-syntax">SAFETY_MARGIN</span><span class="plain-syntax">; </span><span class="comment-syntax"> each allocation is followed by </span><span class="extract"><span class="extract-syntax">SAFETY_MARGIN</span></span><span class="comment-syntax"> null bytes</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP16_1" class="named-paragraph-link"><span class="named-paragraph">Ensure that the current memory block has room for this many bytes</span><span class="named-paragraph-number">16.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">cp</span><span class="plain-syntax"> = ((</span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *) (</span><span class="identifier-syntax">current_memblock_header</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">the_memory</span><span class="plain-syntax">)) + </span><span class="identifier-syntax">used_in_current_memblock</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">used_in_current_memblock</span><span class="plain-syntax"> += </span><span class="identifier-syntax">extent</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">mf</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">cp</span><span class="plain-syntax">; </span><span class="comment-syntax"> the new memory frame,</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">cp</span><span class="plain-syntax"> = </span><span class="identifier-syntax">cp</span><span class="plain-syntax"> + </span><span class="reserved-syntax">sizeof</span><span class="plain-syntax">(</span><span class="reserved-syntax">memory_frame</span><span class="plain-syntax">); </span><span class="comment-syntax"> following which is the actual allocated data</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">mf</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">integrity_check</span><span class="plain-syntax"> = </span><span class="constant-syntax">INTEGRITY_NUMBER</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">mf</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">allocation_id</span><span class="plain-syntax"> = </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">mf</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">mem_type</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP16_2" class="named-paragraph-link"><span class="named-paragraph">Add the new memory frame to the big linked list of all frames</span><span class="named-paragraph-number">16.2</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP16_3" class="named-paragraph-link"><span class="named-paragraph">Update the allocation status for this type of object</span><span class="named-paragraph-number">16.3</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">total_objects_allocated</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">cp</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP16_1"></a><b>&#167;16.1. </b>The granularity error below will be triggered the first time a particular
object type is allocated. So this is not a potential time-bomb just waiting
for a user with a particularly long and involved source text to discover.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Ensure that the current memory block has room for this many bytes</span><span class="named-paragraph-number">16.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">current_memblock_header</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) </span><a href="2-mmr.html#SP11" class="function-link"><span class="function-syntax">Memory::allocate_another_block</span></a><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">bytes_free_in_current_memblock</span><span class="plain-syntax"> = </span><span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax"> - (</span><span class="identifier-syntax">used_in_current_memblock</span><span class="plain-syntax"> + </span><span class="identifier-syntax">extent</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">bytes_free_in_current_memblock</span><span class="plain-syntax"> &lt; </span><span class="constant-syntax">BLANK_END_SIZE</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP11" class="function-link"><span class="function-syntax">Memory::allocate_another_block</span></a><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">extent</span><span class="plain-syntax">+</span><span class="constant-syntax">BLANK_END_SIZE</span><span class="plain-syntax"> &gt;= </span><span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><a href="3-em.html#SP2" class="function-link"><span class="function-syntax">Errors::fatal</span></a><span class="plain-syntax">(</span><span class="string-syntax">"Memory manager failed because granularity too low"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP16">&#167;16</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP16_2"></a><b>&#167;16.2. </b>New memory frames are added to the tail of the list:
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Add the new memory frame to the big linked list of all frames</span><span class="named-paragraph-number">16.2</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">mf</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">next_frame</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">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">first_memory_frame</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) </span><span class="identifier-syntax">first_memory_frame</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mf</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">last_memory_frame</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">next_frame</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mf</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">last_memory_frame</span><span class="plain-syntax"> = </span><span class="identifier-syntax">mf</span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP16">&#167;16</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP16_3"></a><b>&#167;16.3. </b>See the definition of <span class="extract"><span class="extract-syntax">alloc_status</span></span> above.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Update the allocation status for this type of object</span><span class="named-paragraph-number">16.3</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">first_in_memory</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">first_in_memory</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">cp</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">last_in_memory</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">cp</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">mem_type</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</span><span class="plain-syntax"> += </span><span class="identifier-syntax">extent_without_overheads</span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP16">&#167;16</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP17"></a><b>&#167;17. Level 3: managing linked lists of allocated objects. </b>We define macros which look as if they are functions, but for which one
argument is the name of a type: expanding these macros provides suitable C
functions to handle each possible type. These macros provide the interface
through which all other sections allocate and leaf through memory.
</p>
<p class="commentary">Note that Inweb allows multi-line macro definitions without backslashes
to continue them, unlike ordinary C. Otherwise these are "standard"
macros, though this was my first brush with the <span class="extract"><span class="extract-syntax">##</span></span> concatenation
operator: basically <span class="extract"><span class="extract-syntax">CREATE(thing)</span></span> expands into <span class="extract"><span class="extract-syntax">(allocate_thing())</span></span>
because of the <span class="extract"><span class="extract-syntax">##</span></span>. (See Kernighan and Ritchie, section 4.11.2.)
</p>
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="identifier-syntax">CREATE</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) (</span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">())</span>
<span class="definition-keyword">define</span> <span class="identifier-syntax">COPY</span><span class="plain-syntax">(</span><span class="identifier-syntax">to</span><span class="plain-syntax">, </span><span class="identifier-syntax">from</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) (</span><span class="identifier-syntax">copy_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="identifier-syntax">to</span><span class="plain-syntax">, </span><span class="identifier-syntax">from</span><span class="plain-syntax">))</span>
<span class="definition-keyword">define</span> <span class="identifier-syntax">CREATE_BEFORE</span><span class="plain-syntax">(</span><span class="identifier-syntax">existing</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) (</span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_before</span><span class="plain-syntax">(</span><span class="identifier-syntax">existing</span><span class="plain-syntax">))</span>
<span class="definition-keyword">define</span> <span class="identifier-syntax">DESTROY</span><span class="plain-syntax">(</span><span class="identifier-syntax">this</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) (</span><span class="identifier-syntax">deallocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="identifier-syntax">this</span><span class="plain-syntax">))</span>
<span class="definition-keyword">define</span> <span class="identifier-syntax">FIRST_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) ((</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">first_in_memory</span><span class="plain-syntax">)</span>
<span class="definition-keyword">define</span> <span class="identifier-syntax">LAST_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) ((</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">last_in_memory</span><span class="plain-syntax">)</span>
<span class="definition-keyword">define</span> <span class="identifier-syntax">NEXT_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">this</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) ((</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *) (</span><span class="identifier-syntax">this</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">next_structure</span><span class="plain-syntax">))</span>
<span class="definition-keyword">define</span> <span class="identifier-syntax">PREV_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">this</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) ((</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *) (</span><span class="identifier-syntax">this</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax">))</span>
<span class="definition-keyword">define</span> <span class="identifier-syntax">NUMBER_CREATED</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) (</span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">objects_count</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary firstcommentary"><a id="SP18"></a><b>&#167;18. </b>The following macros are widely used (well, the first one is, anyway)
for looking through the double linked list of existing objects of a
given type.
</p>
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="identifier-syntax">LOOP_OVER</span><span class="plain-syntax">(</span><span class="identifier-syntax">var</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</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">var</span><span class="plain-syntax">=</span><span class="identifier-syntax">FIRST_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">); </span><span class="identifier-syntax">var</span><span class="plain-syntax"> != </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">; </span><span class="identifier-syntax">var</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NEXT_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">var</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">))</span>
<span class="definition-keyword">define</span> <span class="identifier-syntax">LOOP_BACKWARDS_OVER</span><span class="plain-syntax">(</span><span class="identifier-syntax">var</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</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">var</span><span class="plain-syntax">=</span><span class="identifier-syntax">LAST_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">); </span><span class="identifier-syntax">var</span><span class="plain-syntax"> != </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">; </span><span class="identifier-syntax">var</span><span class="plain-syntax"> = </span><span class="identifier-syntax">PREV_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">var</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">))</span>
</pre>
<p class="commentary firstcommentary"><a id="SP19"></a><b>&#167;19. Allocator functions created by macros. </b>The following macros generate a family of systematically named functions.
For instance, we shall shortly expand <span class="extract"><span class="extract-syntax">ALLOCATE_INDIVIDUALLY(parse_node)</span></span>,
which will expand to three functions: <span class="extract"><span class="extract-syntax">allocate_parse_node</span></span>,
<span class="extract"><span class="extract-syntax">deallocate_parse_node</span></span> and <span class="extract"><span class="extract-syntax">allocate_parse_node_before</span></span>.
</p>
<p class="commentary">Quaintly, <span class="extract"><span class="extract-syntax">#type_name</span></span> expands into the value of <span class="extract"><span class="extract-syntax">type_name</span></span> put within
double-quotes.
</p>
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="identifier-syntax">NEW_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">) ((</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *) </span><a href="2-mmr.html#SP16" class="function-link"><span class="function-syntax">Memory::allocate</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">, </span><span class="reserved-syntax">sizeof</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">)))</span>
<span class="definition-keyword">define</span> <span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">MAKE_REFERENCE_ROUTINES</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="identifier-syntax">name_of_type</span><span class="plain-syntax"> = #</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">LAST_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">new_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NEW_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">allocation_id</span><span class="plain-syntax"> = </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">-1;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">next_structure</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">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">prev_obj</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">prev_obj</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">next_structure</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="identifier-syntax">objects_count</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</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">new_obj</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="identifier-syntax">deallocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">kill_me</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">PREV_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">kill_me</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NEXT_OBJECT</span><span class="plain-syntax">(</span><span class="identifier-syntax">kill_me</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</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">prev_obj</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">first_in_memory</span><span class="plain-syntax"> = </span><span class="identifier-syntax">next_obj</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">next_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">next_obj</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">next_obj</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">last_in_memory</span><span class="plain-syntax"> = </span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">next_obj</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="identifier-syntax">objects_count</span><span class="plain-syntax">--;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax">}</span>
<span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_before</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">existing</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">new_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">deallocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">existing</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">prev_structure</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">existing</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">prev_structure</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">type_name</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">existing</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax">)-&gt;</span><span class="identifier-syntax">next_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">new_obj</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="element-syntax">first_in_memory</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">next_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">existing</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">existing</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">new_obj</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_MT</span><span class="plain-syntax">].</span><span class="identifier-syntax">objects_count</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</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">new_obj</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="identifier-syntax">copy_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">to</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">from</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next_obj</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">next_structure</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">aid</span><span class="plain-syntax"> = </span><span class="identifier-syntax">to</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">allocation_id</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> *</span><span class="identifier-syntax">to</span><span class="plain-syntax"> = *</span><span class="identifier-syntax">from</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">allocation_id</span><span class="plain-syntax"> = </span><span class="identifier-syntax">aid</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">next_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">next_obj</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">to</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">prev_structure</span><span class="plain-syntax"> = </span><span class="identifier-syntax">prev_obj</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP20"></a><b>&#167;20. </b><span class="extract"><span class="extract-syntax">ALLOCATE_IN_ARRAYS</span></span> is still more obfuscated. When we
<span class="extract"><span class="extract-syntax">ALLOCATE_IN_ARRAYS(X, 100)</span></span>, the result will be definitions of a new type
<span class="extract"><span class="extract-syntax">X_block</span></span> and functions <span class="extract"><span class="extract-syntax">allocate_X</span></span>, <span class="extract"><span class="extract-syntax">allocate_X_block</span></span>,
<span class="extract"><span class="extract-syntax">deallocate_X_block</span></span> and <span class="extract"><span class="extract-syntax">allocate_X_block_before</span></span> (though the last is not
destined ever to be used). Note that we are not provided with the means to
deallocate individual objects this time: that's the trade-off for
allocating in blocks.
</p>
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">, </span><span class="identifier-syntax">NO_TO_ALLOCATE_TOGETHER</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">MAKE_REFERENCE_ROUTINES</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">, </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array_MT</span><span class="plain-syntax">)</span>
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">used</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> </span><span class="identifier-syntax">array</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_TO_ALLOCATE_TOGETHER</span><span class="plain-syntax">];</span>
<span class="plain-syntax"> </span><span class="constant-syntax">MEMORY_MANAGEMENT</span>
<span class="plain-syntax">} </span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">;</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax"> *</span><span class="identifier-syntax">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</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">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</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">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">used</span><span class="plain-syntax"> &gt;= </span><span class="identifier-syntax">NO_TO_ALLOCATE_TOGETHER</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array_MT</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NO_TO_ALLOCATE_TOGETHER</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax"> = </span><span class="identifier-syntax">allocate_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">used</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> &amp;(</span><span class="identifier-syntax">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">array</span><span class="plain-syntax">[</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">next_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">##</span><span class="identifier-syntax">_array</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">used</span><span class="plain-syntax">++]);</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP21"></a><b>&#167;21. Expanding many macros. </b>Each given structure must have a typedef name, say <span class="extract"><span class="extract-syntax">marvel</span></span>, and can be
used in one of two ways. Either way, we can obtain a new one with the macro
<span class="extract"><span class="extract-syntax">CREATE(marvel)</span></span>.
</p>
<p class="commentary">Either (a) it will be individually allocated. In this case <span class="extract"><span class="extract-syntax">marvel_MT</span></span>
should be defined with a new MT (memory type) number, and the macro
<span class="extract"><span class="extract-syntax">ALLOCATE_INDIVIDUALLY(marvel)</span></span> should be expanded. The first and last
objects created will be <span class="extract"><span class="extract-syntax">FIRST_OBJECT(marvel)</span></span> and <span class="extract"><span class="extract-syntax">LAST_OBJECT(marvel)</span></span>,
and we can proceed either way through a double linked list of them with
<span class="extract"><span class="extract-syntax">PREV_OBJECT(mv, marvel)</span></span> and <span class="extract"><span class="extract-syntax">NEXT_OBJECT(mv, marvel)</span></span>. For convenience,
we can loop through marvels, in creation order, using <span class="extract"><span class="extract-syntax">LOOP_OVER(var,
</span></span>marvel)<span class="extract"><span class="extract-syntax">, which expands to a </span></span>for<span class="extract"><span class="extract-syntax"> loop in which the variable </span></span>var<span class="extract"><span class="extract-syntax"> runs
</span></span>through each created marvel in turn; or equally we can run backwards
through using <span class="extract"><span class="extract-syntax">LOOP_BACKWARDS_OVER(var, marvel)</span></span>. In addition, there are
corruption checks to protect the memory from overrunning accidents, and the
structure can be used as a value in the symbols table. Good for large
structures with significant semantic content.
</p>
<p class="commentary">Or (b) it will be allocated in arrays. Once again we can obtain new marvels
with <span class="extract"><span class="extract-syntax">CREATE(marvel)</span></span>. This is more efficient both in speed and memory
usage, but we lose the ability to loop through the objects. For this
arrangement, define <span class="extract"><span class="extract-syntax">marvel_array_MT</span></span> with a new MT number and expand the
macro <span class="extract"><span class="extract-syntax">ALLOCATE_IN_ARRAYS(marvel, 100)</span></span>, where 100 (or what may you) is the
number of objects allocated jointly as a block. Good for small structures
used in the lower levels.
</p>
<p class="commentary">Here goes, then.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">filename</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">pathname</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">string_storage_area</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">scan_directory</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook_datum</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook_volume</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook_chapter</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook_page</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook_image</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">HTML_file_state</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">command_line_switch</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">dictionary</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">debugging_aspect</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">linked_list</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">method</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">method_set</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">ebook_mark</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">semantic_version_number_holder</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">semver_range</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">web_bibliographic_datum</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">web_md</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">chapter_md</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">section_md</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">module</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">module_search</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">heterogeneous_tree</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">tree_type</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">tree_node</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_INDIVIDUALLY</span><span class="plain-syntax">(</span><span class="reserved-syntax">tree_node_type</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="reserved-syntax">dict_entry</span><span class="plain-syntax">, </span><span class="constant-syntax">100</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="reserved-syntax">HTML_tag</span><span class="plain-syntax">, </span><span class="constant-syntax">1000</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="reserved-syntax">linked_list_item</span><span class="plain-syntax">, </span><span class="constant-syntax">1000</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="reserved-syntax">match_avinue</span><span class="plain-syntax">, </span><span class="constant-syntax">1000</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="reserved-syntax">match_trie</span><span class="plain-syntax">, </span><span class="constant-syntax">1000</span><span class="plain-syntax">)</span>
<span class="identifier-syntax">ALLOCATE_IN_ARRAYS</span><span class="plain-syntax">(</span><span class="reserved-syntax">text_stream</span><span class="plain-syntax">, </span><span class="constant-syntax">100</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary firstcommentary"><a id="SP22"></a><b>&#167;22. Simple memory allocations. </b>Not all of our memory will be claimed in the form of structures: now and then
we need to use the equivalent of traditional <span class="extract"><span class="extract-syntax">malloc</span></span> and <span class="extract"><span class="extract-syntax">calloc</span></span> routines.
</p>
<pre class="definitions code-font"><span class="definition-keyword">enum</span> <span class="constant-syntax">STREAM_MREASON</span><span class="plain-syntax"> </span><span class="identifier-syntax">from</span><span class="plain-syntax"> </span><span class="constant-syntax">0</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">FILENAME_STORAGE_MREASON</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">STRING_STORAGE_MREASON</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">DICTIONARY_MREASON</span>
<span class="definition-keyword">enum</span> <span class="constant-syntax">CLS_SORTING_MREASON</span>
</pre>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::name_fundamental_reasons</span><button class="popup" onclick="togglePopup('usagePopup6')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup6">Usage of <span class="code-font"><span class="function-syntax">Memory::name_fundamental_reasons</span></span>:<br/><a href="2-mmr.html#SP5">&#167;5</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP23" class="function-link"><span class="function-syntax">Memory::reason_name</span></a><span class="plain-syntax">(</span><span class="constant-syntax">STREAM_MREASON</span><span class="plain-syntax">, </span><span class="string-syntax">"text stream storage"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP23" class="function-link"><span class="function-syntax">Memory::reason_name</span></a><span class="plain-syntax">(</span><span class="constant-syntax">FILENAME_STORAGE_MREASON</span><span class="plain-syntax">, </span><span class="string-syntax">"filename/pathname storage"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP23" class="function-link"><span class="function-syntax">Memory::reason_name</span></a><span class="plain-syntax">(</span><span class="constant-syntax">STRING_STORAGE_MREASON</span><span class="plain-syntax">, </span><span class="string-syntax">"string storage"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP23" class="function-link"><span class="function-syntax">Memory::reason_name</span></a><span class="plain-syntax">(</span><span class="constant-syntax">DICTIONARY_MREASON</span><span class="plain-syntax">, </span><span class="string-syntax">"dictionary storage"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP23" class="function-link"><span class="function-syntax">Memory::reason_name</span></a><span class="plain-syntax">(</span><span class="constant-syntax">CLS_SORTING_MREASON</span><span class="plain-syntax">, </span><span class="string-syntax">"sorting"</span><span class="plain-syntax">);</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP23"></a><b>&#167;23. </b>And here is the (very simple) implementation.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">memory_needs</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">];</span>
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::reason_name</span><button class="popup" onclick="togglePopup('usagePopup7')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup7">Usage of <span class="code-font"><span class="function-syntax">Memory::reason_name</span></span>:<br/><a href="2-mmr.html#SP22">&#167;22</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">r</span><span class="plain-syntax">, </span><span class="reserved-syntax">char</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">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">r</span><span class="plain-syntax"> &lt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">r</span><span class="plain-syntax"> &gt;= </span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">)) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"MR out of range"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">memory_needs</span><span class="plain-syntax">[</span><span class="identifier-syntax">r</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">char</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::description_of_reason</span><button class="popup" onclick="togglePopup('usagePopup8')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup8">Usage of <span class="code-font"><span class="function-syntax">Memory::description_of_reason</span></span>:<br/><a href="2-mmr.html#SP26_1">&#167;26.1</a>, <a href="2-mmr.html#SP31">&#167;31</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">r</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">r</span><span class="plain-syntax"> &lt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">r</span><span class="plain-syntax"> &gt;= </span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">)) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"MR out of range"</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">memory_needs</span><span class="plain-syntax">[</span><span class="identifier-syntax">r</span><span class="plain-syntax">];</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP24"></a><b>&#167;24. </b>We keep some statistics on this. The value for "memory claimed" is the
net amount of memory currently owned, which is increased when we allocate
it and decreased when we free it. Whether the host OS is able to make
efficient use of the memory we free, we can't know, but it probably is, and
therefore the best estimate of how well we're doing is the "maximum memory
claimed" &mdash; the highest recorded net usage count over the run.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">max_memory_at_once_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">],</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">memory_claimed_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">],</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">number_of_claims_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">];</span>
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total_claimed_simply</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
</pre>
<p class="commentary firstcommentary"><a id="SP25"></a><b>&#167;25. </b>Our allocation routines behave just like the standard C library's <span class="extract"><span class="extract-syntax">malloc</span></span>
and <span class="extract"><span class="extract-syntax">calloc</span></span>, but where a third argument supplies a reason why the memory is
needed, and where any failure to allocate memory is tidily dealt with. We will
exit on any such failure, so that the caller can be certain that the return
values of these functions are always non-<span class="extract"><span class="extract-syntax">NULL</span></span> pointers.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::calloc</span><button class="popup" onclick="togglePopup('usagePopup9')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup9">Usage of <span class="code-font"><span class="function-syntax">Memory::calloc</span></span>:<br/>Streams - <a href="2-str.html#SP26">&#167;26</a><br/>Dictionaries - <a href="2-dct.html#SP2">&#167;2</a><br/>Command Line Arguments - <a href="3-cla.html#SP14">&#167;14</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">how_many</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</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">return</span><span class="plain-syntax"> </span><a href="2-mmr.html#SP26" class="function-link"><span class="function-syntax">Memory::alloc_inner</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">how_many</span><span class="plain-syntax">, </span><span class="identifier-syntax">size_in_bytes</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">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::malloc</span><button class="popup" onclick="togglePopup('usagePopup10')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup10">Usage of <span class="code-font"><span class="function-syntax">Memory::malloc</span></span>:<br/><a href="2-mmr.html#SP29">&#167;29</a><br/>Streams - <a href="2-str.html#SP35_3">&#167;35.3</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</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">return</span><span class="plain-syntax"> </span><a href="2-mmr.html#SP26" class="function-link"><span class="function-syntax">Memory::alloc_inner</span></a><span class="plain-syntax">(-1, </span><span class="identifier-syntax">size_in_bytes</span><span class="plain-syntax">, </span><span class="identifier-syntax">reason</span><span class="plain-syntax">);</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP26"></a><b>&#167;26. </b>And this, then, is the joint routine implementing both.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::alloc_inner</span><button class="popup" onclick="togglePopup('usagePopup11')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup11">Usage of <span class="code-font"><span class="function-syntax">Memory::alloc_inner</span></span>:<br/><a href="2-mmr.html#SP25">&#167;25</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">N</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">S</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">R</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">pointer</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">bytes_needed</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">R</span><span class="plain-syntax"> &lt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">R</span><span class="plain-syntax"> &gt;= </span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">)) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"no such memory reason"</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">total_claimed_simply</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP26_2" class="named-paragraph-link"><span class="named-paragraph">Zero out the statistics on simple memory allocations</span><span class="named-paragraph-number">26.2</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP26_1" class="named-paragraph-link"><span class="named-paragraph">Claim the memory using malloc or calloc as appropriate</span><span class="named-paragraph-number">26.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP26_3" class="named-paragraph-link"><span class="named-paragraph">Update the statistics on simple memory allocations</span><span class="named-paragraph-number">26.3</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</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">pointer</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP26_1"></a><b>&#167;26.1. </b>I am nervous about assuming that <span class="extract"><span class="extract-syntax">calloc(0, X)</span></span> returns a non-<span class="extract"><span class="extract-syntax">NULL</span></span> pointer
in all implementations of the standard C library, so the case when <span class="extract"><span class="extract-syntax">N</span></span> is zero
allocates a tiny but positive amount of memory, just to be safe.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Claim the memory using malloc or calloc as appropriate</span><span class="named-paragraph-number">26.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">N</span><span class="plain-syntax"> &gt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">pointer</span><span class="plain-syntax"> = </span><a href="2-mmr.html#SP35" class="function-link"><span class="function-syntax">Memory::paranoid_calloc</span></a><span class="plain-syntax">((</span><span class="identifier-syntax">size_t</span><span class="plain-syntax">) </span><span class="identifier-syntax">N</span><span class="plain-syntax">, (</span><span class="identifier-syntax">size_t</span><span class="plain-syntax">) </span><span class="identifier-syntax">S</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">bytes_needed</span><span class="plain-syntax"> = </span><span class="identifier-syntax">N</span><span class="plain-syntax">*</span><span class="identifier-syntax">S</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">pointer</span><span class="plain-syntax"> = </span><a href="2-mmr.html#SP35" class="function-link"><span class="function-syntax">Memory::paranoid_calloc</span></a><span class="plain-syntax">(1, (</span><span class="identifier-syntax">size_t</span><span class="plain-syntax">) </span><span class="identifier-syntax">S</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">bytes_needed</span><span class="plain-syntax"> = </span><span class="identifier-syntax">S</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">pointer</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><a href="3-em.html#SP2" class="function-link"><span class="function-syntax">Errors::fatal_with_C_string</span></a><span class="plain-syntax">(</span><span class="string-syntax">"Out of memory for %s"</span><span class="plain-syntax">, </span><a href="2-mmr.html#SP23" class="function-link"><span class="function-syntax">Memory::description_of_reason</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">R</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> }</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP26">&#167;26</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP26_2"></a><b>&#167;26.2. </b>These statistics have no function except to improve the diagnostics in the
debugging log, but they are very cheap to keep, since <span class="extract"><span class="extract-syntax">Memory::alloc_inner</span></span> is called only
rarely and to allocate large blocks of memory.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Zero out the statistics on simple memory allocations</span><span class="named-paragraph-number">26.2</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">int</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">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</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">max_memory_at_once_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</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">memory_claimed_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</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">number_of_claims_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">] = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP26">&#167;26</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP26_3"></a><b>&#167;26.3. </b><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Update the statistics on simple memory allocations</span><span class="named-paragraph-number">26.3</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">memory_claimed_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</span><span class="plain-syntax">] += </span><span class="identifier-syntax">bytes_needed</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">total_claimed_simply</span><span class="plain-syntax"> += </span><span class="identifier-syntax">bytes_needed</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">number_of_claims_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</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">memory_claimed_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</span><span class="plain-syntax">] &gt; </span><span class="identifier-syntax">max_memory_at_once_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</span><span class="plain-syntax">])</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">max_memory_at_once_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</span><span class="plain-syntax">] = </span><span class="identifier-syntax">memory_claimed_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</span><span class="plain-syntax">];</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP26">&#167;26</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP27"></a><b>&#167;27. </b>We also provide our own wrapper for <span class="extract"><span class="extract-syntax">free</span></span>:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::I7_free</span><button class="popup" onclick="togglePopup('usagePopup12')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup12">Usage of <span class="code-font"><span class="function-syntax">Memory::I7_free</span></span>:<br/><a href="2-mmr.html#SP30">&#167;30</a><br/>Streams - <a href="2-str.html#SP34_2">&#167;34.2</a><br/>Dictionaries - <a href="2-dct.html#SP7_2">&#167;7.2</a>, <a href="2-dct.html#SP11">&#167;11</a><br/>Command Line Arguments - <a href="3-cla.html#SP14">&#167;14</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">pointer</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">R</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">bytes_freed</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">R</span><span class="plain-syntax"> &lt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">R</span><span class="plain-syntax"> &gt;= </span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</span><span class="plain-syntax">)) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"no such memory reason"</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">pointer</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"can't free NULL memory"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">memory_claimed_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">R</span><span class="plain-syntax">] -= </span><span class="identifier-syntax">bytes_freed</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">free</span><span class="plain-syntax">(</span><span class="identifier-syntax">pointer</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax">}</span>
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::I7_array_free</span><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">pointer</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">R</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">num_cells</span><span class="plain-syntax">, </span><span class="identifier-syntax">size_t</span><span class="plain-syntax"> </span><span class="identifier-syntax">cell_size</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP27" class="function-link"><span class="function-syntax">Memory::I7_free</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">pointer</span><span class="plain-syntax">, </span><span class="identifier-syntax">R</span><span class="plain-syntax">, </span><span class="identifier-syntax">num_cells</span><span class="plain-syntax">*((</span><span class="reserved-syntax">int</span><span class="plain-syntax">) </span><span class="identifier-syntax">cell_size</span><span class="plain-syntax">));</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP28"></a><b>&#167;28. Text storage. </b>We will also use much simpler memory areas for text, in 64K chunks:
</p>
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="constant-syntax">SSA_CAPACITY</span><span class="plain-syntax"> </span><span class="constant-syntax">64</span><span class="plain-syntax">*1024</span>
</pre>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">string_storage_area</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">storage_at</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">first_free_byte</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="constant-syntax">MEMORY_MANAGEMENT</span>
<span class="plain-syntax">} </span><span class="reserved-syntax">string_storage_area</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">string_storage_area</span><span class="plain-syntax"> *</span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>The structure string_storage_area is private to this section.</li></ul>
<p class="commentary firstcommentary"><a id="SP29"></a><b>&#167;29. </b>The following is ideal for parking a read-only string of text somewhere
safe in memory. Since the length can't be extended, it's usually unsafe
to write to the result.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::new_string</span><span class="plain-syntax">(</span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">from</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">length_needed</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">int</span><span class="plain-syntax">) </span><span class="identifier-syntax">strlen</span><span class="plain-syntax">(</span><span class="identifier-syntax">from</span><span class="plain-syntax">) + </span><span class="constant-syntax">1</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (!((</span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">) &amp;&amp;</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">first_free_byte</span><span class="plain-syntax"> + </span><span class="identifier-syntax">length_needed</span><span class="plain-syntax"> &lt; </span><span class="constant-syntax">SSA_CAPACITY</span><span class="plain-syntax">))) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax"> = </span><span class="identifier-syntax">CREATE</span><span class="plain-syntax">(</span><span class="reserved-syntax">string_storage_area</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">storage_at</span><span class="plain-syntax"> = </span><a href="2-mmr.html#SP25" class="function-link"><span class="function-syntax">Memory::malloc</span></a><span class="plain-syntax">(</span><span class="constant-syntax">SSA_CAPACITY</span><span class="plain-syntax">, </span><span class="constant-syntax">STRING_STORAGE_MREASON</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">first_free_byte</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">char</span><span class="plain-syntax"> *</span><span class="identifier-syntax">rp</span><span class="plain-syntax"> = </span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">storage_at</span><span class="plain-syntax"> + </span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">first_free_byte</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">current_ssa</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">first_free_byte</span><span class="plain-syntax"> += </span><span class="identifier-syntax">length_needed</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">strcpy</span><span class="plain-syntax">(</span><span class="identifier-syntax">rp</span><span class="plain-syntax">, </span><span class="identifier-syntax">from</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</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">rp</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP30"></a><b>&#167;30. </b>And here we free any SSAs needed in the course of the run.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::free_ssas</span><button class="popup" onclick="togglePopup('usagePopup13')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup13">Usage of <span class="code-font"><span class="function-syntax">Memory::free_ssas</span></span>:<br/><a href="2-mmr.html#SP12">&#167;12</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">string_storage_area</span><span class="plain-syntax"> *</span><span class="identifier-syntax">ssa</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOOP_OVER</span><span class="plain-syntax">(</span><span class="identifier-syntax">ssa</span><span class="plain-syntax">, </span><span class="reserved-syntax">string_storage_area</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP27" class="function-link"><span class="function-syntax">Memory::I7_free</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">ssa</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">storage_at</span><span class="plain-syntax">, </span><span class="constant-syntax">STRING_STORAGE_MREASON</span><span class="plain-syntax">, </span><span class="constant-syntax">SSA_CAPACITY</span><span class="plain-syntax">);</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP31"></a><b>&#167;31. </b>And the following provides statistics, and a mini-report, for the memory
report in the debugging log (for which, see below).
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::log_usage</span><button class="popup" onclick="togglePopup('usagePopup14')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup14">Usage of <span class="code-font"><span class="function-syntax">Memory::log_usage</span></span>:<br/><a href="2-mmr.html#SP32">&#167;32</a>, <a href="2-mmr.html#SP32_3">&#167;32.3</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total</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">total_claimed_simply</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">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">, </span><span class="identifier-syntax">t</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">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">NO_DEFINED_MREASON_VALUES</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">t</span><span class="plain-syntax"> += </span><span class="identifier-syntax">max_memory_at_once_for_each_need</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">total</span><span class="plain-syntax"> &gt; </span><span class="constant-syntax">0</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"0.%03d: %s - %d bytes in %d claim(s)\n"</span><span class="plain-syntax">,</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP34" class="function-link"><span class="function-syntax">Memory::proportion</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">max_memory_at_once_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">], </span><span class="identifier-syntax">total</span><span class="plain-syntax">),</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP23" class="function-link"><span class="function-syntax">Memory::description_of_reason</span></a><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">max_memory_at_once_for_each_need</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">number_of_claims_for_each_need</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</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">t</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP32"></a><b>&#167;32. Memory usage report. </b>A small utility routine to help keep track of our unquestioned profligacy.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::log_statistics</span><button class="popup" onclick="togglePopup('usagePopup15')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup15">Usage of <span class="code-font"><span class="function-syntax">Memory::log_statistics</span></span>:<br/>Foundation Module - <a href="1-fm.html#SP9">&#167;9</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total_for_objects</span><span class="plain-syntax"> = </span><span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax">*</span><span class="identifier-syntax">no_blocks_allocated</span><span class="plain-syntax">; </span><span class="comment-syntax"> usage in bytes</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total_for_SMAs</span><span class="plain-syntax"> = </span><a href="2-mmr.html#SP31" class="function-link"><span class="function-syntax">Memory::log_usage</span></a><span class="plain-syntax">(0); </span><span class="comment-syntax"> usage in bytes</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">sorted_usage</span><span class="plain-syntax">[</span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</span><span class="plain-syntax">]; </span><span class="comment-syntax"> memory type numbers, in usage order</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total</span><span class="plain-syntax"> = (</span><span class="identifier-syntax">total_for_objects</span><span class="plain-syntax"> + </span><span class="identifier-syntax">total_for_SMAs</span><span class="plain-syntax">)/1024; </span><span class="comment-syntax"> total memory usage in KB</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP32_2" class="named-paragraph-link"><span class="named-paragraph">Sort the table of memory type usages into decreasing size order</span><span class="named-paragraph-number">32.2</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total_for_objects_used</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">; </span><span class="comment-syntax"> out of the </span><span class="extract"><span class="extract-syntax">total_for_objects</span></span><span class="comment-syntax">, the bytes used</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total_objects</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP32_1" class="named-paragraph-link"><span class="named-paragraph">Calculate the memory usage for objects</span><span class="named-paragraph-number">32.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">overhead_for_objects</span><span class="plain-syntax"> = </span><span class="identifier-syntax">total_for_objects</span><span class="plain-syntax"> - </span><span class="identifier-syntax">total_for_objects_used</span><span class="plain-syntax">; </span><span class="comment-syntax"> bytes wasted</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="2-mmr.html#SP32_3" class="named-paragraph-link"><span class="named-paragraph">Print the report to the debugging log</span><span class="named-paragraph-number">32.3</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP32_1"></a><b>&#167;32.1. </b><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Calculate the memory usage for objects</span><span class="named-paragraph-number">32.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">, </span><span class="identifier-syntax">j</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">j</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">j</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</span><span class="plain-syntax">; </span><span class="identifier-syntax">j</span><span class="plain-syntax">++) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> = </span><span class="identifier-syntax">sorted_usage</span><span class="plain-syntax">[</span><span class="identifier-syntax">j</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</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">total_objects</span><span class="plain-syntax"> += </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</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">total_objects</span><span class="plain-syntax"> += </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">*</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">total_for_objects_used</span><span class="plain-syntax"> += </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP32">&#167;32</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP32_2"></a><b>&#167;32.2. </b>This is the criterion for sorting memory types in the report: descending
order of total number of bytes allocated.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Sort the table of memory type usages into decreasing size order</span><span class="named-paragraph-number">32.2</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">int</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">for</span><span class="plain-syntax"> (</span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) </span><span class="identifier-syntax">sorted_usage</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</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">qsort</span><span class="plain-syntax">(</span><span class="identifier-syntax">sorted_usage</span><span class="plain-syntax">, (</span><span class="identifier-syntax">size_t</span><span class="plain-syntax">) </span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</span><span class="plain-syntax">, </span><span class="reserved-syntax">sizeof</span><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax">), </span><a href="2-mmr.html#SP33" class="function-link"><span class="function-syntax">Memory::compare_usage</span></a><span class="plain-syntax">);</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP32">&#167;32</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP32_3"></a><b>&#167;32.3. </b>And here is the actual report:
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Print the report to the debugging log</span><span class="named-paragraph-number">32.3</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"\nReport by memory manager:\n\n"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"Total consumption was %dK = %dMB, divided up in the following proportions:\n"</span><span class="plain-syntax">,</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">total</span><span class="plain-syntax">, (</span><span class="identifier-syntax">total</span><span class="plain-syntax">+512)/1024);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"0.%03d: %d objects in %d frames in %d memory blocks (of %dK each):\n"</span><span class="plain-syntax">,</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP34" class="function-link"><span class="function-syntax">Memory::proportion</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">total_for_objects</span><span class="plain-syntax">, </span><span class="identifier-syntax">total</span><span class="plain-syntax">),</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">total_objects</span><span class="plain-syntax">, </span><span class="identifier-syntax">total_objects_allocated</span><span class="plain-syntax">, </span><span class="identifier-syntax">no_blocks_allocated</span><span class="plain-syntax">, </span><span class="constant-syntax">MEMORY_GRANULARITY</span><span class="plain-syntax">/1024);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">" 0.%03d: memory manager overhead - %d bytes\n"</span><span class="plain-syntax">,</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP34" class="function-link"><span class="function-syntax">Memory::proportion</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">overhead_for_objects</span><span class="plain-syntax">, </span><span class="identifier-syntax">total</span><span class="plain-syntax">), </span><span class="identifier-syntax">overhead_for_objects</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">, </span><span class="identifier-syntax">j</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">j</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">j</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">NO_DEFINED_MT_VALUES</span><span class="plain-syntax">; </span><span class="identifier-syntax">j</span><span class="plain-syntax">++) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> = </span><span class="identifier-syntax">sorted_usage</span><span class="plain-syntax">[</span><span class="identifier-syntax">j</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</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">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">" 0.%03d: %s - "</span><span class="plain-syntax">,</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP34" class="function-link"><span class="function-syntax">Memory::proportion</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</span><span class="plain-syntax">, </span><span class="identifier-syntax">total</span><span class="plain-syntax">),</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">name_of_type</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</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">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"%d "</span><span class="plain-syntax">, </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_count</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_count</span><span class="plain-syntax"> != </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"(+%d deleted) "</span><span class="plain-syntax">,</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax"> - </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_count</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">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"%d blocks of %d = %d "</span><span class="plain-syntax">,</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">, </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</span><span class="plain-syntax">,</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">objects_allocated</span><span class="plain-syntax">*</span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">no_allocated_together</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"objects, %d bytes\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><a href="2-mmr.html#SP31" class="function-link"><span class="function-syntax">Memory::log_usage</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">total</span><span class="plain-syntax">);</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="2-mmr.html#SP32">&#167;32</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP33"></a><b>&#167;33. </b></p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::compare_usage</span><button class="popup" onclick="togglePopup('usagePopup16')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup16">Usage of <span class="code-font"><span class="function-syntax">Memory::compare_usage</span></span>:<br/><a href="2-mmr.html#SP32_2">&#167;32.2</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">const</span><span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">ent1</span><span class="plain-syntax">, </span><span class="reserved-syntax">const</span><span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">ent2</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">ix1</span><span class="plain-syntax"> = *((</span><span class="reserved-syntax">const</span><span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">ent1</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">ix2</span><span class="plain-syntax"> = *((</span><span class="reserved-syntax">const</span><span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">ent2</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">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">ix2</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</span><span class="plain-syntax"> - </span><span class="identifier-syntax">alloc_status</span><span class="plain-syntax">[</span><span class="identifier-syntax">ix1</span><span class="plain-syntax">].</span><span class="element-syntax">bytes_allocated</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP34"></a><b>&#167;34. </b>Finally, a little routine to compute the proportions of memory for each
usage. Recall that <span class="extract"><span class="extract-syntax">bytes</span></span> is measured in bytes, but <span class="extract"><span class="extract-syntax">total</span></span> in kilobytes.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::proportion</span><button class="popup" onclick="togglePopup('usagePopup17')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup17">Usage of <span class="code-font"><span class="function-syntax">Memory::proportion</span></span>:<br/><a href="2-mmr.html#SP31">&#167;31</a>, <a href="2-mmr.html#SP32_3">&#167;32.3</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">bytes</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">total</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">float</span><span class="plain-syntax"> </span><span class="identifier-syntax">B</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">float</span><span class="plain-syntax">) </span><span class="identifier-syntax">bytes</span><span class="plain-syntax">, </span><span class="identifier-syntax">T</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">float</span><span class="plain-syntax">) </span><span class="identifier-syntax">total</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">float</span><span class="plain-syntax"> </span><span class="identifier-syntax">P</span><span class="plain-syntax"> = (1000*</span><span class="identifier-syntax">B</span><span class="plain-syntax">)/(1024*</span><span class="identifier-syntax">T</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax">) </span><span class="identifier-syntax">P</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP35"></a><b>&#167;35. </b></p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="function-syntax">Memory::paranoid_calloc</span><button class="popup" onclick="togglePopup('usagePopup18')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup18">Usage of <span class="code-font"><span class="function-syntax">Memory::paranoid_calloc</span></span>:<br/><a href="2-mmr.html#SP11_1">&#167;11.1</a>, <a href="2-mmr.html#SP26_1">&#167;26.1</a></span></button><span class="plain-syntax">(</span><span class="identifier-syntax">size_t</span><span class="plain-syntax"> </span><span class="identifier-syntax">N</span><span class="plain-syntax">, </span><span class="identifier-syntax">size_t</span><span class="plain-syntax"> </span><span class="identifier-syntax">S</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">CREATE_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">P</span><span class="plain-syntax"> = </span><span class="identifier-syntax">calloc</span><span class="plain-syntax">(</span><span class="identifier-syntax">N</span><span class="plain-syntax">, </span><span class="identifier-syntax">S</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">UNLOCK_MUTEX</span><span class="plain-syntax">(</span><span class="identifier-syntax">mutex</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">P</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP36"></a><b>&#167;36. Run-time pointer type checking. </b>In several places Inform needs to store pointers of type <span class="extract"><span class="extract-syntax">void *</span></span>, that is,
pointers which have no indication of what type of data they point to.
This is not type-safe and therefore offers plenty of opportunity for
blunders. The following provides run-time type checking to ensure that
each time we dereference a typeless pointer, it does indeed point to
a structure of the type we think it should.
</p>
<p class="commentary">The structure <span class="extract"><span class="extract-syntax">general_pointer</span></span> holds a <span class="extract"><span class="extract-syntax">void *</span></span> pointer to any one of the
following:
</p>
<ul class="items"><li>(a) <span class="extract"><span class="extract-syntax">NULL</span></span>, to which we assign ID number \(-1\);
</li><li>(b) <span class="extract"><span class="extract-syntax">char</span></span>, to which we assign ID number 1000;
</li><li>(c) any individually allocated structure of the types listed above, to
which we assign the ID numbers used above: for instance, <span class="extract"><span class="extract-syntax">blorb_figure_MT</span></span>
is the ID number for a <span class="extract"><span class="extract-syntax">general_pointer</span></span> which points to a <span class="extract"><span class="extract-syntax">blorb_figure</span></span>
structure.
</li></ul>
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="constant-syntax">NULL_GENERAL_POINTER</span><span class="plain-syntax"> (</span><a href="2-mmr.html#SP36" class="function-link"><span class="function-syntax">Memory::store_gp_null</span></a><span class="plain-syntax">())</span>
<span class="definition-keyword">define</span> <span class="identifier-syntax">GENERAL_POINTER_IS_NULL</span><span class="plain-syntax">(</span><span class="identifier-syntax">gp</span><span class="plain-syntax">) (</span><a href="2-mmr.html#SP36" class="function-link"><span class="function-syntax">Memory::test_gp_null</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">gp</span><span class="plain-syntax">))</span>
</pre>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">void</span><span class="plain-syntax"> *</span><span class="identifier-syntax">pointer_to_data</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">run_time_type_code</span><span class="plain-syntax">;</span>
<span class="plain-syntax">} </span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::store_gp_null</span><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">pointer_to_data</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">gp</span><span class="plain-syntax">.</span><span class="element-syntax">run_time_type_code</span><span class="plain-syntax"> = -1; </span><span class="comment-syntax"> guaranteed to differ from all </span><span class="extract"><span class="extract-syntax">_MT</span></span><span class="comment-syntax"> values</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="function-syntax">Memory::test_gp_null</span><span class="plain-syntax">(</span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</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">gp</span><span class="plain-syntax">.</span><span class="identifier-syntax">run_time_type_code</span><span class="plain-syntax"> == -1) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">TRUE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<ul class="endnotetexts"><li>The structure general_pointer is accessed in 2/trs and here.</li></ul>
<p class="commentary firstcommentary"><a id="SP37"></a><b>&#167;37. </b>The symbols tables need to look at pointer values directly without knowing
their types, but only to test equality, so we abstract that thus. And the
debugging log also shows actual hexadecimal addresses to distinguish nameless
objects and to help with interpreting output from GDB, so we abstract that too.
</p>
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="identifier-syntax">COMPARE_GENERAL_POINTERS</span><span class="plain-syntax">(</span><span class="identifier-syntax">gp1</span><span class="plain-syntax">, </span><span class="identifier-syntax">gp2</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">gp1</span><span class="plain-syntax">.</span><span class="element-syntax">pointer_to_data</span><span class="plain-syntax"> == </span><span class="identifier-syntax">gp2</span><span class="plain-syntax">.</span><span class="element-syntax">pointer_to_data</span><span class="plain-syntax">)</span>
<span class="definition-keyword">define</span> <span class="identifier-syntax">GENERAL_POINTER_AS_INT</span><span class="plain-syntax">(</span><span class="identifier-syntax">gp</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> ((</span><span class="identifier-syntax">pointer_sized_int</span><span class="plain-syntax">) </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">pointer_to_data</span><span class="plain-syntax">)</span>
</pre>
<p class="commentary firstcommentary"><a id="SP38"></a><b>&#167;38. </b>If we have a pointer to <span class="extract"><span class="extract-syntax">circus</span></span> (say) then <span class="extract"><span class="extract-syntax">g=STORE_POINTER_circus(p)</span></span>
returns a <span class="extract"><span class="extract-syntax">general_pointer</span></span> with <span class="extract"><span class="extract-syntax">p</span></span> as the actual pointer, but will not
compile unless <span class="extract"><span class="extract-syntax">p</span></span> is indeed of type <span class="extract"><span class="extract-syntax">circus *</span></span>. When we later
<span class="extract"><span class="extract-syntax">RETRIEVE_POINTER_circus(g)</span></span>, an internal error is thrown if <span class="extract"><span class="extract-syntax">g</span></span> contains a pointer
which is other than <span class="extract"><span class="extract-syntax">void *</span></span>, or which has never been referenced.
</p>
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="identifier-syntax">MAKE_REFERENCE_ROUTINES</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">, </span><span class="identifier-syntax">id_code</span><span class="plain-syntax">)</span>
<span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">STORE_POINTER_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">data</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">pointer_to_data</span><span class="plain-syntax"> = (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">data</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">run_time_type_code</span><span class="plain-syntax"> = </span><span class="identifier-syntax">id_code</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">gp</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
<span class="identifier-syntax">type_name</span><span class="plain-syntax"> *</span><span class="identifier-syntax">RETRIEVE_POINTER_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</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">gp</span><span class="plain-syntax">.</span><span class="identifier-syntax">run_time_type_code</span><span class="plain-syntax"> != </span><span class="identifier-syntax">id_code</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"Wanted ID code %d, found %d\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">id_code</span><span class="plain-syntax">, </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">run_time_type_code</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"attempt to retrieve wrong pointer type as "</span><span class="plain-syntax"> #</span><span class="identifier-syntax">type_name</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">type_name</span><span class="plain-syntax"> *) </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">pointer_to_data</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
<span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">PASS_POINTER_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</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">gp</span><span class="plain-syntax">.</span><span class="identifier-syntax">run_time_type_code</span><span class="plain-syntax"> != </span><span class="identifier-syntax">id_code</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"Wanted ID code %d, found %d\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">id_code</span><span class="plain-syntax">, </span><span class="identifier-syntax">gp</span><span class="plain-syntax">.</span><span class="element-syntax">run_time_type_code</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"attempt to pass wrong pointer type as "</span><span class="plain-syntax"> #</span><span class="identifier-syntax">type_name</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">gp</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">VALID_POINTER_</span><span class="plain-syntax">##</span><span class="identifier-syntax">type_name</span><span class="plain-syntax">(</span><span class="reserved-syntax">general_pointer</span><span class="plain-syntax"> </span><span class="identifier-syntax">gp</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">gp</span><span class="plain-syntax">.</span><span class="identifier-syntax">run_time_type_code</span><span class="plain-syntax"> == </span><span class="identifier-syntax">id_code</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">TRUE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP39"></a><b>&#167;39. </b>Suitable <span class="extract"><span class="extract-syntax">MAKE_REFERENCE_ROUTINES</span></span> were expanded for all of the memory
allocated objects above; so that leaves only humble <span class="extract"><span class="extract-syntax">char *</span></span> pointers:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="identifier-syntax">MAKE_REFERENCE_ROUTINES</span><span class="plain-syntax">(</span><span class="reserved-syntax">char</span><span class="plain-syntax">, </span><span class="constant-syntax">1000</span><span class="plain-syntax">)</span>
</pre>
<nav role="progress"><div class="progresscontainer">
<ul class="progressbar"><li class="progressprev"><a href="2-dl.html">&#10094;</a></li><li class="progresschapter"><a href="P-abgtf.html">P</a></li><li class="progresschapter"><a href="1-fm.html">1</a></li><li class="progresscurrentchapter">2</li><li class="progresssection"><a href="2-dl.html">dl</a></li><li class="progresscurrent">mmr</li><li class="progresssection"><a href="2-str.html">str</a></li><li class="progresssection"><a href="2-wal.html">wal</a></li><li class="progresssection"><a href="2-mth.html">mth</a></li><li class="progresssection"><a href="2-llas.html">llas</a></li><li class="progresssection"><a href="2-dct.html">dct</a></li><li class="progresssection"><a href="2-trs.html">trs</a></li><li class="progresschapter"><a href="3-em.html">3</a></li><li class="progresschapter"><a href="4-chr.html">4</a></li><li class="progresschapter"><a href="5-htm.html">5</a></li><li class="progresschapter"><a href="6-bf.html">6</a></li><li class="progresschapter"><a href="7-vn.html">7</a></li><li class="progresschapter"><a href="8-ws.html">8</a></li><li class="progressnext"><a href="2-str.html">&#10095;</a></li></ul></div>
</nav><!--End of weave-->
</main>
</body>
</html>