Refactor component manager#3112
Conversation
| if constexpr (std::same_as<std::decay_t<Args>, EntityFetchCount>) { | ||
| registry_.emplace<std::atomic<EntityFetchCount>>(id, std::forward<decltype(args)>(args)); | ||
| } else { | ||
| registry_.emplace<Args>(id, std::forward<decltype(args)>(args)); | ||
| } |
There was a problem hiding this comment.
Critical: this branch is no longer additive — when Args = EntityFetchCount only the std::atomic<EntityFetchCount> is emplaced, and the plain EntityFetchCount component is no longer added. The comment immediately above still documents that both are intentional: the plain copy is the "first-class" entity "accessible by registry_.get<EntityFetchCount>(id), as this is external facing (used by resample)", and the atomic is the internal counter that gets decremented.
External consumers retrieve the plain value via registry_.view<…, const EntityFetchCount>().get(id):
clause_utils.hpp::gather_entities→get_entities_and_decrement_refcount<…, EntityFetchCount>(...)→ the view path.ResampleClause::processinclause_resample.cpp:290is exactly this on production data.ComponentManager.Simple(test_component_manager.cpp:35) andResampleClausetests attest_resample.cpp:375exercise it directly.
With the plain EntityFetchCount storage now empty, view.get(id) reads from a storage that doesn't contain the entity (UB / assertion in entt). The PR description's reasoning "the EntityFetchCount was always added… which is wrong" doesn't hold here — both entries were required.
The same regression applies to the matching else-branches in add_entities, replace_entities, and replace_entities_zip below. They should remain additive for the EntityFetchCount case (emplace/replace both the plain value and the atomic), not exclusive.
| for (auto [idx, id] : folly::enumerate(ids)) { | ||
| registry_.replace<T>(id, values[idx]); | ||
| if constexpr (std::is_same_v<T, EntityFetchCount>) { | ||
| update_entity_fetch_count(id, values[idx]); | ||
| if constexpr (std::same_as<T, EntityFetchCount>) { | ||
| update_entity_fetch_count(id, std::forward<R>(values)[idx]); | ||
| } else { | ||
| registry_.replace<T>(id, std::forward<R>(values)[idx]); | ||
| } | ||
| } |
There was a problem hiding this comment.
std::forward<R>(values)[idx] does not move the element. std::vector::operator[] has no rvalue overload, so even when std::forward<R>(values) produces an rvalue reference to the vector, indexing it returns T& (lvalue) and the elements are copied, not moved. The PR description cites "perfect forwarding" as the motivation, but here it has no effect.
If the intent is to consume the values, use std::move(values[idx]) (or std::ranges::iter_move) inside the loop — keeping in mind that this should only fire when R is an rvalue reference, otherwise it silently moves out of the caller's container.
ArcticDB Code Review SummaryCorrectness
Code Quality
Testing
|
This PR contains 3 functional changes and one cosmetic change. * There is a special case for component of type EntityFetchCount. They are wrapped in atomic type and stored as atomics in the component manager. There are several constexpr ifs checking this. The problem was that the the EntityFetchCount was always added. So we ended up with one EntityFetchCount and one std::atomic<EntityFetchCount> which is wrong. All constexpr ifs must have an else * Implement perfect forwarding. All entities were passed by value. Now the methods take forwarding reference. * There were two implementations of replace_entities one taking vector and one taking template parameter. There are two issues with this. First we cannot use this to place the same vector in all of the entities because the type deduction will pick up the more specific implementation. Second parameters were passed by value. The function taking vector is now replace_entities_zip and moves the elements of the vector. The function taking a single parameter and placing it in all entities is replace_entities and takes a const ref. We cannot move in this case * Cosmetic changes: some const std::vector were changed to std::span so that it can accept wider range of types (e.g. std::array)
8057533 to
49f31f9
Compare
Reference Issues/PRs
What does this implement or fix?
replace_entities_zipand moves the elements of the vector. The function taking a single parameter and placing it in all entities isreplace_entitiesand takes a const ref. We cannot move in this caseAny other comments?
Checklist
Checklist for code changes...