Browse Source

component traits:
* added page_size to tune the page size on a per-type basis
* turned in_place_delete into a boolean value
* turned ignore_if_empty into a boolean value
* removed in_place_delete_v (no longer required)

Michele Caini 4 years ago
parent
commit
3fcccae241

+ 6 - 4
docs/md/entity.md

@@ -1013,14 +1013,16 @@ The definition common to all components is the following:
 
 ```cpp
 struct basic_component_traits {
-    using in_place_delete = std::false_type;
-    using ignore_if_empty = ENTT_IGNORE_IF_EMPTY;
+    static constexpr auto in_place_delete = false;
+    static constexpr auto ignore_if_empty = ENTT_IGNORE_IF_EMPTY;
+    static constexpr auto page_size = ENTT_PACKED_PAGE;
 };
 ```
 
 Where `in_place_delete` instructs the library on the deletion policy for a given
-type while `ignore_if_empty` selectively disables empty type optimization.<br/>
-The `component_traits` class template is _sfinae-friendly_, it supports single-
+type while `ignore_if_empty` selectively disables empty type optimization and
+`page_size` dictates the storage behavior for non-empty types.<br/>
+The `component_traits` class template is _sfinae-friendly_, it supports single
 and multi type specializations as well as feature-based ones:
 
 ```cpp

+ 2 - 4
src/entt/config/config.h

@@ -49,11 +49,9 @@
 #endif
 
 #ifdef ENTT_NO_ETO
-#    include <type_traits>
-#    define ENTT_IGNORE_IF_EMPTY std::false_type
+#    define ENTT_IGNORE_IF_EMPTY false
 #else
-#    include <type_traits>
-#    define ENTT_IGNORE_IF_EMPTY std::true_type
+#    define ENTT_IGNORE_IF_EMPTY true
 #endif
 
 #ifndef ENTT_STANDARD_CPP

+ 6 - 11
src/entt/entity/component.hpp

@@ -8,10 +8,12 @@ namespace entt {
 
 /*! @brief Commonly used default traits for all types. */
 struct basic_component_traits {
-    /*! @brief Pointer stability, default is `std::false_type`. */
-    using in_place_delete = std::false_type;
+    /*! @brief Pointer stability, default is `false`. */
+    static constexpr auto in_place_delete = false;
     /*! @brief Empty type optimization, default is `ENTT_IGNORE_IF_EMPTY`. */
-    using ignore_if_empty = ENTT_IGNORE_IF_EMPTY;
+    static constexpr auto ignore_if_empty = ENTT_IGNORE_IF_EMPTY;
+    /*! @brief Page size, default is `ENTT_PACKED_PAGE`. */
+    static constexpr auto page_size = ENTT_PACKED_PAGE;
 };
 
 /**
@@ -28,14 +30,7 @@ struct component_traits: basic_component_traits {
  * @tparam Type Type of component.
  */
 template<class Type>
-inline constexpr bool in_place_delete_v = component_traits<Type>::in_place_delete::value;
-
-/**
- * @brief Helper variable template.
- * @tparam Type Type of component.
- */
-template<class Type>
-inline constexpr bool ignore_as_empty_v = component_traits<Type>::ignore_if_empty::value &&std::is_empty_v<Type>;
+inline constexpr bool ignore_as_empty_v = component_traits<Type>::ignore_if_empty &&std::is_empty_v<Type>;
 
 } // namespace entt
 

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

@@ -49,8 +49,7 @@ class basic_registry {
 
     template<typename... Exclude, typename... Get, typename... Owned>
     struct group_handler<exclude_t<Exclude...>, get_t<Get...>, Owned...> {
-        static_assert(!std::disjunction_v<typename component_traits<Owned>::in_place_delete...>, "Groups do not support in-place delete");
-        static_assert(std::conjunction_v<std::is_same<Owned, std::remove_const_t<Owned>>..., std::is_same<Get, std::remove_const_t<Get>>..., std::is_same<Exclude, std::remove_const_t<Exclude>>...>, "One or more component types are invalid");
+        static_assert((!component_traits<Owned>::in_place_delete && ...), "Groups do not support in-place delete");
         std::conditional_t<sizeof...(Owned) == 0, basic_common_type, std::size_t> current{};
 
         template<typename Component>

+ 14 - 18
src/entt/entity/storage.hpp

@@ -34,10 +34,9 @@ template<typename Container>
 class storage_iterator final {
     friend storage_iterator<const Container>;
 
-    static constexpr auto packed_page_v = ENTT_PACKED_PAGE;
-
     using container_type = std::remove_const_t<Container>;
     using allocator_traits = std::allocator_traits<typename container_type::allocator_type>;
+    using comp_traits = component_traits<typename container_type::value_type>;
 
     using iterator_traits = std::iterator_traits<std::conditional_t<
         std::is_const_v<Container>,
@@ -100,12 +99,12 @@ public:
 
     [[nodiscard]] reference operator[](const difference_type value) const ENTT_NOEXCEPT {
         const auto pos = index - value - 1;
-        return (*packed)[pos / packed_page_v][fast_mod(pos, packed_page_v)];
+        return (*packed)[pos / comp_traits::page_size][fast_mod(pos, comp_traits::page_size)];
     }
 
     [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
         const auto pos = index - 1;
-        return (*packed)[pos / packed_page_v] + fast_mod(pos, packed_page_v);
+        return (*packed)[pos / comp_traits::page_size] + fast_mod(pos, comp_traits::page_size);
     }
 
     [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
@@ -191,24 +190,21 @@ template<typename CLhs, typename CRhs>
  */
 template<typename Entity, typename Type, typename Allocator, typename>
 class basic_storage: public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
-    static constexpr auto packed_page_v = ENTT_PACKED_PAGE;
-
     using allocator_traits = std::allocator_traits<Allocator>;
     using alloc = typename allocator_traits::template rebind_alloc<Type>;
     using alloc_traits = typename std::allocator_traits<alloc>;
 
-    using entity_traits = entt_traits<Entity>;
     using comp_traits = component_traits<Type>;
     using underlying_type = basic_sparse_set<Entity, typename allocator_traits::template rebind_alloc<Entity>>;
     using container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
 
     [[nodiscard]] auto &element_at(const std::size_t pos) const {
-        return packed.first()[pos / packed_page_v][fast_mod(pos, packed_page_v)];
+        return packed.first()[pos / comp_traits::page_size][fast_mod(pos, comp_traits::page_size)];
     }
 
     auto assure_at_least(const std::size_t pos) {
         auto &&container = packed.first();
-        const auto idx = pos / packed_page_v;
+        const auto idx = pos / comp_traits::page_size;
 
         if(!(idx < container.size())) {
             auto curr = container.size();
@@ -216,7 +212,7 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
 
             ENTT_TRY {
                 for(const auto last = container.size(); curr < last; ++curr) {
-                    container[curr] = alloc_traits::allocate(packed.second(), packed_page_v);
+                    container[curr] = alloc_traits::allocate(packed.second(), comp_traits::page_size);
                 }
             }
             ENTT_CATCH {
@@ -225,16 +221,16 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
             }
         }
 
-        return container[idx] + fast_mod(pos, packed_page_v);
+        return container[idx] + fast_mod(pos, comp_traits::page_size);
     }
 
     void release_unused_pages() {
         auto &&container = packed.first();
         auto page_allocator{packed.second()};
-        const auto in_use = (base_type::size() + packed_page_v - 1u) / packed_page_v;
+        const auto in_use = (base_type::size() + comp_traits::page_size - 1u) / comp_traits::page_size;
 
         for(auto pos = in_use, last = container.size(); pos < last; ++pos) {
-            alloc_traits::deallocate(page_allocator, container[pos], packed_page_v);
+            alloc_traits::deallocate(page_allocator, container[pos], comp_traits::page_size);
         }
 
         container.resize(in_use);
@@ -242,7 +238,7 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
 
     void release_all_pages() {
         for(size_type pos{}, last = base_type::size(); pos < last; ++pos) {
-            if constexpr(comp_traits::in_place_delete::value) {
+            if constexpr(comp_traits::in_place_delete) {
                 if(base_type::at(pos) != tombstone) {
                     std::destroy_at(std::addressof(element_at(pos)));
                 }
@@ -255,7 +251,7 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
         auto page_allocator{packed.second()};
 
         for(size_type pos{}, last = container.size(); pos < last; ++pos) {
-            alloc_traits::deallocate(page_allocator, container[pos], packed_page_v);
+            alloc_traits::deallocate(page_allocator, container[pos], comp_traits::page_size);
         }
     }
 
@@ -393,7 +389,7 @@ public:
      * @param allocator The allocator to use.
      */
     explicit basic_storage(const allocator_type &allocator)
-        : base_type{type_id<value_type>(), deletion_policy{comp_traits::in_place_delete::value}, allocator},
+        : base_type{type_id<value_type>(), deletion_policy{comp_traits::in_place_delete}, allocator},
           packed{container_type{allocator}, allocator} {}
 
     /**
@@ -476,7 +472,7 @@ public:
      * @return Capacity of the storage.
      */
     [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT override {
-        return packed.first().size() * packed_page_v;
+        return packed.first().size() * comp_traits::page_size;
     }
 
     /*! @brief Requests the removal of unused capacity. */
@@ -741,7 +737,7 @@ public:
      * @param allocator The allocator to use.
      */
     explicit basic_storage(const allocator_type &allocator)
-        : base_type{type_id<value_type>(), deletion_policy{comp_traits::in_place_delete::value}, allocator} {}
+        : base_type{type_id<value_type>(), deletion_policy{comp_traits::in_place_delete}, allocator} {}
 
     /**
      * @brief Move constructor.

+ 1 - 1
src/entt/entity/view.hpp

@@ -657,7 +657,7 @@ private:
  * @tparam Component Type of component iterated by the view.
  */
 template<typename Entity, typename Component>
-class basic_view<Entity, get_t<Component>, exclude_t<>, std::void_t<std::enable_if_t<!in_place_delete_v<std::remove_const_t<Component>>>>> {
+class basic_view<Entity, get_t<Component>, exclude_t<>, std::void_t<std::enable_if_t<!component_traits<std::remove_const_t<Component>>::in_place_delete>>> {
     template<typename, typename, typename, typename>
     friend class basic_view;
 

+ 1 - 1
test/benchmark/benchmark.cpp

@@ -20,7 +20,7 @@ struct comp { int x; };
 
 template<>
 struct entt::component_traits<stable_position>: basic_component_traits {
-    using in_place_delete = std::true_type;
+    static constexpr auto in_place_delete = true;
 };
 
 struct timer final {

+ 1 - 1
test/entt/entity/helper.cpp

@@ -19,7 +19,7 @@ struct stable_type {
 
 template<>
 struct entt::component_traits<stable_type>: basic_component_traits {
-    using in_place_delete = std::true_type;
+    static constexpr auto in_place_delete = true;
 };
 
 TEST(Helper, AsView) {

+ 1 - 1
test/entt/entity/registry.cpp

@@ -18,7 +18,7 @@ struct stable_type {
 
 template<>
 struct entt::component_traits<stable_type>: basic_component_traits {
-    using in_place_delete = std::true_type;
+    static constexpr auto in_place_delete = true;
 };
 
 struct non_default_constructible {

+ 1 - 1
test/entt/entity/runtime_view.cpp

@@ -12,7 +12,7 @@ struct stable_type {
 
 template<>
 struct entt::component_traits<stable_type>: basic_component_traits {
-    using in_place_delete = std::true_type;
+    static constexpr auto in_place_delete = true;
 };
 
 TEST(RuntimeView, Functionalities) {

+ 1 - 1
test/entt/entity/sigh_storage_mixin.cpp

@@ -22,7 +22,7 @@ struct non_default_constructible {
 
 template<>
 struct entt::component_traits<stable_type>: basic_component_traits {
-    using in_place_delete = std::true_type;
+    static constexpr auto in_place_delete = true;
 };
 
 struct counter {

+ 2 - 2
test/entt/entity/storage.cpp

@@ -57,12 +57,12 @@ private:
 
 template<>
 struct entt::component_traits<stable_type>: basic_component_traits {
-    using in_place_delete = std::true_type;
+    static constexpr auto in_place_delete = true;
 };
 
 template<>
 struct entt::component_traits<empty_stable_type>: basic_component_traits {
-    using in_place_delete = std::true_type;
+    static constexpr auto in_place_delete = true;
 };
 
 bool operator==(const boxed_int &lhs, const boxed_int &rhs) {

+ 1 - 1
test/entt/entity/view.cpp

@@ -15,7 +15,7 @@ struct stable_type {
 
 template<>
 struct entt::component_traits<stable_type>: basic_component_traits {
-    using in_place_delete = std::true_type;
+    static constexpr auto in_place_delete = true;
 };
 
 TEST(SingleComponentView, Functionalities) {