1#ifndef ENTT_ENTITY_VIEW_HPP
2#define ENTT_ENTITY_VIEW_HPP
9#include "../config/config.h"
10#include "../core/iterator.hpp"
11#include "../core/type_traits.hpp"
20template<
typename Type,
typename Entity>
21[[nodiscard]]
bool all_of_but(
const std::size_t index,
const Type *
const *it,
const std::size_t len,
const Entity
entt)
noexcept {
23 for(; (pos != index) && it[pos]->contains(
entt); ++pos) {}
26 for(++pos; (pos != len) && it[pos]->contains(
entt); ++pos) {}
32template<
typename Type,
typename Entity>
33[[nodiscard]]
bool none_of(
const Type *
const *it,
const std::size_t len,
const Entity
entt)
noexcept {
35 for(; (pos != len) && !(it[pos] && it[pos]->contains(
entt)); ++pos) {}
39template<
typename Type>
40[[nodiscard]]
bool fully_initialized(
const Type *
const *it,
const std::size_t len)
noexcept {
42 for(; (pos != len) && it[pos]; ++pos) {}
46template<
typename Result,
typename View,
typename Other, std::size_t... VGet, std::size_t... VExclude, std::size_t... OGet, std::size_t... OExclude>
47[[nodiscard]] Result view_pack(
const View &view,
const Other &other, std::index_sequence<VGet...>, std::index_sequence<VExclude...>, std::index_sequence<OGet...>, std::index_sequence<OExclude...>) {
50 elem.pools = {
view.template storage<VGet>()..., other.template storage<OGet>()...};
51 elem.filter = {
view.template
storage<
sizeof...(VGet) + VExclude>()..., other.template
storage<
sizeof...(OGet) + OExclude>()...};
56template<
typename Type, std::
size_t Get, std::
size_t Exclude>
57class view_iterator final {
58 using iterator_type =
typename Type::const_iterator;
60 [[nodiscard]]
bool valid(
const typename iterator_type::value_type
entt)
const noexcept {
61 return ((Get != 1u) || (
entt != tombstone)) && all_of_but(index, pools.data(), Get,
entt) && none_of(filter.data(), Exclude,
entt);
65 using value_type =
typename iterator_type::value_type;
66 using pointer =
typename iterator_type::pointer;
67 using reference =
typename iterator_type::reference;
68 using difference_type =
typename iterator_type::difference_type;
69 using iterator_category = std::forward_iterator_tag;
71 constexpr view_iterator() noexcept
78 view_iterator(iterator_type curr, iterator_type to, std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl,
const std::size_t idx) noexcept
84 while(it != last && !valid(*it)) {
89 view_iterator &operator++() noexcept {
90 while(++it != last && !valid(*it)) {}
94 view_iterator operator++(
int)
noexcept {
95 view_iterator orig = *
this;
96 return ++(*this), orig;
99 [[nodiscard]] pointer operator->() const noexcept {
103 [[nodiscard]] reference operator*() const noexcept {
104 return *operator->();
107 template<
typename LhsType,
auto... LhsArgs,
typename RhsType,
auto... RhsArgs>
108 friend constexpr bool operator==(
const view_iterator<LhsType, LhsArgs...> &,
const view_iterator<RhsType, RhsArgs...> &)
noexcept;
113 std::array<const Type *, Get> pools;
114 std::array<const Type *, Exclude> filter;
118template<
typename LhsType,
auto... LhsArgs,
typename RhsType,
auto... RhsArgs>
119[[nodiscard]]
constexpr bool operator==(
const view_iterator<LhsType, LhsArgs...> &lhs,
const view_iterator<RhsType, RhsArgs...> &rhs)
noexcept {
120 return lhs.it == rhs.it;
123template<
typename LhsType,
auto... LhsArgs,
typename RhsType,
auto... RhsArgs>
124[[nodiscard]]
constexpr bool operator!=(
const view_iterator<LhsType, LhsArgs...> &lhs,
const view_iterator<RhsType, RhsArgs...> &rhs)
noexcept {
125 return !(lhs == rhs);
128template<
typename It,
typename... Type>
129struct extended_view_iterator final {
130 using iterator_type = It;
131 using difference_type = std::ptrdiff_t;
132 using value_type =
decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Type>().get_as_tuple({})...));
133 using pointer = input_iterator_pointer<value_type>;
134 using reference = value_type;
135 using iterator_category = std::input_iterator_tag;
136 using iterator_concept = std::forward_iterator_tag;
138 constexpr extended_view_iterator()
142 extended_view_iterator(iterator_type from, std::tuple<Type *...> value)
146 extended_view_iterator &operator++() noexcept {
150 extended_view_iterator operator++(
int)
noexcept {
151 extended_view_iterator orig = *
this;
152 return ++(*this), orig;
155 [[nodiscard]] reference operator*() const noexcept {
156 return std::apply([
entt = *it](
auto *...curr) {
return std::tuple_cat(std::make_tuple(
entt), curr->get_as_tuple(
entt)...); }, pools);
159 [[nodiscard]] pointer operator->() const noexcept {
163 [[nodiscard]]
constexpr iterator_type base() const noexcept {
167 template<
typename... Lhs,
typename... Rhs>
168 friend bool constexpr operator==(
const extended_view_iterator<Lhs...> &,
const extended_view_iterator<Rhs...> &)
noexcept;
172 std::tuple<Type *...> pools;
175template<
typename... Lhs,
typename... Rhs>
176[[nodiscard]]
constexpr bool operator==(
const extended_view_iterator<Lhs...> &lhs,
const extended_view_iterator<Rhs...> &rhs)
noexcept {
177 return lhs.it == rhs.it;
180template<
typename... Lhs,
typename... Rhs>
181[[nodiscard]]
constexpr bool operator!=(
const extended_view_iterator<Lhs...> &lhs,
const extended_view_iterator<Rhs...> &rhs)
noexcept {
182 return !(lhs == rhs);
206template<
typename,
typename,
typename>
216template<
typename Type, std::
size_t Get, std::
size_t Exclude>
218 template<
typename Return,
typename View,
typename Other, std::size_t... VGet, std::size_t... VExclude, std::size_t... OGet, std::size_t... OExclude>
219 friend Return internal::view_pack(
const View &,
const Other &, std::index_sequence<VGet...>, std::index_sequence<VExclude...>, std::index_sequence<OGet...>, std::index_sequence<OExclude...>);
225 basic_common_view(std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl) noexcept
233 void use(
const std::size_t pos)
noexcept {
236 leading = pools[index];
240 void unchecked_refresh()
noexcept {
243 for(
size_type pos{1u}; pos < Get; ++pos) {
244 if(pools[pos]->size() < pools[index]->size()) {
249 leading = pools[index];
261 using iterator = internal::view_iterator<common_type, Get, Exclude>;
265 size_type pos = (leading !=
nullptr) * Get;
266 for(; pos < Get && pools[pos] !=
nullptr; ++pos) {}
286 return leading ? leading->size() :
size_type{};
297 return leading ?
iterator{leading->begin(0), leading->end(0), pools, filter, index} :
iterator{};
305 return leading ?
iterator{leading->end(0), leading->end(0), pools, filter, index} :
iterator{};
314 const auto it =
begin();
315 return it !=
end() ? *it :
null;
325 auto it = leading->rbegin(0);
326 const auto last = leading->rend(0);
327 for(; it != last && !
contains(*it); ++it) {}
328 return it == last ?
null : *it;
348 [[nodiscard]]
explicit operator bool() const noexcept {
349 return leading && internal::fully_initialized(filter.data(), Exclude);
359 const auto idx = leading->find(
entt).index();
360 return (!(idx < 0 || idx > leading->begin(0).index())) && internal::all_of_but(index, pools.data(), Get,
entt) && internal::none_of(filter.data(), Exclude,
entt);
368 std::array<const common_type *, Get> pools{};
369 std::array<const common_type *, Exclude> filter{};
387template<
typename... Get,
typename... Exclude>
389 using base_type =
basic_common_view<std::common_type_t<
typename Get::base_type...,
typename Exclude::base_type...>,
sizeof...(Get),
sizeof...(Exclude)>;
391 template<
typename Type>
392 static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>,
type_list<
typename Get::value_type...,
typename Exclude::value_type...>>;
394 template<std::size_t... Index>
395 auto storage(std::index_sequence<Index...>)
const noexcept {
399 template<std::size_t Curr, std::size_t Other,
typename... Args>
400 [[nodiscard]]
auto dispatch_get(
const std::tuple<typename base_type::entity_type, Args...> &curr)
const {
401 if constexpr(Curr == Other) {
402 return std::forward_as_tuple(std::get<Args>(curr)...);
408 template<std::size_t Curr,
typename Func, std::size_t... Index>
409 void each(Func &func, std::index_sequence<Index...>)
const {
411 if(
const auto entt = std::get<0>(curr); ((
sizeof...(Get) != 1u) || (
entt !=
tombstone)) && internal::all_of_but(this->index, this->pools.data(),
sizeof...(Get),
entt) && internal::none_of(this->filter.data(),
sizeof...(Exclude),
entt)) {
412 if constexpr(
is_applicable_v<Func,
decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
413 std::apply(func, std::tuple_cat(std::make_tuple(
entt), dispatch_get<Curr, Index>(curr)...));
415 std::apply(func, std::tuple_cat(dispatch_get<Curr, Index>(curr)...));
421 template<
typename Func, std::size_t... Index>
422 void pick_and_each(Func &func, std::index_sequence<Index...> seq)
const {
423 ((
storage<Index>() == base_type::handle() ? each<Index>(func, seq) : void()), ...);
456 basic_view(std::tuple<Get &...> value, std::tuple<Exclude &...> excl = {})
noexcept
463 template<
typename Type>
465 use<index_of<Type>>();
472 template<std::
size_t Index>
474 base_type::use(Index);
482 template<
typename Type>
483 [[nodiscard]]
auto *
storage() const noexcept {
492 template<std::
size_t Index>
493 [[nodiscard]]
auto *
storage() const noexcept {
496 if constexpr(Index <
sizeof...(Get)) {
508 template<
typename Type>
519 template<std::
size_t Index,
typename Type>
523 if constexpr(Index <
sizeof...(Get)) {
524 this->pools[Index] = &elem;
525 base_type::refresh();
527 this->filter[Index -
sizeof...(Get)] = &elem;
547 template<
typename Type,
typename... Other>
549 return get<index_of<Type>, index_of<Other>...>(
entt);
558 template<std::size_t... Index>
560 if constexpr(
sizeof...(Index) == 0) {
561 return std::apply([
entt](
auto *...curr) {
return std::tuple_cat(curr->get_as_tuple(
entt)...); },
storage(std::index_sequence_for<Get...>{}));
562 }
else if constexpr(
sizeof...(Index) == 1) {
584 template<
typename Func>
586 if(base_type::handle() !=
nullptr) {
587 pick_and_each(func, std::index_sequence_for<Get...>{});
601 const auto as_pools =
storage(std::index_sequence_for<Get...>{});
602 return {internal::extended_view_iterator{base_type::begin(), as_pools}, internal::extended_view_iterator{base_type::end(), as_pools}};
612 template<
typename... OGet,
typename... OExclude>
615 *
this, other, std::index_sequence_for<Get...>{}, std::index_sequence_for<Exclude...>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
624template<
typename Type>
659 return leading ? leading->size() :
size_type{};
666 [[nodiscard]]
bool empty() const noexcept {
667 return !leading || leading->empty();
678 return leading ? leading->begin() :
iterator{};
686 return leading ? leading->end() :
iterator{};
716 return empty() ?
null : *leading->begin();
725 return empty() ?
null : *leading->rbegin();
742 [[nodiscard]]
explicit operator bool() const noexcept {
743 return (leading !=
nullptr);
752 return leading && leading->contains(
entt);
771template<
typename Get>
787 using iterable =
decltype(std::declval<Get>().each());
805 basic_view(std::tuple<Get &> value, std::tuple<> = {})
noexcept
813 template<
typename Type =
typename Get::value_type>
814 [[nodiscard]]
auto *
storage() const noexcept {
815 static_assert(std::is_same_v<std::remove_const_t<Type>,
typename Get::value_type>,
"Invalid component type");
824 template<std::
size_t Index>
825 [[nodiscard]]
auto *
storage() const noexcept {
826 static_assert(Index == 0u,
"Index out of bounds");
843 template<std::
size_t Index>
845 static_assert(Index == 0u,
"Index out of bounds");
846 this->leading = &elem;
864 return base_type::begin()[pos];
873 template<
typename Elem>
875 static_assert(std::is_same_v<std::remove_const_t<Elem>,
typename Get::value_type>,
"Invalid component type");
885 template<std::size_t... Index>
887 if constexpr(
sizeof...(Index) == 0) {
909 template<
typename Func>
911 if(
auto *elem =
storage(); elem) {
913 for(
const auto pack: elem->each()) {
914 std::apply(func, pack);
916 }
else if constexpr(std::is_invocable_v<Func,
decltype(*elem->begin())>) {
917 for(
auto &&component: *elem) {
921 for(
size_type pos = elem->size(); pos; --pos) {
939 return elem ? elem->each() :
iterable{};
949 template<
typename... OGet,
typename... OExclude>
952 *
this, other, std::index_sequence_for<Get>{}, std::index_sequence_for<>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
961template<
typename... Type>
969template<
typename... Get,
typename... Exclude>
970basic_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
Bidirectional iterator type.
typename Type::entity_type entity_type
Underlying entity identifier.
Basic storage view implementation.
reverse_iterator rbegin() const noexcept
Returns an iterator to the first entity of the reversed view.
iterator begin() const noexcept
Returns an iterator to the first entity of the view.
reverse_iterator rend() const noexcept
Returns an iterator that is past the last entity of the reversed view.
typename common_type::entity_type entity_type
Underlying entity identifier.
typename common_type::reverse_iterator reverse_iterator
Reversed iterator type.
iterator find(const entity_type entt) const noexcept
Finds an entity.
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.
std::size_t size_type
Unsigned integer type.
iterator end() const noexcept
Returns an iterator that is past the last entity of the view.
size_type size() const noexcept
Returns the number of entities that have the given component.
const common_type * handle() const noexcept
Returns the leading storage of a view, if any.
entity_type front() const noexcept
Returns the first entity of the view, if any.
typename common_type::iterator iterator
Random access iterator type.
Type common_type
Common type among all storage types.
bool empty() const noexcept
Checks whether a view is empty.
Basic storage implementation.
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.
std::tuple< const value_type & > get_as_tuple(const entity_type entt) const noexcept
Returns the object assigned to an entity as a tuple.
iterable each() const noexcept
Returns an iterable object to use to visit a view.
typename base_type::size_type size_type
Unsigned integer type.
void each(Func func) const
Iterates entities and components and applies the given function object to them.
basic_view(Get &value) noexcept
Constructs a view from a storage class.
auto operator|(const basic_view< get_t< OGet... >, exclude_t< OExclude... > > &other) const noexcept
Combines two views in a more specific one.
decltype(std::declval< Get >().each()) iterable
Iterable view type.
decltype(auto) get(const entity_type entt) const
Returns the component assigned to the given entity.
basic_view(std::tuple< Get & > value, std::tuple<>={}) noexcept
Constructs a view from a storage class.
auto * storage() const noexcept
Returns the storage for a given component type, if any.
typename base_type::entity_type entity_type
Underlying entity identifier.
typename base_type::common_type common_type
Common type among all storage types.
entity_type operator[](const size_type pos) const
Returns the identifier that occupies the given position.
void storage(Get &elem) noexcept
Assigns a storage to a view.
void storage(Get &elem) noexcept
Assigns a storage to a view.
typename base_type::reverse_iterator reverse_iterator
Reversed iterator type.
typename base_type::iterator iterator
Random access iterator type.
basic_view() noexcept
Default constructor to use to create empty, invalid views.
decltype(auto) get(const entity_type entt) const
Returns the components assigned to the given entity.
basic_view(Get &...value, Exclude &...excl) noexcept
Constructs a view from a set of storage classes.
typename base_type::iterator iterator
Bidirectional iterator type.
void use() noexcept
Forces a view to use a given component to drive iterations.
void storage(Type &elem) noexcept
Assigns a storage to a view.
typename base_type::size_type size_type
Unsigned integer type.
auto * storage() const noexcept
Returns the storage for a given component type, if any.
iterable each() const noexcept
Returns an iterable object to use to visit a view.
void each(Func func) const
Iterates entities and components and applies the given function object to them.
basic_view(std::tuple< Get &... > value, std::tuple< Exclude &... > excl={}) noexcept
Constructs a view from a set of storage classes.
void storage(Type &elem) noexcept
Assigns a storage to a view.
typename base_type::common_type common_type
Common type among all storage types.
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() noexcept
Default constructor to use to create empty, invalid views.
decltype(auto) get(const entity_type entt) const
Returns the components assigned to the given entity.
basic_view(Type &...storage) -> basic_view< get_t< Type... >, exclude_t<> >
Deduction guide.
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.
basic_storage< Type > storage
Alias declaration for the most common use case.
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
typename constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
constexpr get_t< Type... > get
Variable template for lists of observed components.
typename type_list_element< Index, List >::type type_list_element_t
Helper type.
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.
Alias for exclusion lists.
Alias for lists of observed components.
Utility class to create an iterable object from a pair of iterators.
A class to use to push around lists of types, nothing more.