Browse Source

component_traits:
* removed ::ignore_if_empty member
* use ::page_size 0 for empty types

Michele Caini 4 years ago
parent
commit
805bb84c8f

+ 2 - 3
TODO

@@ -3,13 +3,12 @@
 * add examples (and credits) from @alanjfs :)
 * add examples (and credits) from @alanjfs :)
 
 
 WIP:
 WIP:
-* uses-allocator construction: dense map, compressed pair, any (with allocator support), cache, dispatcher, poly, storage/map/allocate_unique (with uninitialized_construct_using_allocator/construct_at), ...
+* get rid of storage_traits class template
+* uses-allocator construction: any (with allocator support), cache, dispatcher, poly, ...
 * add an ENTT_NOEXCEPT with args and use it to make ie compressed_pair conditionally noexcept
 * add an ENTT_NOEXCEPT with args and use it to make ie compressed_pair conditionally noexcept
-* storage traits: mixin only, make views stop using traits, they can refer to storage<T> only
 * process scheduler: reviews, use free lists internally
 * process scheduler: reviews, use free lists internally
 * runtime events (emitter)
 * runtime events (emitter)
 * iterator based try_emplace vs try_insert for perf reasons
 * iterator based try_emplace vs try_insert for perf reasons
-* registry: remove reference to basic_sparse_set<E>
 * dedicated entity storage, in-place O(1) release/destroy for non-orphaned entities, out-of-sync model
 * dedicated entity storage, in-place O(1) release/destroy for non-orphaned entities, out-of-sync model
 * entity-only and exclude-only views
 * entity-only and exclude-only views
 * custom allocators all over
 * custom allocators all over

+ 7 - 9
docs/md/entity.md

@@ -955,9 +955,8 @@ of `component_traits` implements all the required functionalities.<br/>
 The non-specialized version of this class contains the following members:
 The non-specialized version of this class contains the following members:
 
 
 * `in_place_delete`: `Type::in_place_delete` if present, false otherwise.
 * `in_place_delete`: `Type::in_place_delete` if present, false otherwise.
-* `ignore_if_empty`: `Type::ignore_if_empty` if present, `ENTT_IGNORE_IF_EMPTY`
-  otherwise.
-* `page_size`: `Type::page_size` if present, `ENTT_PACKED_PAGE` otherwise.
+* `page_size`: `Type::page_size` if present, `ENTT_PACKED_PAGE` (for non-empty
+  types) or 0 (for empty types) otherwise.
 
 
 Where `Type` is any type of component. All properties can be customized by
 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
 specializing the above class and defining all its members, or by adding only
@@ -2061,7 +2060,7 @@ groups or as free types with multi type views and groups in general.
 
 
 # Empty type optimization
 # Empty type optimization
 
 
-An empty type `T` is such that `std::is_empty_v<T>` returns true. They are also
+An empty type `T` is such that `std::is_empty_v<T>` returns true. They also are
 the same types for which _empty base optimization_ (EBO) is possible.<br/>
 the same types for which _empty base optimization_ (EBO) is possible.<br/>
 `EnTT` handles these types in a special way, optimizing both in terms of
 `EnTT` handles these types in a special way, optimizing both in terms of
 performance and memory usage. However, this also has consequences that are worth
 performance and memory usage. However, this also has consequences that are worth
@@ -2078,11 +2077,10 @@ it is assigned to.
 
 
 More in general, none of the feature offered by the library is affected, but for
 More in general, none of the feature offered by the library is affected, but for
 the ones that require to return actual instances.<br/>
 the ones that require to return actual instances.<br/>
-This optimization can be disabled for the whole application by defining the
-`ENTT_NO_ETO` macro. In this case, empty types will be treated like all other
-types. Otherwise, users can also specialize the `component_traits` template
-class and in particular the `ignore_if_empty` alias, disabling this optimization
-for some types only.
+This optimization is disabled by defining the `ENTT_NO_ETO` macro. In this case,
+empty types are treated like all other types. Setting a page size at component
+level via the `component_traits` class template is another way to disable this
+optimization selectively rather than globally.
 
 
 # Multithreading
 # Multithreading
 
 

+ 3 - 19
src/entt/entity/component.hpp

@@ -21,15 +21,8 @@ template<typename Type>
 struct in_place_delete<Type, std::enable_if_t<Type::in_place_delete>>
 struct in_place_delete<Type, std::enable_if_t<Type::in_place_delete>>
     : std::true_type {};
     : std::true_type {};
 
 
-template<typename, typename = void>
-struct ignore_if_empty: std::bool_constant<ENTT_IGNORE_IF_EMPTY> {};
-
-template<typename Type>
-struct ignore_if_empty<Type, std::enable_if_t<Type::ignore_if_empty>>
-    : std::true_type {};
-
-template<typename, typename = void>
-struct page_size: std::integral_constant<std::size_t, ENTT_PACKED_PAGE> {};
+template<typename Type, typename = void>
+struct page_size: std::integral_constant<std::size_t, (ENTT_IGNORE_IF_EMPTY && std::is_empty_v<Type>) ? 0u : ENTT_PACKED_PAGE> {};
 
 
 template<typename Type>
 template<typename Type>
 struct page_size<Type, std::enable_if_t<std::is_convertible_v<decltype(Type::page_size), std::size_t>>>
 struct page_size<Type, std::enable_if_t<std::is_convertible_v<decltype(Type::page_size), std::size_t>>>
