EnTT 4.0.0
Loading...
Searching...
No Matches
view.hpp
1#ifndef ENTT_ENTITY_VIEW_HPP
2#define ENTT_ENTITY_VIEW_HPP
3
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"
15#include "entity.hpp"
16#include "fwd.hpp"
17
18namespace entt {
19
21namespace internal {
22
23template<typename... Type>
24// NOLINTNEXTLINE(misc-redundant-expression)
25static constexpr bool tombstone_check_v = ((sizeof...(Type) == 1u) && ... && (Type::storage_policy == deletion_policy::in_place));
26
27template<cvref_unqualified Type>
28const Type *view_placeholder() {
29 static const Type placeholder{};
30 return &placeholder;
31}
32
33[[nodiscard]] bool all_of(auto first, const auto last, const auto entt) noexcept {
34 for(; (first != last) && (*first)->contains(entt); ++first) {}
35 return first == last;
36}
37
38[[nodiscard]] bool none_of(auto first, const auto last, const auto entt) noexcept {
39 for(; (first != last) && !(*first)->contains(entt); ++first) {}
40 return first == last;
41}
42
43template<typename It>
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) {}
46 return first == last;
47}
48
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...>) {
51 Result elem{};
52 // friend-initialization, avoid multiple calls to refresh
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>())...};
56 elem.refresh();
57 return elem;
58}
59
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;
64
65 using iterator_type = Type::const_iterator;
66 using iterator_traits = stl::iterator_traits<iterator_type>;
67
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));
72 }
73
74 void seek_next() {
75 for(constexpr iterator_type sentinel{}; it != sentinel && !valid(*it); ++it) {}
76 }
77
78public:
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;
84
85 constexpr view_iterator() noexcept
86 : it{},
87 pools{},
88 filter{},
89 index{} {}
90
91 view_iterator(iterator_type first, stl::array<const Type *, Get> value, stl::array<const Type *, Exclude> excl, const stl::size_t idx) noexcept
92 : it{first},
93 pools{value},
94 filter{excl},
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");
97 seek_next();
98 }
99
100 view_iterator &operator++() noexcept {
101 ++it;
102 seek_next();
103 return *this;
104 }
105
106 view_iterator operator++(int) noexcept {
107 const view_iterator orig = *this;
108 return ++(*this), orig;
109 }
110
111 [[nodiscard]] pointer operator->() const noexcept {
112 return &*it;
113 }
114
115 [[nodiscard]] reference operator*() const noexcept {
116 return *operator->();
117 }
118
119 template<typename Other, auto... Args>
120 [[nodiscard]] constexpr bool operator==(const view_iterator<Other, Args...> &other) const noexcept {
121 return it == other.it;
122 }
123
124private:
125 iterator_type it;
126 stl::array<const Type *, Get> pools;
127 stl::array<const Type *, Exclude> filter;
128 difference_type index;
129};
130
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;
140
141 constexpr extended_view_iterator()
142 : it{} {}
143
144 extended_view_iterator(iterator_type from)
145 : it{from} {}
146
147 extended_view_iterator &operator++() noexcept {
148 return ++it, *this;
149 }
150
151 extended_view_iterator operator++(int) noexcept {
152 const extended_view_iterator orig = *this;
153 return ++(*this), orig;
154 }
155
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...>{});
160 }
161
162 [[nodiscard]] pointer operator->() const noexcept {
163 return operator*();
164 }
165
166 [[nodiscard]] constexpr iterator_type base() const noexcept {
167 return it;
168 }
169
170 template<typename... Other>
171 [[nodiscard]] constexpr bool operator==(const extended_view_iterator<Other...> &other) const noexcept {
172 return it == other.it;
173 }
174
175private:
176 It it;
177};
178
179} // namespace internal
181
200template<typename, typename>
201class basic_view;
202
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...>);
215
216 [[nodiscard]] auto offset() const noexcept {
217 ENTT_ASSERT(index != Get, "Invalid view");
218 return (pools[index]->policy() == deletion_policy::swap_only) ? pools[index]->free_list() : pools[index]->size();
219 }
220
221 void unchecked_refresh() noexcept {
222 index = 0u;
223
224 if constexpr(Get > 1u) {
225 for(size_type pos{1u}; pos < Get; ++pos) {
226 if(pools[pos]->size() < pools[index]->size()) {
227 index = pos;
228 }
229 }
230 }
231 }
232
233protected:
235 basic_common_view() noexcept {
236 for(size_type pos{}, last = filter.size(); pos < last; ++pos) {
237 filter[pos] = placeholder;
238 }
239 }
240
241 basic_common_view(stl::array<const Type *, Get> value, stl::array<const Type *, Exclude> excl) noexcept
242 : pools{value},
243 filter{excl},
244 index{Get} {
245 unchecked_refresh();
246 }
247
248 [[nodiscard]] const Type *pool_at(const stl::size_t pos) const noexcept {
249 return pools[pos];
250 }
251
252 void pool_at(const stl::size_t pos, const Type *elem) noexcept {
253 ENTT_ASSERT(elem != nullptr, "Unexpected element");
254 pools[pos] = elem;
255 refresh();
256 }
257
258 [[nodiscard]] const Type *filter_at(const stl::size_t pos) const noexcept {
259 return (filter[pos] == placeholder) ? nullptr : filter[pos];
260 }
261
262 void filter_at(const stl::size_t pos, const Type *elem) noexcept {
263 ENTT_ASSERT(elem != nullptr, "Unexpected element");
264 filter[pos] = elem;
265 }
266
267 [[nodiscard]] bool none_of(const Type::entity_type entt) const noexcept {
268 return internal::none_of(filter.begin(), filter.end(), entt);
269 }
270
271 void use(const stl::size_t pos) noexcept {
272 index = (index != Get) ? pos : Get;
273 }
275
276public:
278 using common_type = Type;
280 using entity_type = Type::entity_type;
282 using size_type = stl::size_t;
284 using difference_type = stl::ptrdiff_t;
286 using iterator = internal::view_iterator<common_type, Checked, Get, Exclude>;
287
289 void refresh() noexcept {
290 size_type pos = static_cast<size_type>(index != Get) * Get;
291 for(; pos < Get && pools[pos] != nullptr; ++pos) {}
292
293 if(pos == Get) {
294 unchecked_refresh();
295 }
296 }
297
302 [[nodiscard]] const common_type *handle() const noexcept {
303 return (index != Get) ? pools[index] : nullptr;
304 }
305
310 [[nodiscard]] size_type size_hint() const noexcept {
311 return (index != Get) ? offset() : size_type{};
312 }
313
321 [[nodiscard]] iterator begin() const noexcept {
322 return (index != Get) ? iterator{pools[index]->end() - static_cast<difference_type>(offset()), pools, filter, index} : iterator{};
323 }
324
329 [[nodiscard]] iterator end() const noexcept {
330 return (index != Get) ? iterator{pools[index]->end(), pools, filter, index} : iterator{};
331 }
332
338 [[nodiscard]] entity_type front() const noexcept {
339 const auto it = begin();
340 return it != end() ? *it : null;
341 }
342
348 [[nodiscard]] entity_type back() const noexcept {
349 if(index != Get) {
350 auto it = pools[index]->rbegin();
351 const auto last = it + static_cast<difference_type>(offset());
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;
354 }
355
356 return null;
357 }
358
365 [[nodiscard]] iterator find(const entity_type entt) const noexcept {
366 return contains(entt) ? iterator{pools[index]->find(entt), pools, filter, index} : end();
367 }
368
373 [[nodiscard]] explicit operator bool() const noexcept {
374 return (index != Get) && internal::fully_initialized(filter.begin(), filter.end(), placeholder);
375 }
376
382 [[nodiscard]] bool contains(const entity_type entt) const noexcept {
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();
387 }
388
389private:
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>()};
393 size_type index{Get};
394};
395
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)>;
413
414 template<stl::size_t Index>
415 using element_at = type_list_element_t<Index, type_list<Get..., Exclude...>>;
416
417 template<typename Type>
418 static constexpr stl::size_t index_of = type_list_index_v<stl::remove_const_t<Type>, type_list<typename Get::element_type..., typename Exclude::element_type...>>;
419
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)...);
424 } else {
425 return storage<Other>()->get_as_tuple(stl::get<0>(curr));
426 }
427 }
428
429 template<stl::size_t Curr, typename Func, stl::size_t... Index>
430 void each(Func func, stl::index_sequence<Index...>) const {
431 for(const auto curr: storage<Curr>()->each()) {
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)...));
435 } else {
436 stl::apply(func, stl::tuple_cat(dispatch_get<Curr, Index>(curr)...));
437 }
438 }
439 }
440 }
441
442 template<typename Type>
443 void storage_if(Type *elem) noexcept {
444 if(elem != nullptr) {
446 }
447 }
448
449public:
457 using difference_type = stl::ptrdiff_t;
461 using iterable = iterable_adaptor<internal::extended_view_iterator<iterator, Get...>>;
462
464 basic_view() noexcept
465 : base_type{} {}
466
472 basic_view(Get &...value, Exclude &...excl) noexcept
473 : base_type{{&value...}, {&excl...}} {
474 }
475
481 basic_view(stl::tuple<Get &...> value, stl::tuple<Exclude &...> excl = {}) noexcept
482 : basic_view{stl::make_from_tuple<basic_view>(stl::tuple_cat(value, excl))} {}
483
489 template<typename... Args>
490 requires (!stl::same_as<basic_view, basic_view<Args...>>)
491 basic_view(const basic_view<Args...> &other) noexcept
492 : basic_view{} {
493 (storage_if(other.template storage<typename Get::element_type>()), ...);
494 (storage_if(other.template storage<typename Exclude::element_type>()), ...);
495 }
496
501 template<typename Type>
502 void use() noexcept {
504 }
505
510 template<stl::size_t Index>
511 void use() noexcept {
512 base_type::use(Index);
513 }
514
520 template<typename Type>
521 [[nodiscard]] auto *storage() const noexcept {
522 return storage<index_of<Type>>();
523 }
524
530 template<stl::size_t Index>
531 [[nodiscard]] auto *storage() const noexcept {
532 if constexpr(Index < sizeof...(Get)) {
533 return static_cast<element_at<Index> *>(const_cast<constness_as_t<common_type, element_at<Index>> *>(base_type::pool_at(Index)));
534 } else {
535 return static_cast<element_at<Index> *>(const_cast<constness_as_t<common_type, element_at<Index>> *>(base_type::filter_at(Index - sizeof...(Get))));
536 }
537 }
538
544 template<typename Type>
545 void storage(Type &elem) noexcept {
547 }
548
555 template<stl::size_t Index, typename Type>
556 void storage(Type &elem) noexcept {
557 static_assert(stl::is_convertible_v<Type &, element_at<Index> &>, "Unexpected type");
558
559 if constexpr(Index < sizeof...(Get)) {
560 base_type::pool_at(Index, &elem);
561 } else {
562 base_type::filter_at(Index - sizeof...(Get), &elem);
563 }
564 }
565
571 [[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
572 return get(entt);
573 }
574
582 template<typename Type, typename... Other>
583 [[nodiscard]] decltype(auto) get(const entity_type entt) const {
584 return get<index_of<Type>, index_of<Other>...>(entt);
585 }
586
593 template<stl::size_t... Index>
594 [[nodiscard]] decltype(auto) get(const entity_type entt) const {
595 if constexpr(sizeof...(Index) == 0) {
596 return [this, entt]<auto... Idx>(stl::index_sequence<Idx...>) {
597 return stl::tuple_cat(this->storage<Idx>()->get_as_tuple(entt)...);
598 }(stl::index_sequence_for<Get...>{});
599 } else if constexpr(sizeof...(Index) == 1) {
600 return (storage<Index>()->get(entt), ...);
601 } else {
602 return stl::tuple_cat(storage<Index>()->get_as_tuple(entt)...);
603 }
604 }
605
621 template<typename Func>
622 void each(Func func) const {
623 [this, &func]<auto... Index>(stl::index_sequence<Index...> seq) {
624 if(const auto *view = base_type::handle(); view != nullptr) {
625 ((view == base_type::pool_at(Index) ? each<Index>(stl::move(func), seq) : void()), ...);
626 }
627 }(stl::index_sequence_for<Get...>{});
628 }
629
639 [[nodiscard]] iterable each() const noexcept {
641 }
642
649 template<stl::derived_from<common_type> OGet>
650 [[nodiscard]] basic_view<get_t<Get..., OGet>, exclude_t<Exclude...>> operator|(OGet &other) const noexcept {
651 return *this | basic_view<get_t<OGet>, exclude_t<>>{other};
652 }
653
661 template<stl::derived_from<common_type>... OGet, stl::derived_from<common_type>... OExclude>
662 [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
663 return internal::view_pack<basic_view<get_t<Get..., OGet...>, exclude_t<Exclude..., OExclude...>>>(
664 *this, other, stl::index_sequence_for<Get...>{}, stl::index_sequence_for<Exclude...>{}, stl::index_sequence_for<OGet...>{}, stl::index_sequence_for<OExclude...>{});
665 }
666};
667
674template<cvref_unqualified Type, deletion_policy Policy>
676protected:
678 basic_storage_view() noexcept = default;
679
680 basic_storage_view(const Type *value) noexcept
681 : leading{value} {
682 ENTT_ASSERT(leading->policy() == Policy, "Unexpected storage policy");
683 }
685
686public:
688 using common_type = Type;
690 using entity_type = common_type::entity_type;
692 using size_type = stl::size_t;
694 using difference_type = stl::ptrdiff_t;
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>;
699
704 [[nodiscard]] const common_type *handle() const noexcept {
705 return leading;
706 }
707
712 [[nodiscard]] size_type size() const noexcept
713 requires (Policy != deletion_policy::in_place) {
714 if constexpr(Policy == deletion_policy::swap_and_pop) {
715 return leading ? leading->size() : size_type{};
716 } else {
717 static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy");
718 return leading ? leading->free_list() : size_type{};
719 }
720 }
721
726 [[nodiscard]] size_type size_hint() const noexcept
727 requires (Policy == deletion_policy::in_place) {
728 return leading ? leading->size() : size_type{};
729 }
730
735 [[nodiscard]] bool empty() const noexcept
736 requires (Policy != deletion_policy::in_place) {
737 if constexpr(Policy == deletion_policy::swap_and_pop) {
738 return !leading || leading->empty();
739 } else {
740 static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy");
741 return !leading || (leading->free_list() == 0u);
742 }
743 }
744
752 [[nodiscard]] iterator begin() const noexcept {
753 if constexpr(Policy == deletion_policy::swap_and_pop) {
754 return leading ? leading->begin() : iterator{};
755 } else if constexpr(Policy == deletion_policy::swap_only) {
756 return leading ? (leading->end() - static_cast<difference_type>(leading->free_list())) : iterator{};
757 } else {
758 static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy");
759 return leading ? iterator{leading->begin(), {leading}, {}, 0u} : iterator{};
760 }
761 }
762
767 [[nodiscard]] iterator end() const noexcept {
768 if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) {
769 return leading ? leading->end() : iterator{};
770 } else {
771 static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy");
772 return leading ? iterator{leading->end(), {leading}, {}, 0u} : iterator{};
773 }
774 }
775
783 [[nodiscard]] reverse_iterator rbegin() const noexcept
784 requires (Policy != deletion_policy::in_place) {
785 return leading ? leading->rbegin() : reverse_iterator{};
786 }
787
794 [[nodiscard]] reverse_iterator rend() const noexcept
795 requires (Policy != deletion_policy::in_place) {
796 if constexpr(Policy == deletion_policy::swap_and_pop) {
797 return leading ? leading->rend() : reverse_iterator{};
798 } else {
799 static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy");
800 return leading ? (leading->rbegin() + static_cast<difference_type>(leading->free_list())) : reverse_iterator{};
801 }
802 }
803
809 [[nodiscard]] entity_type front() const noexcept {
810 if constexpr(Policy == deletion_policy::swap_and_pop) {
811 return empty() ? null : *leading->begin();
812 } else if constexpr(Policy == deletion_policy::swap_only) {
813 return empty() ? null : *(leading->end() - static_cast<difference_type>(leading->free_list()));
814 } else {
815 static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy");
816 const auto it = begin();
817 return (it == end()) ? null : *it;
818 }
819 }
820
826 [[nodiscard]] entity_type back() const noexcept {
827 if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) {
828 return empty() ? null : *leading->rbegin();
829 } else {
830 static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy");
831
832 if(leading) {
833 auto it = leading->rbegin();
834 const auto last = leading->rend();
835 for(; (it != last) && (*it == tombstone); ++it) {}
836 return it == last ? null : *it;
837 }
838
839 return null;
840 }
841 }
842
849 [[nodiscard]] iterator find(const entity_type entt) const noexcept {
850 if constexpr(Policy == deletion_policy::swap_and_pop) {
851 return leading ? leading->find(entt) : iterator{};
852 } else if constexpr(Policy == deletion_policy::swap_only) {
853 const auto it = leading ? leading->find(entt) : iterator{};
854 return leading && (static_cast<size_type>(it.index()) < leading->free_list()) ? it : iterator{};
855 } else {
856 return leading ? iterator{leading->find(entt), {leading}, {}, 0u} : iterator{};
857 }
858 }
859
864 [[nodiscard]] explicit operator bool() const noexcept {
865 return (leading != nullptr);
866 }
867
873 [[nodiscard]] bool contains(const entity_type entt) const noexcept {
874 if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::in_place) {
875 return leading && leading->contains(entt);
876 } else {
877 static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy");
878 return leading && leading->contains(entt) && (leading->index(entt) < leading->free_list());
879 }
880 }
881
882private:
883 const common_type *leading{};
884};
885
896template<typename Get>
898 : public basic_storage_view<typename Get::base_type, Get::storage_policy> {
900
901 void storage_if(Get *value) noexcept {
902 if(value != nullptr) {
903 storage(*value);
904 }
905 }
906
907public:
915 using difference_type = stl::ptrdiff_t;
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())>;
922
924 basic_view() noexcept
925 : base_type{} {}
926
931 basic_view(Get &value) noexcept
932 : base_type{&value} {
933 }
934
939 basic_view(stl::tuple<Get &> value, stl::tuple<> = {}) noexcept
940 : basic_view{stl::get<0>(value)} {}
941
947 template<typename... Args>
948 requires (!stl::same_as<basic_view, basic_view<Args...>>)
949 basic_view(const basic_view<Args...> &other) noexcept
950 : base_type{} {
951 storage_if(other.template storage<typename Get::element_type>());
952 }
953
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");
962 return storage<0>();
963 }
964
970 template<stl::size_t Index>
971 [[nodiscard]] auto *storage() const noexcept {
972 static_assert(Index == 0u, "Index out of bounds");
973 return static_cast<Get *>(const_cast<constness_as_t<common_type, Get> *>(base_type::handle()));
974 }
975
980 void storage(Get &elem) noexcept {
981 storage<0>(elem);
982 }
983
989 template<stl::size_t Index>
990 void storage(Get &elem) noexcept {
991 static_assert(Index == 0u, "Index out of bounds");
992 *this = basic_view{elem};
993 }
994
999 [[nodiscard]] Get *operator->() const noexcept {
1000 return storage();
1001 }
1002
1008 [[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
1009 return storage()->get(entt);
1010 }
1011
1018 template<typename Elem>
1019 [[nodiscard]] decltype(auto) get(const entity_type entt) const {
1020 static_assert(stl::is_same_v<stl::remove_const_t<Elem>, typename Get::element_type>, "Invalid element type");
1021 return get<0>(entt);
1022 }
1023
1030 template<stl::size_t... Index>
1031 [[nodiscard]] decltype(auto) get(const entity_type entt) const {
1032 if constexpr(sizeof...(Index) == 0) {
1033 return storage()->get_as_tuple(entt);
1034 } else {
1035 return storage<Index...>()->get(entt);
1036 }
1037 }
1038
1054 template<typename Func>
1055 void each(Func func) const {
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);
1059 }
1060 } else if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) {
1061 if constexpr(stl::is_void_v<typename Get::value_type>) {
1062 for(size_type pos = base_type::size(); pos; --pos) {
1063 func();
1064 }
1065 } else {
1066 if(const auto len = static_cast<difference_type>(base_type::size()); len != 0) {
1067 for(auto last = storage()->end(), first = last - len; first != last; ++first) {
1068 func(*first);
1069 }
1070 }
1071 }
1072 } else {
1073 static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy");
1074
1075 for(const auto pack: each()) {
1076 stl::apply([&func](const auto, auto &&...elem) { func(stl::forward<decltype(elem)>(elem)...); }, pack);
1077 }
1078 }
1079 }
1080
1090 [[nodiscard]] iterable each() const noexcept {
1091 if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) {
1092 return base_type::handle() ? storage()->each() : iterable{};
1093 } else {
1094 static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy");
1096 }
1097 }
1098
1105 template<stl::derived_from<common_type> OGet>
1106 [[nodiscard]] basic_view<get_t<Get, OGet>, exclude_t<>> operator|(OGet &other) const noexcept {
1107 return *this | basic_view<get_t<OGet>, exclude_t<>>{other};
1108 }
1109
1117 template<stl::derived_from<common_type>... OGet, stl::derived_from<common_type>... OExclude>
1118 [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
1119 return internal::view_pack<basic_view<get_t<Get, OGet...>, exclude_t<OExclude...>>>(
1120 *this, other, stl::index_sequence_for<Get>{}, stl::index_sequence_for<>{}, stl::index_sequence_for<OGet...>{}, stl::index_sequence_for<OExclude...>{});
1121 }
1122};
1123
1129template<typename... Type>
1131
1137template<typename... Get, typename... Exclude>
1138basic_view(stl::tuple<Get &...>, stl::tuple<Exclude &...> = {}) -> basic_view<get_t<Get...>, exclude_t<Exclude...>>;
1139
1140} // namespace entt
1141
1142#endif
Basic storage view implementation.
Definition view.hpp:212
iterator begin() const noexcept
Returns an iterator to the first entity of the view.
Definition view.hpp:321
iterator find(const entity_type entt) const noexcept
Finds an entity.
Definition view.hpp:365
const common_type * handle() const noexcept
Returns the leading storage of a view, if any.
Definition view.hpp:302
size_type size_hint() const noexcept
Estimates the number of entities iterated by the view.
Definition view.hpp:310
bool contains(const entity_type entt) const noexcept
Checks if a view contains an entity.
Definition view.hpp:382
entity_type back() const noexcept
Returns the last entity of the view, if any.
Definition view.hpp:348
void refresh() noexcept
Updates the internal leading view if required.
Definition view.hpp:289
stl::size_t size_type
Unsigned integer type.
Definition view.hpp:282
Type::entity_type entity_type
Underlying entity identifier.
Definition view.hpp:280
entity_type front() const noexcept
Returns the first entity of the view, if any.
Definition view.hpp:338
stl::ptrdiff_t difference_type
Signed integer type.
Definition view.hpp:284
internal::view_iterator< common_type, Checked, Get, Exclude > iterator
Forward iterator type.
Definition view.hpp:286
iterator end() const noexcept
Returns an iterator that is past the last entity of the view.
Definition view.hpp:329
Type common_type
Common type among all storage types.
Definition view.hpp:278
Basic storage view implementation.
Definition view.hpp:675
entity_type front() const noexcept
Returns the first entity of the view, if any.
Definition view.hpp:809
stl::conditional_t< Policy==deletion_policy::in_place, void, typename common_type::reverse_iterator > reverse_iterator
Reverse iterator type.
Definition view.hpp:698
entity_type back() const noexcept
Returns the last entity of the view, if any.
Definition view.hpp:826
bool contains(const entity_type entt) const noexcept
Checks if a view contains an entity.
Definition view.hpp:873
iterator end() const noexcept
Returns an iterator that is past the last entity of the view.
Definition view.hpp:767
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.
Definition view.hpp:696
size_type size() const noexcept
Returns the number of entities that have the given element.
Definition view.hpp:712
bool empty() const noexcept
Checks whether a view is empty.
Definition view.hpp:735
common_type::entity_type entity_type
Underlying entity identifier.
Definition view.hpp:690
size_type size_hint() const noexcept
Estimates the number of entities iterated by the view.
Definition view.hpp:726
iterator begin() const noexcept
Returns an iterator to the first entity of the view.
Definition view.hpp:752
stl::ptrdiff_t difference_type
Signed integer type.
Definition view.hpp:694
reverse_iterator rend() const noexcept
Returns an iterator that is past the last entity of the reversed view.
Definition view.hpp:794
const common_type * handle() const noexcept
Returns the leading storage of a view, if any.
Definition view.hpp:704
Type common_type
Common type among all storage types.
Definition view.hpp:688
stl::size_t size_type
Unsigned integer type.
Definition view.hpp:692
iterator find(const entity_type entt) const noexcept
Finds an entity.
Definition view.hpp:849
reverse_iterator rbegin() const noexcept
Returns an iterator to the first entity of the reversed view.
Definition view.hpp:783
const value_type & get(const entity_type entt) const noexcept
Returns the object assigned to an entity.
Definition storage.hpp:632
iterable each() noexcept
Returns an iterable object to use to visit a storage.
Definition storage.hpp:744
stl::tuple< const value_type & > get_as_tuple(const entity_type entt) const noexcept
Returns the object assigned to an entity as a tuple.
Definition storage.hpp:646
auto operator|(const basic_view< get_t< OGet... >, exclude_t< OExclude... > > &other) const noexcept
Combines two views in a more specific one.
Definition view.hpp:1118
basic_view(Get &value) noexcept
Constructs a view from a storage class.
Definition view.hpp:931
void storage(Get &elem) noexcept
Assigns a storage to a view.
Definition view.hpp:990
Get * operator->() const noexcept
Returns a pointer to the underlying storage.
Definition view.hpp:999
basic_view< get_t< Get, OGet >, exclude_t<> > operator|(OGet &other) const noexcept
Combines a view and a storage in more specific view.
Definition view.hpp:1106
auto * storage() const noexcept
Returns the storage for a given element type, if any.
Definition view.hpp:960
basic_view() noexcept
Default constructor to use to create empty, invalid views.
Definition view.hpp:924
base_type::reverse_iterator reverse_iterator
Reverse iterator type.
Definition view.hpp:919
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.
Definition view.hpp:921
base_type::common_type common_type
Common type among all storage types.
Definition view.hpp:909
base_type::iterator iterator
Random access iterator type.
Definition view.hpp:917
void each(Func func) const
Iterates entities and elements and applies the given function object to them.
Definition view.hpp:1055
stl::ptrdiff_t difference_type
Signed integer type.
Definition view.hpp:915
iterable each() const noexcept
Returns an iterable object to use to visit a view.
Definition view.hpp:1090
base_type::size_type size_type
Unsigned integer type.
Definition view.hpp:913
base_type::entity_type entity_type
Underlying entity identifier.
Definition view.hpp:911
void storage(Get &elem) noexcept
Assigns a storage to a view.
Definition view.hpp:980
basic_view(stl::tuple< Get & > value, stl::tuple<>={}) noexcept
Constructs a view from a storage class.
Definition view.hpp:939
basic_view(const basic_view< Args... > &other) noexcept
Constructs a view from a convertible counterpart.
Definition view.hpp:949
decltype(auto) get(const entity_type entt) const
Returns the element assigned to the given entity.
Definition view.hpp:1019
decltype(auto) get(const entity_type entt) const
Returns the elements assigned to the given entity.
Definition view.hpp:583
stl::ptrdiff_t difference_type
Signed integer type.
Definition view.hpp:457
basic_view(Get &...value, Exclude &...excl) noexcept
Constructs a view from a set of storage classes.
Definition view.hpp:472
void use() noexcept
Forces a view to use a given element to drive iterations.
Definition view.hpp:502
void storage(Type &elem) noexcept
Assigns a storage to a view.
Definition view.hpp:556
basic_view< get_t< Get..., OGet >, exclude_t< Exclude... > > operator|(OGet &other) const noexcept
Combines a view and a storage in more specific view.
Definition view.hpp:650
basic_view(stl::tuple< Get &... > value, stl::tuple< Exclude &... > excl={}) noexcept
Constructs a view from a set of storage classes.
Definition view.hpp:481
iterable_adaptor< internal::extended_view_iterator< iterator, Get... > > iterable
Iterable view type.
Definition view.hpp:461
basic_view(const basic_view< Args... > &other) noexcept
Constructs a view from a convertible counterpart.
Definition view.hpp:491
auto * storage() const noexcept
Returns the storage for a given element type, if any.
Definition view.hpp:521
base_type::common_type common_type
Common type among all storage types.
Definition view.hpp:451
iterable each() const noexcept
Returns an iterable object to use to visit a view.
Definition view.hpp:639
void each(Func func) const
Iterates entities and elements and applies the given function object to them.
Definition view.hpp:622
void storage(Type &elem) noexcept
Assigns a storage to a view.
Definition view.hpp:545
base_type::size_type size_type
Unsigned integer type.
Definition view.hpp:455
auto operator|(const basic_view< get_t< OGet... >, exclude_t< OExclude... > > &other) const noexcept
Combines two views in a more specific one.
Definition view.hpp:662
base_type::iterator iterator
Forward iterator type.
Definition view.hpp:459
base_type::entity_type entity_type
Underlying entity identifier.
Definition view.hpp:453
basic_view() noexcept
Default constructor to use to create empty, invalid views.
Definition view.hpp:464
decltype(auto) get(const entity_type entt) const
Returns the elements assigned to the given entity.
Definition view.hpp:594
View implementation.
Definition fwd.hpp:48
Custom EnTT namespace for the standard template library.
Definition entt.hpp:5
EnTT default namespace.
Definition dense_map.hpp:25
basic_view(Type &...storage) -> basic_view< get_t< Type... >, exclude_t<> >
Deduction guide.
deletion_policy
Storage deletion policy.
Definition fwd.hpp:18
@ swap_only
Swap-only deletion policy.
Definition fwd.hpp:24
@ swap_and_pop
Swap-and-pop deletion policy.
Definition fwd.hpp:20
@ in_place
In-place deletion policy.
Definition fwd.hpp:22
type_list_element< Index, List >::type type_list_element_t
Helper type.
constexpr null_t null
Compile-time constant for null entities.
Definition entity.hpp:299
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.
Definition fwd.hpp:278
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.
Definition entity.hpp:308
constexpr get_t< Type... > get
Variable template for lists of observed elements.
Definition fwd.hpp:168
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.
Definition fwd.hpp:79
Alias for exclusion lists.
Definition fwd.hpp:141
Alias for lists of observed elements.
Definition fwd.hpp:158
Utility class to create an iterable object from a pair of iterators.
Definition iterator.hpp:125
A class to use to push around lists of types, nothing more.