Support const-qualified components in ecs::container::apply and add const-related docs
This commit is contained in:
parent
2a97a467aa
commit
eb87f1ea20
2 changed files with 56 additions and 15 deletions
|
|
@ -122,6 +122,8 @@ namespace psemek::ecs
|
|||
void detach(handle const & entity);
|
||||
|
||||
/** Create a query cache that can be used to speed up `apply()` calls.
|
||||
*
|
||||
* The constness of the component types is ignored.
|
||||
*
|
||||
* @tparam Components The component types matching the corresponding `apply()` call
|
||||
* @return A query cache
|
||||
|
|
@ -137,6 +139,11 @@ namespace psemek::ecs
|
|||
* void(container, components...)
|
||||
* void(container, handle, components...)
|
||||
*
|
||||
* The component types can be const-qualified, in which case the corresponding function must
|
||||
* also accept the corresponding components by a const reference. This can be used to indicate
|
||||
* that this function doesn't modify specific components, to prevent modification callbacks
|
||||
* from being triggered.
|
||||
*
|
||||
* The function can freely create or destroy entities, and or attach/detach
|
||||
* components to existing entities. It is unspecified whether the function
|
||||
* will or will not visit newly created entities during this `apply()` call.
|
||||
|
|
@ -150,7 +157,8 @@ namespace psemek::ecs
|
|||
* @param function The function to apply to all entities with the specified components
|
||||
* @param cache A query cache
|
||||
* @return The query cache, either user-provided, or newly-created
|
||||
* @pre The query query cache was created with the exact same sequence of component types
|
||||
* @pre The query query cache was created with the exact same sequence of component types, ignoring
|
||||
* constness
|
||||
* @warning If any two of the passed component types are equal, the call fails with
|
||||
* a compilation error
|
||||
* @warning If the function accesses passed components after destroying the
|
||||
|
|
@ -172,6 +180,11 @@ namespace psemek::ecs
|
|||
* void(container, span<components>...)
|
||||
* void(container, span<handle const>, span<components>...)
|
||||
*
|
||||
* The component types can be const-qualified, in which case the corresponding function must
|
||||
* also accept the corresponding components by views to const. This can be used to indicate
|
||||
* that this function doesn't modify specific components, to prevent modification callbacks
|
||||
* from being triggered.
|
||||
*
|
||||
* The sizes of all spans within a single function call are the same,
|
||||
* except for empty component types (i.e. std::is_empty_v<Component> is true),
|
||||
* each having an unspecified non-zero size. If all components are empty types,
|
||||
|
|
@ -185,7 +198,8 @@ namespace psemek::ecs
|
|||
* @param function The function to batch-apply to all entities with the specified components
|
||||
* @param cache A query cache
|
||||
* @return The query cache, either user-provided, or newly-created
|
||||
* @pre The query query cache was created with the exact same sequence of component types
|
||||
* @pre The query query cache was created with the exact same sequence of component types, ignoring
|
||||
* constness
|
||||
* @warning If any two of the passed component types are equal, the call fails with
|
||||
* a compilation error
|
||||
* @warning If the function creates or destroyes entities, or attaches or detaches components,
|
||||
|
|
@ -201,6 +215,9 @@ namespace psemek::ecs
|
|||
*
|
||||
* The entity is considered `alive()` during the constructor invocation.
|
||||
*
|
||||
* The component types can be const-qualified, in which case the corresponding function must
|
||||
* also accept the corresponding components by a const reference.
|
||||
*
|
||||
* When attaching components to an entity, the constructor is called
|
||||
* exactly when the entity didn't match the constructor's component types
|
||||
* before attaching new components, and does match them after attaching.
|
||||
|
|
@ -210,6 +227,9 @@ namespace psemek::ecs
|
|||
*
|
||||
* The constructor can immediately destroy the created entity.
|
||||
*
|
||||
* The constuctor is not considered to be a modification of the entity, i.e. it
|
||||
* doesn't trigger modification callbacks.
|
||||
*
|
||||
* @param function A function to be applied to created entity's components
|
||||
* @return An ownerwhip token; destroying this token removes
|
||||
* the constructor from this container
|
||||
|
|
@ -230,6 +250,9 @@ namespace psemek::ecs
|
|||
*
|
||||
* The entity is considered `alive()` during the destructor invocation.
|
||||
*
|
||||
* The component types can be const-qualified, in which case the corresponding function must
|
||||
* also accept the corresponding components by a const reference.
|
||||
*
|
||||
* When detaching components from an entity, the destructor is called
|
||||
* exactly when the entity did match the destructor's component types
|
||||
* before detaching components, and doesn't match them after detaching.
|
||||
|
|
@ -239,6 +262,9 @@ namespace psemek::ecs
|
|||
*
|
||||
* Note that there is no way to cancel the entity's destruction.
|
||||
*
|
||||
* The destructor is not considered to be a modification of the entity, i.e. it
|
||||
* doesn't trigger modification callbacks.
|
||||
*
|
||||
* @param function A function to be applied to a to-be destroyed entity's components
|
||||
* @return An ownerwhip token; destroying it removes the destructor from the container
|
||||
* @warning If any two of the passed component types are equal, the call fails with
|
||||
|
|
@ -254,6 +280,9 @@ namespace psemek::ecs
|
|||
* the specified set of components is modified, and the modification affects
|
||||
* one of this callback's component types, the callback is called.
|
||||
*
|
||||
* The component types can be const-qualified, in which case the corresponding function must
|
||||
* also accept the corresponding components by a const reference.
|
||||
*
|
||||
* If the modification occurred via an accessor, the callback is called
|
||||
* after the accessor is destroyed, allowing for transaction-like modification.
|
||||
*
|
||||
|
|
@ -295,16 +324,16 @@ namespace psemek::ecs
|
|||
template <typename ... Components>
|
||||
handle container::create(Components && ... components)
|
||||
{
|
||||
static_assert(detail::all_different_types_v<Components...>, "all component types must be different");
|
||||
static_assert(detail::all_different_types_v<std::remove_cvref_t<Components>...>, "all component types must be different");
|
||||
|
||||
detail::component_uuid_helper<Components...> uuids;
|
||||
detail::component_uuid_helper<std::remove_cvref_t<Components>...> uuids;
|
||||
|
||||
auto table = table_container_.get(uuids.get());
|
||||
|
||||
if (!table)
|
||||
{
|
||||
std::vector<std::unique_ptr<detail::column>> columns;
|
||||
(columns.push_back(std::make_unique<detail::column_impl<Components>>()), ...);
|
||||
(columns.push_back(std::make_unique<detail::column_impl<std::remove_cvref_t<Components>>>()), ...);
|
||||
|
||||
table = insert_table(std::move(columns));
|
||||
}
|
||||
|
|
@ -317,7 +346,7 @@ namespace psemek::ecs
|
|||
[[maybe_unused]] accessor accessor = get(handle);
|
||||
|
||||
table->push_row(handle);
|
||||
((accessor.get<Components>() = std::move(components)), ...);
|
||||
((accessor.get<std::remove_cvref_t<Components>>() = std::forward<Components>(components)), ...);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
|
@ -325,13 +354,13 @@ namespace psemek::ecs
|
|||
template <typename ... Components>
|
||||
void container::attach(handle const & entity, Components && ... components)
|
||||
{
|
||||
static_assert(detail::all_different_types_v<Components...>, "all component types must be different");
|
||||
static_assert(detail::all_different_types_v<std::remove_cvref_t<Components>...>, "all component types must be different");
|
||||
|
||||
auto & data = entity_list_.get_entities()[entity.id];
|
||||
for (auto const & column : data.table->columns())
|
||||
uuid_helper_.push_back(column->uuid());
|
||||
|
||||
((data.table->column(Components::uuid()) ? 0 : (uuid_helper_.push_back(Components::uuid()), 0)), ...);
|
||||
((data.table->column(std::remove_cvref_t<Components>::uuid()) ? 0 : (uuid_helper_.push_back(std::remove_cvref_t<Components>::uuid()), 0)), ...);
|
||||
|
||||
auto table = table_container_.get(uuid_helper_);
|
||||
|
||||
|
|
@ -341,7 +370,7 @@ namespace psemek::ecs
|
|||
for (auto const & column : data.table->columns())
|
||||
columns.push_back(column->clone());
|
||||
|
||||
((data.table->column(Components::uuid()) ? 0 : (columns.push_back(std::make_unique<detail::column_impl<Components>>()), 0)), ...);
|
||||
((data.table->column(std::remove_cvref_t<Components>::uuid()) ? 0 : (columns.push_back(std::make_unique<detail::column_impl<std::remove_cvref_t<Components>>>()), 0)), ...);
|
||||
|
||||
table = insert_table(std::move(columns));
|
||||
}
|
||||
|
|
@ -359,7 +388,7 @@ namespace psemek::ecs
|
|||
}
|
||||
|
||||
auto accessor = get(entity);
|
||||
((accessor.get<Components>() = std::move(components)), ...);
|
||||
((accessor.get<std::remove_cvref_t<Components>>() = std::forward<Components>(components)), ...);
|
||||
|
||||
uuid_helper_.clear();
|
||||
}
|
||||
|
|
@ -367,9 +396,9 @@ namespace psemek::ecs
|
|||
template <typename ... Components>
|
||||
void container::detach(handle const & entity)
|
||||
{
|
||||
static_assert(detail::all_different_types_v<Components...>, "all component types must be different");
|
||||
static_assert(detail::all_different_types_v<std::remove_cvref_t<Components>...>, "all component types must be different");
|
||||
|
||||
(uuid_set_helper_.insert(Components::uuid()), ...);
|
||||
(uuid_set_helper_.insert(std::remove_cvref_t<Components>::uuid()), ...);
|
||||
|
||||
auto & data = entity_list_.get_entities()[entity.id];
|
||||
for (auto const & column : data.table->columns())
|
||||
|
|
@ -407,7 +436,7 @@ namespace psemek::ecs
|
|||
template <typename ... Components>
|
||||
query_cache container::cache()
|
||||
{
|
||||
detail::component_uuid_helper<Components...> uuids;
|
||||
detail::component_uuid_helper<std::remove_cvref_t<Components>...> uuids;
|
||||
|
||||
auto result = query_cache_container_.create(uuids.get());
|
||||
|
||||
|
|
@ -421,7 +450,7 @@ namespace psemek::ecs
|
|||
template <typename ... Components, typename Function>
|
||||
query_cache container::apply(Function && function, query_cache cache)
|
||||
{
|
||||
static_assert(detail::all_different_types_v<Components...>, "all component types must be different");
|
||||
static_assert(detail::all_different_types_v<std::remove_const_t<Components>...>, "all component types must be different");
|
||||
|
||||
if (!cache)
|
||||
cache = this->cache<Components...>();
|
||||
|
|
@ -465,7 +494,7 @@ namespace psemek::ecs
|
|||
template <typename ... Components, typename Function>
|
||||
query_cache container::batch_apply(Function && function, query_cache cache)
|
||||
{
|
||||
static_assert(detail::all_different_types_v<Components...>, "all component types must be different");
|
||||
static_assert(detail::all_different_types_v<std::remove_const_t<Components>...>, "all component types must be different");
|
||||
|
||||
if (!cache)
|
||||
cache = this->cache<Components...>();
|
||||
|
|
|
|||
|
|
@ -261,3 +261,15 @@ test_case(ecs_apply_create)
|
|||
});
|
||||
expect_equal(call_count, 2 * count);
|
||||
}
|
||||
|
||||
test_case(ecs_apply_const)
|
||||
{
|
||||
container container;
|
||||
|
||||
container.create(component_1{10}, component_2{20});
|
||||
container.apply<component_1, component_2 const>([](component_1 & value1, component_2 const & value2){
|
||||
expect_equal(value1.value, 10);
|
||||
expect_equal(value2.value, 20);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue