EnTT 3.15.0
Loading...
Searching...
No Matches
view.hpp
1#ifndef ENTT_ENTITY_VIEW_HPP
2#define ENTT_ENTITY_VIEW_HPP
3
4#include <array>
5#include <cstddef>
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 "entity.hpp"
14#include "fwd.hpp"
15
16namespace entt {
17
19namespace internal {
20
21template<typename... Type>
22// NOLINTNEXTLINE(misc-redundant-expression)
23static constexpr bool tombstone_check_v = ((sizeof...(Type) == 1u) && ... && (Type::storage_policy == deletion_policy::in_place));
24
25template<typename Type>
26const Type *view_placeholder() {
27 static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>, "Unexpected type");
28 static const Type placeholder{};
29 return &placeholder;
30}
31
32template<typename It, typename Entity>
33[[nodiscard]] bool all_of(It first, const It last, const Entity entt) noexcept {
34 for(; (first != last) && (*first)->contains(entt); ++first) {}
35 return first == last;
36}
37
38template<typename It, typename Entity>
39[[nodiscard]] bool none_of(It first, const It last, const Entity entt) noexcept {
40 for(; (first != last) && !(*first)->contains(entt); ++first) {}
41 return first == last;
42}
43
44template<typename It>
45[[nodiscard]] bool fully_initialized(It first, const It last, const std::remove_pointer_t<typename std::iterator_traits<It>::value_type> *placeholder) noexcept {
46 for(; (first != last) && *first != placeholder; ++first) {}
47 return first == last;
48}
49
50template<typename Result, typename View, typename Other, std::size_t... GLhs, std::size_t... ELhs, std::size_t... GRhs, std::size_t... ERhs>
51[[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...>) {
52 Result elem{};
53 // friend-initialization, avoid multiple calls to refresh
54 elem.pools = {view.template storage<GLhs>()..., other.template storage<GRhs>()...};
55 auto filter_or_placeholder = [placeholder = elem.placeholder](auto *value) { return (value == nullptr) ? placeholder : value; };
56 elem.filter = {filter_or_placeholder(view.template storage<sizeof...(GLhs) + ELhs>())..., filter_or_placeholder(other.template storage<sizeof...(GRhs) + ERhs>())...};
57 elem.refresh();
58 return elem;
59}
60
61template<typename Type, bool Checked, std::size_t Get, std::size_t Exclude>
62class view_iterator final {
63 template<typename, typename...>
64 friend class extended_view_iterator;
65
66 using iterator_type = typename Type::const_iterator;
67 using iterator_traits = std::iterator_traits<iterator_type>;
68
69 [[nodiscard]] bool valid(const typename iterator_traits::value_type entt) const noexcept {
70 return (!Checked || (entt != tombstone))
71 && ((Get == 1u) || (internal::all_of(pools.begin(), pools.begin() + index, entt) && internal::all_of(pools.begin() + index + 1, pools.end(), entt)))
72 && ((Exclude == 0u) || internal::none_of(filter.begin(), filter.end(), entt));
73 }
74
75 void seek_next() {
76 for(constexpr iterator_type sentinel{}; it != sentinel && !valid(*it); ++it) {}
77 }
78
79public:
80 using value_type = typename iterator_traits::value_type;
81 using pointer = typename iterator_traits::pointer;
82 using reference = typename iterator_traits::reference;
83 using difference_type = typename iterator_traits::difference_type;
84 using iterator_category = std::forward_iterator_tag;
85
86 constexpr view_iterator() noexcept
87 : it{},
88 pools{},
89 filter{},
90 index{} {}
91
92 view_iterator(iterator_type first, std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl, const std::size_t idx) noexcept
93 : it{first},
94 pools{value},
95 filter{excl},
96 index{static_cast<difference_type>(idx)} {
97 ENTT_ASSERT((Get != 1u) || (Exclude != 0u) || pools[0u]->policy() == deletion_policy::in_place, "Non in-place storage view iterator");
98 seek_next();
99 }
100
101 view_iterator &operator++() noexcept {
102 ++it;
103 seek_next();
104 return *this;
105 }
106
107 view_iterator operator++(int) noexcept {
108 const view_iterator orig = *this;
109 return ++(*this), orig;
110 }
111
112 [[nodiscard]] pointer operator->() const noexcept {
113 return &*it;
114 }
115
116 [[nodiscard]] reference operator*() const noexcept {
117 return *operator->();
118 }
119
120 template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
121 friend constexpr bool operator==(const view_iterator<LhsType, LhsArgs...> &, const view_iterator<RhsType, RhsArgs...> &) noexcept;
122
123private:
124 iterator_type it;
125 std::array<const Type *, Get> pools;
126 std::array<const Type *, Exclude> filter;
127 difference_type index;
128};
129
130template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
131[[nodiscard]] constexpr bool operator==(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) noexcept {
132 return lhs.it == rhs.it;
133}
134
135template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
136[[nodiscard]] constexpr bool operator!=(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) noexcept {
137 return !(lhs == rhs);
138}
139
140template<typename It, typename... Get>
141class extended_view_iterator final {
142 template<std::size_t... Index>
143 [[nodiscard]] auto dereference(std::index_sequence<Index...>) const noexcept {
144 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)...);
145 }
146
147public:
148 using iterator_type = It;
149 using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Get>().get_as_tuple({})...));
150 using pointer = input_iterator_pointer<value_type>;
151 using reference = value_type;
152 using difference_type = std::ptrdiff_t;
153 using iterator_category = std::input_iterator_tag;
154 using iterator_concept = std::forward_iterator_tag;
155
156 constexpr extended_view_iterator()
157 : it{} {}
158
159 extended_view_iterator(iterator_type from)
160 : it{from} {}
161
162 extended_view_iterator &operator++() noexcept {
163 return ++it, *this;
164 }
165
166 extended_view_iterator operator++(int) noexcept {
167 const extended_view_iterator orig = *this;
168 return ++(*this), orig;
169 }
170
171 [[nodiscard]] reference operator*() const noexcept {
172 return dereference(std::index_sequence_for<Get...>{});
173 }
174
175 [[nodiscard]] pointer operator->() const noexcept {
176 return operator*();
177 }
178
179 [[nodiscard]] constexpr iterator_type base() const noexcept {
180 return it;
181 }
182
183 template<typename... Lhs, typename... Rhs>
184 friend bool constexpr operator==(const extended_view_iterator<Lhs...> &, const extended_view_iterator<Rhs...> &) noexcept;
185
186private:
187 It it;
188};
189
190template<typename... Lhs, typename... Rhs>
191[[nodiscard]] constexpr bool operator==(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) noexcept {
192 return lhs.it == rhs.it;
193}
194
195template<typename... Lhs, typename... Rhs>
196[[nodiscard]] constexpr bool operator!=(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) noexcept {
197 return !(lhs == rhs);
198}
199
200} // namespace internal
202
221template<typename, typename, typename>
222class basic_view;
223
232template<typename Type, bool Checked, std::size_t Get, std::size_t Exclude>
234 static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>, "Unexpected type");
235
236 template<typename Return, typename View, typename Other, std::size_t... GLhs, std::size_t... ELhs, std::size_t... GRhs, std::size_t... ERhs>
237 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...>);
238
239 [[nodiscard]] auto offset() const noexcept {
240 ENTT_ASSERT(index != Get, "Invalid view");
241 return (pools[index]->policy() == deletion_policy::swap_only) ? pools[index]->free_list() : pools[index]->size();
242 }
243
244 void unchecked_refresh() noexcept {
245 index = 0u;
246
247 if constexpr(Get > 1u) {
248 for(size_type pos{1u}; pos < Get; ++pos) {
249 if(pools[pos]->size() < pools[index]->size()) {
250 index = pos;
251 }
252 }
253 }
254 }
255
256protected:
258 basic_common_view() noexcept {
259 for(size_type pos{}, last = filter.size(); pos < last; ++pos) {
260 filter[pos] = placeholder;
261 }
262 }
263
264 basic_common_view(std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl) noexcept
265 : pools{value},
266 filter{excl},
267 index{Get} {
268 unchecked_refresh();
269 }
270
271 [[nodiscard]] const Type *pool_at(const std::size_t pos) const noexcept {
272 return pools[pos];
273 }
274
275 void pool_at(const std::size_t pos, const Type *elem) noexcept {
276 ENTT_ASSERT(elem != nullptr, "Unexpected element");
277 pools[pos] = elem;
278 refresh();
279 }
280
281 [[nodiscard]] const Type *filter_at(const std::size_t pos) const noexcept {
282 return (filter[pos] == placeholder) ? nullptr : filter[pos];
283 }
284
285 void filter_at(const std::size_t pos, const Type *elem) noexcept {
286 ENTT_ASSERT(elem != nullptr, "Unexpected element");
287 filter[pos] = elem;
288 }
289
290 [[nodiscard]] bool none_of(const typename Type::entity_type entt) const noexcept {
291 return internal::none_of(filter.begin(), filter.end(), entt);
292 }
293
294 void use(const std::size_t pos) noexcept {
295 index = (index != Get) ? pos : Get;
296 }
298
299public:
301 using common_type = Type;
303 using entity_type = typename Type::entity_type;
305 using size_type = std::size_t;
307 using difference_type = std::ptrdiff_t;
309 using iterator = internal::view_iterator<common_type, Checked, Get, Exclude>;
310
312 void refresh() noexcept {
313 size_type pos = static_cast<size_type>(index != Get) * Get;
314 for(; pos < Get && pools[pos] != nullptr; ++pos) {}
315
316 if(pos == Get) {
317 unchecked_refresh();
318 }
319 }
320
325 [[nodiscard]] const common_type *handle() const noexcept {
326 return (index != Get) ? pools[index] : nullptr;
327 }
328
333 [[nodiscard]] size_type size_hint() const noexcept {
334 return (index != Get) ? offset() : size_type{};
335 }
336
344 [[nodiscard]] iterator begin() const noexcept {
345 return (index != Get) ? iterator{pools[index]->end() - static_cast<difference_type>(offset()), pools, filter, index} : iterator{};
346 }
347
352 [[nodiscard]] iterator end() const noexcept {
353 return (index != Get) ? iterator{pools[index]->end(), pools, filter, index} : iterator{};
354 }
355
361 [[nodiscard]] entity_type front() const noexcept {
362 const auto it = begin();
363 return it != end() ? *it : null;
364 }
365
371 [[nodiscard]] entity_type back() const noexcept {
372 if(index != Get) {
373 auto it = pools[index]->rbegin();
374 const auto last = it + static_cast<difference_type>(offset());
375 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) {}
376 return it == last ? null : *it;
377 }
378
379 return null;
380 }
381
388 [[nodiscard]] iterator find(const entity_type entt) const noexcept {
389 return contains(entt) ? iterator{pools[index]->find(entt), pools, filter, index} : end();
390 }
391
396 [[nodiscard]] explicit operator bool() const noexcept {
397 return (index != Get) && internal::fully_initialized(filter.begin(), filter.end(), placeholder);
398 }
399
405 [[nodiscard]] bool contains(const entity_type entt) const noexcept {
406 return (index != Get)
407 && internal::all_of(pools.begin(), pools.end(), entt)
408 && internal::none_of(filter.begin(), filter.end(), entt)
409 && pools[index]->index(entt) < offset();
410 }
411
412private:
413 std::array<const common_type *, Get> pools{};
414 std::array<const common_type *, Exclude> filter{};
415 const common_type *placeholder{internal::view_placeholder<common_type>()};
416 size_type index{Get};
417};
418
431template<typename... Get, typename... Exclude>
432class basic_view<get_t<Get...>, exclude_t<Exclude...>, std::enable_if_t<(sizeof...(Get) != 0u)>>
433 : public basic_common_view<std::common_type_t<typename Get::base_type...>, internal::tombstone_check_v<Get...>, sizeof...(Get), sizeof...(Exclude)> {
434 using base_type = basic_common_view<std::common_type_t<typename Get::base_type...>, internal::tombstone_check_v<Get...>, sizeof...(Get), sizeof...(Exclude)>;
435
436 template<std::size_t Index>
437 using element_at = type_list_element_t<Index, type_list<Get..., Exclude...>>;
438
439 template<typename Type>
440 static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Get::element_type..., typename Exclude::element_type...>>;
441
442 template<std::size_t... Index>
443 [[nodiscard]] auto get(const typename base_type::entity_type entt, std::index_sequence<Index...>) const noexcept {
444 return std::tuple_cat(storage<Index>()->get_as_tuple(entt)...);
445 }
446
447 template<std::size_t Curr, std::size_t Other, typename... Args>
448 [[nodiscard]] auto dispatch_get(const std::tuple<typename base_type::entity_type, Args...> &curr) const {
449 if constexpr(Curr == Other) {
450 return std::forward_as_tuple(std::get<Args>(curr)...);
451 } else {
452 return storage<Other>()->get_as_tuple(std::get<0>(curr));
453 }
454 }
455
456 template<std::size_t Curr, typename Func, std::size_t... Index>
457 void each(Func &func, std::index_sequence<Index...>) const {
458 for(const auto curr: storage<Curr>()->each()) {
459 if(const auto entt = std::get<0>(curr); (!internal::tombstone_check_v<Get...> || (entt != tombstone)) && ((Curr == Index || base_type::pool_at(Index)->contains(entt)) && ...) && base_type::none_of(entt)) {
460 if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
461 std::apply(func, std::tuple_cat(std::make_tuple(entt), dispatch_get<Curr, Index>(curr)...));
462 } else {
463 std::apply(func, std::tuple_cat(dispatch_get<Curr, Index>(curr)...));
464 }
465 }
466 }
467 }
468
469 template<typename Func, std::size_t... Index>
470 void pick_and_each(Func &func, std::index_sequence<Index...> seq) const {
471 if(const auto *view = base_type::handle(); view != nullptr) {
472 ((view == base_type::pool_at(Index) ? each<Index>(func, seq) : void()), ...);
473 }
474 }
475
476public:
484 using difference_type = std::ptrdiff_t;
488 using iterable = iterable_adaptor<internal::extended_view_iterator<iterator, Get...>>;
489
491 basic_view() noexcept
492 : base_type{} {}
493
499 basic_view(Get &...value, Exclude &...excl) noexcept
500 : base_type{{&value...}, {&excl...}} {
501 }
502
508 basic_view(std::tuple<Get &...> value, std::tuple<Exclude &...> excl = {}) noexcept
509 : basic_view{std::make_from_tuple<basic_view>(std::tuple_cat(value, excl))} {}
510
515 template<typename Type>
516 void use() noexcept {
518 }
519
524 template<std::size_t Index>
525 void use() noexcept {
526 base_type::use(Index);
527 }
528
534 template<typename Type>
535 [[nodiscard]] auto *storage() const noexcept {
536 return storage<index_of<Type>>();
537 }
538
544 template<std::size_t Index>
545 [[nodiscard]] auto *storage() const noexcept {
546 if constexpr(Index < sizeof...(Get)) {
547 return static_cast<element_at<Index> *>(const_cast<constness_as_t<common_type, element_at<Index>> *>(base_type::pool_at(Index)));
548 } else {
549 return static_cast<element_at<Index> *>(const_cast<constness_as_t<common_type, element_at<Index>> *>(base_type::filter_at(Index - sizeof...(Get))));
550 }
551 }
552
558 template<typename Type>
559 void storage(Type &elem) noexcept {
561 }
562
569 template<std::size_t Index, typename Type>
570 void storage(Type &elem) noexcept {
571 static_assert(std::is_convertible_v<Type &, element_at<Index> &>, "Unexpected type");
572
573 if constexpr(Index < sizeof...(Get)) {
574 base_type::pool_at(Index, &elem);
575 } else {
576 base_type::filter_at(Index - sizeof...(Get), &elem);
577 }
578 }
579
585 [[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
586 return get(entt);
587 }
588
596 template<typename Type, typename... Other>
597 [[nodiscard]] decltype(auto) get(const entity_type entt) const {
598 return get<index_of<Type>, index_of<Other>...>(entt);
599 }
600
607 template<std::size_t... Index>
608 [[nodiscard]] decltype(auto) get(const entity_type entt) const {
609 if constexpr(sizeof...(Index) == 0) {
610 return get(entt, std::index_sequence_for<Get...>{});
611 } else if constexpr(sizeof...(Index) == 1) {
612 return (storage<Index>()->get(entt), ...);
613 } else {
614 return std::tuple_cat(storage<Index>()->get_as_tuple(entt)...);
615 }
616 }
617
633 template<typename Func>
634 void each(Func func) const {
635 pick_and_each(func, std::index_sequence_for<Get...>{});
636 }
637
647 [[nodiscard]] iterable each() const noexcept {
649 }
650
657 template<typename OGet>
658 [[nodiscard]] std::enable_if_t<std::is_base_of_v<common_type, OGet>, basic_view<get_t<Get..., OGet>, exclude_t<Exclude...>>> operator|(OGet &other) const noexcept {
659 return *this | basic_view<get_t<OGet>, exclude_t<>>{other};
660 }
661
669 template<typename... OGet, typename... OExclude>
670 [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
671 return internal::view_pack<basic_view<get_t<Get..., OGet...>, exclude_t<Exclude..., OExclude...>>>(
672 *this, other, std::index_sequence_for<Get...>{}, std::index_sequence_for<Exclude...>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
673 }
674};
675
682template<typename Type, deletion_policy Policy>
684 static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>, "Unexpected type");
685
686protected:
688 basic_storage_view() noexcept = default;
689
690 basic_storage_view(const Type *value) noexcept
691 : leading{value} {
692 ENTT_ASSERT(leading->policy() == Policy, "Unexpected storage policy");
693 }
695
696public:
698 using common_type = Type;
700 using entity_type = typename common_type::entity_type;
702 using size_type = std::size_t;
704 using difference_type = std::ptrdiff_t;
706 using iterator = std::conditional_t<Policy == deletion_policy::in_place, internal::view_iterator<common_type, true, 1u, 0u>, typename common_type::iterator>;
708 using reverse_iterator = std::conditional_t<Policy == deletion_policy::in_place, void, typename common_type::reverse_iterator>;
709
714 [[nodiscard]] const common_type *handle() const noexcept {
715 return leading;
716 }
717
723 template<typename..., deletion_policy Pol = Policy>
724 [[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, size_type> size() const noexcept {
725 if constexpr(Policy == deletion_policy::swap_and_pop) {
726 return leading ? leading->size() : size_type{};
727 } else {
728 static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy");
729 return leading ? leading->free_list() : size_type{};
730 }
731 }
732
738 template<typename..., deletion_policy Pol = Policy>
739 [[nodiscard]] std::enable_if_t<Pol == deletion_policy::in_place, size_type> size_hint() const noexcept {
740 return leading ? leading->size() : size_type{};
741 }
742
748 template<typename..., deletion_policy Pol = Policy>
749 [[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, bool> empty() const noexcept {
750 if constexpr(Policy == deletion_policy::swap_and_pop) {
751 return !leading || leading->empty();
752 } else {
753 static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy");
754 return !leading || (leading->free_list() == 0u);
755 }
756 }
757
765 [[nodiscard]] iterator begin() const noexcept {
766 if constexpr(Policy == deletion_policy::swap_and_pop) {
767 return leading ? leading->begin() : iterator{};
768 } else if constexpr(Policy == deletion_policy::swap_only) {
769 return leading ? (leading->end() - static_cast<difference_type>(leading->free_list())) : iterator{};
770 } else {
771 static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy");
772 return leading ? iterator{leading->begin(), {leading}, {}, 0u} : iterator{};
773 }
774 }
775
780 [[nodiscard]] iterator end() const noexcept {
781 if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) {
782 return leading ? leading->end() : iterator{};
783 } else {
784 static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy");
785 return leading ? iterator{leading->end(), {leading}, {}, 0u} : iterator{};
786 }
787 }
788
797 template<typename..., deletion_policy Pol = Policy>
798 [[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, reverse_iterator> rbegin() const noexcept {
799 return leading ? leading->rbegin() : reverse_iterator{};
800 }
801
809 template<typename..., deletion_policy Pol = Policy>
810 [[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, reverse_iterator> rend() const noexcept {
811 if constexpr(Policy == deletion_policy::swap_and_pop) {
812 return leading ? leading->rend() : reverse_iterator{};
813 } else {
814 static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy");
815 return leading ? (leading->rbegin() + static_cast<difference_type>(leading->free_list())) : reverse_iterator{};
816 }
817 }
818
824 [[nodiscard]] entity_type front() const noexcept {
825 if constexpr(Policy == deletion_policy::swap_and_pop) {
826 return empty() ? null : *leading->begin();
827 } else if constexpr(Policy == deletion_policy::swap_only) {
828 return empty() ? null : *(leading->end() - static_cast<difference_type>(leading->free_list()));
829 } else {
830 static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy");
831 const auto it = begin();
832 return (it == end()) ? null : *it;
833 }
834 }
835
841 [[nodiscard]] entity_type back() const noexcept {
842 if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) {
843 return empty() ? null : *leading->rbegin();
844 } else {
845 static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy");
846
847 if(leading) {
848 auto it = leading->rbegin();
849 const auto last = leading->rend();
850 for(; (it != last) && (*it == tombstone); ++it) {}
851 return it == last ? null : *it;
852 }
853
854 return null;
855 }
856 }
857
864 [[nodiscard]] iterator find(const entity_type entt) const noexcept {
865 if constexpr(Policy == deletion_policy::swap_and_pop) {
866 return leading ? leading->find(entt) : iterator{};
867 } else if constexpr(Policy == deletion_policy::swap_only) {
868 const auto it = leading ? leading->find(entt) : iterator{};
869 return leading && (static_cast<size_type>(it.index()) < leading->free_list()) ? it : iterator{};
870 } else {
871 return leading ? iterator{leading->find(entt), {leading}, {}, 0u} : iterator{};
872 }
873 }
874
879 [[nodiscard]] explicit operator bool() const noexcept {
880 return (leading != nullptr);
881 }
882
888 [[nodiscard]] bool contains(const entity_type entt) const noexcept {
889 if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::in_place) {
890 return leading && leading->contains(entt);
891 } else {
892 static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy");
893 return leading && leading->contains(entt) && (leading->index(entt) < leading->free_list());
894 }
895 }
896
897private:
898 const common_type *leading{};
899};
900
911template<typename Get>
913 : public basic_storage_view<typename Get::base_type, Get::storage_policy> {
915
916public:
924 using difference_type = std::ptrdiff_t;
930 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())>;
931
933 basic_view() noexcept
934 : base_type{} {}
935
940 basic_view(Get &value) noexcept
941 : base_type{&value} {
942 }
943
948 basic_view(std::tuple<Get &> value, std::tuple<> = {}) noexcept
949 : basic_view{std::get<0>(value)} {}
950
956 template<typename Type = typename Get::element_type>
957 [[nodiscard]] auto *storage() const noexcept {
958 static_assert(std::is_same_v<std::remove_const_t<Type>, typename Get::element_type>, "Invalid element type");
959 return storage<0>();
960 }
961
967 template<std::size_t Index>
968 [[nodiscard]] auto *storage() const noexcept {
969 static_assert(Index == 0u, "Index out of bounds");
970 return static_cast<Get *>(const_cast<constness_as_t<common_type, Get> *>(base_type::handle()));
971 }
972
977 void storage(Get &elem) noexcept {
978 storage<0>(elem);
979 }
980
986 template<std::size_t Index>
987 void storage(Get &elem) noexcept {
988 static_assert(Index == 0u, "Index out of bounds");
989 *this = basic_view{elem};
990 }
991
996 [[nodiscard]] Get *operator->() const noexcept {
997 return storage();
998 }
999
1005 [[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
1006 return storage()->get(entt);
1007 }
1008
1015 template<typename Elem>
1016 [[nodiscard]] decltype(auto) get(const entity_type entt) const {
1017 static_assert(std::is_same_v<std::remove_const_t<Elem>, typename Get::element_type>, "Invalid element type");
1018 return get<0>(entt);
1019 }
1020
1027 template<std::size_t... Index>
1028 [[nodiscard]] decltype(auto) get(const entity_type entt) const {
1029 if constexpr(sizeof...(Index) == 0) {
1030 return storage()->get_as_tuple(entt);
1031 } else {
1032 return storage<Index...>()->get(entt);
1033 }
1034 }
1035
1051 template<typename Func>
1052 void each(Func func) const {
1053 if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
1054 for(const auto pack: each()) {
1055 std::apply(func, pack);
1056 }
1057 } else if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) {
1058 if constexpr(std::is_void_v<typename Get::value_type>) {
1059 for(size_type pos = base_type::size(); pos; --pos) {
1060 func();
1061 }
1062 } else {
1063 if(const auto len = static_cast<difference_type>(base_type::size()); len != 0) {
1064 for(auto last = storage()->end(), first = last - len; first != last; ++first) {
1065 func(*first);
1066 }
1067 }
1068 }
1069 } else {
1070 static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy");
1071
1072 for(const auto pack: each()) {
1073 std::apply([&func](const auto, auto &&...elem) { func(std::forward<decltype(elem)>(elem)...); }, pack);
1074 }
1075 }
1076 }
1077
1087 [[nodiscard]] iterable each() const noexcept {
1088 if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) {
1089 return base_type::handle() ? storage()->each() : iterable{};
1090 } else {
1091 static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy");
1093 }
1094 }
1095
1102 template<typename OGet>
1103 [[nodiscard]] std::enable_if_t<std::is_base_of_v<common_type, OGet>, basic_view<get_t<Get, OGet>, exclude_t<>>> operator|(OGet &other) const noexcept {
1104 return *this | basic_view<get_t<OGet>, exclude_t<>>{other};
1105 }
1106
1114 template<typename... OGet, typename... OExclude>
1115 [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
1116 return internal::view_pack<basic_view<get_t<Get, OGet...>, exclude_t<OExclude...>>>(
1117 *this, other, std::index_sequence_for<Get>{}, std::index_sequence_for<>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
1118 }
1119};
1120
1126template<typename... Type>
1128
1134template<typename... Get, typename... Exclude>
1135basic_view(std::tuple<Get &...>, std::tuple<Exclude &...> = {}) -> basic_view<get_t<Get...>, exclude_t<Exclude...>>;
1136
1137} // namespace entt
1138
1139#endif
Basic storage view implementation.
Definition view.hpp:233
iterator begin() const noexcept
Returns an iterator to the first entity of the view.
Definition view.hpp:344
iterator find(const entity_type entt) const noexcept
Finds an entity.
Definition view.hpp:388
typename Type::entity_type entity_type
Underlying entity identifier.
Definition view.hpp:303
const common_type * handle() const noexcept
Returns the leading storage of a view, if any.
Definition view.hpp:325
size_type size_hint() const noexcept
Estimates the number of entities iterated by the view.
Definition view.hpp:333
bool contains(const entity_type entt) const noexcept
Checks if a view contains an entity.
Definition view.hpp:405
entity_type back() const noexcept
Returns the last entity of the view, if any.
Definition view.hpp:371
void refresh() noexcept
Updates the internal leading view if required.
Definition view.hpp:312
std::ptrdiff_t difference_type
Signed integer type.
Definition view.hpp:307
entity_type front() const noexcept
Returns the first entity of the view, if any.
Definition view.hpp:361
internal::view_iterator< common_type, Checked, Get, Exclude > iterator
Forward iterator type.
Definition view.hpp:309
iterator end() const noexcept
Returns an iterator that is past the last entity of the view.
Definition view.hpp:352
Type common_type
Common type among all storage types.
Definition view.hpp:301
std::size_t size_type
Unsigned integer type.
Definition view.hpp:305
Basic storage view implementation.
Definition view.hpp:683
entity_type front() const noexcept
Returns the first entity of the view, if any.
Definition view.hpp:824
std::enable_if_t< Pol !=deletion_policy::in_place, bool > empty() const noexcept
Checks whether a view is empty.
Definition view.hpp:749
std::conditional_t< Policy==deletion_policy::in_place, void, typename common_type::reverse_iterator > reverse_iterator
Reverse iterator type.
Definition view.hpp:708
std::ptrdiff_t difference_type
Signed integer type.
Definition view.hpp:704
entity_type back() const noexcept
Returns the last entity of the view, if any.
Definition view.hpp:841
bool contains(const entity_type entt) const noexcept
Checks if a view contains an entity.
Definition view.hpp:888
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.
Definition view.hpp:810
iterator end() const noexcept
Returns an iterator that is past the last entity of the view.
Definition view.hpp:780
std::enable_if_t< Pol==deletion_policy::in_place, size_type > size_hint() const noexcept
Estimates the number of entities iterated by the view.
Definition view.hpp:739
std::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:706
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.
Definition view.hpp:798
std::enable_if_t< Pol !=deletion_policy::in_place, size_type > size() const noexcept
Returns the number of entities that have the given element.
Definition view.hpp:724
std::size_t size_type
Unsigned integer type.
Definition view.hpp:702
typename common_type::entity_type entity_type
Underlying entity identifier.
Definition view.hpp:700
iterator begin() const noexcept
Returns an iterator to the first entity of the view.
Definition view.hpp:765
const common_type * handle() const noexcept
Returns the leading storage of a view, if any.
Definition view.hpp:714
Type common_type
Common type among all storage types.
Definition view.hpp:698
iterator find(const entity_type entt) const noexcept
Finds an entity.
Definition view.hpp:864
const value_type & get(const entity_type entt) const noexcept
Returns the object assigned to an entity.
Definition storage.hpp:648
iterable each() noexcept
Returns an iterable object to use to visit a storage.
Definition storage.hpp:762
std::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:662
basic_view(std::tuple< Get & > value, std::tuple<>={}) noexcept
Constructs a view from a storage class.
Definition view.hpp:948
typename base_type::entity_type entity_type
Underlying entity identifier.
Definition view.hpp:920
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:1115
basic_view(Get &value) noexcept
Constructs a view from a storage class.
Definition view.hpp:940
std::ptrdiff_t difference_type
Signed integer type.
Definition view.hpp:924
void storage(Get &elem) noexcept
Assigns a storage to a view.
Definition view.hpp:987
Get * operator->() const noexcept
Returns a pointer to the underlying storage.
Definition view.hpp:996
typename base_type::common_type common_type
Common type among all storage types.
Definition view.hpp:918
typename base_type::reverse_iterator reverse_iterator
Reverse iterator type.
Definition view.hpp:928
typename base_type::iterator iterator
Random access iterator type.
Definition view.hpp:926
auto * storage() const noexcept
Returns the storage for a given element type, if any.
Definition view.hpp:957
basic_view() noexcept
Default constructor to use to create empty, invalid views.
Definition view.hpp:933
std::enable_if_t< std::is_base_of_v< common_type, OGet >, 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:1103
void each(Func func) const
Iterates entities and elements and applies the given function object to them.
Definition view.hpp:1052
iterable each() const noexcept
Returns an iterable object to use to visit a view.
Definition view.hpp:1087
void storage(Get &elem) noexcept
Assigns a storage to a view.
Definition view.hpp:977
typename base_type::size_type size_type
Unsigned integer type.
Definition view.hpp:922
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.
Definition view.hpp:930
decltype(auto) get(const entity_type entt) const
Returns the element assigned to the given entity.
Definition view.hpp:1016
typename base_type::common_type common_type
Common type among all storage types.
Definition view.hpp:478
basic_view() noexcept
Default constructor to use to create empty, invalid views.
Definition view.hpp:491
void each(Func func) const
Iterates entities and elements and applies the given function object to them.
Definition view.hpp:634
decltype(auto) get(const entity_type entt) const
Returns the elements assigned to the given entity.
Definition view.hpp:608
std::enable_if_t< std::is_base_of_v< common_type, OGet >, 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:658
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:670
iterable each() const noexcept
Returns an iterable object to use to visit a view.
Definition view.hpp:647
decltype(auto) get(const entity_type entt) const
Returns the elements assigned to the given entity.
Definition view.hpp:597
iterable_adaptor< internal::extended_view_iterator< iterator, Get... > > iterable
Iterable view type.
Definition view.hpp:488
void use() noexcept
Forces a view to use a given element to drive iterations.
Definition view.hpp:516
basic_view(std::tuple< Get &... > value, std::tuple< Exclude &... > excl={}) noexcept
Constructs a view from a set of storage classes.
Definition view.hpp:508
basic_view(Get &...value, Exclude &...excl) noexcept
Constructs a view from a set of storage classes.
Definition view.hpp:499
auto * storage() const noexcept
Returns the storage for a given element type, if any.
Definition view.hpp:535
View implementation.
Definition fwd.hpp:47
EnTT default namespace.
Definition dense_map.hpp:22
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.
Definition entity.hpp:375
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.
Definition fwd.hpp:277
constexpr bool is_applicable_v
Helper variable template.
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
Definition entity.hpp:384
constexpr get_t< Type... > get
Variable template for lists of observed elements.
Definition fwd.hpp:167
typename type_list_element< Index, List >::type type_list_element_t
Helper type.
deletion_policy
Storage deletion policy.
Definition fwd.hpp:17
@ swap_only
Swap-only deletion policy.
Definition fwd.hpp:23
@ swap_and_pop
Swap-and-pop deletion policy.
Definition fwd.hpp:19
@ in_place
In-place deletion policy.
Definition fwd.hpp:21
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.
Definition fwd.hpp:78
Alias for exclusion lists.
Definition fwd.hpp:140
Alias for lists of observed elements.
Definition fwd.hpp:157
Utility class to create an iterable object from a pair of iterators.
Definition iterator.hpp:141
A class to use to push around lists of types, nothing more.