1#ifndef ENTT_ENTITY_VIEW_HPP
2#define ENTT_ENTITY_VIEW_HPP
4#include "../config/config.h"
5#include "../core/concepts.hpp"
6#include "../core/iterator.hpp"
7#include "../core/type_traits.hpp"
8#include "../stl/array.hpp"
9#include "../stl/concepts.hpp"
10#include "../stl/cstddef.hpp"
11#include "../stl/iterator.hpp"
12#include "../stl/tuple.hpp"
13#include "../stl/type_traits.hpp"
14#include "../stl/utility.hpp"
23template<
typename... Type>
25static constexpr bool tombstone_check_v = ((
sizeof...(Type) == 1u) && ... && (Type::storage_policy == deletion_policy::in_place));
27template<cvref_unqualified Type>
28const Type *view_placeholder() {
29 static const Type placeholder{};
33[[nodiscard]]
bool all_of(
auto first,
const auto last,
const auto entt)
noexcept {
34 for(; (first != last) && (*first)->contains(entt); ++first) {}
38[[nodiscard]]
bool none_of(
auto first,
const auto last,
const auto entt)
noexcept {
39 for(; (first != last) && !(*first)->contains(entt); ++first) {}
44[[nodiscard]]
bool fully_initialized(It first,
const It last,
const stl::remove_pointer_t<
typename stl::iterator_traits<It>::value_type> *placeholder)
noexcept {
45 for(; (first != last) && *first != placeholder; ++first) {}
49template<
typename Result,
typename View,
typename Other, stl::size_t... GLhs, stl::size_t... ELhs, stl::size_t... GRhs, stl::size_t... ERhs>
50[[nodiscard]] Result view_pack(
const View &view,
const Other &other, stl::index_sequence<GLhs...>, stl::index_sequence<ELhs...>, stl::index_sequence<GRhs...>, stl::index_sequence<ERhs...>) {
53 elem.pools = {
view.template storage<GLhs>()..., other.template storage<GRhs>()...};
54 [[maybe_unused]]
const auto filter_or_placeholder = [placeholder = elem.placeholder](
auto *value) {
return (value ==
nullptr) ? placeholder : value; };
55 elem.filter = {filter_or_placeholder(
view.template storage<
sizeof...(GLhs) + ELhs>())..., filter_or_placeholder(other.template storage<
sizeof...(GRhs) + ERhs>())...};
60template<
typename Type,
bool Checked, stl::
size_t Get, stl::
size_t Exclude>
61class view_iterator final {
62 template<
typename,
typename...>
63 friend struct extended_view_iterator;
65 using iterator_type = Type::const_iterator;
66 using iterator_traits = stl::iterator_traits<iterator_type>;
68 [[nodiscard]]
bool valid(
const iterator_traits::value_type entt)
const noexcept {
69 return (!Checked || (entt != tombstone))
70 && ((Get == 1u) || (internal::all_of(pools.begin(), pools.begin() + index, entt) && internal::all_of(pools.begin() + index + 1, pools.end(), entt)))
71 && ((Exclude == 0u) || internal::none_of(filter.begin(), filter.end(), entt));
75 for(
constexpr iterator_type sentinel{}; it != sentinel && !valid(*it); ++it) {}
79 using value_type = iterator_traits::value_type;
80 using pointer = iterator_traits::pointer;
81 using reference = iterator_traits::reference;
82 using difference_type = iterator_traits::difference_type;
83 using iterator_category = stl::forward_iterator_tag;
85 constexpr view_iterator() noexcept
91 view_iterator(iterator_type first, stl::array<const Type *, Get> value, stl::array<const Type *, Exclude> excl,
const stl::size_t idx) noexcept
95 index{
static_cast<difference_type
>(idx)} {
96 ENTT_ASSERT((Get != 1u) || (Exclude != 0u) || pools[0u]->policy() == deletion_policy::in_place,
"Non in-place storage view iterator");
100 view_iterator &operator++() noexcept {
106 view_iterator operator++(
int)
noexcept {
107 const view_iterator orig = *
this;
108 return ++(*this), orig;
111 [[nodiscard]] pointer operator->() const noexcept {
115 [[nodiscard]] reference operator*() const noexcept {
116 return *operator->();
119 template<
typename Other,
auto... Args>
120 [[nodiscard]]
constexpr bool operator==(
const view_iterator<Other, Args...> &other)
const noexcept {
121 return it == other.it;
126 stl::array<const Type *, Get> pools;
127 stl::array<const Type *, Exclude> filter;
128 difference_type index;
131template<
typename It,
typename... Get>
132struct extended_view_iterator final {
133 using iterator_type = It;
134 using value_type =
decltype(stl::tuple_cat(stl::make_tuple(*stl::declval<It>()), stl::declval<Get>().get_as_tuple({})...));
135 using pointer = input_iterator_pointer<value_type>;
136 using reference = value_type;
137 using difference_type = stl::ptrdiff_t;
138 using iterator_category = stl::input_iterator_tag;
139 using iterator_concept = stl::forward_iterator_tag;
141 constexpr extended_view_iterator()
144 extended_view_iterator(iterator_type from)
147 extended_view_iterator &operator++() noexcept {
151 extended_view_iterator operator++(
int)
noexcept {
152 const extended_view_iterator orig = *
this;
153 return ++(*this), orig;
156 [[nodiscard]] reference operator*() const noexcept {
157 return [
this]<
auto... Index>(stl::index_sequence<Index...>) {
158 return stl::tuple_cat(stl::make_tuple(*it),
static_cast<Get *
>(
const_cast<constness_as_t<typename Get::base_type, Get> *
>(stl::get<Index>(it.pools)))->get_as_tuple(*it)...);
159 }(stl::index_sequence_for<Get...>{});
162 [[nodiscard]] pointer operator->() const noexcept {
166 [[nodiscard]]
constexpr iterator_type base() const noexcept {
170 template<
typename... Other>
171 [[nodiscard]]
constexpr bool operator==(
const extended_view_iterator<Other...> &other)
const noexcept {
172 return it == other.it;
200template<
typename,
typename>
211template<cvref_unqualified Type,
bool Checked, stl::
size_t Get, stl::
size_t Exclude>
213 template<
typename Return,
typename View,
typename Other, stl::size_t... GLhs, stl::size_t... ELhs, stl::size_t... GRhs, stl::size_t... ERhs>
214 friend Return internal::view_pack(
const View &,
const Other &, stl::index_sequence<GLhs...>, stl::index_sequence<ELhs...>, stl::index_sequence<GRhs...>, stl::index_sequence<ERhs...>);
216 [[nodiscard]]
auto offset()
const noexcept {
217 ENTT_ASSERT(index != Get,
"Invalid view");
221 void unchecked_refresh()
noexcept {
224 if constexpr(Get > 1u) {
225 for(
size_type pos{1u}; pos < Get; ++pos) {
226 if(pools[pos]->size() < pools[index]->size()) {
236 for(
size_type pos{}, last = filter.size(); pos < last; ++pos) {
237 filter[pos] = placeholder;
241 basic_common_view(stl::array<const Type *, Get> value, stl::array<const Type *, Exclude> excl) noexcept
248 [[nodiscard]]
const Type *pool_at(
const stl::size_t pos)
const noexcept {
252 void pool_at(
const stl::size_t pos,
const Type *elem)
noexcept {
253 ENTT_ASSERT(elem !=
nullptr,
"Unexpected element");
258 [[nodiscard]]
const Type *filter_at(
const stl::size_t pos)
const noexcept {
259 return (filter[pos] == placeholder) ? nullptr : filter[pos];
262 void filter_at(
const stl::size_t pos,
const Type *elem)
noexcept {
263 ENTT_ASSERT(elem !=
nullptr,
"Unexpected element");
267 [[nodiscard]]
bool none_of(
const Type::entity_type
entt)
const noexcept {
268 return internal::none_of(filter.begin(), filter.end(),
entt);
271 void use(
const stl::size_t pos)
noexcept {
272 index = (index != Get) ? pos : Get;
286 using iterator = internal::view_iterator<common_type, Checked, Get, Exclude>;
291 for(; pos < Get && pools[pos] !=
nullptr; ++pos) {}
303 return (index != Get) ? pools[index] :
nullptr;
311 return (index != Get) ? offset() :
size_type{};
330 return (index != Get) ?
iterator{pools[index]->end(), pools, filter, index} :
iterator{};
339 const auto it =
begin();
340 return it !=
end() ? *it :
null;
350 auto it = pools[index]->rbegin();
352 for(
const auto idx =
static_cast<difference_type>(index); it != last && !(internal::all_of(pools.begin(), pools.begin() + idx, *it) && internal::all_of(pools.begin() + idx + 1, pools.end(), *it) && internal::none_of(filter.begin(), filter.end(), *it)); ++it) {}
353 return it == last ?
null : *it;
373 [[nodiscard]]
explicit operator bool() const noexcept {
374 return (index != Get) && internal::fully_initialized(filter.begin(), filter.end(), placeholder);
383 return (index != Get)
384 && internal::all_of(pools.begin(), pools.end(),
entt)
385 && internal::none_of(filter.begin(), filter.end(),
entt)
386 && pools[index]->index(
entt) < offset();
390 stl::array<const common_type *, Get> pools{};
391 stl::array<const common_type *, Exclude> filter{};
392 const common_type *placeholder{internal::view_placeholder<common_type>()};
408template<
typename... Get,
typename... Exclude>
409requires (
sizeof...(Get) != 0u)
411 : public
basic_common_view<
stl::common_type_t<typename Get::base_type...>, internal::tombstone_check_v<Get...>, sizeof...(Get), sizeof...(Exclude)> {
412 using base_type =
basic_common_view<stl::common_type_t<
typename Get::base_type...>, internal::tombstone_check_v<Get...>,
sizeof...(Get),
sizeof...(Exclude)>;
414 template<stl::
size_t Index>
417 template<
typename Type>
420 template<stl::size_t Curr, stl::size_t Other,
typename... Args>
421 [[nodiscard]]
auto dispatch_get(
const stl::tuple<typename base_type::entity_type, Args...> &curr)
const {
422 if constexpr(Curr == Other) {
423 return stl::forward_as_tuple(stl::get<Args>(curr)...);
429 template<stl::size_t Curr,
typename Func, stl::size_t... Index>
430 void each(Func func, stl::index_sequence<Index...>)
const {
432 if(
const auto entt = stl::get<0>(curr); (!internal::tombstone_check_v<Get...> || (
entt !=
tombstone)) && ((Curr == Index || base_type::pool_at(Index)->contains(
entt)) && ...) && base_type::none_of(
entt)) {
433 if constexpr(
is_applicable_v<Func,
decltype(stl::tuple_cat(stl::tuple<entity_type>{}, stl::declval<basic_view>().get({})))>) {
434 stl::apply(func, stl::tuple_cat(stl::make_tuple(
entt), dispatch_get<Curr, Index>(curr)...));
436 stl::apply(func, stl::tuple_cat(dispatch_get<Curr, Index>(curr)...));
442 template<
typename Type>
443 void storage_if(Type *elem)
noexcept {
444 if(elem !=
nullptr) {
473 : base_type{{&value...}, {&excl...}} {
481 basic_view(stl::tuple<Get &...> value, stl::tuple<Exclude &...> excl = {})
noexcept
489 template<
typename... Args>
501 template<
typename Type>
510 template<stl::
size_t Index>
512 base_type::use(Index);
520 template<
typename Type>
521 [[nodiscard]]
auto *
storage() const noexcept {
530 template<stl::
size_t Index>
531 [[nodiscard]]
auto *
storage() const noexcept {
532 if constexpr(Index <
sizeof...(Get)) {
544 template<
typename Type>
555 template<stl::
size_t Index,
typename Type>
557 static_assert(stl::is_convertible_v<Type &, element_at<Index> &>,
"Unexpected type");
559 if constexpr(Index <
sizeof...(Get)) {
560 base_type::pool_at(Index, &elem);
562 base_type::filter_at(Index -
sizeof...(Get), &elem);
582 template<
typename Type,
typename... Other>
593 template<stl::size_t... Index>
595 if constexpr(
sizeof...(Index) == 0) {
596 return [
this,
entt]<
auto... Idx>(stl::index_sequence<Idx...>) {
598 }(stl::index_sequence_for<Get...>{});
599 }
else if constexpr(
sizeof...(Index) == 1) {
621 template<
typename Func>
623 [
this, &func]<
auto... Index>(stl::index_sequence<Index...> seq) {
625 ((
view == base_type::pool_at(Index) ? each<Index>(stl::move(func), seq) : void()), ...);
627 }(stl::index_sequence_for<Get...>{});
649 template<stl::derived_from<common_type> OGet>
661 template<stl::derived_from<common_type>... OGet, stl::derived_from<common_type>... OExclude>
664 *
this, other, stl::index_sequence_for<Get...>{}, stl::index_sequence_for<Exclude...>{}, stl::index_sequence_for<OGet...>{}, stl::index_sequence_for<OExclude...>{});
674template<cvref_unqualified Type, deletion_policy Policy>
682 ENTT_ASSERT(leading->policy() == Policy,
"Unexpected storage policy");
696 using iterator = stl::conditional_t<Policy == deletion_policy::in_place, internal::view_iterator<common_type, true, 1u, 0u>,
typename common_type::iterator>;
698 using reverse_iterator = stl::conditional_t<Policy == deletion_policy::in_place, void, typename common_type::reverse_iterator>;
715 return leading ? leading->size() :
size_type{};
718 return leading ? leading->free_list() :
size_type{};
728 return leading ? leading->size() :
size_type{};
735 [[nodiscard]]
bool empty() const noexcept
738 return !leading || leading->empty();
741 return !leading || (leading->free_list() == 0u);
754 return leading ? leading->begin() :
iterator{};
759 return leading ?
iterator{leading->begin(), {leading}, {}, 0u} :
iterator{};
769 return leading ? leading->end() :
iterator{};
811 return empty() ?
null : *leading->begin();
816 const auto it =
begin();
817 return (it ==
end()) ?
null : *it;
828 return empty() ?
null : *leading->rbegin();
833 auto it = leading->rbegin();
834 const auto last = leading->rend();
835 for(; (it != last) && (*it ==
tombstone); ++it) {}
836 return it == last ?
null : *it;
853 const auto it = leading ? leading->find(
entt) :
iterator{};
854 return leading && (
static_cast<size_type>(it.index()) < leading->free_list()) ? it :
iterator{};
864 [[nodiscard]]
explicit operator bool() const noexcept {
865 return (leading !=
nullptr);
875 return leading && leading->contains(
entt);
878 return leading && leading->contains(
entt) && (leading->index(
entt) < leading->free_list());
896template<
typename Get>
901 void storage_if(Get *value)
noexcept {
902 if(value !=
nullptr) {
921 using iterable = stl::conditional_t<Get::storage_policy == deletion_policy::in_place, iterable_adaptor<internal::extended_view_iterator<iterator, Get>>,
decltype(stl::declval<Get>().each())>;
932 : base_type{&value} {
939 basic_view(stl::tuple<Get &> value, stl::tuple<> = {})
noexcept
947 template<
typename... Args>
959 template<
typename Type = Get::element_type>
960 [[nodiscard]]
auto *
storage() const noexcept {
961 static_assert(stl::is_same_v<stl::remove_const_t<Type>,
typename Get::element_type>,
"Invalid element type");
970 template<stl::
size_t Index>
971 [[nodiscard]]
auto *
storage() const noexcept {
972 static_assert(Index == 0u,
"Index out of bounds");
989 template<stl::
size_t Index>
991 static_assert(Index == 0u,
"Index out of bounds");
1018 template<
typename Elem>
1020 static_assert(stl::is_same_v<stl::remove_const_t<Elem>,
typename Get::element_type>,
"Invalid element type");
1030 template<stl::size_t... Index>
1032 if constexpr(
sizeof...(Index) == 0) {
1054 template<
typename Func>
1056 if constexpr(
is_applicable_v<Func,
decltype(stl::tuple_cat(stl::tuple<entity_type>{}, stl::declval<basic_view>().get({})))>) {
1057 for(
const auto pack:
each()) {
1058 stl::apply(func, pack);
1061 if constexpr(stl::is_void_v<typename Get::value_type>) {
1067 for(
auto last =
storage()->
end(), first = last - len; first != last; ++first) {
1075 for(
const auto pack:
each()) {
1076 stl::apply([&func](
const auto,
auto &&...elem) { func(stl::forward<
decltype(elem)>(elem)...); }, pack);
1105 template<stl::derived_from<common_type> OGet>
1117 template<stl::derived_from<common_type>... OGet, stl::derived_from<common_type>... OExclude>
1120 *
this, other, stl::index_sequence_for<Get>{}, stl::index_sequence_for<>{}, stl::index_sequence_for<OGet...>{}, stl::index_sequence_for<OExclude...>{});
1129template<
typename... Type>
1137template<
typename... Get,
typename... Exclude>
1138basic_view(stl::tuple<Get &...>, stl::tuple<Exclude &...> = {}) ->
basic_view<get_t<Get...>, exclude_t<Exclude...>>;
Basic storage view implementation.
iterator begin() const noexcept
Returns an iterator to the first entity of the view.
iterator find(const entity_type entt) const noexcept
Finds an entity.
const common_type * handle() const noexcept
Returns the leading storage of a view, if any.
size_type size_hint() const noexcept
Estimates the number of entities iterated by the view.
bool contains(const entity_type entt) const noexcept
Checks if a view contains an entity.
entity_type back() const noexcept
Returns the last entity of the view, if any.
void refresh() noexcept
Updates the internal leading view if required.
stl::size_t size_type
Unsigned integer type.
Type::entity_type entity_type
Underlying entity identifier.
entity_type front() const noexcept
Returns the first entity of the view, if any.
stl::ptrdiff_t difference_type
Signed integer type.
internal::view_iterator< common_type, Checked, Get, Exclude > iterator
Forward iterator type.
iterator end() const noexcept
Returns an iterator that is past the last entity of the view.
Type common_type
Common type among all storage types.
Basic storage view implementation.
entity_type front() const noexcept
Returns the first entity of the view, if any.
stl::conditional_t< Policy==deletion_policy::in_place, void, typename common_type::reverse_iterator > reverse_iterator
Reverse iterator type.
entity_type back() const noexcept
Returns the last entity of the view, if any.
bool contains(const entity_type entt) const noexcept
Checks if a view contains an entity.
iterator end() const noexcept
Returns an iterator that is past the last entity of the view.
stl::conditional_t< Policy==deletion_policy::in_place, internal::view_iterator< common_type, true, 1u, 0u >, typename common_type::iterator > iterator
Random access iterator type.
size_type size() const noexcept
Returns the number of entities that have the given element.
bool empty() const noexcept
Checks whether a view is empty.
common_type::entity_type entity_type
Underlying entity identifier.
size_type size_hint() const noexcept
Estimates the number of entities iterated by the view.
iterator begin() const noexcept
Returns an iterator to the first entity of the view.
stl::ptrdiff_t difference_type
Signed integer type.
reverse_iterator rend() const noexcept
Returns an iterator that is past the last entity of the reversed view.
const common_type * handle() const noexcept
Returns the leading storage of a view, if any.
Type common_type
Common type among all storage types.
stl::size_t size_type
Unsigned integer type.
iterator find(const entity_type entt) const noexcept
Finds an entity.
reverse_iterator rbegin() const noexcept
Returns an iterator to the first entity of the reversed view.
const value_type & get(const entity_type entt) const noexcept
Returns the object assigned to an entity.
iterable each() noexcept
Returns an iterable object to use to visit a storage.
stl::tuple< const value_type & > get_as_tuple(const entity_type entt) const noexcept
Returns the object assigned to an entity as a tuple.
auto operator|(const basic_view< get_t< OGet... >, exclude_t< OExclude... > > &other) const noexcept
Combines two views in a more specific one.
basic_view(Get &value) noexcept
Constructs a view from a storage class.
void storage(Get &elem) noexcept
Assigns a storage to a view.
Get * operator->() const noexcept
Returns a pointer to the underlying storage.
basic_view< get_t< Get, OGet >, exclude_t<> > operator|(OGet &other) const noexcept
Combines a view and a storage in more specific view.
auto * storage() const noexcept
Returns the storage for a given element type, if any.
basic_view() noexcept
Default constructor to use to create empty, invalid views.
base_type::reverse_iterator reverse_iterator
Reverse iterator type.
stl::conditional_t< Get::storage_policy==deletion_policy::in_place, iterable_adaptor< internal::extended_view_iterator< iterator, Get > >, decltype(stl::declval< Get >().each())> iterable
Iterable view type.
base_type::common_type common_type
Common type among all storage types.
base_type::iterator iterator
Random access iterator type.
void each(Func func) const
Iterates entities and elements and applies the given function object to them.
stl::ptrdiff_t difference_type
Signed integer type.
iterable each() const noexcept
Returns an iterable object to use to visit a view.
base_type::size_type size_type
Unsigned integer type.
base_type::entity_type entity_type
Underlying entity identifier.
void storage(Get &elem) noexcept
Assigns a storage to a view.
basic_view(stl::tuple< Get & > value, stl::tuple<>={}) noexcept
Constructs a view from a storage class.
basic_view(const basic_view< Args... > &other) noexcept
Constructs a view from a convertible counterpart.
decltype(auto) get(const entity_type entt) const
Returns the element assigned to the given entity.
decltype(auto) get(const entity_type entt) const
Returns the elements assigned to the given entity.
stl::ptrdiff_t difference_type
Signed integer type.
basic_view(Get &...value, Exclude &...excl) noexcept
Constructs a view from a set of storage classes.
void use() noexcept
Forces a view to use a given element to drive iterations.
void storage(Type &elem) noexcept
Assigns a storage to a view.
basic_view< get_t< Get..., OGet >, exclude_t< Exclude... > > operator|(OGet &other) const noexcept
Combines a view and a storage in more specific view.
basic_view(stl::tuple< Get &... > value, stl::tuple< Exclude &... > excl={}) noexcept
Constructs a view from a set of storage classes.
iterable_adaptor< internal::extended_view_iterator< iterator, Get... > > iterable
Iterable view type.
basic_view(const basic_view< Args... > &other) noexcept
Constructs a view from a convertible counterpart.
auto * storage() const noexcept
Returns the storage for a given element type, if any.
base_type::common_type common_type
Common type among all storage types.
iterable each() const noexcept
Returns an iterable object to use to visit a view.
void each(Func func) const
Iterates entities and elements and applies the given function object to them.
void storage(Type &elem) noexcept
Assigns a storage to a view.
base_type::size_type size_type
Unsigned integer type.
auto operator|(const basic_view< get_t< OGet... >, exclude_t< OExclude... > > &other) const noexcept
Combines two views in a more specific one.
base_type::iterator iterator
Forward iterator type.
base_type::entity_type entity_type
Underlying entity identifier.
basic_view() noexcept
Default constructor to use to create empty, invalid views.
decltype(auto) get(const entity_type entt) const
Returns the elements assigned to the given entity.
Custom EnTT namespace for the standard template library.
basic_view(Type &...storage) -> basic_view< get_t< Type... >, exclude_t<> >
Deduction guide.
deletion_policy
Storage deletion policy.
@ swap_only
Swap-only deletion policy.
@ swap_and_pop
Swap-and-pop deletion policy.
@ in_place
In-place deletion policy.
type_list_element< Index, List >::type type_list_element_t
Helper type.
constexpr null_t null
Compile-time constant for null entities.
basic_view< type_list_transform_t< Get, storage_for >, type_list_transform_t< Exclude, storage_for > > view
Alias declaration for the most common use case.
constexpr bool is_applicable_v
Helper variable template.
constexpr stl::size_t type_list_index_v
Helper variable template.
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
constexpr get_t< Type... > get
Variable template for lists of observed elements.
constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
basic_storage< Type > storage
Alias declaration for the most common use case.
Alias for exclusion lists.
Alias for lists of observed elements.
Utility class to create an iterable object from a pair of iterators.
A class to use to push around lists of types, nothing more.