Add a second partitioner, so the vtable is a seam and not a decoration
A binary space partition on libakstdlib's tree links and lists, registered in the factory as "bsp". It runs the same assertions the grid does, because tests/partition.c is a table over partitioners and adding a row is all it takes to be held to the contract. **Use the grid.** This is here to prove the vtable works and to have something to measure the grid against, and the file says so at the top. It rebuilds whenever the proxy set changes, which is the shape PERFORMANCE.md records Phaser using and capping out around five thousand bodies. It would earn its place in a world with wildly non-uniform object sizes, or one larger than the grid's fixed cell array covers. The difference is visible in the code rather than buried in a benchmark: the grid's `move` compares four integers and returns when a proxy has not left its cells, and this one marks the whole partition stale. The incremental-move assertion in the suite is therefore grid-only, and says why. aksl_tree_iterate is not used, and the file carries the three reasons so the next reader does not rediscover them: it is a complete traversal whose only control signal stops the entire walk, so there is no way to prune a subtree -- which is the only operation a spatial query is made of; it carries no per-node context, and a pruning descent needs each node's bounds and plane; and its breadth-first modes allocate, while only the depth-first ones are malloc-free and those are the ones without pruning. aksl_tree_insert is unusable for a different reason again: it is a comparator-ordered BST, and a spatial insert has to compare a leaf against a plane, which aksl_TreeCompareFunc cannot express. What is used is the link structure and the lists, neither of which allocates, which is why they fit here at all. The descent is an explicit stack rather than recursion, so the depth bound is an array bound the compiler can see -- this library already has one documented way to blow the C stack and does not need a second. Split planes are the median of the item centres on the longer axis, not the spatial midpoint: actors in a tile game cluster on the floor, and a midpoint split gives one empty child and one full one for several levels running. A split that separates nothing degrades the node to a leaf rather than recursing forever on the same set. Co-Authored-By: Claude Code <noreply@anthropic.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
#include "testutil.h"
|
||||
|
||||
/** @brief Every partitioner the factory knows, so the same tests run over each. */
|
||||
static char *partitioners[] = { "grid" };
|
||||
static char *partitioners[] = { "grid", "bsp" };
|
||||
|
||||
/** @brief What a visit callback accumulates. */
|
||||
typedef struct {
|
||||
@@ -283,12 +283,20 @@ akerr_ErrorContext *test_move_is_incremental(char *name)
|
||||
* checked rather than trusted: the proxy's chain head is the cheapest
|
||||
* observable proof that no entry was released and re-claimed.
|
||||
*/
|
||||
firstbefore = proxy->first;
|
||||
CATCH(errctx, akgl_collision_proxy_sync(proxy, &shape, 201.0f, 201.0f, 0.0f));
|
||||
CATCH(errctx, world.partitioner.move(&world.partitioner, proxy));
|
||||
TEST_ASSERT(errctx, (proxy->first == firstbefore),
|
||||
"%s re-celled a proxy that did not leave its cells; the structure is not "
|
||||
"incremental and the argument for choosing it does not hold", name);
|
||||
/*
|
||||
* Only the grid claims to be incremental, and this is where that claim
|
||||
* is checked rather than believed. The BSP is exempt by construction: it
|
||||
* marks itself stale on any move and rebuilds, which is exactly the cost
|
||||
* the grid was chosen to avoid and exactly why it is not the default.
|
||||
*/
|
||||
if ( strcmp(name, "grid") == 0 ) {
|
||||
firstbefore = proxy->first;
|
||||
CATCH(errctx, akgl_collision_proxy_sync(proxy, &shape, 201.0f, 201.0f, 0.0f));
|
||||
CATCH(errctx, world.partitioner.move(&world.partitioner, proxy));
|
||||
TEST_ASSERT(errctx, (proxy->first == firstbefore),
|
||||
"%s re-celled a proxy that did not leave its cells; the structure is "
|
||||
"not incremental and the argument for choosing it does not hold", name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Moving repeatedly must not accumulate index entries. A move that links
|
||||
|
||||
Reference in New Issue
Block a user