Просмотр исходного кода

component_traits: support specializations based on entity type

Michele Caini 3 лет назад
Родитель
Сommit
0a82b777b2
6 измененных файлов с 47 добавлено и 12 удалено
  1. 1 1
      TODO
  2. 24 7
      docs/md/entity.md
  3. 2 1
      src/entt/entity/component.hpp
  4. 3 0
      src/entt/entity/fwd.hpp
  5. 3 3
      src/entt/entity/storage.hpp
  6. 14 0
      test/entt/entity/component.cpp

+ 1 - 1
TODO

@@ -12,7 +12,7 @@ DOC:
 * update entity doc when the storage based model is in place
 
 TODO (high prio):
-* make component_traits depend on the entity type
+* check natvis files (periodically :)
 * remove the static storage from the const assure in the registry
 
 WIP:

+ 24 - 7
docs/md/entity.md

@@ -990,9 +990,9 @@ The non-specialized version of this class contains the following members:
 * `page_size`: `Type::page_size` if present, `ENTT_PACKED_PAGE` for non-empty
   types and 0 otherwise.
 
-Where `Type` is any type of component. All properties can be customized by
-specializing the above class and defining all its members, or by adding only
-those of interest to a component definition:
+Where `Type` is any type of component. Properties are customized by specializing
+the above class and defining its members, or by adding only those of interest to
+a component definition:
 
 ```cpp
 struct transform {
@@ -1001,10 +1001,27 @@ struct transform {
 };
 ```
 
-The `component_traits` class template will take care of correctly extracting the
-properties from the supplied type to pass them to the rest of the library.<br/>
-In the case of a direct specialization, the class is also _sfinae-friendly_. It
-supports single and multi type specializations as well as feature-based ones.
+The `component_traits` class template takes care of _extracting_ the properties
+from the supplied type.<br/>
+Plus, it's _sfinae-friendly_ and also supports feature-based specialization:
+
+```cpp
+template<typename Type>
+struct entt::component_traits<Type, std::enable_if_t<Type::never_instantiate_me, entt::entity>> {
+    using type = Type;
+    static constexpr auto in_place_delete = false;
+    static constexpr auto page_size = 0u;
+};
+```
+
+The second template parameter isn't used directly by this class and could be any
+type actually.<br/>
+However, quite often the library provides an entity type as a parameter, such as
+when a storage retrieves component traits for its value type. This also makes it
+possible to create specializations based on the entity type, if needed.<br/>
+If in doubt, it's recommended to use the chosen entity type, avoid passing the
+parameter (since it has a default) or use a more generic type to _extend_ the
+specialization to all entity types.
 
 ## Pointer stability
 

+ 2 - 1
src/entt/entity/component.hpp

@@ -4,6 +4,7 @@
 #include <cstddef>
 #include <type_traits>
 #include "../config/config.h"
+#include "fwd.hpp"
 
 namespace entt {
 
@@ -45,7 +46,7 @@ struct page_size<Type, std::enable_if_t<std::is_convertible_v<decltype(Type::pag
  * @brief Common way to access various properties of components.
  * @tparam Type Type of component.
  */
-template<typename Type, typename = void>
+template<typename Type, typename>
 struct component_traits {
     static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
 

+ 3 - 0
src/entt/entity/fwd.hpp

@@ -11,6 +11,9 @@ namespace entt {
 /*! @brief Default entity identifier. */
 enum class entity : id_type {};
 
+template<typename, typename = entity>
+struct component_traits;
+
 template<typename Entity = entity, typename = std::allocator<Entity>>
 class basic_sparse_set;
 

+ 3 - 3
src/entt/entity/storage.hpp

@@ -380,7 +380,7 @@ public:
     /*! @brief Base type. */
     using base_type = underlying_type;
     /*! @brief Component traits. */
-    using traits_type = component_traits<Type>;
+    using traits_type = component_traits<Type, Entity>;
     /*! @brief Allocator type. */
     using allocator_type = Allocator;
     /*! @brief Type of the objects assigned to entities. */
@@ -745,7 +745,7 @@ private:
 
 /*! @copydoc basic_storage */
 template<typename Type, typename Entity, typename Allocator>
-class basic_storage<Type, Entity, Allocator, std::enable_if_t<component_traits<Type>::page_size == 0u>>
+class basic_storage<Type, Entity, Allocator, std::enable_if_t<component_traits<Type, Entity>::page_size == 0u>>
     : public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
     using alloc_traits = std::allocator_traits<Allocator>;
     static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
@@ -755,7 +755,7 @@ public:
     /*! @brief Base type. */
     using base_type = underlying_type;
     /*! @brief Component traits. */
-    using traits_type = component_traits<Type>;
+    using traits_type = component_traits<Type, Entity>;
     /*! @brief Allocator type. */
     using allocator_type = Allocator;
     /*! @brief Type of the objects assigned to entities. */

+ 14 - 0
test/entt/entity/component.cpp

@@ -29,6 +29,13 @@ struct entt::component_traits<traits_based> {
     static constexpr auto page_size = 8u;
 };
 
+template<>
+struct entt::component_traits<traits_based, void> {
+    using type = traits_based;
+    static constexpr auto in_place_delete = true;
+    static constexpr auto page_size = 16u;
+};
+
 TEST(Component, VoidType) {
     using traits_type = entt::component_traits<void>;
 
@@ -70,3 +77,10 @@ TEST(Component, TraitsBased) {
     static_assert(!traits_type::in_place_delete);
     static_assert(traits_type::page_size == 8u);
 }
+
+TEST(Component, TraitsBasedTagged) {
+    using traits_type = entt::component_traits<traits_based, void>;
+
+    static_assert(traits_type::in_place_delete);
+    static_assert(traits_type::page_size == 16u);
+}