1#ifndef ENTT_ENTITY_STORAGE_HPP
2#define ENTT_ENTITY_STORAGE_HPP
5#include "../config/config.h"
6#include "../core/bit.hpp"
7#include "../core/iterator.hpp"
8#include "../core/memory.hpp"
9#include "../core/type_info.hpp"
10#include "../stl/concepts.hpp"
11#include "../stl/cstddef.hpp"
12#include "../stl/iterator.hpp"
13#include "../stl/memory.hpp"
14#include "../stl/tuple.hpp"
15#include "../stl/type_traits.hpp"
16#include "../stl/utility.hpp"
17#include "../stl/vector.hpp"
18#include "component.hpp"
21#include "sparse_set.hpp"
28template<
typename Container, auto Page>
29class storage_iterator final {
30 template<
typename, auto>
31 friend class storage_iterator;
33 using container_type = stl::remove_const_t<Container>;
34 using alloc_traits = stl::allocator_traits<typename container_type::allocator_type>;
36 using iterator_traits = stl::iterator_traits<stl::conditional_t<
37 stl::is_const_v<Container>,
38 typename alloc_traits::template rebind_traits<typename stl::pointer_traits<typename container_type::value_type>::element_type>::const_pointer,
39 typename alloc_traits::template rebind_traits<typename stl::pointer_traits<typename container_type::value_type>::element_type>::pointer>>;
42 using value_type = iterator_traits::value_type;
43 using pointer = iterator_traits::pointer;
44 using reference = iterator_traits::reference;
45 using difference_type = iterator_traits::difference_type;
46 using iterator_category = stl::random_access_iterator_tag;
48 constexpr storage_iterator() noexcept = default;
50 constexpr storage_iterator(Container *ref, const difference_type idx) noexcept
54 template<stl::same_as<stl::remove_const_t<Container>> Other>
55 requires stl::is_const_v<Container>
56 constexpr storage_iterator(
const storage_iterator<Other, Page> &other) noexcept
57 : storage_iterator{other.payload, other.offset} {}
59 constexpr storage_iterator &operator++() noexcept {
60 return --offset, *
this;
63 constexpr storage_iterator operator++(
int)
noexcept {
64 const storage_iterator orig = *
this;
65 return ++(*this), orig;
68 constexpr storage_iterator &operator--() noexcept {
69 return ++offset, *
this;
72 constexpr storage_iterator operator--(
int)
noexcept {
73 const storage_iterator orig = *
this;
74 return operator--(), orig;
77 constexpr storage_iterator &operator+=(
const difference_type value)
noexcept {
82 constexpr storage_iterator
operator+(
const difference_type value)
const noexcept {
83 storage_iterator copy = *
this;
84 return (copy += value);
87 constexpr storage_iterator &operator-=(
const difference_type value)
noexcept {
88 return (*
this += -value);
91 constexpr storage_iterator operator-(
const difference_type value)
const noexcept {
92 return (*
this + -value);
95 [[nodiscard]]
constexpr reference operator[](
const difference_type value)
const noexcept {
96 const auto pos =
static_cast<Container::size_type
>(index() - value);
97 return (*payload)[pos / Page][
fast_mod(
static_cast<stl::size_t
>(pos), Page)];
100 [[nodiscard]]
constexpr pointer operator->() const noexcept {
101 return stl::addressof(
operator[](0));
104 [[nodiscard]]
constexpr reference operator*() const noexcept {
105 return operator[](0);
108 template<
typename Other, auto Arg>
109 [[nodiscard]]
constexpr stl::ptrdiff_t operator-(
const storage_iterator<Other, Arg> &other)
const noexcept {
111 return other.offset - offset;
114 template<
typename Other, auto Arg>
115 [[nodiscard]]
constexpr bool operator==(
const storage_iterator<Other, Arg> &other)
const noexcept {
116 return offset == other.offset;
119 template<
typename Other, auto Arg>
120 [[nodiscard]]
constexpr auto operator<=>(
const storage_iterator<Other, Arg> &other)
const noexcept {
122 return other.offset <=> offset;
125 [[nodiscard]]
constexpr difference_type index() const noexcept {
131 difference_type offset;
134template<
typename It,
typename... Other>
135class extended_storage_iterator final {
136 template<
typename,
typename...>
137 friend class extended_storage_iterator;
140 using iterator_type = It;
141 using value_type =
decltype(stl::tuple_cat(stl::make_tuple(*stl::declval<It>()), stl::forward_as_tuple(*stl::declval<Other>()...)));
142 using pointer = input_iterator_pointer<value_type>;
143 using reference = value_type;
144 using difference_type = stl::ptrdiff_t;
145 using iterator_category = stl::input_iterator_tag;
146 using iterator_concept = stl::forward_iterator_tag;
148 constexpr extended_storage_iterator()
151 constexpr extended_storage_iterator(iterator_type base, Other... other)
152 : it{base, other...} {}
154 template<
typename... Args>
155 requires (!stl::same_as<Other, Args> && ...) && (stl::constructible_from<Other, Args> && ...)
156 constexpr extended_storage_iterator(
const extended_storage_iterator<It, Args...> &other)
159 constexpr extended_storage_iterator &operator++() noexcept {
160 return ++stl::get<It>(it), (++stl::get<Other>(it), ...), *
this;
163 constexpr extended_storage_iterator operator++(
int)
noexcept {
164 const extended_storage_iterator orig = *
this;
165 return ++(*this), orig;
168 [[nodiscard]]
constexpr pointer operator->() const noexcept {
172 [[nodiscard]]
constexpr reference operator*() const noexcept {
173 return {*stl::get<It>(it), *stl::get<Other>(it)...};
176 [[nodiscard]]
constexpr iterator_type base() const noexcept {
177 return stl::get<It>(it);
180 template<
typename... Args>
181 [[nodiscard]]
constexpr bool operator==(
const extended_storage_iterator<Args...> &other)
const noexcept {
182 return stl::get<0>(it) == stl::get<0>(other.it);
186 stl::tuple<It, Other...> it;
207template<
typename Type,
typename Entity,
typename Allocator>
209 using alloc_traits = stl::allocator_traits<Allocator>;
210 static_assert(stl::is_same_v<typename alloc_traits::value_type, Type>,
"Invalid value type");
211 using container_type = stl::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
216 [[nodiscard]]
auto &element_at(
const stl::size_t pos)
const {
220 auto assure_at_least(
const stl::size_t pos) {
223 if(!(idx < payload.size())) {
224 auto curr = payload.size();
226 payload.resize(idx + 1u,
nullptr);
229 for(
const auto last = payload.size(); curr < last; ++curr) {
234 payload.resize(curr);
242 template<
typename... Args>
243 auto emplace_element(
const Entity
entt,
const bool force_back, Args &&...args) {
247 auto *elem = stl::to_address(assure_at_least(
static_cast<size_type>(it.index())));
258 void shrink_to_size(
const stl::size_t sz) {
262 if constexpr(!stl::is_trivially_destructible_v<element_type>) {
266 alloc_traits::destroy(allocator, stl::addressof(element_at(pos)));
269 alloc_traits::destroy(allocator, stl::addressof(element_at(pos)));
274 for(
auto pos = from, last = payload.size(); pos < last; ++pos) {
278 payload.resize(from);
279 payload.shrink_to_fit();
282 void swap_at(
const stl::size_t lhs,
const stl::size_t rhs) {
284 swap(element_at(lhs), element_at(rhs));
287 void move_to(
const stl::size_t lhs,
const stl::size_t rhs) {
288 auto &elem = element_at(lhs);
291 alloc_traits::destroy(allocator, stl::addressof(elem));
295 [[nodiscard]]
const void *get_at(
const stl::size_t pos)
const final {
296 return stl::addressof(element_at(pos));
299 void swap_or_move([[maybe_unused]]
const stl::size_t from, [[maybe_unused]]
const stl::size_t to)
override {
300 static constexpr bool is_pinned_type = !(stl::is_move_constructible_v<Type> && stl::is_move_assignable_v<Type>);
302 ENTT_ASSERT((from + 1u) && !is_pinned_type,
"Pinned type");
304 if constexpr(!is_pinned_type) {
319 void pop(underlying_iterator first, underlying_iterator last)
override {
326 alloc_traits::destroy(allocator, stl::addressof(elem));
327 }
else if constexpr(stl::is_trivially_destructible_v<element_type>) {
333 [[maybe_unused]]
auto unused = stl::exchange(elem, stl::move(other));
334 alloc_traits::destroy(allocator, stl::addressof(other));
342 if constexpr(stl::is_trivially_destructible_v<element_type>) {
351 alloc_traits::destroy(allocator, stl::addressof(element_at(
static_cast<size_type>(first.index()))));
355 alloc_traits::destroy(allocator, stl::addressof(element_at(
static_cast<size_type>(first.index()))));
368 underlying_iterator
try_emplace([[maybe_unused]]
const Entity
entt, [[maybe_unused]]
const bool force_back,
const void *
value)
override {
369 if(
value !=
nullptr) {
370 if constexpr(stl::is_copy_constructible_v<element_type>) {
376 if constexpr(stl::is_default_constructible_v<element_type>) {
377 return emplace_element(
entt, force_back);
402 using const_pointer = alloc_traits::template rebind_traits<typename alloc_traits::const_pointer>::const_pointer;
404 using iterator = internal::storage_iterator<container_type, traits_type::page_size>;
406 using const_iterator = internal::storage_iterator<const container_type, traits_type::page_size>;
432 payload{allocator} {}
443 payload{stl::move(other.payload)} {}
452 payload{
stl::move(other.payload), allocator} {
453 ENTT_ASSERT(alloc_traits::is_always_equal::value ||
get_allocator() == other.get_allocator(),
"Copying a storage is not allowed");
474 ENTT_ASSERT(alloc_traits::is_always_equal::value ||
get_allocator() == other.get_allocator(),
"Copying a storage is not allowed");
485 swap(payload, other.payload);
494 return payload.get_allocator();
508 assure_at_least(cap - 1u);
532 return payload.data();
537 return payload.data();
590 return stl::make_reverse_iterator(
cend());
600 return stl::make_reverse_iterator(
end());
609 return stl::make_reverse_iterator(
cbegin());
619 return stl::make_reverse_iterator(
begin());
647 return stl::forward_as_tuple(
get(
entt));
652 return stl::forward_as_tuple(
get(
entt));
667 template<
typename... Args>
669 if constexpr(stl::is_aggregate_v<value_type> && (
sizeof...(Args) != 0u || !stl::is_default_constructible_v<value_type>)) {
670 const auto it = emplace_element(
entt,
false, Type{stl::forward<Args>(args)...});
671 return element_at(
static_cast<size_type>(it.index()));
673 const auto it = emplace_element(
entt,
false, stl::forward<Args>(args)...);
674 return element_at(
static_cast<size_type>(it.index()));
685 template<
typename... Func>
688 auto &elem = element_at(idx);
689 (stl::forward<Func>(func)(elem), ...);
707 for(; first != last; ++first) {
708 emplace_element(*first,
true,
value);
726 template<stl::input_iterator It>
727 requires stl::same_as<typename stl::iterator_traits<It>::value_type,
value_type>
728 iterator insert(stl::input_iterator
auto first, stl::input_iterator
auto last, It from) {
729 for(; first != last; ++first, ++from) {
730 emplace_element(*first,
true, *from);
770 container_type payload;
774template<
typename Type,
typename Entity,
typename Allocator>
777 : public
basic_sparse_set<Entity, typename
stl::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
778 using alloc_traits = stl::allocator_traits<Allocator>;
779 static_assert(stl::is_same_v<typename alloc_traits::value_type, Type>,
"Invalid value type");
902 template<
typename... Func>
905 (stl::forward<Func>(func)(), ...);
913 void insert(stl::input_iterator
auto first, stl::input_iterator
auto last,
const auto &...) {
914 for(; first != last; ++first) {
957template<
typename Entity,
typename Allocator>
960 using alloc_traits = stl::allocator_traits<Allocator>;
961 static_assert(stl::is_same_v<typename alloc_traits::value_type, Entity>,
"Invalid value type");
965 auto from_placeholder()
noexcept {
967 ENTT_ASSERT(
entt !=
null,
"No more entities available");
972 auto next()
noexcept {
976 entt = from_placeholder();
994 underlying_iterator
try_emplace(
const Entity hint,
const bool,
const void *)
override {
1046 placeholder{other.placeholder} {}
1056 placeholder{other.placeholder} {}
1073 placeholder = other.placeholder;
1084 swap(placeholder, other.placeholder);
1108 return stl::tuple{};
1146 template<stl::output_iterator<entity_type> It>
1152 for(; first != last; ++first) {
1163 template<
typename... Func>
1166 (stl::forward<Func>(func)(), ...);
1177 return stl::as_const(*this).each();
1195 return stl::as_const(*this).reach();
static constexpr value_type construct(const entity_type entity, const version_type version) noexcept
internal::entt_traits< Type >::entity_type entity_type
static constexpr entity_type to_entity(const value_type value) noexcept
static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept
static constexpr version_type to_version(const value_type value) noexcept
iterator begin() const noexcept
const_iterator cbegin() const noexcept
virtual basic_iterator try_emplace(const Entity entt, const bool force_back, const void *=nullptr)
iterator end() const noexcept
reverse_iterator rend() const noexcept
pointer data() const noexcept
virtual void reserve(const size_type cap)
size_type size() const noexcept
basic_sparse_set & operator=(const basic_sparse_set &)=delete
virtual void shrink_to_fit()
void swap(basic_sparse_set &other) noexcept
const_iterator find(const entity_type entt) const noexcept
void in_place_pop(const Entity entt)
virtual void pop(basic_iterator first, basic_iterator last)
version_type current(const entity_type entt) const noexcept
Returns the contained version for an identifier.
bool contains(const entity_type entt) const noexcept
const_iterator cend() const noexcept
const_reverse_iterator crend() const noexcept
constexpr allocator_type get_allocator() const noexcept
const void * value(const entity_type entt) const noexcept
reverse_iterator rbegin() const noexcept
entity_type operator[](const size_type pos) const noexcept
size_type free_list() const noexcept
Returns data on the free list whose meaning depends on the mode.
void swap_and_pop(const Entity entt)
internal::sparse_set_iterator< packed_container_type > basic_iterator
const_reverse_iterator crbegin() const noexcept
size_type index(const entity_type entt) const noexcept
const_reverse_iterable reach() const noexcept
Returns a reverse iterable object to use to visit a storage.
stl::size_t size_type
Unsigned integer type.
stl::ptrdiff_t difference_type
Signed integer type.
stl::tuple get_as_tuple(const entity_type entt) const noexcept
Returns an empty tuple.
iterable_adaptor< internal::extended_storage_iterator< typename base_type::reverse_iterator > > reverse_iterable
Extended reverse iterable storage proxy.
static constexpr deletion_policy storage_policy
Storage deletion policy.
void get(const entity_type entt) const noexcept
Returns the object assigned to an entity, that is void.
void value_type
Type of the objects assigned to entities.
entity_type generate(const entity_type hint)
Creates a new identifier or recycles a destroyed one.
iterable_adaptor< internal::extended_storage_iterator< typename base_type::const_iterator > > const_iterable
Constant extended iterable storage proxy.
Entity entity_type
Underlying entity identifier.
void pop_all() override
Erases all entities of a storage.
~basic_storage() override=default
Default destructor.
underlying_iterator try_emplace(const Entity hint, const bool, const void *) override
Assigns an entity to a storage.
basic_storage & operator=(basic_storage &&other) noexcept
Move assignment operator.
entity_type generate()
Creates a new identifier or recycles a destroyed one.
reverse_iterable reach() noexcept
Returns a reverse iterable object to use to visit a storage.
basic_storage(basic_storage &&other, const allocator_type &allocator)
Allocator-extended move constructor.
void swap(basic_storage &other) noexcept
Exchanges the contents with those of a given storage.
Entity element_type
Element type.
const_iterable each() const noexcept
Returns an iterable object to use to visit a storage.
basic_storage(const allocator_type &allocator)
Constructs an empty container with a given allocator.
void generate(It first, It last)
Assigns each element in a range an identifier.
Allocator allocator_type
Allocator type.
iterable_adaptor< internal::extended_storage_iterator< typename base_type::const_reverse_iterator > > const_reverse_iterable
Constant extended reverse iterable storage proxy.
iterable_adaptor< internal::extended_storage_iterator< typename base_type::iterator > > iterable
Extended iterable storage proxy.
basic_sparse_set< Entity, Allocator > base_type
Base type.
basic_storage(basic_storage &&other) noexcept
Move constructor.
iterable each() noexcept
Returns an iterable object to use to visit a storage.
basic_storage(const basic_storage &)=delete
Default copy constructor, deleted on purpose.
void patch(const entity_type entt, Func &&...func)
Updates a given identifier.
basic_storage()
Default constructor.
void start_from(const entity_type hint)
Sets the starting identifier for generation.
basic_storage & operator=(const basic_storage &)=delete
Default copy assignment operator, deleted on purpose.
Type element_type
Element type.
iterable_adaptor< internal::extended_storage_iterator< typename base_type::reverse_iterator > > reverse_iterable
Extended reverse iterable storage proxy.
basic_storage(const basic_storage &)=delete
Default copy constructor, deleted on purpose.
iterable each() noexcept
Returns an iterable object to use to visit a storage.
void insert(stl::input_iterator auto first, stl::input_iterator auto last, const auto &...)
Assigns entities to a storage.
const_iterable each() const noexcept
Returns an iterable object to use to visit a storage.
void emplace(const entity_type entt, const auto &...)
Assigns an entity to a storage and constructs its object.
stl::tuple get_as_tuple(const entity_type entt) const noexcept
Returns an empty tuple.
void get(const entity_type entt) const noexcept
Returns the object assigned to an entity, that is void.
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
iterable_adaptor< internal::extended_storage_iterator< typename base_type::const_reverse_iterator > > const_reverse_iterable
Constant extended reverse iterable storage proxy.
stl::ptrdiff_t difference_type
Signed integer type.
void value_type
Type of the objects assigned to entities.
basic_storage(basic_storage &&other, const allocator_type &allocator)
Allocator-extended move constructor.
stl::size_t size_type
Unsigned integer type.
basic_storage & operator=(basic_storage &&other) noexcept=default
Move assignment operator.
basic_storage()
Default constructor.
iterable_adaptor< internal::extended_storage_iterator< typename base_type::iterator > > iterable
Extended iterable storage proxy.
void patch(const entity_type entt, Func &&...func)
Updates the instance assigned to a given entity in-place.
basic_storage & operator=(const basic_storage &)=delete
Default copy assignment operator, deleted on purpose.
static constexpr deletion_policy storage_policy
Storage deletion policy.
const_reverse_iterable reach() const noexcept
Returns a reverse iterable object to use to visit a storage.
Entity entity_type
Underlying entity identifier.
basic_storage(basic_storage &&other) noexcept=default
Move constructor.
iterable_adaptor< internal::extended_storage_iterator< typename base_type::const_iterator > > const_iterable
Constant extended iterable storage proxy.
Allocator allocator_type
Allocator type.
basic_sparse_set< Entity, typename alloc_traits::template rebind_alloc< Entity > > base_type
Base type.
~basic_storage() override=default
Default destructor.
reverse_iterable reach() noexcept
Returns a reverse iterable object to use to visit a storage.
basic_storage(const allocator_type &allocator)
Constructs an empty container with a given allocator.
const value_type & get(const entity_type entt) const noexcept
Returns the object assigned to an entity.
iterator begin() noexcept
Returns an iterator to the beginning.
const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
basic_storage(const basic_storage &)=delete
Default copy constructor, deleted on purpose.
void pop(underlying_iterator first, underlying_iterator last) override
Erases entities from a storage.
iterable each() noexcept
Returns an iterable object to use to visit a storage.
stl::tuple< value_type & > get_as_tuple(const entity_type entt) noexcept
Returns the object assigned to an entity as a tuple.
const_reverse_iterator crend() const noexcept
Returns a reverse iterator to the end.
const_iterable each() const noexcept
Returns an iterable object to use to visit a storage.
container_type::pointer pointer
value_type & emplace(const entity_type entt, Args &&...args)
Assigns an entity to a storage and constructs its object.
internal::storage_iterator< container_type, traits_type::page_size > iterator
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
const_pointer raw() const noexcept
Direct access to the array of objects.
stl::ptrdiff_t difference_type
iterator end() noexcept
Returns an iterator to the end.
basic_storage(basic_storage &&other, const allocator_type &allocator)
Allocator-extended move constructor.
alloc_traits::template rebind_traits< typename alloc_traits::const_pointer >::const_pointer const_pointer
iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, const value_type &value={})
Assigns one or more entities to a storage and constructs their objects from a given instance.
~basic_storage() override
Default destructor.
stl::size_t size_type
Unsigned integer type.
void reserve(const size_type cap) override
Increases the capacity of a storage.
internal::storage_iterator< const container_type, traits_type::page_size > const_iterator
basic_storage()
Default constructor.
underlying_type base_type
iterable_adaptor< internal::extended_storage_iterator< typename base_type::const_reverse_iterator, const_reverse_iterator > > const_reverse_iterable
iterable_adaptor< internal::extended_storage_iterator< typename base_type::iterator, iterator > > iterable
basic_storage & operator=(const basic_storage &)=delete
Default copy assignment operator, deleted on purpose.
pointer raw() noexcept
Direct access to the array of objects.
value_type & patch(const entity_type entt, Func &&...func)
Updates the instance assigned to a given entity in-place.
reverse_iterator rbegin() noexcept
Returns a reverse iterator to the beginning.
static constexpr deletion_policy storage_policy
const_reverse_iterator crbegin() const noexcept
Returns a reverse iterator to the beginning.
const_reverse_iterable reach() const noexcept
Returns a reverse iterable object to use to visit a storage.
const_iterator cend() const noexcept
Returns an iterator to the end.
underlying_iterator try_emplace(const Entity entt, const bool force_back, const void *value) override
Assigns an entity to a storage.
size_type capacity() const noexcept override
Returns the number of elements that a storage has currently allocated space for.
iterable_adaptor< internal::extended_storage_iterator< typename base_type::const_iterator, const_iterator > > const_iterable
const_reverse_iterator rend() const noexcept
Returns a reverse iterator to the end.
reverse_iterator rend() noexcept
Returns a reverse iterator to the end.
void shrink_to_fit() override
Requests the removal of unused capacity.
iterable_adaptor< internal::extended_storage_iterator< typename base_type::reverse_iterator, reverse_iterator > > reverse_iterable
void swap(basic_storage &other) noexcept
Exchanges the contents with those of a given storage.
const_reverse_iterator rbegin() const noexcept
Returns a reverse iterator to the beginning.
Allocator allocator_type
Allocator type.
void pop_all() override
Erases all entities of a storage.
basic_storage(basic_storage &&other) noexcept
Move constructor.
iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, It from)
Assigns one or more entities to a storage and constructs their objects from a given range.
stl::tuple< const value_type & > get_as_tuple(const entity_type entt) const noexcept
Returns the object assigned to an entity as a tuple.
value_type & get(const entity_type entt) noexcept
Returns the object assigned to an entity.
basic_storage & operator=(basic_storage &&other) noexcept
Move assignment operator.
reverse_iterable reach() noexcept
Returns a reverse iterable object to use to visit a storage.
const_iterator begin() const noexcept
Returns an iterator to the beginning.
basic_storage(const allocator_type &allocator)
Constructs an empty storage with a given allocator.
stl::reverse_iterator< iterator > reverse_iterator
stl::reverse_iterator< const_iterator > const_reverse_iterator
const_iterator end() const noexcept
Returns an iterator to the end.
Custom EnTT namespace for the standard template library.
deletion_policy
Storage deletion policy.
@ swap_only
Swap-only deletion policy.
constexpr null_t null
Compile-time constant for null entities.
constexpr Type * uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
constexpr get_t< Type... > get
Variable template for lists of observed elements.
constexpr type_list< Type..., Other... > operator+(type_list< Type... >, type_list< Other... >)
Concatenates multiple type lists.
@ ref
Aliasing mode, non-const reference.
const type_info & type_id() noexcept
Returns the type info object associated to a given type.
constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept
Fast module utility function (powers of two only).
Common way to access various properties of components.
static constexpr stl::size_t page_size
Page size, default is ENTT_PACKED_PAGE for non-empty types.
static constexpr bool in_place_delete
Pointer stability, default is false.
Utility class to create an iterable object from a pair of iterators.