diff --git a/TODO b/TODO index 73ede450df..83d1482dec 100644 --- a/TODO +++ b/TODO @@ -16,7 +16,7 @@ TODO (high prio): * update view doc: single vs multi type views are no longer a thing actually * further improve meta resolve function by id (bimap) * make ::pack part of the sparse set interface -* storage-based to_entity and invoke helpers +* storage-based invoke helpers (update sigh mixin to also support storage based cbs) * make nth_argument use function types rather than pointers * ===> TEST: view (scoped begin) tests after the last changes diff --git a/src/entt/entity/helper.hpp b/src/entt/entity/helper.hpp index 9cf257068b..c7abcd4bfa 100644 --- a/src/entt/entity/helper.hpp +++ b/src/entt/entity/helper.hpp @@ -9,6 +9,7 @@ #include "../signal/delegate.hpp" #include "fwd.hpp" #include "group.hpp" +#include "storage.hpp" #include "view.hpp" namespace entt { @@ -115,27 +116,41 @@ void invoke(Registry ®, const typename Registry::entity_type entt) { * @brief Returns the entity associated with a given component. * * @warning - * Currently, this function only works correctly with the default pool as it + * Currently, this function only works correctly with the default storage as it * makes assumptions about how the components are laid out. * - * @tparam Registry Basic registry type. + * @tparam Args Storage type template parameters. + * @param storage A storage that contains the given component. + * @param instance A valid component instance. + * @return The entity associated with the given component. + */ +template +auto to_entity(const basic_storage &storage, const typename basic_storage::value_type &instance) -> typename basic_storage::entity_type { + constexpr auto page_size = basic_storage::traits_type::page_size; + const typename basic_storage::base_type &base = storage; + const auto *addr = std::addressof(instance); + + for(auto it = base.rbegin(), last = base.rend(); it < last; it += page_size) { + if(const auto dist = (addr - std::addressof(storage.get(*it))); dist >= 0 && dist < static_cast(page_size)) { + return *(it + dist); + } + } + + return null; +} + +/** + * @copybrief to_entity + * @tparam Args Registry type template parameters. * @tparam Component Type of component. * @param reg A registry that contains the given entity and its components. * @param instance A valid component instance. * @return The entity associated with the given component. */ -template -typename Registry::entity_type to_entity(const Registry ®, const Component &instance) { +template +[[deprecated("use storage based to_entity instead")]] typename basic_registry::entity_type to_entity(const basic_registry ®, const Component &instance) { if(const auto *storage = reg.template storage(); storage) { - constexpr auto page_size = std::remove_const_t>::traits_type::page_size; - const typename Registry::common_type &base = *storage; - const auto *addr = std::addressof(instance); - - for(auto it = base.rbegin(), last = base.rend(); it < last; it += page_size) { - if(const auto dist = (addr - std::addressof(storage->get(*it))); dist >= 0 && dist < static_cast(page_size)) { - return *(it + dist); - } - } + return to_entity(*storage, instance); } return null; diff --git a/test/entt/entity/helper.cpp b/test/entt/entity/helper.cpp index 50ab87a01b..d036313a5d 100644 --- a/test/entt/entity/helper.cpp +++ b/test/entt/entity/helper.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -11,16 +12,29 @@ struct clazz { entt::entity entt{entt::null}; }; -struct stable_type { - static constexpr auto in_place_delete = true; - int value; -}; - void sigh_callback(int &value) { ++value; } -TEST(Helper, AsView) { +struct pointer_stable { + static constexpr auto in_place_delete = true; + int value{}; +}; + +template +struct ToEntity: testing::Test { + using type = Type; +}; + +template +using ToEntityDeprecated = ToEntity; + +using ToEntityTypes = ::testing::Types; + +TYPED_TEST_SUITE(ToEntity, ToEntityTypes, ); +TYPED_TEST_SUITE(ToEntityDeprecated, ToEntityTypes, ); + +TEST(AsView, Functionalities) { entt::registry registry; const entt::registry cregistry; @@ -30,7 +44,7 @@ TEST(Helper, AsView) { ([](entt::view, entt::exclude_t>) {})(entt::as_view{cregistry}); } -TEST(Helper, AsGroup) { +TEST(AsGroup, Functionalities) { entt::registry registry; const entt::registry cregistry; @@ -39,7 +53,7 @@ TEST(Helper, AsGroup) { ([](entt::group, entt::get_t, entt::exclude_t>) {})(entt::as_group{cregistry}); } -TEST(Helper, Invoke) { +TEST(Invoke, Functionalities) { entt::registry registry; const auto entity = registry.create(); @@ -49,87 +63,93 @@ TEST(Helper, Invoke) { ASSERT_EQ(entity, registry.get(entity).entt); } -TEST(Helper, ToEntity) { +TYPED_TEST(ToEntity, Functionalities) { + using value_type = typename TestFixture::type; + using traits_type = entt::component_traits; + entt::registry registry; const entt::entity null = entt::null; - constexpr auto page_size = entt::storage_type_t::traits_type::page_size; - const int value = 42; + auto &storage = registry.storage(); + constexpr auto page_size = entt::storage_type_t::traits_type::page_size; + const value_type value{42}; - ASSERT_EQ(entt::to_entity(registry, 42), null); - ASSERT_EQ(entt::to_entity(registry, value), null); + ASSERT_EQ(entt::to_entity(storage, value_type{42}), null); + ASSERT_EQ(entt::to_entity(storage, value), null); const auto entity = registry.create(); - auto &&storage = registry.storage(); storage.emplace(entity); - while(storage.size() < (page_size - 1u)) { + while(storage.size() < (page_size - (1u + traits_type::in_place_delete))) { storage.emplace(registry.create(), value); } const auto other = registry.create(); const auto next = registry.create(); - registry.emplace(other); - registry.emplace(next); + registry.emplace(other); + registry.emplace(next); - ASSERT_EQ(entt::to_entity(registry, registry.get(entity)), entity); - ASSERT_EQ(entt::to_entity(registry, registry.get(other)), other); - ASSERT_EQ(entt::to_entity(registry, registry.get(next)), next); + ASSERT_EQ(entt::to_entity(storage, registry.get(entity)), entity); + ASSERT_EQ(entt::to_entity(storage, registry.get(other)), other); + ASSERT_EQ(entt::to_entity(storage, registry.get(next)), next); - ASSERT_EQ(®istry.get(entity) + page_size - 1u, ®istry.get(other)); + ASSERT_EQ(®istry.get(entity) + page_size - (1u + traits_type::in_place_delete), ®istry.get(other)); registry.destroy(other); - ASSERT_EQ(entt::to_entity(registry, registry.get(entity)), entity); - ASSERT_EQ(entt::to_entity(registry, registry.get(next)), next); + ASSERT_EQ(entt::to_entity(storage, registry.get(entity)), entity); + ASSERT_EQ(entt::to_entity(storage, registry.get(next)), next); - ASSERT_EQ(®istry.get(entity) + page_size - 1u, ®istry.get(next)); + ASSERT_EQ(®istry.get(entity) + page_size - 1u, ®istry.get(next)); - ASSERT_EQ(entt::to_entity(registry, 42), null); - ASSERT_EQ(entt::to_entity(registry, value), null); + ASSERT_EQ(entt::to_entity(storage, value_type{42}), null); + ASSERT_EQ(entt::to_entity(storage, value), null); } -TEST(Helper, ToEntityStableType) { +TYPED_TEST(ToEntityDeprecated, Functionalities) { + using value_type = typename TestFixture::type; + using traits_type = entt::component_traits; + entt::registry registry; const entt::entity null = entt::null; - constexpr auto page_size = entt::storage_type_t::traits_type::page_size; - const stable_type value{42}; + constexpr auto page_size = entt::storage_type_t::traits_type::page_size; + const value_type value{42}; - ASSERT_EQ(entt::to_entity(registry, stable_type{42}), null); + ASSERT_EQ(entt::to_entity(registry, value_type{42}), null); ASSERT_EQ(entt::to_entity(registry, value), null); const auto entity = registry.create(); - auto &&storage = registry.storage(); - registry.emplace(entity); + auto &&storage = registry.storage(); + storage.emplace(entity); - while(storage.size() < (page_size - 2u)) { + while(storage.size() < (page_size - (1u + traits_type::in_place_delete))) { storage.emplace(registry.create(), value); } const auto other = registry.create(); const auto next = registry.create(); - registry.emplace(other); - registry.emplace(next); + registry.emplace(other); + registry.emplace(next); - ASSERT_EQ(entt::to_entity(registry, registry.get(entity)), entity); - ASSERT_EQ(entt::to_entity(registry, registry.get(other)), other); - ASSERT_EQ(entt::to_entity(registry, registry.get(next)), next); + ASSERT_EQ(entt::to_entity(registry, registry.get(entity)), entity); + ASSERT_EQ(entt::to_entity(registry, registry.get(other)), other); + ASSERT_EQ(entt::to_entity(registry, registry.get(next)), next); - ASSERT_EQ(®istry.get(entity) + page_size - 2u, ®istry.get(other)); + ASSERT_EQ(®istry.get(entity) + page_size - (1u + traits_type::in_place_delete), ®istry.get(other)); registry.destroy(other); - ASSERT_EQ(entt::to_entity(registry, registry.get(entity)), entity); - ASSERT_EQ(entt::to_entity(registry, registry.get(next)), next); + ASSERT_EQ(entt::to_entity(registry, registry.get(entity)), entity); + ASSERT_EQ(entt::to_entity(registry, registry.get(next)), next); - ASSERT_EQ(®istry.get(entity) + page_size - 1u, ®istry.get(next)); + ASSERT_EQ(®istry.get(entity) + page_size - 1u, ®istry.get(next)); - ASSERT_EQ(entt::to_entity(registry, stable_type{42}), null); + ASSERT_EQ(entt::to_entity(registry, value_type{42}), null); ASSERT_EQ(entt::to_entity(registry, value), null); } -TEST(Helper, SighHelper) { +TEST(SighHelper, Functionalities) { using namespace entt::literals; entt::registry registry{};