diff --git a/TODO b/TODO index c43b6ff98..a9c689403 100644 --- a/TODO +++ b/TODO @@ -3,13 +3,12 @@ * add examples (and credits) from @alanjfs :) 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 -* storage traits: mixin only, make views stop using traits, they can refer to storage only * process scheduler: reviews, use free lists internally * runtime events (emitter) * iterator based try_emplace vs try_insert for perf reasons -* registry: remove reference to basic_sparse_set * dedicated entity storage, in-place O(1) release/destroy for non-orphaned entities, out-of-sync model * entity-only and exclude-only views * custom allocators all over diff --git a/docs/md/entity.md b/docs/md/entity.md index e0efdbe06..cf40bb71e 100644 --- a/docs/md/entity.md +++ b/docs/md/entity.md @@ -955,9 +955,8 @@ of `component_traits` implements all the required functionalities.
The non-specialized version of this class contains the following members: * `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 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 -An empty type `T` is such that `std::is_empty_v` returns true. They are also +An empty type `T` is such that `std::is_empty_v` returns true. They also are the same types for which _empty base optimization_ (EBO) is possible.
`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 @@ -2078,11 +2077,10 @@ it is assigned to. More in general, none of the feature offered by the library is affected, but for the ones that require to return actual instances.
-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 diff --git a/src/entt/entity/component.hpp b/src/entt/entity/component.hpp index 9716be6dd..4d2a8b8c4 100644 --- a/src/entt/entity/component.hpp +++ b/src/entt/entity/component.hpp @@ -21,15 +21,8 @@ template struct in_place_delete> : std::true_type {}; -template -struct ignore_if_empty: std::bool_constant {}; - -template -struct ignore_if_empty> - : std::true_type {}; - -template -struct page_size: std::integral_constant {}; +template +struct page_size: std::integral_constant) ? 0u : ENTT_PACKED_PAGE> {}; template struct page_size>> @@ -52,19 +45,10 @@ struct component_traits { /*! @brief Pointer stability, default is `false`. */ static constexpr bool in_place_delete = internal::in_place_delete::value; - /*! @brief Empty type optimization, default is `ENTT_IGNORE_IF_EMPTY`. */ - static constexpr bool ignore_if_empty = internal::ignore_if_empty::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::value; }; -/** - * @brief Helper variable template. - * @tparam Type Type of component. - */ -template -inline constexpr bool ignore_as_empty_v = component_traits::ignore_if_empty &&std::is_empty_v; - } // namespace entt #endif diff --git a/src/entt/entity/storage.hpp b/src/entt/entity/storage.hpp index 9deff02dd..c33319e12 100644 --- a/src/entt/entity/storage.hpp +++ b/src/entt/entity/storage.hpp @@ -234,10 +234,9 @@ template class basic_storage: public basic_sparse_set::template rebind_alloc> { using alloc_traits = std::allocator_traits; static_assert(std::is_same_v); - - using comp_traits = component_traits; using underlying_type = basic_sparse_set>; using container_type = std::vector>; + using comp_traits = component_traits; [[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)]; @@ -744,13 +743,12 @@ private: /*! @copydoc basic_storage */ template -class basic_storage>> +class basic_storage::page_size == 0u>> : public basic_sparse_set::template rebind_alloc> { using alloc_traits = std::allocator_traits; static_assert(std::is_same_v); - - using comp_traits = component_traits; using underlying_type = basic_sparse_set>; + using comp_traits = component_traits; public: /*! @brief Base type. */ diff --git a/test/entt/entity/component.cpp b/test/entt/entity/component.cpp index b4ad0d9bd..7df300cc4 100644 --- a/test/entt/entity/component.cpp +++ b/test/entt/entity/component.cpp @@ -11,17 +11,25 @@ struct traits_based {}; template<> struct entt::component_traits { static constexpr auto in_place_delete = false; - static constexpr auto ignore_if_empty = false; static constexpr auto page_size = 8u; }; -struct default_params {}; +struct default_params_empty {}; +struct default_params_non_empty { + int value; +}; -TEST(Component, DefaultParams) { - using traits = entt::component_traits; +TEST(Component, DefaultParamsEmpty) { + using traits = entt::component_traits; + + static_assert(!traits::in_place_delete); + static_assert(traits::page_size == 0u); +} + +TEST(Component, DefaultParamsNonEmpty) { + using traits = entt::component_traits; static_assert(!traits::in_place_delete); - static_assert(traits::ignore_if_empty); static_assert(traits::page_size == ENTT_PACKED_PAGE); } @@ -29,7 +37,6 @@ TEST(Component, SelfContained) { using traits = entt::component_traits; static_assert(traits::in_place_delete); - static_assert(traits::ignore_if_empty); static_assert(traits::page_size == 4u); } @@ -37,6 +44,5 @@ TEST(Component, TraitsBased) { using traits = entt::component_traits; static_assert(!traits::in_place_delete); - static_assert(!traits::ignore_if_empty); static_assert(traits::page_size == 8u); } diff --git a/test/entt/entity/storage.cpp b/test/entt/entity/storage.cpp index 2411a3549..6dc2cf9c0 100644 --- a/test/entt/entity/storage.cpp +++ b/test/entt/entity/storage.cpp @@ -78,7 +78,6 @@ struct crete_from_constructor { template<> struct entt::component_traits> { 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; };