component_traits:

* removed ::ignore_if_empty member
* use ::page_size 0 for empty types
This commit is contained in:
Michele Caini
2022-03-02 16:32:38 +01:00
parent 1a62338349
commit 805bb84c8f
6 changed files with 28 additions and 44 deletions

5
TODO
View File

@@ -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<T> 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<E>
* 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

View File

@@ -955,9 +955,8 @@ of `component_traits` implements all the required functionalities.<br/>
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<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/>
`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.<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

View File

@@ -21,15 +21,8 @@ template<typename Type>
struct in_place_delete<Type, std::enable_if_t<Type::in_place_delete>>
: 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>
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`. */
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;
};
/**
* @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
#endif

View File

@@ -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>> {
using alloc_traits = std::allocator_traits<Allocator>;
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 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 {
return packed.first()[pos / comp_traits::page_size][fast_mod(pos, comp_traits::page_size)];
@@ -744,13 +743,12 @@ private:
/*! @copydoc basic_storage */
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>> {
using alloc_traits = std::allocator_traits<Allocator>;
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 comp_traits = component_traits<Type>;
public:
/*! @brief Base type. */

View File

@@ -11,17 +11,25 @@ struct traits_based {};
template<>
struct entt::component_traits<traits_based> {
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<default_params>;
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, DefaultParamsNonEmpty) {
using traits = entt::component_traits<default_params_non_empty>;
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<self_contained>;
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<traits_based>;
static_assert(!traits::in_place_delete);
static_assert(!traits::ignore_if_empty);
static_assert(traits::page_size == 8u);
}

View File

@@ -78,7 +78,6 @@ struct crete_from_constructor {
template<>
struct entt::component_traits<std::unordered_set<char>> {
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;
};