Skip to content
This repository was archived by the owner on Jul 29, 2026. It is now read-only.
This repository was archived by the owner on Jul 29, 2026. It is now read-only.

feat(core/ecs): add compile-time capacity and storage policy to EntityRegistry #266

Description

@ThorstenSuckow

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

  • EntityRegistry compiles with TLocked = true using fixed-size arrays.
  • EntityRegistry compiles with TLocked = false using vectors (no regression).
  • static_assert fires when TLocked = true and TCapacity == 0.
  • Assertion (or defined error) when a locked registry exceeds capacity at runtime.
  • Existing tests pass without modification for the default (TLocked = false) path.
  • New tests cover the locked path (capacity enforcement, create/destroy cycle).
  • Documentation updated for EntityRegistry and related core-concept pages.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions