Use when designing or refactoring performance-critical data layouts for cache efficiency, in any language. Triggers on prompts about SoA/AoS/AoSoA, cache misses, hot/cold field splitting, data-oriented design, component-storage layout, batch/bulk processing, handles vs pointers, avoiding pointer chasing, even when the user doesn't say 'data-oriented' or 'cache'.
Use when designing or refactoring performance-critical data layouts for cache efficiency, in any language. Triggers on prompts about SoA/AoS/AoSoA, cache misses, hot/cold field splitting, data-oriented design, component-storage layout, batch/bulk processing, handles vs pointers, avoiding pointer chasing, even when the user doesn't say 'data-oriented' or 'cache'.
Record cheaply, always on - Per-frame accumulating counters recorded via a cached accumulator pointer (one store, no lookup/branch/lock), history allocated only for viewed counters, see references/statistics-recording.md
Default to zero - Make all-zero a valid default; reserve 0 for none/neutral, not magic sentinels, see references/zero-as-default.md
Memory
Handles, not pointers - Reference by index/generational handle for relocatable, stable arrays, see references/handles-and-indices.md
Allocation - Contiguous storage matters for cache, but the allocators themselves (arenas/pools/lifetimes) are general — see memory-management-guide
Gotchas
SoA only wins when loops touch a subset of fields; full-record access can favor AoS — measure both.
A generational handle prevents use-after-free dangling on swap-remove, but only if you actually compare the generation.
The hardware prefetcher tracks linear strides; randomizing your index order silently disables it.
Padding for alignment trades memory for throughput — on cache-bound loads, the smaller packed layout can still win.
A counter you cache as a raw pointer dangles if its backing array reallocates — hand out indices into a stable block, or pointers into a non-relocating pool.