registry: added ::patch, reintroduced ::replace from arguments (close #437)

This commit is contained in:
Michele Caini
2020-03-09 14:34:28 +01:00
parent 58885854f1
commit 32fb335832
3 changed files with 48 additions and 6 deletions

View File

@@ -228,11 +228,15 @@ This function is overloaded and accepts also a couple of iterators in order to:
registry.assign<position>(first, last, instances);
```
If an entity already has the given component, the `replace` member function
template can be used to edit it in-place:
If an entity already has the given component, the `replace` and `patch` member
function templates can be used to updated it:
```cpp
registry.replace<position>(entity, [](auto &pos) { pos.x = pos.y = 0.; });
// replaces the component in-place
registry.patch<position>(entity, [](auto &pos) { pos.x = pos.y = 0.; });
// constructs a new instance from a list of arguments and replaces the component
registry.replace<position>(entity, 0., 0.);
```
When it's unknown whether an entity already owns an instance of a component,

View File

@@ -693,7 +693,7 @@ public:
}
/**
* @brief Replaces the given component for an entity.
* @brief Replaces the given component for an entity in-place.
*
* The signature of the functions should be equivalent to the following:
*
@@ -718,11 +718,48 @@ public:
* @return A reference to the replaced component.
*/
template<typename Component, typename... Func>
decltype(auto) replace(const entity_type entity, Func &&... func) {
[[deprecated("use registry::patch instead")]]
decltype(auto) patch(const entity_type entity, Func &&... func) {
ENTT_ASSERT(valid(entity));
return assure<Component>().replace(*this, entity, std::forward<Func>(func)...);
}
/*! @copydoc patch */
template<typename Component, typename... Func>
[[deprecated("use registry::patch instead")]]
auto replace(const entity_type entity, Func &&... func)
-> decltype((func(assure<Component>().get(entity)), ...), assure<Component>().get(entity)) {
return patch<Component>(entity, std::forward<Func>(func)...);
}
/**
* @brief Replaces the given component for an entity.
*
* A new instance of the given component is created and initialized with the
* arguments provided (the component must have a proper constructor or be of
* aggregate type). Then the component is assigned to the given entity.
*
* @warning
* Attempting to use an invalid entity or to replace a component of an
* entity that doesn't own it results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode in case of
* invalid entity or if the entity doesn't own an instance of the given
* component.
*
* @tparam Component Type of component to replace.
* @tparam Args Types of arguments to use to construct the component.
* @param entity A valid entity identifier.
* @param args Parameters to use to initialize the component.
* @return A reference to the component being replaced.
*/
template<typename Component, typename... Args>
auto replace(const entity_type entity, Args &&... args)
-> decltype(std::enable_if_t<sizeof...(Args) != 0>(), Component{std::forward<Args>(args)...}, assure<Component>().get(entity)) {
return patch<Component>(entity, [args = std::forward_as_tuple(std::forward<Args>(args)...)](auto &&component) {
component = std::make_from_tuple<Component>(std::move(args));
});
}
/**
* @brief Removes the given components from an entity.
*

View File

@@ -181,7 +181,8 @@ TEST(Registry, Functionalities) {
ASSERT_NE(&registry.get<int>(e0), &registry.get<int>(e2));
ASSERT_NE(&registry.get<char>(e0), &registry.get<char>(e2));
ASSERT_EQ(registry.replace<int>(e0, [](auto &instance) { instance = 3; }), 3);
ASSERT_EQ(registry.replace<int>(e0, [](auto &instance) { instance = 2; }), 2);
ASSERT_EQ(registry.replace<int>(e0, 3), 3);
ASSERT_NO_THROW(registry.assign_or_replace<int>(e0, 1));
ASSERT_NO_THROW(registry.assign_or_replace<int>(e1, 1));