FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

docs(engine): specify which inline file extension to use inl, tpp or ipp and when by Miou-zora · Pull Request #580 · EngineSquared/EngineSquared · GitHub

docs(engine): specify which inline file extension to use inl, tpp or ipp and when - #580

Merged
Miou-zora merged 5 commits into
mainfrom
526-doc-specify-which-inline-file-extension-to-use-inl-tpp-or-ipp-and-when
Apr 11, 2026
Merged

docs(engine): specify which inline file extension to use inl, tpp or ipp and when#580
Miou-zora merged 5 commits into
mainfrom
526-doc-specify-which-inline-file-extension-to-use-inl-tpp-or-ipp-and-when

Conversation

Miou-zora commented Apr 10, 2026
edited by coderabbitai Bot
Loading

Copy link
Copy Markdown
Contributor

Pull Request

Description

I included inside wiki (contributing) what kind of file we should put implementations and fixed it inside core.

Related Issues (Put "None" if there are no related issues)

close #526

Type of Change

Please delete options that are not relevant.

  • Documentation update
  • Code refactoring

Changes Made

List the main changes in this PR:

  • Added precisions of usage of cpp, hpp and ipp files
  • Fixed some todos inside the core about it

Testing

Describe the tests you ran to verify your changes. Please delete options that are not relevant.

  • Unit tests pass (xmake test)
  • Code follows the project's style guidelines (clang-format)

Test Environment

  • OS: macOS
  • Compiler: Clang

Screenshots/Videos (Put "None" if there are no related issues)

None

Documentation

Please delete options that are not relevant.

  • I have updated the relevant documentation
  • I have added/updated comments in the code

