Przeglądaj źródła

helper: storage-based to_entity function

Michele Caini 2 lat temu
rodzic
commit
9d33ae86be
3 zmienionych plików z 93 dodań i 58 usunięć
  1. 1 1
      TODO
  2. 28 13
      src/entt/entity/helper.hpp
  3. 64 44
      test/entt/entity/helper.cpp

+ 1 - 1
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
 

+ 28 - 13
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 &reg, 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<typename... Args>
+auto to_entity(const basic_storage<Args...> &storage, const typename basic_storage<Args...>::value_type &instance) -> typename basic_storage<Args...>::entity_type {
+    constexpr auto page_size = basic_storage<Args...>::traits_type::page_size;
+    const typename basic_storage<Args...>::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<decltype(dist)>(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, typename Component>
-typename Registry::entity_type to_entity(const Registry &reg, const Component &instance) {
+template<typename... Args, typename Component>
+[[deprecated("use storage based to_entity instead")]] typename basic_registry<Args...>::entity_type to_entity(const basic_registry<Args...> &reg, const Component &instance) {
     if(const auto *storage = reg.template storage<Component>(); storage) {
-        constexpr auto page_size = std::remove_const_t<std::remove_pointer_t<decltype(storage)>>::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<decltype(dist)>(page_size)) {
-                return *(it + dist);
-            }
-        }
+        return to_entity(*storage, instance);
     }
 
     return null;

+ 64 - 44
test/entt/entity/helper.cpp

@@ -1,4 +1,5 @@
 #include <gtest/gtest.h>
+#include <entt/entity/component.hpp>
 #include <entt/entity/entity.hpp>
 #include <entt/entity/helper.hpp>
 #include <entt/entity/registry.hpp>
@@ -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<typename Type>
+struct ToEntity: testing::Test {
+    using type = Type;
+};
+
+template<typename Type>
+using ToEntityDeprecated = ToEntity<Type>;
+
+using ToEntityTypes = ::testing::Types<int, pointer_stable>;
+
+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::get_t<const char, const double>, entt::exclude_t<const int>>) {})(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::owned_t<const double>, entt::get_t<const char>, entt::exclude_t<const int>>) {})(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<clazz>(entity).entt);
 }
 
-TEST(Helper, ToEntity) {
+TYPED_TEST(ToEntity, Functionalities) {
+    using value_type = typename TestFixture::type;
+    using traits_type = entt::component_traits<value_type>;
+
     entt::registry registry;
     const entt::entity null = entt::null;
-    constexpr auto page_size = entt::storage_type_t<int>::traits_type::page_size;
-    const int value = 42;
+    auto &storage = registry.storage<value_type>();
+    constexpr auto page_size = entt::storage_type_t<value_type>::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<int>();
     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<int>(other);
-    registry.emplace<int>(next);
+    registry.emplace<value_type>(other);
+    registry.emplace<value_type>(next);
 
-    ASSERT_EQ(entt::to_entity(registry, registry.get<int>(entity)), entity);
-    ASSERT_EQ(entt::to_entity(registry, registry.get<int>(other)), other);
-    ASSERT_EQ(entt::to_entity(registry, registry.get<int>(next)), next);
+    ASSERT_EQ(entt::to_entity(storage, registry.get<value_type>(entity)), entity);
+    ASSERT_EQ(entt::to_entity(storage, registry.get<value_type>(other)), other);
+    ASSERT_EQ(entt::to_entity(storage, registry.get<value_type>(next)), next);
 
-    ASSERT_EQ(&registry.get<int>(entity) + page_size - 1u, &registry.get<int>(other));
+    ASSERT_EQ(&registry.get<value_type>(entity) + page_size - (1u + traits_type::in_place_delete), &registry.get<value_type>(other));
 
     registry.destroy(other);
 
-    ASSERT_EQ(entt::to_entity(registry, registry.get<int>(entity)), entity);
-    ASSERT_EQ(entt::to_entity(registry, registry.get<int>(next)), next);
+    ASSERT_EQ(entt::to_entity(storage, registry.get<value_type>(entity)), entity);
+    ASSERT_EQ(entt::to_entity(storage, registry.get<value_type>(next)), next);
 
-    ASSERT_EQ(&registry.get<int>(entity) + page_size - 1u, &registry.get<int>(next));
+    ASSERT_EQ(&registry.get<value_type>(entity) + page_size - 1u, &registry.get<value_type>(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<value_type>;
+
     entt::registry registry;
     const entt::entity null = entt::null;
-    constexpr auto page_size = entt::storage_type_t<stable_type>::traits_type::page_size;
-    const stable_type value{42};
+    constexpr auto page_size = entt::storage_type_t<value_type>::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<stable_type>();
-    registry.emplace<stable_type>(entity);
+    auto &&storage = registry.storage<value_type>();
+    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<stable_type>(other);
-    registry.emplace<stable_type>(next);
+    registry.emplace<value_type>(other);
+    registry.emplace<value_type>(next);
 
-    ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(entity)), entity);
-    ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(other)), other);
-    ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(next)), next);
+    ASSERT_EQ(entt::to_entity(registry, registry.get<value_type>(entity)), entity);
+    ASSERT_EQ(entt::to_entity(registry, registry.get<value_type>(other)), other);
+    ASSERT_EQ(entt::to_entity(registry, registry.get<value_type>(next)), next);
 
-    ASSERT_EQ(&registry.get<stable_type>(entity) + page_size - 2u, &registry.get<stable_type>(other));
+    ASSERT_EQ(&registry.get<value_type>(entity) + page_size - (1u + traits_type::in_place_delete), &registry.get<value_type>(other));
 
     registry.destroy(other);
 
-    ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(entity)), entity);
-    ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(next)), next);
+    ASSERT_EQ(entt::to_entity(registry, registry.get<value_type>(entity)), entity);
+    ASSERT_EQ(entt::to_entity(registry, registry.get<value_type>(next)), next);
 
-    ASSERT_EQ(&registry.get<stable_type>(entity) + page_size - 1u, &registry.get<stable_type>(next));
+    ASSERT_EQ(&registry.get<value_type>(entity) + page_size - 1u, &registry.get<value_type>(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{};