@@ -52,19 +45,10 @@ struct component_traits {
 
 
     /*! @brief Pointer stability, default is `false`. */
     /*! @brief Pointer stability, default is `false`. */
     static constexpr bool in_place_delete = internal::in_place_delete<Type>::value;
     static constexpr bool in_place_delete = internal::in_place_delete<Type>::value;
-    /*! @brief Empty type optimization, default is `ENTT_IGNORE_IF_EMPTY`. */
-    static constexpr bool ignore_if_empty = internal::ignore_if_empty<Type>::value;
-    /*! @brief Page size, default is `ENTT_PACKED_PAGE`. */
+    /*! @brief Page size, default is `ENTT_PACKED_PAGE` for non-empty types. */
     static constexpr std::size_t page_size = internal::page_size<Type>::value;
     static constexpr std::size_t page_size = internal::page_size<Type>::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 &&std::is_empty_v<Type>;
-
 } // namespace entt
 } // namespace entt
 
 
 #endif
 #endif

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

@@ -234,10 +234,9 @@ 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>> {
 class basic_storage: public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
     using alloc_traits = std::allocator_traits<Allocator>;
     using alloc_traits = std::allocator_traits<Allocator>;
     static_assert(std::is_same_v<typename alloc_traits::value_type, Type>);
     static_assert(std::is_same_v<typename alloc_traits::value_type, Type>);
-
-    using comp_traits = component_traits<Type>;
     using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
     using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
     using container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
     using container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
+    using comp_traits = component_traits<Type>;
 
 
     [[nodiscard]] auto &element_at(const std::size_t pos) const {
     [[nodiscard]] auto &element_at(const std::size_t pos) const {
         return packed.first()[pos / comp_traits::page_size][fast_mod(pos, comp_traits::page_size)];
         return packed.first()[pos / comp_traits::page_size][fast_mod(pos, comp_traits::page_size)];
@@ -744,13 +743,12 @@ private:
 
 
 /*! @copydoc basic_storage */
 /*! @copydoc basic_storage */
 template<typename Entity, typename Type, typename Allocator>
 template<typename Entity, typename Type, typename Allocator>
-class basic_storage<Entity, Type, Allocator, std::enable_if_t<ignore_as_empty_v<Type>>>
+class basic_storage<Entity, Type, Allocator, std::enable_if_t<component_traits<Type>::page_size == 0u>>
     : public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
     : public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
     using alloc_traits = std::allocator_traits<Allocator>;
     using alloc_traits = std::allocator_traits<Allocator>;
     static_assert(std::is_same_v<typename alloc_traits::value_type, Type>);
     static_assert(std::is_same_v<typename alloc_traits::value_type, Type>);
-
-    using comp_traits = component_traits<Type>;
     using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
     using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
+    using comp_traits = component_traits<Type>;
 
 
 public:
 public:
     /*! @brief Base type. */
     /*! @brief Base type. */

+ 13 - 7
test/entt/entity/component.cpp

@@ -11,17 +11,25 @@ struct traits_based {};
 template<>
 template<>
 struct entt::component_traits<traits_based> {
 struct entt::component_traits<traits_based> {
     static constexpr auto in_place_delete = false;
     static constexpr auto in_place_delete = false;
-    static constexpr auto ignore_if_empty = false;
     static constexpr auto page_size = 8u;
     static constexpr auto page_size = 8u;
 };
 };
 
 
-struct default_params {};
+struct default_params_empty {};
+struct default_params_non_empty {
+    int value;
+};
+
+TEST(Component, DefaultParamsEmpty) {
+    using traits = entt::component_traits<default_params_empty>;
+
+    static_assert(!traits::in_place_delete);
+    static_assert(traits::page_size == 0u);
+}
 
 
-TEST(Component, DefaultParams) {
-    using traits = entt::component_traits<default_params>;
+TEST(Component, DefaultParamsNonEmpty) {
+    using traits = entt::component_traits<default_params_non_empty>;
 
 
     static_assert(!traits::in_place_delete);
     static_assert(!traits::in_place_delete);
-    static_assert(traits::ignore_if_empty);
     static_assert(traits::page_size == ENTT_PACKED_PAGE);
     static_assert(traits::page_size == ENTT_PACKED_PAGE);
 }
 }
 
 
@@ -29,7 +37,6 @@ TEST(Component, SelfContained) {
     using traits = entt::component_traits<self_contained>;
     using traits = entt::component_traits<self_contained>;
 
 
     static_assert(traits::in_place_delete);
     static_assert(traits::in_place_delete);
-    static_assert(traits::ignore_if_empty);
     static_assert(traits::page_size == 4u);
     static_assert(traits::page_size == 4u);
 }
 }
 
 
@@ -37,6 +44,5 @@ TEST(Component, TraitsBased) {
     using traits = entt::component_traits<traits_based>;
     using traits = entt::component_traits<traits_based>;
 
 
     static_assert(!traits::in_place_delete);
     static_assert(!traits::in_place_delete);
-    static_assert(!traits::ignore_if_empty);
     static_assert(traits::page_size == 8u);
     static_assert(traits::page_size == 8u);
 }
 }

+ 0 - 1
test/entt/entity/storage.cpp

@@ -78,7 +78,6 @@ struct crete_from_constructor {
 template<>
 template<>
 struct entt::component_traits<std::unordered_set<char>> {
 struct entt::component_traits<std::unordered_set<char>> {
     static constexpr auto in_place_delete = true;
     static constexpr auto in_place_delete = true;
-    static constexpr auto ignore_if_empty = ENTT_IGNORE_IF_EMPTY;
     static constexpr auto page_size = ENTT_PACKED_PAGE;
     static constexpr auto page_size = ENTT_PACKED_PAGE;
 };
 };