Last active
December 10, 2025 02:41
-
-
Save unrays/b160f014ff7c6629007eccb661fe6eab to your computer and use it in GitHub Desktop.
High-performance C++ ECS with cache-friendly design
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Copyright (c) November 2025 Félix-Olivier Dumas. All rights reserved. | |
| // Licensed under the terms described in the LICENSE file. | |
| class Registry { | |
| private: | |
| static constexpr std::uint32_t InitialEntityCapacity = 131072; | |
| static constexpr std::uint32_t InitialPoolCapacity = 262143; | |
| std::vector<ComponentMask> _cmask; | |
| std::vector<ComponentMask> _ctype; | |
| std::vector<Position> _positions; | |
| std::vector<int> _entityToPosIndex; | |
| std::vector<Velocity> _velocities; | |
| std::vector<int> _entityToVelIndex; | |
| std::vector<Rotation> _rotations; | |
| std::vector<int> _entityToRotIndex; | |
| std::vector<Scale> _scales; | |
| std::vector<int> _entityToScaleIndex; | |
| std::vector<Color> _colors; | |
| std::vector<int> _entityToColorIndex; | |
| private: | |
| template <typename T> static ComponentMask MaskOf() { | |
| static_assert(std::is_trivially_copyable_v<T>); | |
| if constexpr (std::is_same_v<T, Position>) return ComponentMask::Position; | |
| if constexpr (std::is_same_v<T, Velocity>) return ComponentMask::Velocity; | |
| if constexpr (std::is_same_v<T, Rotation>) return ComponentMask::Rotation; | |
| if constexpr (std::is_same_v<T, Scale>) return ComponentMask::Scale; | |
| if constexpr (std::is_same_v<T, Color>) return ComponentMask::Color; | |
| throw std::runtime_error("Component type not supported"); | |
| } | |
| public: | |
| Registry(std::size_t maxEntities, std::size_t maxPool) { | |
| _cmask.resize(maxEntities, ComponentMask::None); | |
| _entityToPosIndex.resize(maxEntities, -1); | |
| _entityToVelIndex.resize(maxEntities, -1); | |
| _entityToRotIndex.resize(maxEntities, -1); | |
| _entityToScaleIndex.resize(maxEntities, -1); | |
| _entityToColorIndex.resize(maxEntities, -1); | |
| _positions.reserve(maxPool); | |
| _velocities.reserve(maxPool); | |
| _rotations.reserve(maxPool); | |
| _scales.reserve(maxPool); | |
| _colors.reserve(maxPool); | |
| } | |
| template <typename T> void Add(std::uint32_t eidx) { | |
| if constexpr (std::is_same_v<T, Position>) { | |
| if (_entityToPosIndex[eidx] != -1) { | |
| printf("[ERROR] Entity %u already has Position component\n", eidx); | |
| return; | |
| } | |
| _entityToPosIndex[eidx] = _positions.size(); | |
| _positions.push_back(Position{}); | |
| } | |
| else if constexpr (std::is_same_v<T, Velocity>) { | |
| if (_entityToVelIndex[eidx] != -1) { | |
| printf("[ERROR] Entity %u already has Velocity component\n", eidx); | |
| return; | |
| } | |
| _entityToVelIndex[eidx] = _velocities.size(); | |
| _velocities.push_back(Velocity{}); | |
| } | |
| else if constexpr (std::is_same_v<T, Rotation>) { | |
| if (_entityToRotIndex[eidx] != -1) { | |
| printf("[ERROR] Entity %u already has Rotation component\n", eidx); | |
| return; | |
| } | |
| _entityToRotIndex[eidx] = _rotations.size(); | |
| _rotations.push_back(Rotation{}); | |
| } | |
| else if constexpr (std::is_same_v<T, Scale>) { | |
| if (_entityToScaleIndex[eidx] != -1) { | |
| printf("[ERROR] Entity %u already has Scale component\n", eidx); | |
| return; | |
| } | |
| _entityToScaleIndex[eidx] = _scales.size(); | |
| _scales.push_back(Scale{}); | |
| } | |
| else if constexpr (std::is_same_v<T, Color>) { | |
| if (_entityToColorIndex[eidx] != -1) { | |
| printf("[ERROR] Entity %u already has Color component\n", eidx); | |
| return; | |
| } | |
| _entityToColorIndex[eidx] = _colors.size(); | |
| _colors.push_back(Color{}); | |
| } | |
| } | |
| template<typename T> T& Get(std::uint32_t eidx) { | |
| if constexpr (std::is_same_v<T, Position>) { | |
| if (_entityToPosIndex[eidx] == -1) | |
| throw std::runtime_error( | |
| "Entity " + std::to_string(eidx) + " does NOT have Position component" | |
| ); | |
| return _positions[_entityToPosIndex[eidx]]; | |
| } | |
| else if constexpr (std::is_same_v<T, Velocity>) { | |
| if (_entityToVelIndex[eidx] == -1) | |
| throw std::runtime_error( | |
| "Entity " + std::to_string(eidx) + " does NOT have Velocity component" | |
| ); | |
| return _velocities[_entityToVelIndex[eidx]]; | |
| } | |
| else if constexpr (std::is_same_v<T, Rotation>) { | |
| if (_entityToRotIndex[eidx] == -1) | |
| throw std::runtime_error( | |
| "Entity " + std::to_string(eidx) + " does NOT have Rotation component" | |
| ); | |
| return _rotations[_entityToRotIndex[eidx]]; | |
| } | |
| else if constexpr (std::is_same_v<T, Scale>) { | |
| if (_entityToScaleIndex[eidx] == -1) | |
| throw std::runtime_error( | |
| "Entity " + std::to_string(eidx) + " does NOT have Scale component" | |
| ); | |
| return _scales[_entityToScaleIndex[eidx]]; | |
| } | |
| else if constexpr (std::is_same_v<T, Color>) { | |
| if (_entityToColorIndex[eidx] == -1) | |
| throw std::runtime_error( | |
| "Entity " + std::to_string(eidx) + " does NOT have Color component" | |
| ); | |
| return _colors[_entityToColorIndex[eidx]]; | |
| } | |
| throw std::runtime_error("Component type not supported"); | |
| } | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment