Summary
EntityRegistry (and related ECS infrastructure in helios.core.ecs) should support a compile-time capacity (TCapacity) and a storage policy (TLocked) that determines whether the underlying containers use fixed-size arrays or dynamically growing vectors.
Motivation
The current implementation already accepts a TCapacity template parameter but still relies on std::vector internally. For scenarios where the maximum entity count is known at compile time (e.g., pooled game objects with a hard upper bound), a fixed-size std::array can:
- Eliminate heap allocations at runtime, avoiding allocator overhead entirely.
- Improve cache locality, since the storage lives inline or in a single contiguous block.
- Provide stronger guarantees: a locked registry can never silently reallocate, making it safe for use in real-time or latency-sensitive contexts.
Conversely, when the upper bound is unknown or varies significantly, the existing std::vector-based approach should remain available.
Proposed Design
Add a boolean template parameter TLocked (default false) to EntityRegistry:
template<
typename TStrongId,
typename TLookupStrategy = HashedLookupStrategy,
size_t TCapacity = 0,
bool TLocked = false,
bool TAllowRemoval = true
>
class EntityRegistry;
TLocked |
TCapacity |
Behavior |
false |
0 |
Dynamic growth via std::vector (current behavior). |
false |
> 0 |
std::vector with reserve(TCapacity) (current behavior). |
true |
> 0 |
Fixed std::array<T, TCapacity> — no heap allocation, hard limit enforced via assertion. |
true |
0 |
Static assert / compile error (locked mode requires a capacity). |
Affected members
The storage policy applies to the internal containers:
versions_ → std::array<VersionId, TCapacity> or std::vector<VersionId>
strongIds_ → std::array<StrongId_t, TCapacity> or std::vector<StrongId_t>
freeList_ → std::array<EntityId, TCapacity> or std::vector<EntityId>
A std::conditional_t-based type alias or a small storage-policy trait can keep the implementation clean:
template<typename T, size_t N, bool Locked>
using Storage = std::conditional_t<Locked, std::array<T, N>, std::vector<T>>;
Scope
The same pattern should be evaluated for other ECS containers that currently use std::vector internally (e.g., SparseSet, lookup strategies), so that a fully allocation-free ECS path becomes possible when desired.
Acceptance Criteria
Summary
EntityRegistry(and related ECS infrastructure inhelios.core.ecs) should support a compile-time capacity (TCapacity) and a storage policy (TLocked) that determines whether the underlying containers use fixed-size arrays or dynamically growing vectors.Motivation
The current implementation already accepts a
TCapacitytemplate parameter but still relies onstd::vectorinternally. For scenarios where the maximum entity count is known at compile time (e.g., pooled game objects with a hard upper bound), a fixed-sizestd::arraycan:Conversely, when the upper bound is unknown or varies significantly, the existing
std::vector-based approach should remain available.Proposed Design
Add a boolean template parameter
TLocked(defaultfalse) toEntityRegistry:TLockedTCapacityfalse0std::vector(current behavior).false> 0std::vectorwithreserve(TCapacity)(current behavior).true> 0std::array<T, TCapacity>— no heap allocation, hard limit enforced via assertion.true0Affected members
The storage policy applies to the internal containers:
versions_→std::array<VersionId, TCapacity>orstd::vector<VersionId>strongIds_→std::array<StrongId_t, TCapacity>orstd::vector<StrongId_t>freeList_→std::array<EntityId, TCapacity>orstd::vector<EntityId>A
std::conditional_t-based type alias or a small storage-policy trait can keep the implementation clean:Scope
The same pattern should be evaluated for other ECS containers that currently use
std::vectorinternally (e.g.,SparseSet, lookup strategies), so that a fully allocation-free ECS path becomes possible when desired.Acceptance Criteria
EntityRegistrycompiles withTLocked = trueusing fixed-size arrays.EntityRegistrycompiles withTLocked = falseusing vectors (no regression).static_assertfires whenTLocked = trueandTCapacity == 0.TLocked = false) path.EntityRegistryand related core-concept pages.