1#ifndef ENTT_ENTITY_VIEW_HPP
2#define ENTT_ENTITY_VIEW_HPP
10#include "../config/config.h"
11#include "../core/iterator.hpp"
12#include "../core/type_traits.hpp"
21template<
typename Type>
22const Type *view_placeholder() {
23 static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>,
"Unexpected type");
24 static const Type placeholder{};
28template<
typename It,
typename Entity>
29[[nodiscard]]
bool all_of(It first,
const It last,
const Entity
entt)
noexcept {
30 for(; (first != last) && (*first)->contains(
entt); ++first) {}
34template<
typename It,
typename Entity>
35[[nodiscard]]
bool none_of(It first,
const It last,
const Entity
entt)
noexcept {
36 for(; (first != last) && !(*first)->contains(
entt); ++first) {}
41[[nodiscard]]
bool fully_initialized(It first,
const It last)
noexcept {
42 for(
const auto *placeholder = view_placeholder<std::remove_const_t<std::remove_pointer_t<
typename std::iterator_traits<It>::value_type>>>(); (first != last) && *first != placeholder; ++first) {}
46template<
typename Result,
typename View,
typename Other, std::size_t... GLhs, std::size_t... ELhs, std::size_t... GRhs, std::size_t... ERhs>
47[[nodiscard]] Result view_pack(
const View &view,
const Other &other, std::index_sequence<GLhs...>, std::index_sequence<ELhs...>, std::index_sequence<GRhs...>, std::index_sequence<ERhs...>) {
50 elem.pools = {
view.template storage<GLhs>()..., other.template storage<GRhs>()...};
51 elem.filter = {
view.template
storage<
sizeof...(GLhs) + ELhs>()..., other.template
storage<
sizeof...(GRhs) + ERhs>()...};
56template<
typename Type, std::
size_t Get, std::
size_t Exclude>
57class view_iterator final {
58 template<
typename,
typename...>
59 friend class extended_view_iterator;
61 using iterator_type =
typename Type::const_iterator;
62 using iterator_traits = std::iterator_traits<iterator_type>;
64 [[nodiscard]]
bool valid(
const typename iterator_traits::value_type
entt)
const noexcept {
65 return ((Get != 1u) || (
entt != tombstone))
66 && internal::all_of(pools.begin(), pools.begin() + index,
entt) && internal::all_of(pools.begin() + index + 1, pools.end(),
entt)
67 && internal::none_of(filter.begin(), filter.end(),
entt);
71 for(
constexpr iterator_type sentinel{}; it != sentinel && !valid(*it); ++it) {}
75 using value_type =
typename iterator_traits::value_type;
76 using pointer =
typename iterator_traits::pointer;
77 using reference =
typename iterator_traits::reference;
78 using difference_type =
typename iterator_traits::difference_type;
79 using iterator_category = std::forward_iterator_tag;
81 constexpr view_iterator() noexcept
87 view_iterator(iterator_type first, std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl,
const std::size_t idx) noexcept
95 view_iterator &operator++() noexcept {
101 view_iterator operator++(
int)
noexcept {
102 view_iterator orig = *
this;
103 return ++(*this), orig;
106 [[nodiscard]] pointer operator->() const noexcept {
110 [[nodiscard]] reference operator*() const noexcept {
111 return *operator->();
114 template<
typename LhsType,
auto... LhsArgs,
typename RhsType,
auto... RhsArgs>
115 friend constexpr bool operator==(
const view_iterator<LhsType, LhsArgs...> &,
const view_iterator<RhsType, RhsArgs...> &)
noexcept;
119 std::array<const Type *, Get> pools;
120 std::array<const Type *, Exclude> filter;
124template<
typename LhsType,
auto... LhsArgs,
typename RhsType,
auto... RhsArgs>
125[[nodiscard]]
constexpr bool operator==(
const view_iterator<LhsType, LhsArgs...> &lhs,
const view_iterator<RhsType, RhsArgs...> &rhs)
noexcept {
126 return lhs.it == rhs.it;
129template<
typename LhsType,
auto... LhsArgs,
typename RhsType,
auto... RhsArgs>
130[[nodiscard]]
constexpr bool operator!=(
const view_iterator<LhsType, LhsArgs...> &lhs,
const view_iterator<RhsType, RhsArgs...> &rhs)
noexcept {
131 return !(lhs == rhs);
134template<
typename It,
typename... Get>
135class extended_view_iterator final {
136 template<std::size_t... Index>
137 [[nodiscard]]
auto dereference(std::index_sequence<Index...>)
const noexcept {
138 return std::tuple_cat(std::make_tuple(*it),
static_cast<Get *
>(
const_cast<constness_as_t<typename Get::base_type, Get> *
>(std::get<Index>(it.pools)))->get_as_tuple(*it)...);
142 using iterator_type = It;
143 using value_type =
decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Get>().get_as_tuple({})...));
144 using pointer = input_iterator_pointer<value_type>;
145 using reference = value_type;
146 using difference_type = std::ptrdiff_t;
147 using iterator_category = std::input_iterator_tag;
148 using iterator_concept = std::forward_iterator_tag;
150 constexpr extended_view_iterator()
153 extended_view_iterator(iterator_type from)
156 extended_view_iterator &operator++() noexcept {
160 extended_view_iterator operator++(
int)
noexcept {
161 extended_view_iterator orig = *
this;
162 return ++(*this), orig;
165 [[nodiscard]] reference operator*() const noexcept {
166 return dereference(std::index_sequence_for<Get...>{});
169 [[nodiscard]] pointer operator->() const noexcept {
173 [[nodiscard]]
constexpr iterator_type base() const noexcept {
177 template<
typename... Lhs,
typename... Rhs>
178 friend bool constexpr operator==(
const extended_view_iterator<Lhs...> &,
const extended_view_iterator<Rhs...> &)
noexcept;
184template<
typename... Lhs,
typename... Rhs>
185[[nodiscard]]
constexpr bool operator==(
const extended_view_iterator<Lhs...> &lhs,
const extended_view_iterator<Rhs...> &rhs)
noexcept {
186 return lhs.it == rhs.it;
189template<
typename... Lhs,
typename... Rhs>
190[[nodiscard]]
constexpr bool operator!=(
const extended_view_iterator<Lhs...> &lhs,
const extended_view_iterator<Rhs...> &rhs)
noexcept {
191 return !(lhs == rhs);
215template<
typename,
typename,
typename>
225template<
typename Type, std::
size_t Get, std::
size_t Exclude>
227 static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>,
"Unexpected type");
229 template<
typename Return,
typename View,
typename Other, std::size_t... GLhs, std::size_t... ELhs, std::size_t... GRhs, std::size_t... ERhs>
230 friend Return internal::view_pack(
const View &,
const Other &, std::index_sequence<GLhs...>, std::index_sequence<ELhs...>, std::index_sequence<GRhs...>, std::index_sequence<ERhs...>);
232 [[nodiscard]]
auto offset()
const noexcept {
233 ENTT_ASSERT(index != Get,
"Invalid view");
237 void unchecked_refresh()
noexcept {
240 if constexpr(Get > 1u) {
241 for(
size_type pos{1u}; pos < Get; ++pos) {
242 if(pools[pos]->size() < pools[index]->size()) {
252 for(
size_type pos{}; pos < Exclude; ++pos) {
253 filter[pos] = internal::view_placeholder<Type>();
257 basic_common_view(std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl) noexcept
264 [[nodiscard]]
const Type *pool_at(
const std::size_t pos)
const noexcept {
268 [[nodiscard]]
const Type *
storage(
const std::size_t pos)
const noexcept {
273 if(
const auto idx = pos - Get; filter[idx] != internal::view_placeholder<Type>()) {
280 void storage(
const std::size_t pos,
const Type *elem)
noexcept {
281 ENTT_ASSERT(elem !=
nullptr,
"Unexpected element");
287 filter[pos - Get] = elem;
291 [[nodiscard]]
bool none_of(
const typename Type::entity_type
entt)
const noexcept {
292 return internal::none_of(filter.begin(), filter.end(),
entt);
295 void use(
const std::size_t pos)
noexcept {
296 index = (index != Get) ? pos : Get;
308 using iterator = internal::view_iterator<common_type, Get, Exclude>;
313 for(; pos < Get && pools[pos] !=
nullptr; ++pos) {}
325 return (index != Get) ? pools[index] :
nullptr;
333 return (index != Get) ? offset() :
size_type{};
344 return (index != Get) ?
iterator{pools[index]->end() -
static_cast<typename iterator::difference_type
>(offset()), pools, filter, index} :
iterator{};
352 return (index != Get) ?
iterator{pools[index]->end(), pools, filter, index} :
iterator{};
361 const auto it =
begin();
362 return it !=
end() ? *it :
null;
372 auto it = pools[index]->rbegin();
373 const auto last = it +
static_cast<typename iterator::difference_type
>(offset());
374 for(; it != last && !
contains(*it); ++it) {}
375 return it == last ?
null : *it;
395 [[nodiscard]]
explicit operator bool() const noexcept {
396 return (index != Get) && internal::fully_initialized(filter.begin(), filter.end());
405 return (index != Get)
406 && internal::all_of(pools.begin(), pools.end(),
entt)
407 && internal::none_of(filter.begin(), filter.end(),
entt)
408 && pools[index]->index(
entt) < offset();
412 std::array<const common_type *, Get> pools{};
413 std::array<const common_type *, Exclude> filter{};
429template<
typename... Get,
typename... Exclude>
431 :
public basic_common_view<std::common_type_t<typename Get::base_type..., typename Exclude::base_type...>, sizeof...(Get), sizeof...(Exclude)> {
432 using base_type =
basic_common_view<std::common_type_t<
typename Get::base_type...,
typename Exclude::base_type...>,
sizeof...(Get),
sizeof...(Exclude)>;
434 template<
typename Type>
437 template<std::size_t... Index>
442 template<std::size_t Curr, std::size_t Other,
typename... Args>
443 [[nodiscard]]
auto dispatch_get(
const std::tuple<typename base_type::entity_type, Args...> &curr)
const {
444 if constexpr(Curr == Other) {
445 return std::forward_as_tuple(std::get<Args>(curr)...);
451 template<std::size_t Curr,
typename Func, std::size_t... Index>
452 void each(Func &func, std::index_sequence<Index...>)
const {
453 static constexpr bool tombstone_check_required = ((
sizeof...(Get) == 1u) && ... && (Get::storage_policy ==
deletion_policy::in_place));
456 if(
const auto entt = std::get<0>(curr); (!tombstone_check_required || (
entt !=
tombstone)) && ((Curr == Index || base_type::pool_at(Index)->contains(
entt)) && ...) && base_type::none_of(
entt)) {
457 if constexpr(
is_applicable_v<Func,
decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
458 std::apply(func, std::tuple_cat(std::make_tuple(
entt), dispatch_get<Curr, Index>(curr)...));
460 std::apply(func, std::tuple_cat(dispatch_get<Curr, Index>(curr)...));
466 template<
typename Func, std::size_t... Index>
467 void pick_and_each(Func &func, std::index_sequence<Index...> seq)
const {
468 if(
const auto *
view = base_type::handle();
view !=
nullptr) {
469 ((
view == base_type::pool_at(Index) ? each<Index>(func, seq) : void()), ...);
503 basic_view(std::tuple<Get &...> value, std::tuple<Exclude &...> excl = {})
noexcept
510 template<
typename Type>
512 use<index_of<Type>>();
519 template<std::
size_t Index>
521 base_type::use(Index);
529 template<
typename Type>
530 [[nodiscard]]
auto *
storage() const noexcept {
539 template<std::
size_t Index>
540 [[nodiscard]]
auto *
storage() const noexcept {
550 template<
typename Type>
561 template<std::
size_t Index,
typename Type>
564 base_type::storage(Index, &elem);
583 template<
typename Type,
typename... Other>
594 template<std::size_t... Index>
596 if constexpr(
sizeof...(Index) == 0) {
597 return get(
entt, std::index_sequence_for<Get...>{});
598 }
else if constexpr(
sizeof...(Index) == 1) {
620 template<
typename Func>
622 pick_and_each(func, std::index_sequence_for<Get...>{});
635 return iterable{base_type::begin(), base_type::end()};
645 template<
typename... OGet,
typename... OExclude>
648 *
this, other, std::index_sequence_for<Get...>{}, std::index_sequence_for<Exclude...>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
658template<
typename Type, deletion_policy Policy>
660 static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>,
"Unexpected type");
668 ENTT_ASSERT(leading->policy() == Policy,
"Unexpected storage policy");
680 using iterator = std::conditional_t<Policy == deletion_policy::in_place, internal::view_iterator<common_type, 1u, 0u>,
typename common_type::iterator>;
682 using reverse_iterator = std::conditional_t<Policy == deletion_policy::in_place, void, typename common_type::reverse_iterator>;
698 [[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, size_type>
size() const noexcept {
700 return leading ? leading->size() :
size_type{};
703 return leading ? leading->free_list() :
size_type{};
713 [[nodiscard]] std::enable_if_t<Pol == deletion_policy::in_place, size_type>
size_hint() const noexcept {
714 return leading ? leading->size() :
size_type{};
723 [[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, bool>
empty() const noexcept {
725 return !leading || leading->empty();
728 return !leading || (leading->free_list() == 0u);
741 return leading ? leading->begin() :
iterator{};
743 return leading ? (leading->end() - leading->free_list()) :
iterator{};
746 return leading ?
iterator{leading->begin(), {leading}, {}, 0u} :
iterator{};
756 return leading ? leading->end() :
iterator{};
772 [[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, reverse_iterator>
rbegin() const noexcept {
784 [[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, reverse_iterator>
rend() const noexcept {
789 return leading ? (leading->rbegin() + leading->free_list()) :
reverse_iterator{};
800 return empty() ?
null : *leading->begin();
802 return empty() ?
null : *(leading->end() - leading->free_list());
805 const auto it =
begin();
806 return (it ==
end()) ?
null : *it;
817 return empty() ?
null : *leading->rbegin();
822 auto it = leading->rbegin();
823 const auto last = leading->rend();
824 for(; (it != last) && (*it ==
tombstone); ++it) {}
825 return it == last ?
null : *it;
842 const auto it = leading ? leading->find(
entt) :
iterator{};
843 return leading && (
static_cast<size_type>(it.index()) < leading->free_list()) ? it :
iterator{};
845 const auto it = leading ? leading->find(
entt) :
typename common_type::iterator{};
846 return iterator{it, {leading}, {}, 0u};
854 [[nodiscard]]
explicit operator bool() const noexcept {
855 return (leading !=
nullptr);
865 return leading && leading->contains(
entt);
868 return leading && leading->contains(
entt) && (leading->index(
entt) < leading->free_list());
886template<
typename Get>
903 using iterable = std::conditional_t<Get::storage_policy == deletion_policy::in_place, iterable_adaptor<internal::extended_view_iterator<iterator, Get>>,
decltype(std::declval<Get>().each())>;
921 basic_view(std::tuple<Get &> value, std::tuple<> = {})
noexcept
929 template<
typename Type =
typename Get::element_type>
930 [[nodiscard]]
auto *
storage() const noexcept {
931 static_assert(std::is_same_v<std::remove_const_t<Type>,
typename Get::element_type>,
"Invalid element type");
940 template<std::
size_t Index>
941 [[nodiscard]]
auto *
storage() const noexcept {
942 static_assert(Index == 0u,
"Index out of bounds");
959 template<std::
size_t Index>
961 static_assert(Index == 0u,
"Index out of bounds");
988 template<
typename Elem>
990 static_assert(std::is_same_v<std::remove_const_t<Elem>,
typename Get::element_type>,
"Invalid element type");
1000 template<std::size_t... Index>
1002 if constexpr(
sizeof...(Index) == 0) {
1024 template<
typename Func>
1026 if constexpr(
is_applicable_v<Func,
decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
1027 for(
const auto pack: each()) {
1028 std::apply(func, pack);
1031 if constexpr(std::is_void_v<typename Get::value_type>) {
1032 for(
size_type pos = base_type::size(); pos; --pos) {
1036 if(
const auto len = base_type::size(); len != 0u) {
1037 for(
auto last =
storage()->end(), first = last - len; first != last; ++first) {
1045 for(
const auto pack: each()) {
1046 std::apply([&func](
const auto,
auto &&...elem) { func(std::forward<
decltype(elem)>(elem)...); }, pack);
1065 return iterable{base_type::begin(), base_type::end()};
1076 template<
typename... OGet,
typename... OExclude>
1079 *
this, other, std::index_sequence_for<Get>{}, std::index_sequence_for<>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
1088template<
typename... Type>
1096template<
typename... Get,
typename... Exclude>
1097basic_view(std::tuple<Get &...>, std::tuple<Exclude &...> = {}) ->
basic_view<get_t<Get...>, exclude_t<Exclude...>>;
Basic storage view implementation.
size_type size_hint() const noexcept
Estimates the number of entities iterated by the view.
void refresh() noexcept
Updates the internal leading view if required.
Type common_type
Common type among all storage types.
const common_type * handle() const noexcept
Returns the leading storage of a view, if any.
bool contains(const entity_type entt) const noexcept
Checks if a view contains an entity.
iterator begin() const noexcept
Returns an iterator to the first entity of the view.
entity_type back() const noexcept
Returns the last entity of the view, if any.
entity_type front() const noexcept
Returns the first entity of the view, if any.
std::size_t size_type
Unsigned integer type.
iterator end() const noexcept
Returns an iterator that is past the last entity of the view.
iterator find(const entity_type entt) const noexcept
Finds an entity.
internal::view_iterator< common_type, Get, Exclude > iterator
Forward iterator type.
typename Type::entity_type entity_type
Underlying entity identifier.
Basic storage view implementation.
entity_type front() const noexcept
Returns the first entity of the view, if any.
std::enable_if_t< Pol !=deletion_policy::in_place, bool > empty() const noexcept
Checks whether a view is empty.
std::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.
std::enable_if_t< Pol !=deletion_policy::in_place, reverse_iterator > rend() const noexcept
Returns an iterator that is past the last entity of the reversed view.
iterator end() const noexcept
Returns an iterator that is past the last entity of the view.
std::conditional_t< Policy==deletion_policy::in_place, internal::view_iterator< common_type, 1u, 0u >, typename common_type::iterator > iterator
Random access iterator type.
std::enable_if_t< Pol==deletion_policy::in_place, size_type > size_hint() const noexcept
Estimates the number of entities iterated by the view.
std::enable_if_t< Pol !=deletion_policy::in_place, reverse_iterator > rbegin() const noexcept
Returns an iterator to the first entity of the reversed view.
std::enable_if_t< Pol !=deletion_policy::in_place, size_type > size() const noexcept
Returns the number of entities that have the given element.
std::size_t size_type
Unsigned integer type.
typename common_type::entity_type entity_type
Underlying entity identifier.
iterator begin() const noexcept
Returns an iterator to the first entity of the 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.
iterator find(const entity_type entt) const noexcept
Finds an entity.
basic_view(std::tuple< Get & > value, std::tuple<>={}) noexcept
Constructs a view from a storage class.
typename base_type::entity_type entity_type
Underlying entity identifier.
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.
typename base_type::common_type common_type
Common type among all storage types.
typename base_type::reverse_iterator reverse_iterator
Reverse iterator type.
typename base_type::iterator iterator
Random access iterator type.
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.
void each(Func func) const
Iterates entities and elements and applies the given function object to them.
iterable each() const noexcept
Returns an iterable object to use to visit a view.
void storage(Get &elem) noexcept
Assigns a storage to a view.
typename base_type::size_type size_type
Unsigned integer type.
std::conditional_t< Get::storage_policy==deletion_policy::in_place, iterable_adaptor< internal::extended_view_iterator< iterator, Get > >, decltype(std::declval< Get >().each())> iterable
Iterable view type.
decltype(auto) get(const entity_type entt) const
Returns the element assigned to the given entity.
typename base_type::entity_type entity_type
Underlying entity identifier.
typename base_type::common_type common_type
Common type among all storage types.
basic_view() noexcept
Default constructor to use to create empty, invalid views.
void each(Func func) const
Iterates entities and elements and applies the given function object to them.
decltype(auto) get(const entity_type entt) const
Returns the elements assigned to the given entity.
void storage(Type &elem) noexcept
Assigns a storage to a view.
void storage(Type &elem) noexcept
Assigns a storage to a view.
auto operator|(const basic_view< get_t< OGet... >, exclude_t< OExclude... > > &other) const noexcept
Combines two views in a more specific one.
typename base_type::iterator iterator
Forward iterator type.
iterable each() const noexcept
Returns an iterable object to use to visit a view.
decltype(auto) get(const entity_type entt) const
Returns the elements assigned to the given entity.
void use() noexcept
Forces a view to use a given element to drive iterations.
basic_view(std::tuple< Get &... > value, std::tuple< Exclude &... > excl={}) noexcept
Constructs a view from a set of storage classes.
basic_view(Get &...value, Exclude &...excl) noexcept
Constructs a view from a set of storage classes.
auto * storage() const noexcept
Returns the storage for a given element type, if any.
typename base_type::size_type size_type
Unsigned integer type.
basic_view(Type &...storage) -> basic_view< get_t< Type... >, exclude_t<> >
Deduction guide.
typename constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
constexpr null_t null
Compile-time constant for null entities.
constexpr std::size_t type_list_index_v
Helper variable template.
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 tombstone_t tombstone
Compile-time constant for tombstone entities.
constexpr get_t< Type... > get
Variable template for lists of observed elements.
typename type_list_element< Index, List >::type type_list_element_t
Helper type.
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.
constexpr bool operator!=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
constexpr bool operator==(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
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.