component_traits:
* removed ::ignore_if_empty member * use ::page_size 0 for empty types
This commit is contained in:
5
TODO
5
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<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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user