From 32fb335832e6cc3ce67f9ea6c19b6e81354a6b5b Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 9 Mar 2020 14:34:28 +0100 Subject: [PATCH] registry: added ::patch, reintroduced ::replace from arguments (close #437) --- docs/md/entity.md | 10 ++++++--- src/entt/entity/registry.hpp | 41 +++++++++++++++++++++++++++++++++-- test/entt/entity/registry.cpp | 3 ++- 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/docs/md/entity.md b/docs/md/entity.md index f7a998dd5..c3268bdda 100644 --- a/docs/md/entity.md +++ b/docs/md/entity.md @@ -228,11 +228,15 @@ This function is overloaded and accepts also a couple of iterators in order to: registry.assign(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(entity, [](auto &pos) { pos.x = pos.y = 0.; }); +// replaces the component in-place +registry.patch(entity, [](auto &pos) { pos.x = pos.y = 0.; }); + +// constructs a new instance from a list of arguments and replaces the component +registry.replace(entity, 0., 0.); ``` When it's unknown whether an entity already owns an instance of a component, diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index 12a5b1191..51ed6c7df 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -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 - 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().replace(*this, entity, std::forward(func)...); } + /*! @copydoc patch */ + template + [[deprecated("use registry::patch instead")]] + auto replace(const entity_type entity, Func &&... func) + -> decltype((func(assure().get(entity)), ...), assure().get(entity)) { + return patch(entity, std::forward(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.
+ * 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 + auto replace(const entity_type entity, Args &&... args) + -> decltype(std::enable_if_t(), Component{std::forward(args)...}, assure().get(entity)) { + return patch(entity, [args = std::forward_as_tuple(std::forward(args)...)](auto &&component) { + component = std::make_from_tuple(std::move(args)); + }); + } + /** * @brief Removes the given components from an entity. * diff --git a/test/entt/entity/registry.cpp b/test/entt/entity/registry.cpp index bb7cdf3c1..ce1780193 100644 --- a/test/entt/entity/registry.cpp +++ b/test/entt/entity/registry.cpp @@ -181,7 +181,8 @@ TEST(Registry, Functionalities) { ASSERT_NE(®istry.get(e0), ®istry.get(e2)); ASSERT_NE(®istry.get(e0), ®istry.get(e2)); - ASSERT_EQ(registry.replace(e0, [](auto &instance) { instance = 3; }), 3); + ASSERT_EQ(registry.replace(e0, [](auto &instance) { instance = 2; }), 2); + ASSERT_EQ(registry.replace(e0, 3), 3); ASSERT_NO_THROW(registry.assign_or_replace(e0, 1)); ASSERT_NO_THROW(registry.assign_or_replace(e1, 1));