Checklist (Don't delete any options)

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

Breaking Changes (Put "None" if there are no related issues)

None

Additional Notes (Put "None" if there are no related issues)

None

Summary by CodeRabbit

  • Refactor

    • Major internal reorganization: many implementations moved out of headers into separate implementation units to improve build structure and maintainability.
  • New Features

    • Scheduler: runtime accessors for tick rate and delta time, startup callback hook, and clearer scheduler error reporting.
    • Entities & components: richer identity/equality behavior, easier component add/remove, and temporary-component lifecycle support.
    • Plugins/core: plugins retain and expose core access for runtime registration.
  • Style

    • Improved formatting and debug/log output for identifiers and entities.

Miou-zora self-assigned this Apr 10, 2026

coderabbitai Bot commented Apr 10, 2026
edited
Loading

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Moved many inline/template implementations out of headers into .ipp/.cpp files across Id, Entity/EntityId, Core, schedulers, plugins, systems, and time; added corresponding .ipp implementations and updated build globs to include .ipp files. No behavioral changes announced beyond new/relocated APIs.

Changes

Cohort / File(s) Summary
ID Type System
src/engine/src/Id.hpp, src/engine/src/Id.ipp
Declarations for BasicId/Id/StringId (constructors, Null/IsNull, conversion) moved from header to Id.ipp. fmt::formatter formatters declared in header and implemented in Id.ipp.
Entity & EntityId Types
src/engine/src/entity/Entity.hpp, src/engine/src/entity/Entity.ipp, src/engine/src/entity/EntityId.hpp, src/engine/src/entity/EntityId.ipp, src/engine/src/entity/Entity.cpp
Entity and EntityId constructors, conversion operators, component-management templates, temporary-component lifecycle, validity checks, hash/fmt formatter implementations moved out-of-line into .ipp/.cpp. Header APIs now declaration-only.
Core Engine & Registry
src/engine/src/core/Core.hpp, src/engine/src/core/Core.ipp, src/engine/src/core/Core.cpp
GetRegistry() made non-inline (mutable + const overloads) with implementations in Core.cpp; scheduler dependency template helpers (SetSchedulerBefore/After, RemoveDependency*, SetDefaultScheduler<T>) moved to Core.ipp.
Plugin System
src/engine/src/plugin/APlugin.hpp, src/engine/src/plugin/APlugin.ipp, src/engine/src/plugin/APlugin.cpp
APlugin constructor/GetCore moved to .cpp; template helpers (RegisterSystems, RegisterResource, RequirePlugins, RegisterScheduler, RequirePlugin) moved to APlugin.ipp and implemented to forward to Core.
Scheduler Base & Concrete Types
src/engine/src/scheduler/AScheduler.hpp, src/engine/src/scheduler/AScheduler.ipp, src/engine/src/scheduler/AScheduler.cpp, src/engine/src/scheduler/FixedTimeUpdate.hpp, src/engine/src/scheduler/FixedTimeUpdate.cpp, src/engine/src/scheduler/RelativeTimeUpdate.hpp, src/engine/src/scheduler/RelativeTimeUpdate.cpp, src/engine/src/scheduler/Update.hpp, src/engine/src/scheduler/Update.cpp, src/engine/src/scheduler/Startup.hpp, src/engine/src/scheduler/Startup.cpp
Scheduler constructors and accessors (GetSystems, AddSystems template, tick rate/delta accessors, startup callback) moved out-of-line; AScheduler::AddSystems implemented in .ipp; added error ctor/what.
Scheduler Container & Error Handling
src/engine/src/scheduler/SchedulerContainer.hpp, src/engine/src/scheduler/SchedulerContainer.cpp, src/engine/src/scheduler/SchedulerContainer.ipp
SchedulerError ctor/what moved out-of-line; template DeleteScheduler<TScheduler>() implemented in .ipp forwarding to type_index-based delete.
Time Resource
src/engine/src/resource/Time.hpp, src/engine/src/resource/Time.cpp
Time::Update(Core&) implementation moved from header to Time.cpp, computing elapsed time via high-resolution clock.
System Management
src/engine/src/system/System.hpp, src/engine/src/system/System.ipp, src/engine/src/system/System.cpp, src/engine/src/system/WrappedSystem.hpp, src/engine/src/system/WrappedSystem.ipp
SystemContainer template methods (AddSystems, AddSystem) moved to System.ipp; Get/Delete system implementations moved to System.cpp. WrappedSystem template implementation (constructor, operator(), GetID/GetName, exception handling, callable identification) added in WrappedSystem.ipp.
Build Configuration
src/engine/xmake.lua
Updated build globs to include .ipp files (replacing .inl) and added src/*.ipp to header list.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • ripel2

Poem

🐰
I hop from header to .ipp with glee,
I tuck templates snug where they should be,
Declarations neat, implementations hid,
A carrot-coded change—oh what a tidbit!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main objective: documenting which inline file extension (.inl, .tpp, or .ipp) to use and when, supported by corresponding code refactoring throughout the codebase.
Linked Issues check ✅ Passed The PR successfully addresses all coding requirements from issue #526: establishes .ipp as the standard extension, applies it consistently across all template/inline implementations (Id, Entity, EntityId, Core, APlugin, System, WrappedSystem, and Scheduler classes), and moves implementations from headers to dedicated .ipp files.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #526: refactoring code to use standardized .ipp extension, moving inline implementations to dedicated files, and updating build configuration accordingly. No extraneous changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches 📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 526-doc-specify-which-inline-file-extension-to-use-inl-tpp-or-ipp-and-when

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Miou-zora changed the title doc(engine): specify which inline file extension to use inl, tpp or ipp and when docs(engine): specify which inline file extension to use inl, tpp or ipp and when Apr 10, 2026

coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Actionable comments posted: 7

🧹 Nitpick comments (1)
src/engine/src/scheduler/SchedulerContainer.hpp (1)

27-27: Consider using noexcept instead of throw().

The throw() exception specification is deprecated since C++11 and removed in C++17. The base class std::exception::what() uses noexcept in modern C++.

♻️ Suggested fix
-    const char *what() const throw() override;
+    const char *what() const noexcept override;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/engine/src/scheduler/SchedulerContainer.hpp` at line 27, The declaration
of the exception specification for the overridden what() method uses the
deprecated throw() spec; update the SchedulerContainer::what() declaration (and
its corresponding definition) to use noexcept instead of throw(), e.g. change
"const char *what() const throw() override;" to use noexcept so the signature
matches modern std::exception::what() and keeps the override valid.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/engine/src/entity/EntityId.hpp`:
- Around line 113-116: The shared map temporaryComponent must be protected
against concurrent access: add an inline static mutex (e.g.,
temporaryComponentMutex) alongside temporaryComponent and take a lock
(std::lock_guard or std::unique_lock) whenever AddTemporaryComponent and
RemoveTemporaryComponents access or mutate the map (and any other access sites);
use a shared_mutex if you want concurrent reads and exclusive writes, and ensure
all reads are also properly synchronized to prevent data races and corruption.

In `@src/engine/src/entity/EntityId.ipp`:
- Line 12: The three non-template out-of-class definitions need the inline
keyword to avoid ODR violations when EntityId.ipp is included in multiple
translation units: mark bool EntityId::IsValid(const Engine::Core &core) const,
void EntityId::RemoveTemporaryComponents(Core &core), and std::size_t
std::hash<Engine::EntityId>::operator()(const Engine::EntityId &entityId) const
noexcept as inline; update their declarations/definitions in EntityId.ipp
accordingly so they can be duplicated across TUs without linker errors.

In `@src/engine/src/scheduler/FixedTimeUpdate.cpp`:
- Around line 6-13: Validate tickRate is strictly positive to avoid
divide-by-zero: update the FixedTimeUpdate constructor and SetTickRate(float
tickRate) to check tickRate > 0 and reject invalid values (e.g., throw
std::invalid_argument with a clear message or assert) instead of assigning
zero/negative to _tickRate; keep GetTickRate() unchanged and ensure callers like
RunSystems() rely on this invariant so division by _tickRate is safe.

In `@src/engine/src/scheduler/RelativeTimeUpdate.cpp`:
- Around line 6-14: Validate and guard the tickRate value in
Engine::Scheduler::RelativeTimeUpdate: in the constructor
RelativeTimeUpdate(Core &core, float tickRate) and in SetTargetTickRate(float
tickRate) ensure tickRate is > 0 before assigning to _tickRate (either throw
std::invalid_argument or clamp to a small positive epsilon and/or log), so that
_tickRate is never zero or negative when used as a divisor in RunSystems(); keep
GetTargetTickRate unchanged.

In `@src/engine/src/system/System.hpp`:
- Around line 34-36: Update the GetSystems() doxygen comment to match the
function signature: change the return description that currently mentions
"vector" to "std::list" (or "list") so the doc for const
std::list<std::unique_ptr<SystemBase>>& GetSystems() correctly reflects the
returned container type; locate the comment above the GetSystems() declaration
in System.hpp and update the `@return` text accordingly.
- Line 54: SystemContainer::GetSystems() and SystemContainer::DeleteSystem() are
defined non-inline in System.ipp which is included into System.hpp causing
ODR/linker issues; fix by either marking both member functions as inline in
their definitions in System.ipp or by moving their full definitions out of
System.ipp into a dedicated System.cpp (and keep only declarations in
System.hpp), ensuring the declarations in System.hpp correspond to the
moved/inline definitions.

In `@src/engine/xmake.lua`:
- Around line 20-29: The xmake.lua header file globs omit entity implementation
files: add_headerfiles currently includes "src/(entity/*.hpp)" but not
"src/(entity/*.ipp)", so consumers that rely on Entity.hpp including an .ipp
will break; update the add_headerfiles calls to also include
"src/(entity/*.ipp)" (matching the pattern used for scheduler/system) so that
entity implementation .ipp files are exported alongside the .hpp headers.

---

Nitpick comments:
In `@src/engine/src/scheduler/SchedulerContainer.hpp`:
- Line 27: The declaration of the exception specification for the overridden
what() method uses the deprecated throw() spec; update the
SchedulerContainer::what() declaration (and its corresponding definition) to use
noexcept instead of throw(), e.g. change "const char *what() const throw()
override;" to use noexcept so the signature matches modern
std::exception::what() and keeps the override valid.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info ⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4e1a8ad4-7651-4914-9a71-e32c54c326dd

📥 Commits

Reviewing files that changed from the base of the PR and between eeb34c9 and 6e421a4.

📒 Files selected for processing (34)
  • src/engine/src/Id.hpp
  • src/engine/src/Id.ipp
  • src/engine/src/core/Core.cpp
  • src/engine/src/core/Core.hpp
  • src/engine/src/core/Core.ipp
  • src/engine/src/entity/Entity.cpp
  • src/engine/src/entity/Entity.hpp
  • src/engine/src/entity/Entity.ipp
  • src/engine/src/entity/EntityId.hpp
  • src/engine/src/entity/EntityId.ipp
  • src/engine/src/plugin/APlugin.cpp
  • src/engine/src/plugin/APlugin.hpp
  • src/engine/src/plugin/APlugin.ipp
  • src/engine/src/resource/Time.cpp
  • src/engine/src/resource/Time.hpp
  • src/engine/src/scheduler/AScheduler.cpp
  • src/engine/src/scheduler/AScheduler.hpp
  • src/engine/src/scheduler/AScheduler.ipp
  • src/engine/src/scheduler/FixedTimeUpdate.cpp
  • src/engine/src/scheduler/FixedTimeUpdate.hpp
  • src/engine/src/scheduler/RelativeTimeUpdate.cpp
  • src/engine/src/scheduler/RelativeTimeUpdate.hpp
  • src/engine/src/scheduler/SchedulerContainer.cpp
  • src/engine/src/scheduler/SchedulerContainer.hpp
  • src/engine/src/scheduler/SchedulerContainer.ipp
  • src/engine/src/scheduler/Startup.cpp
  • src/engine/src/scheduler/Startup.hpp
  • src/engine/src/scheduler/Update.cpp
  • src/engine/src/scheduler/Update.hpp
  • src/engine/src/system/System.hpp
  • src/engine/src/system/System.ipp
  • src/engine/src/system/WrappedSystem.hpp
  • src/engine/src/system/WrappedSystem.ipp
  • src/engine/xmake.lua

Comment thread src/engine/src/entity/EntityId.ipp Outdated
Comment thread src/engine/xmake.lua

coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/engine/src/entity/EntityId.ipp`:
- Around line 45-53: The shared static map temporaryComponent is accessed
without synchronization in EntityId::AddTemporaryComponent and where it's
iterated/cleared (lines ~86-91), creating TOCTOU and concurrent-modification
races; fix by introducing a dedicated mutex (e.g., temporaryComponentMutex) and
acquire a lock (std::lock_guard or std::scoped_lock) around all accesses and
mutations of temporaryComponent, and replace the separate contains-then-assign
pattern in AddTemporaryComponent with an atomic insert/emplace that uses the
insertion result while still holding the lock to avoid race windows.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info ⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8a49d813-298b-4281-9049-7a0f68ebd876

📥 Commits

Reviewing files that changed from the base of the PR and between 6e421a4 and 9666d32.

📒 Files selected for processing (3)
  • src/engine/src/entity/EntityId.ipp
  • src/engine/src/system/System.cpp
  • src/engine/src/system/System.ipp
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/engine/src/system/System.ipp

Comment on lines +45 to +53
decltype(auto) EntityId::AddTemporaryComponent(Engine::Core &core, TArgs &&...args)
{
if (!temporaryComponent.contains(std::type_index(typeid(TTempComponent))))
{
temporaryComponent[std::type_index(typeid(TTempComponent))] = [](Core &c) {
Log::Debug(fmt::format("RemoveTemporaryComponent: {}", typeid(TTempComponent).name()));
c.GetRegistry().clear<TTempComponent>();
};
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Shared temporary component state and synchronization usage:"
rg -n "temporaryComponent|mutex|lock_guard|scoped_lock" src/engine/src/entity/EntityId.hpp src/engine/src/entity/EntityId.ipp

echo
echo "Mutation/iteration points in EntityId.ipp:"
rg -n "temporaryComponent\\.contains|temporaryComponent\\[|temporaryComponent\\.clear|for \\(const auto \\&\\[typeIndex, func\\] : temporaryComponent\\)" src/engine/src/entity/EntityId.ipp

Repository: EngineSquared/EngineSquared

Length of output: 1071


🏁 Script executed:

# First, let's see the complete EntityId.hpp to understand the shared static state
cat -n src/engine/src/entity/EntityId.hpp | tail -20

Repository: EngineSquared/EngineSquared

Length of output: 1323


🏁 Script executed:

# Now let's examine the complete EntityId.ipp file around the critical lines
head -95 src/engine/src/entity/EntityId.ipp | tail -55

Repository: EngineSquared/EngineSquared

Length of output: 1857


🏁 Script executed:

# Let's also check if there are any includes of mutex or synchronization primitives
rg -n "#include.*mutex|#include.*lock|#include.*thread" src/engine/src/entity/EntityId.hpp src/engine/src/entity/EntityId.ipp

Repository: EngineSquared/EngineSquared

Length of output: 53


🏁 Script executed:

# Check if there are any other synchronization mechanisms used elsewhere in the codebase for similar patterns
rg -n "std::mutex|std::lock_guard|std::scoped_lock" src/engine/src/entity/ --type cpp --type hpp

Repository: EngineSquared/EngineSquared

Length of output: 98


🏁 Script executed:

# Find the exact location of temporaryComponent definition
rg -n "temporaryComponent\s*=" src/engine/src/entity/EntityId.hpp

Repository: EngineSquared/EngineSquared

Length of output: 182


🏁 Script executed:

# Check if these functions are called from multiple threads or async contexts
rg -n "AddTemporaryComponent|RemoveTemporaryComponents" src/engine/src/ --type cpp --type hpp -A 2 -B 2

Repository: EngineSquared/EngineSquared

Length of output: 98


🏁 Script executed:

# Check if there are any threading primitives used anywhere in the Core or Engine
rg -n "std::thread|std::async|\.spawn|std::mutex" src/engine/src/ -c

Repository: EngineSquared/EngineSquared

Length of output: 53


🏁 Script executed:

# Try searching for function calls without type specification
rg -n "AddTemporaryComponent|RemoveTemporaryComponents" src/engine/src/ -A 2 -B 2

Repository: EngineSquared/EngineSquared

Length of output: 4821


🏁 Script executed:

# Check for threading usage more broadly
rg -n "std::thread|std::async|spawn" src/engine/src/

Repository: EngineSquared/EngineSquared

Length of output: 53


🏁 Script executed:

# Check if the Core class uses multithreading or async operations
rg -n "class Core|struct Core" src/engine/src/core/ -A 20

Repository: EngineSquared/EngineSquared

Length of output: 2301


🏁 Script executed:

# Check if the scheduler system uses threading
rg -n "Scheduler|scheduler" src/engine/src/core/ -A 5 | head -100

Repository: EngineSquared/EngineSquared

Length of output: 6465


🏁 Script executed:

# Check for any system that might process entities concurrently
rg -n "RemoveTemporaryComponents" src/engine/src/core/ -B 5 -A 5

Repository: EngineSquared/EngineSquared

Length of output: 53


🏁 Script executed:

# Let's see the complete picture of when temporaryComponent is accessed
rg -n "temporaryComponent" src/engine/src/ -B 2 -A 2

Repository: EngineSquared/EngineSquared

Length of output: 1838


🏁 Script executed:

# Check if there are any async operations or threading in schedulers
rg -n "async|thread|concurrent|parallel" src/engine/src/scheduler/ -i

Repository: EngineSquared/EngineSquared

Length of output: 53


🏁 Script executed:

# Check the main application loop to see if multiple threads could call these functions
rg -n "AddTemporaryComponent|RemoveTemporaryComponents" src/engine/src/core/Core.cpp -A 3 -B 3

Repository: EngineSquared/EngineSquared

Length of output: 53


🏁 Script executed:

# Look for plugin or system execution that might be multithreaded
find src/engine/src -name "*.cpp" -o -name "*.hpp" | xargs grep -l "AddTemporaryComponent\|RemoveTemporaryComponents"

Repository: EngineSquared/EngineSquared

Length of output: 171


Protect temporaryComponent access with synchronization (data race / UB).

Lines 47-53 mutate the shared static map with a check-then-act pattern while lines 86-91 iterate and clear it with no synchronization. The TOCTOU window at line 47-49 and concurrent modification between iteration and clear create data races if called concurrently.

🔧 Suggested fix
+#include <mutex>
+
 namespace Engine {
+namespace {
+std::mutex temporaryComponentMutex;
+}
+
 template <typename TTempComponent, typename... TArgs>
 decltype(auto) EntityId::AddTemporaryComponent(Engine::Core &core, TArgs &&...args)
 {
-    if (!temporaryComponent.contains(std::type_index(typeid(TTempComponent))))
-    {
-        temporaryComponent[std::type_index(typeid(TTempComponent))] = [](Core &c) {
+    {
+        std::lock_guard<std::mutex> lock(temporaryComponentMutex);
+        temporaryComponent.try_emplace(std::type_index(typeid(TTempComponent)), [](Core &c) {
             Log::Debug(fmt::format("RemoveTemporaryComponent: {}", typeid(TTempComponent).name()));
             c.GetRegistry().clear<TTempComponent>();
-        };
+        });
     }
 
     return this->AddComponent<TTempComponent>(core, std::forward<TArgs>(args)...);
 }
@@
 inline void EntityId::RemoveTemporaryComponents(Core &core)
 {
-    if (temporaryComponent.empty())
-    {
-        return;
-    }
-    for (const auto &[typeIndex, func] : temporaryComponent)
+    std::unordered_map<std::type_index, std::function<void(Core &)>> cleanupFns;
+    {
+        std::lock_guard<std::mutex> lock(temporaryComponentMutex);
+        if (temporaryComponent.empty())
+        {
+            return;
+        }
+        cleanupFns = temporaryComponent;
+        temporaryComponent.clear();
+    }
+    for (const auto &[typeIndex, func] : cleanupFns)
     {
         func(core);
     }
-    temporaryComponent.clear();
 }

Also applies to: 80-91

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/engine/src/entity/EntityId.ipp` around lines 45 - 53, The shared static
map temporaryComponent is accessed without synchronization in
EntityId::AddTemporaryComponent and where it's iterated/cleared (lines ~86-91),
creating TOCTOU and concurrent-modification races; fix by introducing a
dedicated mutex (e.g., temporaryComponentMutex) and acquire a lock
(std::lock_guard or std::scoped_lock) around all accesses and mutations of
temporaryComponent, and replace the separate contains-then-assign pattern in
AddTemporaryComponent with an atomic insert/emplace that uses the insertion
result while still holding the lock to avoid race windows.

coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/engine/src/entity/Entity.cpp`:
- Line 15: The method Entity::RemoveTemporaryComponents currently calls
EntityId::RemoveTemporaryComponents(core) directly which bypasses the instance's
context; change it to delegate via the wrapped id and context by invoking
_entityId.RemoveTemporaryComponents(GetCore()) so it uses this Entity's stored
_entityId and GetCore() rather than an arbitrary Core passed by callers.
- Around line 17-19: The equality operators on Entity currently only compare
_entityId.value; update both Entity::operator==(const Entity &rhs) and
Entity::operator==(const EntityId &rhs) to include Core identity by delegating
to EntityId's own operator== (or by comparing both _core and _entityId) instead
of only comparing _entityId.value — i.e., use _entityId == rhs._entityId (or
_entityId == rhs) and ensure the comparison accounts for the Core
pointer/identifier so entities from different cores are not considered equal.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info ⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 58695a9c-6ad1-4c7a-ad21-4c5171ae1510

📥 Commits

Reviewing files that changed from the base of the PR and between 9666d32 and 9ccfd9a.

📒 Files selected for processing (2)
  • src/engine/src/Id.ipp
  • src/engine/src/entity/Entity.cpp
✅ Files skipped from review due to trivial changes (1)
  • src/engine/src/Id.ipp


Entity::operator EntityId() const { return _entityId; }

void Entity::RemoveTemporaryComponents(Core &core) { EntityId::RemoveTemporaryComponents(core); }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

⚠️ Potential issue | 🟠 Major

RemoveTemporaryComponents bypasses the entity instance context.

This implementation ignores both _entityId and GetCore(), so callers can pass an unrelated Core. Delegate through the wrapped id/context like the rest of Entity APIs.

Proposed fix
-void Entity::RemoveTemporaryComponents(Core &core) { EntityId::RemoveTemporaryComponents(core); }
+void Entity::RemoveTemporaryComponents(Core &core) { _entityId.RemoveTemporaryComponents(core); }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void Entity::RemoveTemporaryComponents(Core &core) { EntityId::RemoveTemporaryComponents(core); }
void Entity::RemoveTemporaryComponents(Core &core) { _entityId.RemoveTemporaryComponents(core); }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/engine/src/entity/Entity.cpp` at line 15, The method
Entity::RemoveTemporaryComponents currently calls
EntityId::RemoveTemporaryComponents(core) directly which bypasses the instance's
context; change it to delegate via the wrapped id and context by invoking
_entityId.RemoveTemporaryComponents(GetCore()) so it uses this Entity's stored
_entityId and GetCore() rather than an arbitrary Core passed by callers.

Comment on lines +17 to +19
bool Entity::operator==(const Entity &rhs) const { return _entityId.value == rhs._entityId.value; }

bool Entity::operator==(const EntityId &rhs) const { return _entityId.value == rhs.value; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

⚠️ Potential issue | 🟠 Major

Entity equality should include Core identity.

Comparing only EntityId.value can mark entities from different Core instances as equal. Compare both core identity and EntityId via its own operator.

Proposed fix
-bool Entity::operator==(const Entity &rhs) const { return _entityId.value == rhs._entityId.value; }
+bool Entity::operator==(const Entity &rhs) const
+{
+    return &GetCore() == &rhs.GetCore() && _entityId == rhs._entityId;
+}
 
-bool Entity::operator==(const EntityId &rhs) const { return _entityId.value == rhs.value; }
+bool Entity::operator==(const EntityId &rhs) const { return _entityId == rhs; }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bool Entity::operator==(const Entity &rhs) const { return _entityId.value == rhs._entityId.value; }
bool Entity::operator==(const EntityId &rhs) const { return _entityId.value == rhs.value; }
bool Entity::operator==(const Entity &rhs) const
{
return &GetCore() == &rhs.GetCore() && _entityId == rhs._entityId;
}
bool Entity::operator==(const EntityId &rhs) const { return _entityId == rhs; }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/engine/src/entity/Entity.cpp` around lines 17 - 19, The equality
operators on Entity currently only compare _entityId.value; update both
Entity::operator==(const Entity &rhs) and Entity::operator==(const EntityId
&rhs) to include Core identity by delegating to EntityId's own operator== (or by
comparing both _core and _entityId) instead of only comparing _entityId.value —
i.e., use _entityId == rhs._entityId (or _entityId == rhs) and ensure the
comparison accounts for the Core pointer/identifier so entities from different
cores are not considered equal.

Copy link
Copy Markdown

Miou-zora merged commit 404f7b7 into main Apr 11, 2026
43 of 44 checks passed
Miou-zora deleted the 526-doc-specify-which-inline-file-extension-to-use-inl-tpp-or-ipp-and-when branch April 11, 2026 09:21
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
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.

[DOC] Specify which inline file extension to use (.inl, .tpp, or .ipp) and when

1 participant


Back | FazBrowse Home | New Git URL