Skip to content

[M1-ECS-03] Archetype SoA storage - #18

Merged
offdev merged 2 commits into
masterfrom
m1-ecs-03-archetype
Sep 13, 2026
Merged

offdev merged 2 commits into
masterfrom
m1-ecs-03-archetype

Conversation

@offdev

@offdev offdev commented Sep 13, 2026

Copy link
Copy Markdown
Owner

M1-ECS-03 · Archetype SoA storage

Implements roadmap/M1-heartbeat.md M1-ECS-03 (scope only — no query API,
no iteration, no G-R4 thresholds):

  • Archetype = ordered component set, stored SoA: one packed T[]
    column per component, rows kept in ascending slot-id order (a pure
    function of the world state; the convergence property M1-ECS-05 will
    iterate).
  • entity→archetype map: two dense per-slot tables (archetypeOf_ 2 B +
    rowOf_ 4 B; no hash) → get<T>(e) / has<T>(e) are O(1).
  • addComponent<T>(e, v) create-or-update / removeComponent<T>(e)
    no-op-ok: pool-backed moves (tail memmove + rowOf_ re-sync) with
    zero heap allocation per operation — bounded reserve policy
    (initial min(16, capacity) rows, ×2 growth capped at world capacity,
    every reserve accounted + logged; log2(capacity/16)+1 bounded).
  • Budgets kMaxArchetypes = 256 / kMaxArchetypeComponents = 32
    (BudgetExhausted + rate-limited warns ecs/archetype_budget,
    ecs/component_limit); unregistered type → InvalidArgument +
    ecs/component_unregistered; stale handle → the M1-ECS-01 contract.
  • Per-slot bookkeeping 5 → 11 B (entity.md updated); destroy/clear
    detach rows first (documented O(tail × row-stride) cost, no allocation).

Tests — archetype CTest entry, 25 cases: basics, stale/unregistered
matrix, layout properties (per-column contiguity, 32 B alignment,
slot-ordered addresses, shift semantics), move data preservation,
two-world layout convergence, budget boundaries (256 sets / 32 components /
growth cap at odd capacity), warn-once rate-limit summary, stats/bytes
tracking, and the 10k-entity churn: 20k add/remove ops in seeded random
order — zero failures, zero reservation delta, zero process-wide
allocations
(test-only operator new counter on non-sanitizer trees;
sanitizer trees prove it leak-free), p99/p50 ≈ 1.98 (flat), and a
machine-greppable archetype-churn <stats> line on every ctest run
(CORE-001). Measured baseline (g++ 16.2.1, single-threaded headless):
Debug p50 0.123 ms/op, Release p50 0.0021 ms/op.

Docs: new docs/api/archetype.md (contract + Performance section),
cross-refs in entity.md / component_registry.md / docs index / sim
README; laige-api.json regenerated (443 symbols); roadmap checkbox,
Progress Board 3/25, one-line Change Log.

Verify: canonical g++ tree zero-warning; full ctest 36/36;
ctest -R archetype green; sim suites green on build-asan (ASan+UBSan,
leak-free churn), build-clang, build-release, build-shared,
build-tsan; tools/laige-include-lint OK.

Base commit: 452ab86.

Archetype = ordered component set stored SoA (one packed T[] column per
component, rows in ascending slot-id order); entity->archetype map as two
dense per-slot tables (archetypeOf_ + rowOf_, no hash); O(1) get<T>/has<T>;
addComponent<T> create-or-update / removeComponent<T> no-op-ok with
pool-backed moves (tail memmove + rowOf_ re-sync) and zero heap allocation
per operation (bounded reserve policy: min(16,capacity) initial, x2 growth
capped at world capacity, accounted + logged).

Budgets: kMaxArchetypes=256, kMaxArchetypeComponents=32 (BudgetExhausted +
rate-limited warns ecs/archetype_budget, ecs/component_limit). Per-slot
bookkeeping 5 -> 11 B; destroy/clear detach rows first (documented cost).

25 test cases in the 'archetype' CTest entry, incl. the 10k-entity churn
(20k add/remove ops, seeded random order: zero failures, zero reservation
delta, zero process-wide allocations via test-only operator new counter,
p99/p50 ~ 1.98, machine-greppable stats line per ctest run).

Docs: docs/api/archetype.md (+ cross-refs), laige-api.json regenerated
(443 symbols), roadmap checkbox + Progress Board 3/25 + Change Log.

Verify: canonical g++ tree zero-warning, full ctest 36/36, ctest -R archetype
green, sim suites green on build-asan/build-clang/build-release/build-shared/
build-tsan, tools/laige-include-lint OK.
@offdev
offdev merged commit 44991de into master Sep 13, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant