Kaynağa Gözat

mixin: make sigh mixin work with custom registry types - close #1079

Michele Caini 2 yıl önce
ebeveyn
işleme
e3475c026c
3 değiştirilmiş dosya ile 141 ekleme ve 97 silme
  1. 90 83
      src/entt/entity/fwd.hpp
  2. 19 14
      src/entt/entity/mixin.hpp
  3. 32 0
      test/entt/entity/sigh_mixin.cpp

+ 90 - 83
src/entt/entity/fwd.hpp

@@ -28,46 +28,8 @@ class basic_sparse_set;
 template<typename Type, typename = entity, typename = std::allocator<Type>, typename = void>
 class basic_storage;
 
-template<typename Type>
-class sigh_mixin;
-
-/**
- * @brief Provides a common way to define storage types.
- * @tparam Type Storage value type.
- * @tparam Entity A valid entity type.
- * @tparam Allocator Type of allocator used to manage memory and elements.
- */
-template<typename Type, typename Entity = entity, typename Allocator = std::allocator<Type>, typename = void>
-struct storage_type {
-    /*! @brief Type-to-storage conversion result. */
-    using type = sigh_mixin<basic_storage<Type, Entity, Allocator>>;
-};
-
-/**
- * @brief Helper type.
- * @tparam Args Arguments to forward.
- */
-template<typename... Args>
-using storage_type_t = typename storage_type<Args...>::type;
-
-/**
- * Type-to-storage conversion utility that preserves constness.
- * @tparam Type Storage value type, eventually const.
- * @tparam Entity A valid entity type.
- * @tparam Allocator Type of allocator used to manage memory and elements.
- */
-template<typename Type, typename Entity = entity, typename Allocator = std::allocator<std::remove_const_t<Type>>>
-struct storage_for {
-    /*! @brief Type-to-storage conversion result. */
-    using type = constness_as_t<storage_type_t<std::remove_const_t<Type>, Entity, Allocator>, Type>;
-};
-
-/**
- * @brief Helper type.
- * @tparam Args Arguments to forward.
- */
-template<typename... Args>
-using storage_for_t = typename storage_for<Args...>::type;
+template<typename, typename>
+class basic_sigh_mixin;
 
 template<typename Entity = entity, typename = std::allocator<Entity>>
 class basic_registry;
@@ -99,6 +61,67 @@ class basic_snapshot_loader;
 template<typename>
 class basic_continuous_loader;
 
+/*! @brief Alias declaration for the most common use case. */
+using sparse_set = basic_sparse_set<>;
+
+/**
+ * @brief Alias declaration for the most common use case.
+ * @tparam Type Type of objects assigned to the entities.
+ */
+template<typename Type>
+using storage = basic_storage<Type>;
+
+/**
+ * @brief Alias declaration for the most common use case.
+ * @tparam Type Underlying storage type.
+ */
+template<typename Type>
+using sigh_mixin = basic_sigh_mixin<Type, basic_registry<typename Type::entity_type, typename Type::base_type::allocator_type>>;
+
+/*! @brief Alias declaration for the most common use case. */
+using registry = basic_registry<>;
+
+/*! @brief Alias declaration for the most common use case. */
+using observer = basic_observer<registry>;
+
+/*! @brief Alias declaration for the most common use case. */
+using organizer = basic_organizer<registry>;
+
+/*! @brief Alias declaration for the most common use case. */
+using handle = basic_handle<registry>;
+
+/*! @brief Alias declaration for the most common use case. */
+using const_handle = basic_handle<const registry>;
+
+/**
+ * @brief Alias declaration for the most common use case.
+ * @tparam Args Other template parameters.
+ */
+template<typename... Args>
+using handle_view = basic_handle<registry, Args...>;
+
+/**
+ * @brief Alias declaration for the most common use case.
+ * @tparam Args Other template parameters.
+ */
+template<typename... Args>
+using const_handle_view = basic_handle<const registry, Args...>;
+
+/*! @brief Alias declaration for the most common use case. */
+using snapshot = basic_snapshot<registry>;
+
+/*! @brief Alias declaration for the most common use case. */
+using snapshot_loader = basic_snapshot_loader<registry>;
+
+/*! @brief Alias declaration for the most common use case. */
+using continuous_loader = basic_continuous_loader<registry>;
+
+/*! @brief Alias declaration for the most common use case. */
+using runtime_view = basic_runtime_view<sparse_set>;
+
+/*! @brief Alias declaration for the most common use case. */
+using const_runtime_view = basic_runtime_view<const sparse_set>;
+
 /**
  * @brief Alias for exclusion lists.
  * @tparam Type List of types.
@@ -183,53 +206,43 @@ struct type_list_transform<owned_t<Type...>, Op> {
     using type = owned_t<typename Op<Type>::type...>;
 };
 
-/*! @brief Alias declaration for the most common use case. */
-using sparse_set = basic_sparse_set<>;
-
 /**
- * @brief Alias declaration for the most common use case.
- * @tparam Type Type of objects assigned to the entities.
+ * @brief Provides a common way to define storage types.
+ * @tparam Type Storage value type.
+ * @tparam Entity A valid entity type.
+ * @tparam Allocator Type of allocator used to manage memory and elements.
  */
-template<typename Type>
-using storage = basic_storage<Type>;
-
-/*! @brief Alias declaration for the most common use case. */
-using registry = basic_registry<>;
-
-/*! @brief Alias declaration for the most common use case. */
-using observer = basic_observer<registry>;
-
-/*! @brief Alias declaration for the most common use case. */
-using organizer = basic_organizer<registry>;
-
-/*! @brief Alias declaration for the most common use case. */
-using handle = basic_handle<registry>;
-
-/*! @brief Alias declaration for the most common use case. */
-using const_handle = basic_handle<const registry>;
+template<typename Type, typename Entity = entity, typename Allocator = std::allocator<Type>, typename = void>
+struct storage_type {
+    /*! @brief Type-to-storage conversion result. */
+    using type = sigh_mixin<basic_storage<Type, Entity, Allocator>>;
+};
 
 /**
- * @brief Alias declaration for the most common use case.
- * @tparam Args Other template parameters.
+ * @brief Helper type.
+ * @tparam Args Arguments to forward.
  */
 template<typename... Args>
-using handle_view = basic_handle<registry, Args...>;
+using storage_type_t = typename storage_type<Args...>::type;
 
 /**
- * @brief Alias declaration for the most common use case.
- * @tparam Args Other template parameters.
+ * Type-to-storage conversion utility that preserves constness.
+ * @tparam Type Storage value type, eventually const.
+ * @tparam Entity A valid entity type.
+ * @tparam Allocator Type of allocator used to manage memory and elements.
  */
-template<typename... Args>
-using const_handle_view = basic_handle<const registry, Args...>;
-
-/*! @brief Alias declaration for the most common use case. */
-using snapshot = basic_snapshot<registry>;
-
-/*! @brief Alias declaration for the most common use case. */
-using snapshot_loader = basic_snapshot_loader<registry>;
+template<typename Type, typename Entity = entity, typename Allocator = std::allocator<std::remove_const_t<Type>>>
+struct storage_for {
+    /*! @brief Type-to-storage conversion result. */
+    using type = constness_as_t<storage_type_t<std::remove_const_t<Type>, Entity, Allocator>, Type>;
+};
 
-/*! @brief Alias declaration for the most common use case. */
-using continuous_loader = basic_continuous_loader<registry>;
+/**
+ * @brief Helper type.
+ * @tparam Args Arguments to forward.
+ */
+template<typename... Args>
+using storage_for_t = typename storage_for<Args...>::type;
 
 /**
  * @brief Alias declaration for the most common use case.
@@ -239,12 +252,6 @@ using continuous_loader = basic_continuous_loader<registry>;
 template<typename Get, typename Exclude = exclude_t<>>
 using view = basic_view<type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>;
 
-/*! @brief Alias declaration for the most common use case. */
-using runtime_view = basic_runtime_view<sparse_set>;
-
-/*! @brief Alias declaration for the most common use case. */
-using const_runtime_view = basic_runtime_view<const sparse_set>;
-
 /**
  * @brief Alias declaration for the most common use case.
  * @tparam Owned Types of storage _owned_ by the group.

+ 19 - 14
src/entt/entity/mixin.hpp

@@ -22,18 +22,23 @@ namespace entt {
  *
  * This applies to all signals made available.
  *
- * @tparam Type The type of the underlying storage.
+ * @tparam Type Underlying storage type.
+ * @tparam Registry Basic registry type.
  */
