diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index 2406cf662..000d73bb2 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -58,11 +58,11 @@ class basic_registry { template void maybe_valid_if(basic_registry &owner, const Entity entt) { - [[maybe_unused]] const auto cpools = std::forward_as_tuple(owner.assure()...); + [[maybe_unused]] const auto cpools = std::forward_as_tuple(owner.storage()...); const auto is_valid = ((std::is_same_v || std::get &>(cpools).contains(entt)) && ...) - && ((std::is_same_v || owner.assure().contains(entt)) && ...) - && ((std::is_same_v || !owner.assure().contains(entt)) && ...); + && ((std::is_same_v || owner.storage().contains(entt)) && ...) + && ((std::is_same_v || !owner.storage().contains(entt)) && ...); if constexpr(sizeof...(Owned) == 0) { if(is_valid && !current.contains(entt)) { @@ -80,7 +80,7 @@ class basic_registry { if constexpr(sizeof...(Owned) == 0) { current.remove(entt); } else { - if(const auto cpools = std::forward_as_tuple(owner.assure()...); std::get<0>(cpools).contains(entt) && (std::get<0>(cpools).index(entt) < current)) { + if(const auto cpools = std::forward_as_tuple(owner.storage()...); std::get<0>(cpools).contains(entt) && (std::get<0>(cpools).index(entt) < current)) { const auto pos = --current; (std::get &>(cpools).swap_elements(std::get &>(cpools).data()[pos], entt), ...); } @@ -96,31 +96,6 @@ class basic_registry { bool (*exclude)(const id_type) ENTT_NOEXCEPT; }; - template - [[nodiscard]] storage_type &assure() { - static_assert(std::is_same_v>, "Non-decayed types not allowed"); - auto &&cpool = pools[type_id().hash()]; - - if(!cpool) { - cpool.reset(new storage_type{}); - cpool->bind(forward_as_any(*this)); - } - - return static_cast &>(*cpool); - } - - template - [[nodiscard]] const storage_type &assure() const { - static_assert(std::is_same_v>, "Non-decayed types not allowed"); - - if(const auto it = pools.find(type_id().hash()); it != pools.cend()) { - return static_cast &>(*it->second); - } - - static storage_type placeholder{}; - return placeholder; - } - auto generate_identifier(const std::size_t pos) ENTT_NOEXCEPT { ENTT_ASSERT(pos < entity_traits::to_integral(null), "No entities available"); return entity_traits::combine(static_cast(pos), {}); @@ -186,13 +161,45 @@ public: } /** - * @brief Prepares a pool for the given type if required. - * @tparam Component Type of component for which to prepare a pool. + * @brief Returns the container for a given component type. + * @tparam Component Type of component of which to return the container. + * @param id Optional name used to map the container for a given component. + * @return The container for the given component type. */ template - void prepare() { - // suppress the warning due to the [[nodiscard]] attribute - static_cast(assure()); + [[nodiscard]] storage_type &storage(const id_type id = type_hash::value()) { + static_assert(std::is_same_v>, "Non-decayed types not allowed"); + auto &&cpool = pools[id]; + + if(!cpool) { + cpool.reset(new storage_type{}); + cpool->bind(forward_as_any(*this)); + } + + return static_cast &>(*cpool); + } + + /** + * @copybrief storage + * + * @warning + * If a container for the given component doesn't exist yet, a temporary + * placeholder is returned. + * + * @tparam Component Type of component of which to return the container. + * @param id Optional name used to map the container for a given component. + * @return The container for the given component type. + */ + template + [[nodiscard]] const storage_type &storage(const id_type id = type_hash::value()) const { + static_assert(std::is_same_v>, "Non-decayed types not allowed"); + + if(const auto it = pools.find(id); it != pools.cend()) { + return static_cast &>(*it->second); + } + + static storage_type placeholder{}; + return placeholder; } /** @@ -202,7 +209,7 @@ public: */ template [[nodiscard]] size_type size() const { - return assure>().size(); + return storage>().size(); } /** @@ -245,7 +252,7 @@ public: if constexpr(sizeof...(Component) == 0) { entities.reserve(cap); } else { - (assure().reserve(cap), ...); + (storage().reserve(cap), ...); } } @@ -256,7 +263,7 @@ public: */ template [[nodiscard]] size_type capacity() const { - return assure>().capacity(); + return storage>().capacity(); } /** @@ -275,7 +282,7 @@ public: */ template void shrink_to_fit() { - (assure().shrink_to_fit(), ...); + (storage().shrink_to_fit(), ...); } /** @@ -294,7 +301,7 @@ public: if constexpr(sizeof...(Component) == 0) { return !alive(); } else { - return (assure>().empty() && ...); + return (storage>().empty() && ...); } } @@ -573,7 +580,7 @@ public: template decltype(auto) emplace(const entity_type entity, Args &&...args) { ENTT_ASSERT(valid(entity), "Invalid entity"); - return assure().emplace(entity, std::forward(args)...); + return storage().emplace(entity, std::forward(args)...); } /** @@ -590,7 +597,7 @@ public: template void insert(It first, It last, const Component &value = {}) { ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }), "Invalid entity"); - assure().insert(first, last, value); + storage().insert(first, last, value); } /** @@ -609,7 +616,7 @@ public: void insert(EIt first, EIt last, CIt from) { static_assert(std::is_constructible_v::value_type>, "Invalid value type"); ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }), "Invalid entity"); - assure().insert(first, last, from); + storage().insert(first, last, from); } /** @@ -627,7 +634,7 @@ public: template decltype(auto) emplace_or_replace(const entity_type entity, Args &&...args) { ENTT_ASSERT(valid(entity), "Invalid entity"); - auto &cpool = assure(); + auto &cpool = storage(); return cpool.contains(entity) ? cpool.patch(entity, [&args...](auto &...curr) { ((curr = Component{std::forward(args)...}), ...); }) @@ -661,7 +668,7 @@ public: template decltype(auto) patch(const entity_type entity, Func &&...func) { ENTT_ASSERT(valid(entity), "Invalid entity"); - return assure().patch(entity, std::forward(func)...); + return storage().patch(entity, std::forward(func)...); } /** @@ -684,7 +691,7 @@ public: template decltype(auto) replace(const entity_type entity, Args &&...args) { ENTT_ASSERT(valid(entity), "Invalid entity"); - return assure().patch(entity, [&args...](auto &...curr) { ((curr = Component{std::forward(args)...}), ...); }); + return storage().patch(entity, [&args...](auto &...curr) { ((curr = Component{std::forward(args)...}), ...); }); } /** @@ -701,7 +708,7 @@ public: size_type remove(const entity_type entity) { ENTT_ASSERT(valid(entity), "Invalid entity"); static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - return (assure().remove(entity) + ... + size_type{}); + return (storage().remove(entity) + ... + size_type{}); } /** @@ -718,7 +725,7 @@ public: template size_type remove(It first, It last) { static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - const auto cpools = std::forward_as_tuple(assure()...); + const auto cpools = std::forward_as_tuple(storage()...); size_type count{}; for(; first != last; ++first) { @@ -744,7 +751,7 @@ public: void erase(const entity_type entity) { ENTT_ASSERT(valid(entity), "Invalid entity"); static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - (assure().erase(entity), ...); + (storage().erase(entity), ...); } /** @@ -760,7 +767,7 @@ public: template void erase(It first, It last) { static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - const auto cpools = std::forward_as_tuple(assure()...); + const auto cpools = std::forward_as_tuple(storage()...); for(; first != last; ++first) { const auto entity = *first; @@ -781,7 +788,7 @@ public: curr.second->compact(); } } else { - (assure().compact(), ...); + (storage().compact(), ...); } } @@ -798,7 +805,7 @@ public: template [[nodiscard]] bool all_of(const entity_type entity) const { ENTT_ASSERT(valid(entity), "Invalid entity"); - return (assure>().contains(entity) && ...); + return (storage>().contains(entity) && ...); } /** @@ -815,7 +822,7 @@ public: template [[nodiscard]] bool any_of(const entity_type entity) const { ENTT_ASSERT(valid(entity), "Invalid entity"); - return (assure>().contains(entity) || ...); + return (storage>().contains(entity) || ...); } /** @@ -834,7 +841,7 @@ public: ENTT_ASSERT(valid(entity), "Invalid entity"); if constexpr(sizeof...(Component) == 1) { - return assure...>().get(entity); + return storage...>().get(entity); } else { return std::forward_as_tuple(get(entity)...); } @@ -846,7 +853,7 @@ public: ENTT_ASSERT(valid(entity), "Invalid entity"); if constexpr(sizeof...(Component) == 1) { - return (const_cast(assure>().get(entity)), ...); + return (const_cast(storage>().get(entity)), ...); } else { return std::forward_as_tuple(get(entity)...); } @@ -870,7 +877,7 @@ public: template [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entity, Args &&...args) { ENTT_ASSERT(valid(entity), "Invalid entity"); - auto &cpool = assure(); + auto &cpool = storage(); return cpool.contains(entity) ? cpool.get(entity) : cpool.emplace(entity, std::forward(args)...); } @@ -892,7 +899,7 @@ public: ENTT_ASSERT(valid(entity), "Invalid entity"); if constexpr(sizeof...(Component) == 1) { - const auto &cpool = assure...>(); + const auto &cpool = storage...>(); return cpool.contains(entity) ? std::addressof(cpool.get(entity)) : nullptr; } else { return std::make_tuple(try_get(entity)...); @@ -922,7 +929,7 @@ public: each([this](const auto entity) { release_entity(entity, entity_traits::to_version(entity) + 1u); }); } else { - (assure().clear(), ...); + (storage().clear(), ...); } } @@ -1015,7 +1022,7 @@ public: */ template [[nodiscard]] auto on_construct() { - return assure().on_construct(); + return storage().on_construct(); } /** @@ -1038,7 +1045,7 @@ public: */ template [[nodiscard]] auto on_update() { - return assure().on_update(); + return storage().on_update(); } /** @@ -1063,7 +1070,7 @@ public: */ template [[nodiscard]] auto on_destroy() { - return assure().on_destroy(); + return storage().on_destroy(); } /** @@ -1101,14 +1108,14 @@ public: template [[nodiscard]] basic_view...>, exclude_t> view(exclude_t = {}) const { static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported"); - return {assure>()..., assure()...}; + return {storage>()..., storage()...}; } /*! @copydoc view */ template [[nodiscard]] basic_view, exclude_t> view(exclude_t = {}) { static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported"); - return {assure>()..., assure()...}; + return {storage>()..., storage()...}; } /** @@ -1194,7 +1201,7 @@ public: using handler_type = group_handler, get_t...>, std::remove_const_t...>; - const auto cpools = std::forward_as_tuple(assure>()..., assure>()...); + const auto cpools = std::forward_as_tuple(storage>()..., storage>()...); constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude); handler_type *handler = nullptr; @@ -1282,7 +1289,7 @@ public: return {}; } else { using handler_type = group_handler, get_t...>, std::remove_const_t...>; - return {static_cast(it->group.get())->current, assure>()..., assure>()...}; + return {static_cast(it->group.get())->current, storage>()..., storage>()...}; } } @@ -1364,7 +1371,7 @@ public: template void sort(Compare compare, Sort algo = Sort{}, Args &&...args) { ENTT_ASSERT(sortable(), "Cannot sort owned storage"); - auto &cpool = assure(); + auto &cpool = storage(); if constexpr(std::is_invocable_v) { auto comp = [&cpool, compare = std::move(compare)](const auto lhs, const auto rhs) { return compare(std::as_const(cpool.get(lhs)), std::as_const(cpool.get(rhs))); }; @@ -1401,7 +1408,7 @@ public: template void sort() { ENTT_ASSERT(sortable(), "Cannot sort owned storage"); - assure().respect(assure()); + storage().respect(storage()); } /** diff --git a/test/entt/entity/registry.cpp b/test/entt/entity/registry.cpp index 226ff10af..1e96a983a 100644 --- a/test/entt/entity/registry.cpp +++ b/test/entt/entity/registry.cpp @@ -173,8 +173,6 @@ TEST(Registry, Functionalities) { ASSERT_EQ(registry.size(), 0u); ASSERT_TRUE((registry.empty())); - registry.prepare(); - const auto e0 = registry.create(); const auto e1 = registry.create(); @@ -1933,3 +1931,33 @@ TEST(Registry, ScramblingPoolsIsAllowed) { ASSERT_EQ(entt::to_integral(entity), value); }); } + +TEST(Registry, RuntimePools) { + using namespace entt::literals; + + entt::registry registry; + auto &storage = registry.storage("other"_hs); + const auto entity = registry.create(); + + ASSERT_FALSE(registry.any_of(entity)); + ASSERT_FALSE(storage.contains(entity)); + + registry.emplace(entity); + + ASSERT_FALSE(storage.contains(entity)); + ASSERT_TRUE(registry.any_of(entity)); + ASSERT_EQ((entt::basic_view{registry.storage(), storage}.size_hint()), 0u); + + storage.emplace(entity); + + ASSERT_TRUE(storage.contains(entity)); + ASSERT_TRUE(registry.any_of(entity)); + ASSERT_EQ((entt::basic_view{registry.storage(), storage}.size_hint()), 1u); + + registry.destroy(entity); + + ASSERT_EQ(registry.create(entity), entity); + + ASSERT_FALSE(storage.contains(entity)); + ASSERT_FALSE(registry.any_of(entity)); +} diff --git a/test/lib/registry/lib.cpp b/test/lib/registry/lib.cpp index 09ee3481b..1f74348f9 100644 --- a/test/lib/registry/lib.cpp +++ b/test/lib/registry/lib.cpp @@ -11,7 +11,7 @@ ENTT_API void update_position(entt::registry ®istry) { ENTT_API void emplace_velocity(entt::registry ®istry) { // forces the creation of the pool for the velocity component - registry.prepare(); + registry.storage(); for(auto entity: registry.view()) { registry.emplace(entity, 1., 1.); diff --git a/test/lib/registry_plugin/plugin.cpp b/test/lib/registry_plugin/plugin.cpp index 7870fba81..e3d6dd3c9 100644 --- a/test/lib/registry_plugin/plugin.cpp +++ b/test/lib/registry_plugin/plugin.cpp @@ -8,7 +8,8 @@ CR_EXPORT int cr_main(cr_plugin *ctx, cr_op operation) { // forces things to break auto ®istry = *static_cast(ctx->userdata); - registry.prepare(); + // forces the creation of the pool for the velocity component + registry.storage(); const auto view = registry.view(); registry.insert(view.begin(), view.end(), velocity{1., 1.});