EnTT  3.10.0
view.hpp
1 #ifndef ENTT_ENTITY_VIEW_HPP
2 #define ENTT_ENTITY_VIEW_HPP
3 
4 #include <algorithm>
5 #include <array>
6 #include <iterator>
7 #include <tuple>
8 #include <type_traits>
9 #include <utility>
10 #include "../config/config.h"
11 #include "../core/iterator.hpp"
12 #include "../core/type_traits.hpp"
13 #include "component.hpp"
14 #include "entity.hpp"
15 #include "fwd.hpp"
16 #include "sparse_set.hpp"
17 #include "storage.hpp"
18 #include "utility.hpp"
19 
20 namespace entt {
21 
27 namespace internal {
28 
29 template<typename Type, std::size_t Component, std::size_t Exclude>
30 class view_iterator final {
31  using iterator_type = typename Type::const_iterator;
32 
33  [[nodiscard]] bool valid() const ENTT_NOEXCEPT {
34  return ((Component != 0u) || (*it != tombstone))
35  && std::apply([entt = *it](const auto *...curr) { return (curr->contains(entt) && ...); }, pools)
36  && std::apply([entt = *it](const auto *...curr) { return (!curr->contains(entt) && ...); }, filter);
37  }
38 
39 public:
40  using value_type = typename iterator_type::value_type;
41  using pointer = typename iterator_type::pointer;
42  using reference = typename iterator_type::reference;
43  using difference_type = typename iterator_type::difference_type;
44  using iterator_category = std::forward_iterator_tag;
45 
46  view_iterator() ENTT_NOEXCEPT = default;
47 
48  view_iterator(iterator_type curr, iterator_type to, std::array<const Type *, Component> all_of, std::array<const Type *, Exclude> none_of) ENTT_NOEXCEPT
49  : it{curr},
50  last{to},
51  pools{all_of},
52  filter{none_of} {
53  if(it != last && !valid()) {
54  ++(*this);
55  }
56  }
57 
58  view_iterator &operator++() ENTT_NOEXCEPT {
59  while(++it != last && !valid()) {}
60  return *this;
61  }
62 
63  view_iterator operator++(int) ENTT_NOEXCEPT {
64  view_iterator orig = *this;
65  return ++(*this), orig;
66  }
67 
68  [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
69  return &*it;
70  }
71 
72  [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
73  return *operator->();
74  }
75 
76  template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
77  friend bool operator==(const view_iterator<LhsType, LhsArgs...> &, const view_iterator<RhsType, RhsArgs...> &) ENTT_NOEXCEPT;
78 
79 private:
80  iterator_type it;
81  iterator_type last;
82  std::array<const Type *, Component> pools;
83  std::array<const Type *, Exclude> filter;
84 };
85 
86 template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
87 [[nodiscard]] bool operator==(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) ENTT_NOEXCEPT {
88  return lhs.it == rhs.it;
89 }
90 
91 template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
92 [[nodiscard]] bool operator!=(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) ENTT_NOEXCEPT {
93  return !(lhs == rhs);
94 }
95 
96 template<typename It, typename... Storage>
97 struct extended_view_iterator final {
98  using difference_type = std::ptrdiff_t;
99  using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Storage>().get_as_tuple({})...));
100  using pointer = input_iterator_pointer<value_type>;
101  using reference = value_type;
102  using iterator_category = std::input_iterator_tag;
103 
104  extended_view_iterator() = default;
105 
106  extended_view_iterator(It from, std::tuple<Storage *...> storage)
107  : it{from},
108  pools{storage} {}
109 
110  extended_view_iterator &operator++() ENTT_NOEXCEPT {
111  return ++it, *this;
112  }
113 
114  extended_view_iterator operator++(int) ENTT_NOEXCEPT {
115  extended_view_iterator orig = *this;
116  return ++(*this), orig;
117  }
118 
119  [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
120  return std::apply([entt = *it](auto *...curr) { return std::tuple_cat(std::make_tuple(entt), curr->get_as_tuple(entt)...); }, pools);
121  }
122 
123  [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
124  return operator*();
125  }
126 
127  template<typename... Lhs, typename... Rhs>
128  friend bool operator==(const extended_view_iterator<Lhs...> &, const extended_view_iterator<Rhs...> &) ENTT_NOEXCEPT;
129 
130 private:
131  It it;
132  std::tuple<Storage *...> pools;
133 };
134 
135 template<typename... Lhs, typename... Rhs>
136 [[nodiscard]] bool operator==(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) ENTT_NOEXCEPT {
137  return lhs.it == rhs.it;
138 }
139 
140 template<typename... Lhs, typename... Rhs>
141 [[nodiscard]] bool operator!=(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) ENTT_NOEXCEPT {
142  return !(lhs == rhs);
143 }
144 
145 } // namespace internal
146 
158 template<typename, typename, typename, typename>
159 class basic_view;
160 
185 template<typename Entity, typename... Component, typename... Exclude>
186 class basic_view<Entity, get_t<Component...>, exclude_t<Exclude...>> {
187  template<typename, typename, typename, typename>
188  friend class basic_view;
189 
190  template<typename Comp>
191  using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Comp>>::storage_type, Comp>;
192 
193  template<std::size_t... Index>
194  [[nodiscard]] auto pools_to_array(std::index_sequence<Index...>) const ENTT_NOEXCEPT {
195  std::size_t pos{};
196  std::array<const base_type *, sizeof...(Component) - 1u> other{};
197  (static_cast<void>(std::get<Index>(pools) == view ? void() : void(other[pos++] = std::get<Index>(pools))), ...);
198  return other;
199  }
200 
201  template<std::size_t Comp, std::size_t Other, typename... Args>
202  [[nodiscard]] auto dispatch_get(const std::tuple<Entity, Args...> &curr) const {
203  if constexpr(Comp == Other) {
204  return std::forward_as_tuple(std::get<Args>(curr)...);
205  } else {
206  return std::get<Other>(pools)->get_as_tuple(std::get<0>(curr));
207  }
208  }
209 
210  template<std::size_t Comp, typename Func, std::size_t... Index>
211  void each(Func func, std::index_sequence<Index...>) const {
212  for(const auto curr: std::get<Comp>(pools)->each()) {
213  const auto entt = std::get<0>(curr);
214 
215  if(((sizeof...(Component) != 1u) || (entt != tombstone))
216  && ((Comp == Index || std::get<Index>(pools)->contains(entt)) && ...)
217  && std::apply([entt](const auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
218  if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
219  std::apply(func, std::tuple_cat(std::make_tuple(entt), dispatch_get<Comp, Index>(curr)...));
220  } else {
221  std::apply(func, std::tuple_cat(dispatch_get<Comp, Index>(curr)...));
222  }
223  }
224  }
225  }
226 
227  template<typename Func, std::size_t... Index>
228  void pick_and_each(Func func, std::index_sequence<Index...> seq) const {
229  ((std::get<Index>(pools) == view ? each<Index>(std::move(func), seq) : void()), ...);
230  }
231 
232 public:
234  using entity_type = Entity;
236  using size_type = std::size_t;
238  using base_type = std::common_type_t<typename storage_type<Component>::base_type...>;
240  using iterator = internal::view_iterator<base_type, sizeof...(Component) - 1u, sizeof...(Exclude)>;
243 
245  basic_view() ENTT_NOEXCEPT
246  : pools{},
247  filter{},
248  view{} {}
249 
255  basic_view(storage_type<Component> &...component, const storage_type<Exclude> &...epool) ENTT_NOEXCEPT
256  : pools{&component...},
257  filter{&epool...},
258  view{(std::min)({&static_cast<const base_type &>(component)...}, [](auto *lhs, auto *rhs) { return lhs->size() < rhs->size(); })} {}
259 
265  template<typename Comp>
266  [[nodiscard]] basic_view use() const ENTT_NOEXCEPT {
267  basic_view other{*this};
268  other.view = std::get<storage_type<Comp> *>(pools);
269  return other;
270  }
271 
277  template<std::size_t Comp>
278  [[nodiscard]] basic_view use() const ENTT_NOEXCEPT {
279  basic_view other{*this};
280  other.view = std::get<Comp>(pools);
281  return other;
282  }
283 
288  const base_type &handle() const ENTT_NOEXCEPT {
289  return *view;
290  }
291 
297  template<typename Comp>
298  [[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
299  return *std::get<storage_type<Comp> *>(pools);
300  }
301 
307  template<std::size_t Comp>
308  [[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
309  return *std::get<Comp>(pools);
310  }
311 
316  [[nodiscard]] size_type size_hint() const ENTT_NOEXCEPT {
317  return view->size();
318  }
319 
328  [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
329  return iterator{view->begin(), view->end(), pools_to_array(std::index_sequence_for<Component...>{}), filter};
330  }
331 
341  [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
342  return iterator{view->end(), view->end(), pools_to_array(std::index_sequence_for<Component...>{}), filter};
343  }
344 
350  [[nodiscard]] entity_type front() const ENTT_NOEXCEPT {
351  const auto it = begin();
352  return it != end() ? *it : null;
353  }
354 
360  [[nodiscard]] entity_type back() const ENTT_NOEXCEPT {
361  auto it = view->rbegin();
362  for(const auto last = view->rend(); it != last && !contains(*it); ++it) {}
363  return it == view->rend() ? null : *it;
364  }
365 
372  [[nodiscard]] iterator find(const entity_type entt) const ENTT_NOEXCEPT {
373  return contains(entt) ? iterator{view->find(entt), view->end(), pools_to_array(std::index_sequence_for<Component...>{}), filter} : end();
374  }
375 
381  [[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
382  return get<Component...>(entt);
383  }
384 
389  [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
390  return view != nullptr;
391  }
392 
398  [[nodiscard]] bool contains(const entity_type entt) const ENTT_NOEXCEPT {
399  return std::apply([entt](const auto *...curr) { return (curr->contains(entt) && ...); }, pools)
400  && std::apply([entt](const auto *...curr) { return (!curr->contains(entt) && ...); }, filter);
401  }
402 
414  template<typename... Comp>
415  [[nodiscard]] decltype(auto) get(const entity_type entt) const {
416  ENTT_ASSERT(contains(entt), "View does not contain entity");
417 
418  if constexpr(sizeof...(Comp) == 0) {
419  return std::apply([entt](auto *...curr) { return std::tuple_cat(curr->get_as_tuple(entt)...); }, pools);
420  } else if constexpr(sizeof...(Comp) == 1) {
421  return (std::get<storage_type<Comp> *>(pools)->get(entt), ...);
422  } else {
423  return std::tuple_cat(std::get<storage_type<Comp> *>(pools)->get_as_tuple(entt)...);
424  }
425  }
426 
439  template<std::size_t First, std::size_t... Other>
440  [[nodiscard]] decltype(auto) get(const entity_type entt) const {
441  ENTT_ASSERT(contains(entt), "View does not contain entity");
442 
443  if constexpr(sizeof...(Other) == 0) {
444  return std::get<First>(pools)->get(entt);
445  } else {
446  return std::tuple_cat(std::get<First>(pools)->get_as_tuple(entt), std::get<Other>(pools)->get_as_tuple(entt)...);
447  }
448  }
449 
468  template<typename Func>
469  void each(Func func) const {
470  pick_and_each(std::move(func), std::index_sequence_for<Component...>{});
471  }
472 
482  [[nodiscard]] iterable each() const ENTT_NOEXCEPT {
483  return {internal::extended_view_iterator{begin(), pools}, internal::extended_view_iterator{end(), pools}};
484  }
485 
493  template<typename... Get, typename... Excl>
494  [[nodiscard]] auto operator|(const basic_view<Entity, get_t<Get...>, exclude_t<Excl...>> &other) const ENTT_NOEXCEPT {
495  using view_type = basic_view<Entity, get_t<Component..., Get...>, exclude_t<Exclude..., Excl...>>;
496  return std::make_from_tuple<view_type>(std::tuple_cat(
497  std::apply([](auto *...curr) { return std::forward_as_tuple(*curr...); }, pools),
498  std::apply([](auto *...curr) { return std::forward_as_tuple(*curr...); }, other.pools),
499  std::apply([](const auto *...curr) { return std::forward_as_tuple(static_cast<const storage_type<Exclude> &>(*curr)...); }, filter),
500  std::apply([](const auto *...curr) { return std::forward_as_tuple(static_cast<const storage_type<Excl> &>(*curr)...); }, other.filter)));
501  }
502 
503 private:
504  std::tuple<storage_type<Component> *...> pools;
505  std::array<const base_type *, sizeof...(Exclude)> filter;
506  const base_type *view;
507 };
508 
531 template<typename Entity, typename Component>
532 class basic_view<Entity, get_t<Component>, exclude_t<>, std::void_t<std::enable_if_t<!component_traits<std::remove_const_t<Component>>::in_place_delete>>> {
533  template<typename, typename, typename, typename>
534  friend class basic_view;
535 
536  using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Component>>::storage_type, Component>;
537 
538 public:
540  using entity_type = Entity;
542  using size_type = std::size_t;
544  using base_type = typename storage_type::base_type;
546  using iterator = typename base_type::iterator;
548  using reverse_iterator = typename base_type::reverse_iterator;
550  using iterable = decltype(std::declval<storage_type>().each());
551 
553  basic_view() ENTT_NOEXCEPT
554  : pools{},
555  filter{},
556  view{} {}
557 
562  basic_view(storage_type &ref) ENTT_NOEXCEPT
563  : pools{&ref},
564  filter{},
565  view{&ref} {}
566 
571  const base_type &handle() const ENTT_NOEXCEPT {
572  return *view;
573  }
574 
580  template<typename Comp = Component>
581  [[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
582  static_assert(std::is_same_v<Comp, Component>, "Invalid component type");
583  return *std::get<0>(pools);
584  }
585 
591  template<std::size_t Comp>
592  [[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
593  return *std::get<Comp>(pools);
594  }
595 
600  [[nodiscard]] size_type size() const ENTT_NOEXCEPT {
601  return view->size();
602  }
603 
608  [[nodiscard]] bool empty() const ENTT_NOEXCEPT {
609  return view->empty();
610  }
611 
620  [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
621  return view->begin();
622  }
623 
633  [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
634  return view->end();
635  }
636 
645  [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
646  return view->rbegin();
647  }
648 
660  [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
661  return view->rend();
662  }
663 
669  [[nodiscard]] entity_type front() const ENTT_NOEXCEPT {
670  return empty() ? null : *begin();
671  }
672 
678  [[nodiscard]] entity_type back() const ENTT_NOEXCEPT {
679  return empty() ? null : *rbegin();
680  }
681 
688  [[nodiscard]] iterator find(const entity_type entt) const ENTT_NOEXCEPT {
689  return contains(entt) ? view->find(entt) : end();
690  }
691 
697  [[nodiscard]] entity_type operator[](const size_type pos) const {
698  return begin()[pos];
699  }
700 
706  [[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
707  return get<Component>(entt);
708  }
709 
714  [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
715  return view != nullptr;
716  }
717 
723  [[nodiscard]] bool contains(const entity_type entt) const ENTT_NOEXCEPT {
724  return view->contains(entt);
725  }
726 
738  template<typename... Comp>
739  [[nodiscard]] decltype(auto) get(const entity_type entt) const {
740  ENTT_ASSERT(contains(entt), "View does not contain entity");
741 
742  if constexpr(sizeof...(Comp) == 0) {
743  return std::get<0>(pools)->get_as_tuple(entt);
744  } else {
745  static_assert(std::is_same_v<Comp..., Component>, "Invalid component type");
746  return std::get<0>(pools)->get(entt);
747  }
748  }
749 
751  template<std::size_t Comp>
752  [[nodiscard]] decltype(auto) get(const entity_type entt) const {
753  ENTT_ASSERT(contains(entt), "View does not contain entity");
754  return std::get<0>(pools)->get(entt);
755  }
756 
775  template<typename Func>
776  void each(Func func) const {
777  if constexpr(is_applicable_v<Func, decltype(*each().begin())>) {
778  for(const auto pack: each()) {
779  std::apply(func, pack);
780  }
781  } else if constexpr(std::is_invocable_v<Func, Component &>) {
782  for(auto &&component: *std::get<0>(pools)) {
783  func(component);
784  }
785  } else if constexpr(std::is_invocable_v<Func, Entity>) {
786  for(auto entity: *view) {
787  func(entity);
788  }
789  } else {
790  for(size_type pos{}, last = size(); pos < last; ++pos) {
791  func();
792  }
793  }
794  }
795 
805  [[nodiscard]] iterable each() const ENTT_NOEXCEPT {
806  return std::get<0>(pools)->each();
807  }
808 
816  template<typename... Get, typename... Excl>
817  [[nodiscard]] auto operator|(const basic_view<Entity, get_t<Get...>, exclude_t<Excl...>> &other) const ENTT_NOEXCEPT {
818  using view_type = basic_view<Entity, get_t<Component, Get...>, exclude_t<Excl...>>;
819  return std::make_from_tuple<view_type>(std::tuple_cat(
820  std::forward_as_tuple(*std::get<0>(pools)),
821  std::apply([](auto *...curr) { return std::forward_as_tuple(*curr...); }, other.pools),
822  std::apply([](const auto *...curr) { return std::forward_as_tuple(static_cast<const typename view_type::template storage_type<Excl> &>(*curr)...); }, other.filter)));
823  }
824 
825 private:
826  std::tuple<storage_type *> pools;
827  std::array<const base_type *, 0u> filter;
828  const base_type *view;
829 };
830 
836 template<typename... Storage>
837 basic_view(Storage &...storage) -> basic_view<std::common_type_t<typename Storage::entity_type...>, get_t<constness_as_t<typename Storage::value_type, Storage>...>, exclude_t<>>;
838 
839 } // namespace entt
840 
841 #endif
Basic storage implementation.
Definition: storage.hpp:234
auto operator|(const basic_view< Entity, get_t< Get... >, exclude_t< Excl... >> &other) const
Combines two views in a more specific one (friend function).
Definition: view.hpp:817
const base_type & handle() const
Returns the leading storage of a view.
Definition: view.hpp:288
basic_view()
Default constructor to use to create empty, invalid views.
Definition: view.hpp:245
iterator find(const entity_type entt) const
Finds an entity.
Definition: view.hpp:372
entity_type back() const
Returns the last entity of the view, if any.
Definition: view.hpp:360
iterator end() const
Returns an iterator that is past the last entity of the view.
Definition: view.hpp:341
iterator begin() const
Returns an iterator to the first entity of the view.
Definition: view.hpp:328
auto operator|(const basic_view< Entity, get_t< Get... >, exclude_t< Excl... >> &other) const
Combines two views in a more specific one (friend function).
Definition: view.hpp:494
internal::view_iterator< base_type, sizeof...(Component) - 1u, sizeof...(Exclude)> iterator
Bidirectional iterator type.
Definition: view.hpp:240
iterable each() const
Returns an iterable object to use to visit a view.
Definition: view.hpp:482
basic_view use() const
Creates a new view driven by a given component in its iterations.
Definition: view.hpp:266
entity_type front() const
Returns the first entity of the view, if any.
Definition: view.hpp:350
std::common_type_t< typename storage_type< Component >::base_type... > base_type
Common type among all storage types.
Definition: view.hpp:238
bool contains(const entity_type entt) const
Checks if a view contains an entity.
Definition: view.hpp:398
void each(Func func) const
Iterates entities and components and applies the given function object to them.
Definition: view.hpp:469
size_type size_hint() const
Estimates the number of entities iterated by the view.
Definition: view.hpp:316
basic_view(storage_type< Component > &...component, const storage_type< Exclude > &...epool)
Constructs a multi-type view from a set of storage classes.
Definition: view.hpp:255
View implementation.
Definition: fwd.hpp:20
EnTT default namespace.
Definition: dense_map.hpp:22
constexpr bool operator==(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs)
Compares two hashed strings.
entity
Default entity identifier.
Definition: fwd.hpp:47
basic_view(Storage &...storage) -> basic_view< std::common_type_t< typename Storage::entity_type... >, get_t< constness_as_t< typename Storage::value_type, Storage >... >, exclude_t<>>
Deduction guide.
constexpr null_t null
Compile-time constant for null entities.
Definition: entity.hpp:326
constexpr bool is_applicable_v
Helper variable template.
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
Definition: entity.hpp:335
typename constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
basic_view< entity, Get, Exclude > view
Alias declaration for the most common use case.
Definition: fwd.hpp:103
constexpr get_t< Type... > get
Variable template for lists of observed components.
Definition: utility.hpp:34
basic_storage< entity, Args... > storage
Alias declaration for the most common use case.
Definition: fwd.hpp:57
bool operator!=(const basic_any< Len, Align > &lhs, const basic_any< Len, Align > &rhs)
Checks if two wrappers differ in their content.
Definition: any.hpp:402
Alias for exclusion lists.
Definition: utility.hpp:13
Alias for lists of observed components.
Definition: utility.hpp:27
Utility class to create an iterable object from a pair of iterators.
Definition: iterator.hpp:63