Skip to content

perf(storage): cache column maps and intern archetypes by bitmask - #12

Merged
Stephanvs merged 1 commit into
mainfrom
feat/step6-column-maps
Oct 30, 2026
Merged

Stephanvs merged 1 commit into
mainfrom
feat/step6-column-maps

Conversation

@Stephanvs

Copy link
Copy Markdown
Owner

Why

Get<T>, bundle writes, inserts, and every structural move binary-searched an archetype's sorted component IDs, and archetypes were interned by a joined string. This is ROADMAP step 6. Each archetype now holds a dense component-to-column lookup, and each cached transition holds the column map for its move. Archetypes are interned by their component bitmask.

Scope

  • Archetype.Columns replaces Array.BinarySearch in TryGet<T>, WriteBundle, ApplyInsert, and QueryState.Refresh.
  • ArchetypeEdge holds a transition's target and its column map. Table.CopyRowTo copies through it. AddTransitions, RemoveTransitions, and BundleBinding.Destinations cache edges.
  • World interns archetypes by ulong[] mask and creates the empty archetype at build time. Archetype derives its sorted IDs from its mask.
  • EntityTable.TryLocate lets TryGet<T> read the directory entry once. IsAlive delegates to it.
  • ROADMAP.md status and amendments after step 6, benchmarks/step6-cached-column-maps.md, and one sentence in docs/concepts/architecture.mdx.

Tradeoffs

The amendment after step 4 suggested that BundleBinding hold its destination columns. The dense lookup costs one array read for every caller, so the binding does not need its own copy. Transition edges stay in per-archetype dictionaries. Dense edge arrays would cost memory for every archetype and component pair.

Blast Radius

Internal storage only, with no public API change. Merging publishes a patch release through the release workflow. Every structural move and bundle write goes through the new column maps. The reference-model trace test and the multi-word mask test pass unchanged.

Verification

  • scripts/verify.ps1 passed: 165 tests, Archeoids headless, package contents, JIT and NativeAOT consumers, the NativeAOT sample, and the performance smoke check. The docs site builds.
  • Get<T> at 100,000 entities: 1,702 → 1,316 µs. Tag and wide round trips, Spawn, and SpawnBatch improved at both sizes, and managed allocation did not change. The gate is met. Full interleaved measurements are in benchmarks/step6-cached-column-maps.md.

🤖 Generated with Claude Code

Each archetype maps every registered component to its table column, and
each cached transition stores the column map for its move. Get<T>,
bundle writes, inserts, and row moves no longer binary-search component
IDs. Archetypes are interned by component bitmask, the empty archetype
is cached, and TryGet reads the directory entry once.

Measurements are in benchmarks/step6-cached-column-maps.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://feat-step6-column-maps-archevolt.hayman.workers.dev (commit 65330d3)

This URL reflects your latest Preview deployment

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://13f2f8f6-archevolt.hayman.workers.dev 65330d3 2026-10-29T21:24:48.550Z Visit the dashboard ↗

@Stephanvs
Stephanvs merged commit 1ea88b7 into main Oct 30, 2026
2 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