<pclass="author-description"><center><i>"Love God. Live Righteously. Die Well."</i><br/><br/><atarget="_blank"rel="noopener"href="https://source.starfort.tech/andrew">Source Code</a> || <atarget="_blank"rel="noopener"href="https://www.linkedin.com/in/andrewkesterson/">LinkedIn</a><br/></center></p>
<p>Development log entry for the week ending 27 June 2026. Improvements to libakerror logging, libakstdlib gets linked list and binary tree implementations, and I’m banging my head against libakgl to get binary space partitioning implemented correctly, as well as documentation improvements to all of these libraries.</p>
<h1id="libakerror-logging-cleanup"><ahref="#libakerror-logging-cleanup"class="headerlink"title="libakerror logging cleanup"></a>libakerror logging cleanup</h1><p>First, I fixed a couple of minor bugs that impacted the correct installation of <code>libakerror</code>. I almost never use <code>libakerror</code> standalone, it’s basically always a cmake dependency, and these only impacted the standalone behavior, so I never saw it. I’ve since added <atarget="_blank"rel="noopener"href="https://source.starfort.tech/andrew/libakerror/actions">a CI build that runs on every push to main</a> and a <atarget="_blank"rel="noopener"href="https://source.starfort.tech/andrew/libakerror/src/branch/main/README.md">badge on the README</a>.</p>
<p>The traceback logging from <atarget="_blank"rel="noopener"href="https://source.starfort.tech/andrew/libakerror">libakerror</a> was needlessly noisy. Some lines were duplicated, others just weren’t particularly helpful. For example:</p>
<preclass="line-numbers language-none"><codeclass="language-none">err_trace.c:func2:7: 134 (Null Pointer Error) : This is a failure in func2
err_trace.c:func2:10
err_trace.c:func1:18: Detected error 0 from array (refcount 1)
err_trace.c:func1:18
err_trace.c:func1:21
err_trace.c:main:30: Detected error 0 from array (refcount 1)
err_trace.c:main:30
err_trace.c:main:33: Unhandled Error 134 (Null Pointer Error): This is a failure in func2<spanaria-hidden="true"class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>There are three lines from func1. There are two lines for the <code>CATCH()</code> call that actually detected the error coming out of <code>func2()</code>, and there is a line for the <code>FINISH()</code> statement. Similarly, for func2, there are two lines - one for the <code>FAIL()</code> that generated the exception and one for the <code>FINISH()</code> that emitted it. Then in <code>main()</code> we see the same kind of noise; two lines for the <code>CATCH()</code> that detected the error, and one for the <code>FINISH()</code> that emitted it. We don’t need all that. I think I put the extra lines in there when I was initially building the library and was having some trouble determining where an exception was leaving the control flow - I don’t need that anymore. I just want to know where the exception <em>actually got generated</em> and the call stack directly to that. The new logging behavior is thus:</p>
<preclass="line-numbers language-none"><codeclass="language-none">err_trace.c:func2:7: 134 (Null Pointer Error) : This is a failure in func2
err_trace.c:func1:18
err_trace.c:main:30
err_trace.c:main:33: Unhandled Error 134 (Null Pointer Error): This is a failure in func2<spanaria-hidden="true"class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>
<p>This is much neater. We still get two lines from <code>main()</code>, but I’m willing to live with that. The second <code>main()</code> line comes from <code>FINISH_NORETURN</code> which summarizes the error from the deepest exception frame, and then calls <code>akerr_handler_unhandled_error()</code> which (generally) aborts the program. I’m fine with that getting its own line.</p>
<p>If you haven’t seen <code>libakerror</code> before, <ahref="https://aklabs.net/2026/01/10/libakerror/">you can read about it here</a>.</p>
<h1id="libakstdlib"><ahref="#libakstdlib"class="headerlink"title="libakstdlib"></a>libakstdlib</h1><p>My C standard library <atarget="_blank"rel="noopener"href="https://source.starfort.tech/andrew/libakstdlib">libakstdlib</a> got some new features. I started adding Doxygen tags to the source code to start improving the documentation around this. It’s incomplete, I’m adding as I go, but it’ll get there.</p>
<h2id="Linked-List-Handling"><ahref="#Linked-List-Handling"class="headerlink"title="Linked List Handling"></a>Linked List Handling</h2><preclass="line-numbers language-c"data-language="c"><codeclass="language-c"><spanclass="token keyword">typedef</span><spanclass="token keyword">struct</span><spanclass="token class-name">aksl_ListNode</span><spanclass="token punctuation">{</span>
<p>Linked Lists are fairly intuitive if you’ve done any linked list handling in C before. You have a list node structure that contains pointers to the next and previous items in the list; if <code>prev</code> is NULL, that is the head node, and if <code>next</code> is NULL, that is the tail. Each node contains a <code>void *</code> to some <code>data</code>, and it is the library user’s responsibility to know how to set, retrieve, and properly manage that data. You have functions for pushing a new object on to the END of an existing list, and for removing a node from whatever list it is currently in.</p>
<p>You can iterate over each node in a list with an iterator function. The iterator function accepts a pointer to a node, and a pointer to an optional data object. The iteration proceeds <em>forward</em> through the list (reverse iteration is not supported yet), and the iterator function is called for each node in the list, with the user-provided data.</p>
<p>If you want to stop iteration before the end of the list is reached, you can raise an AKERR_ITERATOR_BREAK exception to halt the iteration early.</p>
<p>The library includes built-in circular reference detection using <atarget="_blank"rel="noopener"href="https://en.wikipedia.org/wiki/Cycle_detection">Floyd’s Cycle-Finding Algorithm</a>. Both <code>append()</code> and <code>iterate()</code> perform cycle detection. <code>push()</code> does it while searching for the tail, <code>iterate()</code> does it before beginning the iteration cycle.</p>
<p>A complete sample program is <atarget="_blank"rel="noopener"href="https://source.starfort.tech/andrew/libakstdlib/src/branch/main/tests/test_linkedlist.c">in the tests directory</a>.</p>
<spanclass="token macro property"><spanclass="token directive-hash">#</span><spanclass="token directive keyword">define</span><spanclass="token macro-name">AKSL_TREE_SEARCH_BFS</span><spanclass="token expression"><spanclass="token number">0</span></span><spanclass="token comment">/** Breadth-first search mode for tree nodes. Currently unsupported. */</span></span>
<spanclass="token macro property"><spanclass="token directive-hash">#</span><spanclass="token directive keyword">define</span><spanclass="token macro-name">AKSL_TREE_SEARCH_BFS_RIGHT</span><spanclass="token expression"><spanclass="token number">1</span></span><spanclass="token comment">/** Right-hand breadth-first search mode for tree nodes. Currentl unsupported. */</span></span>
<spanclass="token macro property"><spanclass="token directive-hash">#</span><spanclass="token directive keyword">define</span><spanclass="token macro-name">AKSL_TREE_SEARCH_DFS</span><spanclass="token expression"><spanclass="token number">2</span></span><spanclass="token comment">/** Alias for AKSL_TREE_SEARCH_DFS_PREORDER */</span></span>
<spanclass="token macro property"><spanclass="token directive-hash">#</span><spanclass="token directive keyword">define</span><spanclass="token macro-name">AKSL_TREE_SEARCH_DFS_PREORDER</span><spanclass="token expression"><spanclass="token number">2</span></span><spanclass="token comment">/** Depth first pre-order (root, left, right) search mode for tree nodes */</span></span>
<spanclass="token macro property"><spanclass="token directive-hash">#</span><spanclass="token directive keyword">define</span><spanclass="token macro-name">AKSL_TREE_SEARCH_DFS_INORDER</span><spanclass="token expression"><spanclass="token number">3</span></span><spanclass="token comment">/** Depth first in-order (left, root, right) search mode for tree nodes. Currently unsupported. */</span></span>
<spanclass="token macro property"><spanclass="token directive-hash">#</span><spanclass="token directive keyword">define</span><spanclass="token macro-name">AKSL_TREE_SEARCH_DFS_POSTORDER</span><spanclass="token expression"><spanclass="token number">4</span></span><spanclass="token comment">/** Depth first post-order (left, right, root) search mode for tree nodes. Currently unsupported. */</span></span>
<spanclass="token macro property"><spanclass="token directive-hash">#</span><spanclass="token directive keyword">define</span><spanclass="token macro-name">AKSL_TREE_SEARCH_VISIT</span><spanclass="token expression"><spanclass="token number">5</span></span><spanclass="token comment">/** Used when iterating through a tree structure as a control flag: don't traverse the children, just visit the node */</span></span>
<p>The library only supports binary trees (though I can see a use for trees with arbitrary branches from a given node, I haven’t taken that leap yet). You can populate them and iterate over them using a few varieties of Depth-First Search.</p>
<p>Currently the library has some known bugs. I would’ve fixed them this week, but I built the library functions in concert with some <atarget="_blank"rel="noopener"href="https://source.starfort.tech/andrew/libakgl/pulls/1/files">in-progress libakgl functionality</a> that uses this library to perform binary space partitioning on the game scene, to prepare the scene for collision detection. So I prioritized the interfaces between those two, and the bits that most directly enabled the BSP partitioning. But…</p>
<p>The way in which search (iteration) is performed isn’t really right. In <code>AKSL_TREE_SEARCH_DFS_INORDER</code>, some nodes get visited by the iterator twice. In <code>AKSL_TREE_SEARCH_DFS_POSTORDER</code>, some nodes get visited three times. This is because the <em>proper</em> way to do tree search is to use a linked list to build a line of all nodes in the tree, in search order, and then iterate over those lists. Doing this allows you to ensure that there is only one link to a given node in the list before you start iterating. </p>
<p>The akstdlib tree library doesn’t use that method yet. We just process the nodes as soon as we see them. And because of that, for any gievn node of the tree, we wind up processing the root nodes more than once. Now that I’ve worked out some of the other behavioral processes, I’m going to implement the linked list handling.</p>
<p>On the tree iterator method, there are two function pointers and one list node provided by the user. The function pointers are for a linked list allocator and free function; the defaults are <code>aksl_malloc</code> and <code>aksl_free</code>. Certain implementations (like mine in <code>libakgl</code>) want control over how objects are allocated or released in memory; in <code>libakgl</code>, I use a series of static arrays allocated in the data segment, and I provide a couple of functions that find unused resources from there, allocate them, and release them back to the pool later.</p>
<p>This part of the library has quite a bit more work to do. But there is a complete example (with a test case that currently fails for the aforementioned reasons) <atarget="_blank"rel="noopener"href="https://source.starfort.tech/andrew/libakstdlib/src/branch/main/tests/test_tree.c">in the tests directory</a>.</p>
<h1id="libakgl"><ahref="#libakgl"class="headerlink"title="libakgl"></a>libakgl</h1><p>All of the work in libakerror and libakstdlib this week was supporting <atarget="_blank"rel="noopener"href="https://source.starfort.tech/andrew/libakgl/pulls/1/files">a larger effort in libakgl</a>: I’m trying to add binary space partitioning of the world so that I can arrange actors into linked lists of near neighbors for collision detection. This will allow me to compare collisions for only a few actors in a given screen area that are near each other, rather than checking every actor against every other actor. On small simple games it’s no big deal, but on a bullet hell or something similar, it’s a problem.</p>
<p>Unfortunately it’s not working quite right yet. At this point I have:</p>
<ul>
<li>A new <code>Stage</code> object has been introduced to represent and track the larger game world (which may or may not have the same extents as the camera, the screen, or the tilemap)</li>
<li>A partitioning function on the Stage object that performs the job of partitioning the stage</li>
<li>The screen gets subdivided into 32 areas consisting of a 4-deep BSP tree.</li>
<li>All actors on the screen are partitioned into the correct area of the tree on level load</li>
<li>The area containing the player is currently drawn with a red outline in the <code>sdl3-gametest</code> sample application</li>
<li>The physics simulation of actor movement attempts to move the actor through the BSP on the Stage</li>
</ul>
<p>However lots of it still doesn’t work like it should:</p>
<ul>
<li>When an actor moves, it’s supposed to traverse the BSP tree as it moves in world coordinates. The actors aren’t doing this.</li>
<li>Sometimes the algorithm will attempt to get more tree node objects from the data segment than it should, which results in an <code>AKGL_ERR_OOHEAP</code> exception</li>
</ul>
<p>And then there’s the fact that I’m just not happy with some of the original design assumptions. For example, right now I only divide the visible screen; off-screen actors will never collide. It also is not very intelligent about how it chooses what to subdivide; if it encounters half of the screen that has no actors in it, it knows this almost immediately, but stubbornly divides it anyway. A more efficient method <em>might</em> be to focus on the areas of greatest actor population (heat mapping). But that would require changing the partitioning process and actor movement logic from “partition once at the beginning, and then update when the actor moves”. Choices, choices.</p>
<p>I’m going to have to spend some more time with this one to get it right. But that’s probably going to have to wait a couple weeks; I’ve got a trip planned, and I’m onboarding onto a different team at work, plus I’ve got embedded projects I need to keep moving. So there’s no shortage of distractions.</p>
<p>Also, if you go poking around <atarget="_blank"rel="noopener"href="https://source.starfort.tech/andrew/libakgl">libakgl</a> you will notice a new README with some compact usage instructions, as well as new doxygen comment blocks scattered around the code. I’m trying to bring it all up to speed in that regard.</p>