Deploying upstream@e67f0616ec53232109bc712cecc817578173c218: 27 June 2026 Devlog Entry
This commit is contained in:
861
2026/06/27/Devlog-20260627/index.html
Normal file
861
2026/06/27/Devlog-20260627/index.html
Normal file
@@ -0,0 +1,861 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
||||
<meta
|
||||
http-equiv="X-UA-Compatible"
|
||||
content="ie=edge">
|
||||
<meta
|
||||
name="theme-color"
|
||||
content="#fff"
|
||||
id="theme-color">
|
||||
<meta
|
||||
name="description"
|
||||
content="AKLabs">
|
||||
<link
|
||||
rel="icon"
|
||||
href="/">
|
||||
<title>Devlog Entry - 27 June 2026</title>
|
||||
|
||||
|
||||
<meta
|
||||
property="og:title"
|
||||
content="Devlog Entry - 27 June 2026">
|
||||
|
||||
|
||||
<meta
|
||||
property="og:url"
|
||||
content="https://aklabs.net/2026/06/27/Devlog-20260627/index.html">
|
||||
|
||||
|
||||
<meta
|
||||
property="og:img"
|
||||
content="/images/akesterson.webp">
|
||||
|
||||
|
||||
|
||||
<meta
|
||||
property="og:type"
|
||||
content="article">
|
||||
<meta
|
||||
property="og:article:published_time"
|
||||
content="2026-06-27">
|
||||
<meta
|
||||
property="og:article:modified_time"
|
||||
content="2026-06-27">
|
||||
<meta
|
||||
property="og:article:author"
|
||||
content="Andrew Kesterson">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="preload" href="//at.alicdn.com/t/font_1946621_i1kgafibvw.css" as="style" >
|
||||
<link rel="preload" href="//at.alicdn.com/t/font_1952792_89b4ac4k4up.css" as="style" >
|
||||
<link rel="preload" href="/css/main.css" as="style" >
|
||||
|
||||
<link rel="modulepreload" href="//instant.page/5.1.0">
|
||||
|
||||
<link rel="stylesheet" href="/css/main.css">
|
||||
|
||||
<link rel="stylesheet" href="//at.alicdn.com/t/font_1946621_i1kgafibvw.css">
|
||||
|
||||
<link rel="stylesheet" href="//at.alicdn.com/t/font_1952792_89b4ac4k4up.css">
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="/js/lib/lightbox/baguetteBox.min.css">
|
||||
|
||||
<script>
|
||||
function loadScript(url, cb) {
|
||||
var script = document.createElement('script');
|
||||
script.src = url;
|
||||
if (cb) script.onload = cb;
|
||||
script.async = true;
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
function loadCSS(href, data, attr) {
|
||||
var sheet = document.createElement('link');
|
||||
sheet.ref = 'stylesheet';
|
||||
sheet.href = href;
|
||||
sheet.dataset[data] = attr;
|
||||
document.head.appendChild(sheet);
|
||||
}
|
||||
function changeCSS(cssFile, data, attr) {
|
||||
var oldlink = document.querySelector(data);
|
||||
var newlink = document.createElement("link");
|
||||
newlink.setAttribute("rel", "stylesheet");
|
||||
newlink.setAttribute("href", cssFile);
|
||||
newlink.dataset.prism = attr;
|
||||
document.head.replaceChild(newlink, oldlink);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
function prismThemeChange() {
|
||||
if(document.getElementById('theme-color').dataset.mode === 'dark') {
|
||||
if(document.querySelector('[data-prism]')) {
|
||||
changeCSS('/js/lib/prism/prism-tomorrow.min.css', '[data-prism]', 'prism-tomorrow');
|
||||
} else {
|
||||
loadCSS('/js/lib/prism/prism-tomorrow.min.css', 'prism', 'prism-tomorrow');
|
||||
}
|
||||
} else {
|
||||
if(document.querySelector('[data-prism]')) {
|
||||
changeCSS('/js/lib/prism/prism-defauult.min.css', '[data-prism]', 'prism-defauult');
|
||||
} else {
|
||||
loadCSS('/js/lib/prism/prism-defauult.min.css', 'prism', 'prism-defauult');
|
||||
}
|
||||
}
|
||||
}
|
||||
prismThemeChange()
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="/js/lib/prism/prism-line-numbers.min.css">
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
// control reverse button
|
||||
var reverseDarkList = {
|
||||
dark: 'light',
|
||||
light: 'dark'
|
||||
};
|
||||
var themeColor = {
|
||||
dark: '#1c1c1e',
|
||||
light: '#fff'
|
||||
}
|
||||
// get the data of css prefers-color-scheme
|
||||
var getCssMediaQuery = function() {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
};
|
||||
// reverse current darkmode setting function
|
||||
var reverseDarkModeSetting = function() {
|
||||
var setting = localStorage.getItem('user-color-scheme');
|
||||
if(reverseDarkList[setting]) {
|
||||
setting = reverseDarkList[setting];
|
||||
} else if(setting === null) {
|
||||
setting = reverseDarkList[getCssMediaQuery()];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
localStorage.setItem('user-color-scheme', setting);
|
||||
return setting;
|
||||
};
|
||||
// apply current darkmode setting
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var setDarkmode = function(mode) {
|
||||
var setting = mode || localStorage.getItem('user-color-scheme');
|
||||
if(setting === getCssMediaQuery()) {
|
||||
document.documentElement.removeAttribute('data-user-color-scheme');
|
||||
localStorage.removeItem('user-color-scheme');
|
||||
document.getElementById('theme-color').content = themeColor[setting];
|
||||
document.getElementById('theme-color').dataset.mode = setting;
|
||||
prismThemeChange();
|
||||
} else if(reverseDarkList[setting]) {
|
||||
document.documentElement.setAttribute('data-user-color-scheme', setting);
|
||||
document.getElementById('theme-color').content = themeColor[setting];
|
||||
document.getElementById('theme-color').dataset.mode = setting;
|
||||
prismThemeChange();
|
||||
} else {
|
||||
document.documentElement.removeAttribute('data-user-color-scheme');
|
||||
localStorage.removeItem('user-color-scheme');
|
||||
document.getElementById('theme-color').content = themeColor[getCssMediaQuery()];
|
||||
document.getElementById('theme-color').dataset.mode = getCssMediaQuery();
|
||||
prismThemeChange();
|
||||
}
|
||||
};
|
||||
setDarkmode();
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<link rel="preload" href="/js/lib/lightbox/baguetteBox.min.js" as="script">
|
||||
<link rel="preload" href="/js/lib/lightbox/baguetteBox.min.css" as="style" >
|
||||
|
||||
|
||||
<link rel="preload" href="/js/lib/lozad.min.js" as="script">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<meta name="generator" content="Hexo 6.0.0"><link rel="alternate" href="/atom.xml" title="AKLabs" type="application/atom+xml">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
|
||||
<nav class="navbar">
|
||||
<div class="navbar-logo">
|
||||
<a class="navbar-logo-main" href="/">
|
||||
|
||||
<span class="navbar-logo-dsc">AKLabs</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="navbar-menu">
|
||||
|
||||
<a
|
||||
href="/now"
|
||||
class="navbar-menu-item">
|
||||
|
||||
~/.plan
|
||||
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/archives"
|
||||
class="navbar-menu-item">
|
||||
|
||||
Archive
|
||||
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/categories"
|
||||
class="navbar-menu-item">
|
||||
|
||||
Categories
|
||||
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/about"
|
||||
class="navbar-menu-item">
|
||||
|
||||
About
|
||||
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/contact"
|
||||
class="navbar-menu-item">
|
||||
|
||||
Contact
|
||||
|
||||
</a>
|
||||
|
||||
<button
|
||||
class="navbar-menu-item darknavbar navbar-menu-btn"
|
||||
aria-label="Toggle dark mode"
|
||||
id="dark">
|
||||
<i class="iconfont icon-weather"></i>
|
||||
</button>
|
||||
<button
|
||||
class="navbar-menu-item searchnavbar navbar-menu-btn"
|
||||
aria-label="Toggle search"
|
||||
id="search">
|
||||
<!-- <i
|
||||
class="iconfont icon-search"
|
||||
style="font-size: 1.2rem; font-weight: 400;">
|
||||
</i> -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img"
|
||||
class="iconify iconify--ion" width="28" height="28" preserveAspectRatio="xMidYMid meet" viewBox="0 0 512 512">
|
||||
<path fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="28"
|
||||
d="M256 80a176 176 0 1 0 176 176A176 176 0 0 0 256 80Z"></path>
|
||||
<path fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="28"
|
||||
d="M232 160a72 72 0 1 0 72 72a72 72 0 0 0-72-72Z"></path>
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="28"
|
||||
d="M283.64 283.64L336 336"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div
|
||||
id="local-search"
|
||||
style="display: none">
|
||||
<input
|
||||
class="navbar-menu-item"
|
||||
id="search-input"
|
||||
placeholder="请输入搜索内容..." />
|
||||
<div id="search-content"></div>
|
||||
</div>
|
||||
|
||||
<div class="section-wrap">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<aside class="left-column">
|
||||
|
||||
<div class="card card-author">
|
||||
|
||||
<img
|
||||
src="/images/akesterson.webp"
|
||||
class="author-img"
|
||||
width="88"
|
||||
height="88"
|
||||
alt="author avatar">
|
||||
|
||||
<p class="author-name">Andrew Kesterson</p>
|
||||
<p class="author-description"><center><i>"Love God. Live Righteously. Die Well."</i> <br/> <br/> <a target="_blank" rel="noopener" href="https://source.starfort.tech/andrew">Source Code</a> || <a target="_blank" rel="noopener" href="https://www.linkedin.com/in/andrewkesterson/">LinkedIn</a> <br/> </center></p>
|
||||
<div class="author-message">
|
||||
<a
|
||||
class="author-posts-count"
|
||||
href="/archives">
|
||||
<span>35</span>
|
||||
<span>Posts</span>
|
||||
</a>
|
||||
<a
|
||||
class="author-categories-count"
|
||||
href="/categories">
|
||||
<span>9</span>
|
||||
<span>Categories</span>
|
||||
</a>
|
||||
<a
|
||||
class="author-tags-count"
|
||||
href="/tags">
|
||||
<span>0</span>
|
||||
<span>Tags</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="sticky-tablet">
|
||||
|
||||
|
||||
<article class="display-when-two-columns spacer">
|
||||
<div class="card card-content toc-card">
|
||||
<div class="toc-header">
|
||||
<i
|
||||
class="iconfont icon-menu"
|
||||
style="padding-right: 2px;">
|
||||
</i>TOC
|
||||
</div>
|
||||
<ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#libakerror-logging-cleanup"><span class="toc-text">libakerror logging cleanup</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#libakstdlib"><span class="toc-text">libakstdlib</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#Linked-List-Handling"><span class="toc-text">Linked List Handling</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Binary-Trees"><span class="toc-text">Binary Trees</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#libakgl"><span class="toc-text">libakgl</span></a></li></ol>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
|
||||
<article class="card card-content categories-widget">
|
||||
<div class="categories-card">
|
||||
<div class="categories-header">
|
||||
<i
|
||||
class="iconfont icon-fenlei"
|
||||
style="padding-right: 2px;">
|
||||
</i>Categories
|
||||
</div>
|
||||
<div class="categories-list">
|
||||
|
||||
<a href="/categories/Books/">
|
||||
<div class="categories-list-item">
|
||||
Books
|
||||
<span class="categories-list-item-badge">14</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="/categories/Faith/">
|
||||
<div class="categories-list-item">
|
||||
Faith
|
||||
<span class="categories-list-item-badge">7</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="/categories/Technology/">
|
||||
<div class="categories-list-item">
|
||||
Technology
|
||||
<span class="categories-list-item-badge">16</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="/categories/Outdoors/">
|
||||
<div class="categories-list-item">
|
||||
Outdoors
|
||||
<span class="categories-list-item-badge">1</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="/categories/Philosophy/">
|
||||
<div class="categories-list-item">
|
||||
Philosophy
|
||||
<span class="categories-list-item-badge">7</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="/categories/Current-Events/">
|
||||
<div class="categories-list-item">
|
||||
Current-Events
|
||||
<span class="categories-list-item-badge">6</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="/categories/Leadership/">
|
||||
<div class="categories-list-item">
|
||||
Leadership
|
||||
<span class="categories-list-item-badge">8</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="/categories/History/">
|
||||
<div class="categories-list-item">
|
||||
History
|
||||
<span class="categories-list-item-badge">1</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="/categories/Liberal-Education/">
|
||||
<div class="categories-list-item">
|
||||
Liberal-Education
|
||||
<span class="categories-list-item-badge">1</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card card-content tags-widget">
|
||||
<div class="tags-card">
|
||||
<div class="tags-header">
|
||||
<i
|
||||
class="iconfont icon-biaoqian"
|
||||
style="padding-right: 2px;">
|
||||
</i>hot tags
|
||||
</div>
|
||||
<div class="tags-list">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
|
||||
</div>
|
||||
</aside>
|
||||
<main class="main-column">
|
||||
|
||||
<article class="card card-content">
|
||||
<header>
|
||||
<h1 class="post-title">
|
||||
Devlog Entry - 27 June 2026
|
||||
</h1>
|
||||
</header>
|
||||
<div class="post-meta post-show-meta">
|
||||
<time datetime="2026-06-27T07:45:42.000Z">
|
||||
<i
|
||||
class="iconfont icon-calendar"
|
||||
style="margin-right: 2px;">
|
||||
</i>
|
||||
<span>2026-06-27</span>
|
||||
</time>
|
||||
|
||||
<span class="dot"></span>
|
||||
|
||||
<a
|
||||
href="/categories/Technology/"
|
||||
class="post-meta-link">
|
||||
Technology
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<span class="dot"></span>
|
||||
<span>1.8k words</span>
|
||||
|
||||
</div>
|
||||
|
||||
</header>
|
||||
<div
|
||||
id="section"
|
||||
class="post-content">
|
||||
<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>
|
||||
<h1 id="libakerror-logging-cleanup"><a href="#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 <a target="_blank" rel="noopener" href="https://source.starfort.tech/andrew/libakerror/actions">a CI build that runs on every push to main</a> and a <a target="_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 <a target="_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>
|
||||
<pre class="line-numbers language-none"><code class="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<span aria-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>
|
||||
<pre class="line-numbers language-none"><code class="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<span aria-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, <a href="https://aklabs.net/2026/01/10/libakerror/">you can read about it here</a>.</p>
|
||||
<h1 id="libakstdlib"><a href="#libakstdlib" class="headerlink" title="libakstdlib"></a>libakstdlib</h1><p>My C standard library <a target="_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>
|
||||
<h2 id="Linked-List-Handling"><a href="#Linked-List-Handling" class="headerlink" title="Linked List Handling"></a>Linked List Handling</h2><pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token keyword">typedef</span> <span class="token keyword">struct</span> <span class="token class-name">aksl_ListNode</span> <span class="token punctuation">{</span>
|
||||
<span class="token keyword">void</span> <span class="token operator">*</span>data<span class="token punctuation">;</span>
|
||||
<span class="token keyword">struct</span> <span class="token class-name">aksl_ListNode</span> <span class="token operator">*</span>next<span class="token punctuation">;</span>
|
||||
<span class="token keyword">struct</span> <span class="token class-name">aksl_ListNode</span> <span class="token operator">*</span>prev<span class="token punctuation">;</span>
|
||||
<span class="token punctuation">}</span> aksl_ListNode<span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre>
|
||||
|
||||
<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>
|
||||
<pre class="line-numbers language-c" data-language="c"><code class="language-c">akerr_ErrorContext AKERR_NOIGNORE <span class="token operator">*</span><span class="token function">aksl_list_append</span><span class="token punctuation">(</span>aksl_ListNode <span class="token operator">*</span>list<span class="token punctuation">,</span> aksl_ListNode <span class="token operator">*</span>obj<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
||||
akerr_ErrorContext AKERR_NOIGNORE <span class="token operator">*</span><span class="token function">aksl_list_pop</span><span class="token punctuation">(</span>aksl_ListNode <span class="token operator">*</span>node<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
|
||||
|
||||
<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>
|
||||
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token keyword">typedef</span> akerr_ErrorContext AKERR_NOIGNORE <span class="token operator">*</span><span class="token punctuation">(</span><span class="token operator">*</span>aksl_ListNodeIterator<span class="token punctuation">)</span><span class="token punctuation">(</span>aksl_ListNode <span class="token operator">*</span>node<span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token operator">*</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE <span class="token operator">*</span><span class="token function">aksl_list_iterate</span><span class="token punctuation">(</span>aksl_ListNode <span class="token operator">*</span>list<span class="token punctuation">,</span> aksl_ListNodeIterator iter<span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token operator">*</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>
|
||||
|
||||
<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>
|
||||
<pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token function">PREPARE_ERROR</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
||||
<span class="token function">FAIL_RETURN</span><span class="token punctuation">(</span>e<span class="token punctuation">,</span> AKERR_ITERATOR_BREAK<span class="token punctuation">,</span> <span class="token string">"stop"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
|
||||
|
||||
<p>The library includes built-in circular reference detection using <a target="_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 <a target="_blank" rel="noopener" href="https://source.starfort.tech/andrew/libakstdlib/src/branch/main/tests/test_linkedlist.c">in the tests directory</a>.</p>
|
||||
<h2 id="Binary-Trees"><a href="#Binary-Trees" class="headerlink" title="Binary Trees"></a>Binary Trees</h2><pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token keyword">typedef</span> <span class="token keyword">struct</span> <span class="token class-name">aksl_TreeNode</span> <span class="token punctuation">{</span>
|
||||
<span class="token keyword">struct</span> <span class="token class-name">aksl_TreeNode</span> <span class="token operator">*</span>parent<span class="token punctuation">;</span>
|
||||
<span class="token keyword">struct</span> <span class="token class-name">aksl_TreeNode</span> <span class="token operator">*</span>left<span class="token punctuation">;</span>
|
||||
<span class="token keyword">struct</span> <span class="token class-name">aksl_TreeNode</span> <span class="token operator">*</span>right<span class="token punctuation">;</span>
|
||||
<span class="token keyword">void</span> <span class="token operator">*</span>leaf<span class="token punctuation">;</span>
|
||||
<span class="token punctuation">}</span> aksl_TreeNode<span class="token punctuation">;</span>
|
||||
|
||||
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">AKSL_TREE_SEARCH_BFS</span> <span class="token expression"><span class="token number">0</span> </span><span class="token comment">/** Breadth-first search mode for tree nodes. Currently unsupported. */</span></span>
|
||||
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">AKSL_TREE_SEARCH_BFS_RIGHT</span> <span class="token expression"><span class="token number">1</span> </span><span class="token comment">/** Right-hand breadth-first search mode for tree nodes. Currentl unsupported. */</span></span>
|
||||
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">AKSL_TREE_SEARCH_DFS</span> <span class="token expression"><span class="token number">2</span> </span><span class="token comment">/** Alias for AKSL_TREE_SEARCH_DFS_PREORDER */</span></span>
|
||||
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">AKSL_TREE_SEARCH_DFS_PREORDER</span> <span class="token expression"><span class="token number">2</span> </span><span class="token comment">/** Depth first pre-order (root, left, right) search mode for tree nodes */</span></span>
|
||||
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">AKSL_TREE_SEARCH_DFS_INORDER</span> <span class="token expression"><span class="token number">3</span> </span><span class="token comment">/** Depth first in-order (left, root, right) search mode for tree nodes. Currently unsupported. */</span></span>
|
||||
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">AKSL_TREE_SEARCH_DFS_POSTORDER</span> <span class="token expression"><span class="token number">4</span> </span><span class="token comment">/** Depth first post-order (left, right, root) search mode for tree nodes. Currently unsupported. */</span></span>
|
||||
<span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">AKSL_TREE_SEARCH_VISIT</span> <span class="token expression"><span class="token number">5</span> </span><span class="token comment">/** Used when iterating through a tree structure as a control flag: don't traverse the children, just visit the node */</span></span>
|
||||
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
|
||||
|
||||
<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>
|
||||
<pre class="line-numbers language-c" data-language="c"><code class="language-c">akerr_ErrorContext AKERR_NOIGNORE <span class="token operator">*</span><span class="token function">aksl_tree_iterate</span><span class="token punctuation">(</span>aksl_TreeNode <span class="token operator">*</span>root<span class="token punctuation">,</span> aksl_TreeNodeIterator iter<span class="token punctuation">,</span> aksl_AllocFunc lalloc<span class="token punctuation">,</span> aksl_FreeFunc lfree<span class="token punctuation">,</span> <span class="token class-name">uint8_t</span> searchmode<span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token operator">*</span>data<span class="token punctuation">,</span> aksl_ListNode <span class="token operator">*</span>queue<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
|
||||
|
||||
<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 <a target="_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) <a target="_blank" rel="noopener" href="https://source.starfort.tech/andrew/libakstdlib/src/branch/main/tests/test_tree.c">in the tests directory</a>.</p>
|
||||
<h1 id="libakgl"><a href="#libakgl" class="headerlink" title="libakgl"></a>libakgl</h1><p>All of the work in libakerror and libakstdlib this week was supporting <a target="_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 <a target="_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>
|
||||
<!--
|
||||
-- tags
|
||||
INFO Validating config
|
||||
INFO Start processing
|
||||
Name Posts Path
|
||||
No tags.
|
||||
---------------
|
||||
-- categories
|
||||
INFO Validating config
|
||||
INFO Start processing
|
||||
Name Posts
|
||||
Books 14
|
||||
Current Events 6
|
||||
Current Events 0
|
||||
Faith 7
|
||||
History 1
|
||||
Leadership 8
|
||||
Liberal Education 1
|
||||
Outdoors 1
|
||||
Philosophy 7
|
||||
Philosophy 0
|
||||
Technology 15
|
||||
technology 0
|
||||
--!>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
</article>
|
||||
<div class="nav">
|
||||
|
||||
<div class="nav-item-prev">
|
||||
<a
|
||||
href="/2026/06/27/News-2026-Week-2/"
|
||||
class="nav-link">
|
||||
<i class="iconfont icon-left nav-prev-icon"></i>
|
||||
<div>
|
||||
<div class="nav-label">Prev</div>
|
||||
|
||||
<div class="nav-title">News-2026-Week-2 </div>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="nav-item-next">
|
||||
<a
|
||||
href="/2026/06/23/News-2026-Week-26/"
|
||||
class="nav-link">
|
||||
<div>
|
||||
<div class="nav-label">Next</div>
|
||||
|
||||
<div class="nav-title">News - 2026 - Week - 26 </div>
|
||||
|
||||
</div>
|
||||
<i class="iconfont icon-right nav-next-icon"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="card card-content toc-card"
|
||||
id="mobiletoc">
|
||||
<div class="toc-header">
|
||||
<i
|
||||
class="iconfont icon-menu"
|
||||
style="padding-right: 2px;">
|
||||
</i>TOC
|
||||
</div>
|
||||
<ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#libakerror-logging-cleanup"><span class="toc-text">libakerror logging cleanup</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#libakstdlib"><span class="toc-text">libakstdlib</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#Linked-List-Handling"><span class="toc-text">Linked List Handling</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Binary-Trees"><span class="toc-text">Binary Trees</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#libakgl"><span class="toc-text">libakgl</span></a></li></ol>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
<aside class="right-column">
|
||||
<div class="sticky-widescreen">
|
||||
|
||||
|
||||
<article class="card card-content toc-card">
|
||||
<div class="toc-header">
|
||||
<i
|
||||
class="iconfont icon-menu"
|
||||
style="padding-right: 2px;">
|
||||
</i>TOC
|
||||
</div>
|
||||
<ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#libakerror-logging-cleanup"><span class="toc-text">libakerror logging cleanup</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#libakstdlib"><span class="toc-text">libakstdlib</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#Linked-List-Handling"><span class="toc-text">Linked List Handling</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Binary-Trees"><span class="toc-text">Binary Trees</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#libakgl"><span class="toc-text">libakgl</span></a></li></ol>
|
||||
</article>
|
||||
|
||||
|
||||
<article class="card card-content">
|
||||
<div class="recent-posts-card">
|
||||
<div class="recent-posts-header">
|
||||
<i
|
||||
class="iconfont icon-wenzhang_huaban"
|
||||
style="padding-right: 2px;">
|
||||
</i>Recent Posts
|
||||
</div>
|
||||
<div class="recent-posts-list">
|
||||
|
||||
<div class="recent-posts-item">
|
||||
<div class="recent-posts-item-title">2026-06-27</div>
|
||||
<a href="/2026/06/27/News-2026-Week-2/"><div class="recent-posts-item-content">News-2026-Week-2</div></a>
|
||||
</div>
|
||||
|
||||
<div class="recent-posts-item">
|
||||
<div class="recent-posts-item-title">2026-06-27</div>
|
||||
<a href="/2026/06/27/Devlog-20260627/"><div class="recent-posts-item-content">Devlog Entry - 27 June 2026</div></a>
|
||||
</div>
|
||||
|
||||
<div class="recent-posts-item">
|
||||
<div class="recent-posts-item-title">2026-06-23</div>
|
||||
<a href="/2026/06/23/News-2026-Week-26/"><div class="recent-posts-item-content">News - 2026 - Week - 26</div></a>
|
||||
</div>
|
||||
|
||||
<div class="recent-posts-item">
|
||||
<div class="recent-posts-item-title">2026-06-18</div>
|
||||
<a href="/2026/06/18/Devlog-20260618/"><div class="recent-posts-item-content">Devlog Entry - 18 June 2026</div></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="footer-container">
|
||||
<div>
|
||||
<div class="footer-dsc">
|
||||
<span>
|
||||
Copyright ©
|
||||
|
||||
|
||||
-
|
||||
2026
|
||||
|
||||
</span>
|
||||
|
||||
<a
|
||||
href="mailto:andrew@aklabs.net"
|
||||
class="footer-link">
|
||||
Andrew Kesterson
|
||||
</a>
|
||||
<br/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="footer-dsc">
|
||||
|
||||
Powered by
|
||||
<a
|
||||
href="https://hexo.io/"
|
||||
class="footer-link"
|
||||
target="_blank"
|
||||
rel="nofollow noopener noreferrer">
|
||||
Hexo
|
||||
</a>
|
||||
|
||||
|
||||
<span> | </span>
|
||||
|
||||
|
||||
Theme -
|
||||
<a
|
||||
href="https://github.com/theme-kaze"
|
||||
class="footer-link"
|
||||
target="_blank"
|
||||
rel="nofollow noopener noreferrer">
|
||||
Kaze
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</footer>
|
||||
|
||||
|
||||
<a
|
||||
role="button"
|
||||
id="scrollbutton"
|
||||
class="basebutton"
|
||||
aria-label="回到顶部">
|
||||
<i class="iconfont icon-arrowleft button-icon"></i>
|
||||
</a>
|
||||
|
||||
<a
|
||||
role="button"
|
||||
id="menubutton"
|
||||
aria-label="menu button"
|
||||
class="basebutton">
|
||||
<i class="iconfont icon-menu button-icon"></i>
|
||||
</a>
|
||||
<a
|
||||
role="button"
|
||||
id="popbutton"
|
||||
class="basebutton"
|
||||
aria-label="控制中心">
|
||||
<i class="iconfont icon-expand button-icon"></i>
|
||||
</a>
|
||||
<a
|
||||
role="button"
|
||||
id="darkbutton"
|
||||
class="basebutton darkwidget"
|
||||
aria-label="夜色模式">
|
||||
<i class="iconfont icon-weather button-icon"></i>
|
||||
</a>
|
||||
<a
|
||||
role="button"
|
||||
id="searchbutton"
|
||||
class="basebutton searchwidget"
|
||||
aria-label="搜索">
|
||||
<i class="iconfont icon-search button-icon"></i>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
var addImgLayout = function () {
|
||||
var img = document.querySelectorAll('.post-content img')
|
||||
var i
|
||||
for (i = 0; i < img.length; i++) {
|
||||
var wrapper = document.createElement('a')
|
||||
wrapper.setAttribute('href', img[i].getAttribute('data-src'))
|
||||
wrapper.setAttribute('aria-label', 'illustration')
|
||||
wrapper.style.cssText =
|
||||
'width: 100%; display: flex; justify-content: center;'
|
||||
if (img[i].alt) wrapper.dataset.caption = img[i].alt
|
||||
wrapper.dataset.nolink = true
|
||||
img[i].before(wrapper)
|
||||
wrapper.append(img[i])
|
||||
var divWrap = document.createElement('div')
|
||||
divWrap.classList.add('gallery')
|
||||
wrapper.before(divWrap)
|
||||
divWrap.append(wrapper)
|
||||
}
|
||||
baguetteBox.run('.gallery')
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
loadScript(
|
||||
"/js/lib/lightbox/baguetteBox.min.js",
|
||||
addImgLayout
|
||||
)
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<script src="/js/main.js"></script>
|
||||
|
||||
|
||||
<script>
|
||||
var addLazyload = function () {
|
||||
var observer = lozad('.lozad', {
|
||||
load: function (el) {
|
||||
el.srcset = el.getAttribute('data-src')
|
||||
},
|
||||
loaded: function (el) {
|
||||
el.classList.add('loaded')
|
||||
},
|
||||
})
|
||||
observer.observe()
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
loadScript('/js/lib/lozad.min.js', addLazyload)
|
||||
</script>
|
||||
|
||||
<script src="//instant.page/5.1.0" type="module"
|
||||
integrity="sha384-by67kQnR+pyfy8yWP4kPO12fHKRLHZPfEsiSXR8u2IKcTdxD805MGUXBzVPnkLHw"></script>
|
||||
|
||||
<script>
|
||||
var googleAnalytics = function () {
|
||||
window.dataLayer = window.dataLayer || []
|
||||
function gtag() {
|
||||
dataLayer.push(arguments)
|
||||
}
|
||||
gtag('js', new Date())
|
||||
gtag('config', 'G-S3YLF516N6')
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
loadScript(
|
||||
'https://www.googletagmanager.com/gtag/js?id=' +
|
||||
'G-S3YLF516N6',
|
||||
googleAnalytics
|
||||
)
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user