-template<typename Type>
-class sigh_mixin final: public Type {
+template<typename Type, typename Registry>
+class basic_sigh_mixin final: public Type {
     using underlying_type = Type;
+    using owner_type = Registry;
+
     using basic_registry_type = basic_registry<typename underlying_type::entity_type, typename underlying_type::base_type::allocator_type>;
-    using sigh_type = sigh<void(basic_registry_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>;
+    using sigh_type = sigh<void(owner_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>;
     using underlying_iterator = typename underlying_type::base_type::basic_iterator;
 
-    basic_registry_type &owner_or_assert() const noexcept {
+    static_assert(std::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
+
+    owner_type &owner_or_assert() const noexcept {
         ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
-        return *owner;
+        return static_cast<owner_type &>(*owner);
     }
 
     void pop(underlying_iterator first, underlying_iterator last) final {
@@ -85,17 +90,17 @@ public:
     /*! @brief Underlying entity identifier. */
     using entity_type = typename underlying_type::entity_type;
     /*! @brief Expected registry type. */
-    using registry_type = basic_registry_type;
+    using registry_type = owner_type;
 
     /*! @brief Default constructor. */
-    sigh_mixin()
-        : sigh_mixin{allocator_type{}} {}
+    basic_sigh_mixin()
+        : basic_sigh_mixin{allocator_type{}} {}
 
     /**
      * @brief Constructs an empty storage with a given allocator.
      * @param allocator The allocator to use.
      */
-    explicit sigh_mixin(const allocator_type &allocator)
+    explicit basic_sigh_mixin(const allocator_type &allocator)
         : underlying_type{allocator},
           owner{},
           construction{allocator},
@@ -106,7 +111,7 @@ public:
      * @brief Move constructor.
      * @param other The instance to move from.
      */
-    sigh_mixin(sigh_mixin &&other) noexcept
+    basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
         : underlying_type{std::move(other)},
           owner{other.owner},
           construction{std::move(other.construction)},
@@ -118,7 +123,7 @@ public:
      * @param other The instance to move from.
      * @param allocator The allocator to use.
      */
-    sigh_mixin(sigh_mixin &&other, const allocator_type &allocator) noexcept
+    basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator) noexcept
         : underlying_type{std::move(other), allocator},
           owner{other.owner},
           construction{std::move(other.construction), allocator},
@@ -130,7 +135,7 @@ public:
      * @param other The instance to move from.
      * @return This storage.
      */
-    sigh_mixin &operator=(sigh_mixin &&other) noexcept {
+    basic_sigh_mixin &operator=(basic_sigh_mixin &&other) noexcept {
         underlying_type::operator=(std::move(other));
         owner = other.owner;
         construction = std::move(other.construction);
@@ -143,7 +148,7 @@ public:
      * @brief Exchanges the contents with those of a given storage.
      * @param other Storage to exchange the content with.
      */
-    void swap(sigh_mixin &other) {
+    void swap(basic_sigh_mixin &other) {
         using std::swap;
         underlying_type::swap(other);
         swap(owner, other.owner);

+ 32 - 0
test/entt/entity/sigh_mixin.cpp

@@ -10,6 +10,7 @@
 #include <entt/entity/mixin.hpp>
 #include <entt/entity/registry.hpp>
 #include <entt/entity/storage.hpp>
+#include "../common/custom_entity.h"
 #include "../common/non_default_constructible.h"
 #include "../common/pointer_stable.h"
 #include "../common/throwing_allocator.hpp"
@@ -20,6 +21,13 @@ void listener(std::size_t &counter, Registry &, typename Registry::entity_type)
     ++counter;
 }
 
+struct custom_registry: entt::basic_registry<test::custom_entity> {};
+
+template<typename Component>
+struct entt::storage_type<Component, test::custom_entity> {
+    using type = entt::basic_sigh_mixin<entt::basic_storage<Component, test::custom_entity>, custom_registry>;
+};
+
 template<typename Type>
 struct SighMixin: testing::Test {
     using type = Type;
@@ -414,6 +422,30 @@ TYPED_TEST(SighMixin, Swap) {
     ASSERT_EQ(on_destroy, 3u);
 }
 
+TYPED_TEST(SighMixin, CustomRegistry) {
+    using value_type = typename TestFixture::type;
+    entt::basic_sigh_mixin<entt::basic_storage<value_type, test::custom_entity>, custom_registry> pool;
+    custom_registry registry;
+
+    std::size_t on_construct{};
+    std::size_t on_destroy{};
+
+    pool.bind(entt::forward_as_any(static_cast<entt::basic_registry<test::custom_entity> &>(registry)));
+    pool.on_construct().template connect<&listener<custom_registry>>(on_construct);
+    pool.on_destroy().template connect<&listener<custom_registry>>(on_destroy);
+
+    pool.emplace(test::custom_entity{3});
+    pool.emplace(test::custom_entity{42});
+
+    ASSERT_EQ(on_construct, 2u);
+    ASSERT_EQ(on_destroy, 0u);
+
+    pool.clear();
+
+    ASSERT_EQ(on_construct, 2u);
+    ASSERT_EQ(on_destroy, 2u);
+}
+
 TYPED_TEST(SighMixin, CustomAllocator) {
     using value_type = typename TestFixture::type;
     test::throwing_allocator<entt::entity> allocator{};