EnTT 4.0.0
Loading...
Searching...
No Matches
storage.hpp
1#ifndef ENTT_ENTITY_STORAGE_HPP
2#define ENTT_ENTITY_STORAGE_HPP
3
4#include <compare>
5#include "../config/config.h"
6#include "../core/bit.hpp"
7#include "../core/iterator.hpp"
8#include "../core/memory.hpp"
9#include "../core/type_info.hpp"
10#include "../stl/concepts.hpp"
11#include "../stl/cstddef.hpp"
12#include "../stl/iterator.hpp"
13#include "../stl/memory.hpp"
14#include "../stl/tuple.hpp"
15#include "../stl/type_traits.hpp"
16#include "../stl/utility.hpp"
17#include "../stl/vector.hpp"
18#include "component.hpp"
19#include "entity.hpp"
20#include "fwd.hpp"
21#include "sparse_set.hpp"
22
23namespace entt {
24
26namespace internal {
27
28template<typename Container, auto Page>
29class storage_iterator final {
30 template<typename, auto>
31 friend class storage_iterator;
32
33 using container_type = stl::remove_const_t<Container>;
34 using alloc_traits = stl::allocator_traits<typename container_type::allocator_type>;
35
36 using iterator_traits = stl::iterator_traits<stl::conditional_t<
37 stl::is_const_v<Container>,
38 typename alloc_traits::template rebind_traits<typename stl::pointer_traits<typename container_type::value_type>::element_type>::const_pointer,
39 typename alloc_traits::template rebind_traits<typename stl::pointer_traits<typename container_type::value_type>::element_type>::pointer>>;
40
41public:
42 using value_type = iterator_traits::value_type;
43 using pointer = iterator_traits::pointer;
44 using reference = iterator_traits::reference;
45 using difference_type = iterator_traits::difference_type;
46 using iterator_category = stl::random_access_iterator_tag;
47
48 constexpr storage_iterator() noexcept = default;
49
50 constexpr storage_iterator(Container *ref, const difference_type idx) noexcept
51 : payload{ref},
52 offset{idx} {}
53
54 template<stl::same_as<stl::remove_const_t<Container>> Other>
55 requires stl::is_const_v<Container>
56 constexpr storage_iterator(const storage_iterator<Other, Page> &other) noexcept
57 : storage_iterator{other.payload, other.offset} {}
58
59 constexpr storage_iterator &operator++() noexcept {
60 return --offset, *this;
61 }
62
63 constexpr storage_iterator operator++(int) noexcept {
64 const storage_iterator orig = *this;
65 return ++(*this), orig;
66 }
67
68 constexpr storage_iterator &operator--() noexcept {
69 return ++offset, *this;
70 }
71
72 constexpr storage_iterator operator--(int) noexcept {
73 const storage_iterator orig = *this;
74 return operator--(), orig;
75 }
76
77 constexpr storage_iterator &operator+=(const difference_type value) noexcept {
78 offset -= value;
79 return *this;
80 }
81
82 constexpr storage_iterator operator+(const difference_type value) const noexcept {
83 storage_iterator copy = *this;
84 return (copy += value);
85 }
86
87 constexpr storage_iterator &operator-=(const difference_type value) noexcept {
88 return (*this += -value);
89 }
90
91 constexpr storage_iterator operator-(const difference_type value) const noexcept {
92 return (*this + -value);
93 }
94
95 [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
96 const auto pos = static_cast<Container::size_type>(index() - value);
97 return (*payload)[pos / Page][fast_mod(static_cast<stl::size_t>(pos), Page)];
98 }
99
100 [[nodiscard]] constexpr pointer operator->() const noexcept {
101 return stl::addressof(operator[](0));
102 }
103
104 [[nodiscard]] constexpr reference operator*() const noexcept {
105 return operator[](0);
106 }
107
108 template<typename Other, auto Arg>
109 [[nodiscard]] constexpr stl::ptrdiff_t operator-(const storage_iterator<Other, Arg> &other) const noexcept {
110 // intentionally reversed due to backward iteration
111 return other.offset - offset;
112 }
113
114 template<typename Other, auto Arg>
115 [[nodiscard]] constexpr bool operator==(const storage_iterator<Other, Arg> &other) const noexcept {
116 return offset == other.offset;
117 }
118
119 template<typename Other, auto Arg>
120 [[nodiscard]] constexpr auto operator<=>(const storage_iterator<Other, Arg> &other) const noexcept {
121 // intentionally reversed due to backward iteration
122 return other.offset <=> offset;
123 }
124
125 [[nodiscard]] constexpr difference_type index() const noexcept {
126 return offset - 1;
127 }
128
129private:
130 Container *payload;
131 difference_type offset;
132};
133
134template<typename It, typename... Other>
135class extended_storage_iterator final {
136 template<typename, typename...>
137 friend class extended_storage_iterator;
138
139public:
140 using iterator_type = It;
141 using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval<It>()), stl::forward_as_tuple(*stl::declval<Other>()...)));
142 using pointer = input_iterator_pointer<value_type>;
143 using reference = value_type;
144 using difference_type = stl::ptrdiff_t;
145 using iterator_category = stl::input_iterator_tag;
146 using iterator_concept = stl::forward_iterator_tag;
147
148 constexpr extended_storage_iterator()
149 : it{} {}
150
151 constexpr extended_storage_iterator(iterator_type base, Other... other)
152 : it{base, other...} {}
153
154 template<typename... Args>
155 requires (!stl::same_as<Other, Args> && ...) && (stl::constructible_from<Other, Args> && ...)
156 constexpr extended_storage_iterator(const extended_storage_iterator<It, Args...> &other)
157 : it{other.it} {}
158
159 constexpr extended_storage_iterator &operator++() noexcept {
160 return ++stl::get<It>(it), (++stl::get<Other>(it), ...), *this;
161 }
162
163 constexpr extended_storage_iterator operator++(int) noexcept {
164 const extended_storage_iterator orig = *this;
165 return ++(*this), orig;
166 }
167
168 [[nodiscard]] constexpr pointer operator->() const noexcept {
169 return operator*();
170 }
171
172 [[nodiscard]] constexpr reference operator*() const noexcept {
173 return {*stl::get<It>(it), *stl::get<Other>(it)...};
174 }
175
176 [[nodiscard]] constexpr iterator_type base() const noexcept {
177 return stl::get<It>(it);
178 }
179
180 template<typename... Args>
181 [[nodiscard]] constexpr bool operator==(const extended_storage_iterator<Args...> &other) const noexcept {
182 return stl::get<0>(it) == stl::get<0>(other.it);
183 }
184
185private:
186 stl::tuple<It, Other...> it;
187};
188
189} // namespace internal
191
207template<typename Type, typename Entity, typename Allocator>
208class basic_storage: public basic_sparse_set<Entity, typename stl::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
209 using alloc_traits = stl::allocator_traits<Allocator>;
210 static_assert(stl::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
211 using container_type = stl::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
213 using underlying_iterator = underlying_type::basic_iterator;
214 using traits_type = component_traits<Type, Entity>;
215
216 [[nodiscard]] auto &element_at(const stl::size_t pos) const {
217 return payload[pos / traits_type::page_size][fast_mod(pos, traits_type::page_size)];
218 }
219
220 auto assure_at_least(const stl::size_t pos) {
221 const auto idx = pos / traits_type::page_size;
222
223 if(!(idx < payload.size())) {
224 auto curr = payload.size();
225 allocator_type allocator{get_allocator()};
226 payload.resize(idx + 1u, nullptr);
227
228 ENTT_TRY {
229 for(const auto last = payload.size(); curr < last; ++curr) {
230 payload[curr] = alloc_traits::allocate(allocator, traits_type::page_size);
231 }
232 }
233 ENTT_CATCH {
234 payload.resize(curr);
235 ENTT_THROW;
236 }
237 }
238
239 return payload[idx] + fast_mod(pos, traits_type::page_size);
240 }
241
242 template<typename... Args>
243 auto emplace_element(const Entity entt, const bool force_back, Args &&...args) {
244 const auto it = base_type::try_emplace(entt, force_back);
245
246 ENTT_TRY {
247 auto *elem = stl::to_address(assure_at_least(static_cast<size_type>(it.index())));
248 entt::uninitialized_construct_using_allocator(elem, get_allocator(), stl::forward<Args>(args)...);
249 }
250 ENTT_CATCH {
251 base_type::pop(it, it + 1u);
252 ENTT_THROW;
253 }
254
255 return it;
256 }
257
258 void shrink_to_size(const stl::size_t sz) {
259 const auto from = (sz + traits_type::page_size - 1u) / traits_type::page_size;
260 allocator_type allocator{get_allocator()};
261
262 if constexpr(!stl::is_trivially_destructible_v<element_type>) {
263 for(auto pos = sz, length = base_type::size(); pos < length; ++pos) {
264 if constexpr(traits_type::in_place_delete) {
265 if(base_type::data()[pos] != tombstone) {
266 alloc_traits::destroy(allocator, stl::addressof(element_at(pos)));
267 }
268 } else {
269 alloc_traits::destroy(allocator, stl::addressof(element_at(pos)));
270 }
271 }
272 }
273
274 for(auto pos = from, last = payload.size(); pos < last; ++pos) {
275 alloc_traits::deallocate(allocator, payload[pos], traits_type::page_size);
276 }
277
278 payload.resize(from);
279 payload.shrink_to_fit();
280 }
281
282 void swap_at(const stl::size_t lhs, const stl::size_t rhs) {
283 using stl::swap;
284 swap(element_at(lhs), element_at(rhs));
285 }
286
287 void move_to(const stl::size_t lhs, const stl::size_t rhs) {
288 auto &elem = element_at(lhs);
289 allocator_type allocator{get_allocator()};
290 entt::uninitialized_construct_using_allocator(stl::to_address(assure_at_least(rhs)), allocator, stl::move(elem));
291 alloc_traits::destroy(allocator, stl::addressof(elem));
292 }
293
294private:
295 [[nodiscard]] const void *get_at(const stl::size_t pos) const final {
296 return stl::addressof(element_at(pos));
297 }
298
299 void swap_or_move([[maybe_unused]] const stl::size_t from, [[maybe_unused]] const stl::size_t to) override {
300 static constexpr bool is_pinned_type = !(stl::is_move_constructible_v<Type> && stl::is_move_assignable_v<Type>);
301 // use a runtime value to avoid compile-time suppression that drives the code coverage tool crazy
302 ENTT_ASSERT((from + 1u) && !is_pinned_type, "Pinned type");
303
304 if constexpr(!is_pinned_type) {
305 if constexpr(traits_type::in_place_delete) {
306 (base_type::operator[](to) == tombstone) ? move_to(from, to) : swap_at(from, to);
307 } else {
308 swap_at(from, to);
309 }
310 }
311 }
312
313protected:
319 void pop(underlying_iterator first, underlying_iterator last) override {
320 for(allocator_type allocator{get_allocator()}; first != last; ++first) {
321 // cannot use first.index() because it would break with cross iterators
322 auto &elem = element_at(base_type::index(*first));
323
324 if constexpr(traits_type::in_place_delete) {
326 alloc_traits::destroy(allocator, stl::addressof(elem));
327 } else if constexpr(stl::is_trivially_destructible_v<element_type>) {
328 elem = stl::move(element_at(base_type::size() - 1u));
330 } else {
331 auto &other = element_at(base_type::size() - 1u);
332 // destroying on exit allows reentrant destructors
333 [[maybe_unused]] auto unused = stl::exchange(elem, stl::move(other));
334 alloc_traits::destroy(allocator, stl::addressof(other));
336 }
337 }
338 }
339
341 void pop_all() override {
342 if constexpr(stl::is_trivially_destructible_v<element_type>) {
344 } else {
345 allocator_type allocator{get_allocator()};
346
347 for(auto first = base_type::begin(); !(first.index() < 0); ++first) {
348 if constexpr(traits_type::in_place_delete) {
349 if(*first != tombstone) {
351 alloc_traits::destroy(allocator, stl::addressof(element_at(static_cast<size_type>(first.index()))));
352 }
353 } else {
355 alloc_traits::destroy(allocator, stl::addressof(element_at(static_cast<size_type>(first.index()))));
356 }
357 }
358 }
359 }
360
368 underlying_iterator try_emplace([[maybe_unused]] const Entity entt, [[maybe_unused]] const bool force_back, const void *value) override {
369 if(value != nullptr) {
370 if constexpr(stl::is_copy_constructible_v<element_type>) {
371 return emplace_element(entt, force_back, *static_cast<const element_type *>(value));
372 } else {
373 return base_type::end();
374 }
375 } else {
376 if constexpr(stl::is_default_constructible_v<element_type>) {
377 return emplace_element(entt, force_back);
378 } else {
379 return base_type::end();
380 }
381 }
382 }
383
384public:
386 using allocator_type = Allocator;
388 using base_type = underlying_type;
390 using element_type = Type;
394 using entity_type = Entity;
396 using size_type = stl::size_t;
398 using difference_type = stl::ptrdiff_t;
400 using pointer = container_type::pointer;
402 using const_pointer = alloc_traits::template rebind_traits<typename alloc_traits::const_pointer>::const_pointer;
404 using iterator = internal::storage_iterator<container_type, traits_type::page_size>;
406 using const_iterator = internal::storage_iterator<const container_type, traits_type::page_size>;
408 using reverse_iterator = stl::reverse_iterator<iterator>;
410 using const_reverse_iterator = stl::reverse_iterator<const_iterator>;
421
425
430 explicit basic_storage(const allocator_type &allocator)
432 payload{allocator} {}
433
435 basic_storage(const basic_storage &) = delete;
436
441 basic_storage(basic_storage &&other) noexcept
442 : base_type{static_cast<base_type &&>(other)},
443 payload{stl::move(other.payload)} {}
444
450 basic_storage(basic_storage &&other, const allocator_type &allocator)
451 : base_type{static_cast<base_type &&>(other), allocator},
452 payload{stl::move(other.payload), allocator} {
453 ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a storage is not allowed");
454 }
455
457 // NOLINTNEXTLINE(bugprone-exception-escape)
458 ~basic_storage() override {
459 shrink_to_size(0u);
460 }
461
467
474 ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a storage is not allowed");
475 swap(other);
476 return *this;
477 }
478
483 void swap(basic_storage &other) noexcept {
484 using stl::swap;
485 swap(payload, other.payload);
486 base_type::swap(other);
487 }
488
493 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
494 return payload.get_allocator();
495 }
496
505 void reserve(const size_type cap) override {
506 if(cap != 0u) {
508 assure_at_least(cap - 1u);
509 }
510 }
511
517 [[nodiscard]] size_type capacity() const noexcept override {
518 return payload.size() * traits_type::page_size;
519 }
520
522 void shrink_to_fit() override {
524 shrink_to_size(base_type::size());
525 }
526
531 [[nodiscard]] const_pointer raw() const noexcept {
532 return payload.data();
533 }
534
536 [[nodiscard]] pointer raw() noexcept {
537 return payload.data();
538 }
539
547 [[nodiscard]] const_iterator cbegin() const noexcept {
548 const auto pos = static_cast<difference_type>(base_type::size());
549 return const_iterator{&payload, pos};
550 }
551
553 [[nodiscard]] const_iterator begin() const noexcept {
554 return cbegin();
555 }
556
558 [[nodiscard]] iterator begin() noexcept {
559 const auto pos = static_cast<difference_type>(base_type::size());
560 return iterator{&payload, pos};
561 }
562
568 [[nodiscard]] const_iterator cend() const noexcept {
569 return const_iterator{&payload, {}};
570 }
571
573 [[nodiscard]] const_iterator end() const noexcept {
574 return cend();
575 }
576
578 [[nodiscard]] iterator end() noexcept {
579 return iterator{&payload, {}};
580 }
581
589 [[nodiscard]] const_reverse_iterator crbegin() const noexcept {
590 return stl::make_reverse_iterator(cend());
591 }
592
594 [[nodiscard]] const_reverse_iterator rbegin() const noexcept {
595 return crbegin();
596 }
597
599 [[nodiscard]] reverse_iterator rbegin() noexcept {
600 return stl::make_reverse_iterator(end());
601 }
602
608 [[nodiscard]] const_reverse_iterator crend() const noexcept {
609 return stl::make_reverse_iterator(cbegin());
610 }
611
613 [[nodiscard]] const_reverse_iterator rend() const noexcept {
614 return crend();
615 }
616
618 [[nodiscard]] reverse_iterator rend() noexcept {
619 return stl::make_reverse_iterator(begin());
620 }
621
632 [[nodiscard]] const value_type &get(const entity_type entt) const noexcept {
633 return element_at(base_type::index(entt));
634 }
635
637 [[nodiscard]] value_type &get(const entity_type entt) noexcept {
638 return const_cast<value_type &>(stl::as_const(*this).get(entt));
639 }
640
646 [[nodiscard]] stl::tuple<const value_type &> get_as_tuple(const entity_type entt) const noexcept {
647 return stl::forward_as_tuple(get(entt));
648 }
649
651 [[nodiscard]] stl::tuple<value_type &> get_as_tuple(const entity_type entt) noexcept {
652 return stl::forward_as_tuple(get(entt));
653 }
654
667 template<typename... Args>
668 value_type &emplace(const entity_type entt, Args &&...args) {
669 if constexpr(stl::is_aggregate_v<value_type> && (sizeof...(Args) != 0u || !stl::is_default_constructible_v<value_type>)) {
670 const auto it = emplace_element(entt, false, Type{stl::forward<Args>(args)...});
671 return element_at(static_cast<size_type>(it.index()));
672 } else {
673 const auto it = emplace_element(entt, false, stl::forward<Args>(args)...);
674 return element_at(static_cast<size_type>(it.index()));
675 }
676 }
677
685 template<typename... Func>
686 value_type &patch(const entity_type entt, Func &&...func) {
687 const auto idx = base_type::index(entt);
688 auto &elem = element_at(idx);
689 (stl::forward<Func>(func)(elem), ...);
690 return elem;
691 }
692
706 iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, const value_type &value = {}) {
707 for(; first != last; ++first) {
708 emplace_element(*first, true, value);
709 }
710
711 return begin();
712 }
713
726 template<stl::input_iterator It>
727 requires stl::same_as<typename stl::iterator_traits<It>::value_type, value_type>
728 iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, It from) {
729 for(; first != last; ++first, ++from) {
730 emplace_element(*first, true, *from);
731 }
732
733 return begin();
734 }
735
744 [[nodiscard]] iterable each() noexcept {
745 return iterable{{base_type::begin(), begin()}, {base_type::end(), end()}};
746 }
747
749 [[nodiscard]] const_iterable each() const noexcept {
751 }
752
760 [[nodiscard]] reverse_iterable reach() noexcept {
762 }
763
765 [[nodiscard]] const_reverse_iterable reach() const noexcept {
767 }
768
769private:
770 container_type payload;
771};
772
774template<typename Type, typename Entity, typename Allocator>
777 : public basic_sparse_set<Entity, typename stl::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
778 using alloc_traits = stl::allocator_traits<Allocator>;
779 static_assert(stl::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
780 using traits_type = component_traits<Type, Entity>;
781
782public:
784 using allocator_type = Allocator;
788 using element_type = Type;
790 using value_type = void;
792 using entity_type = Entity;
794 using size_type = stl::size_t;
796 using difference_type = stl::ptrdiff_t;
807
811
816 explicit basic_storage(const allocator_type &allocator)
817 : base_type{type_id<element_type>(), storage_policy, allocator} {}
818
820 basic_storage(const basic_storage &) = delete;
821
826 basic_storage(basic_storage &&other) noexcept = default;
827
833 basic_storage(basic_storage &&other, const allocator_type &allocator)
834 : base_type{stl::move(other), allocator} {}
835
837 ~basic_storage() override = default;
838
844
850 basic_storage &operator=(basic_storage &&other) noexcept = default;
851
856 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
858 }
859
869 void get([[maybe_unused]] const entity_type entt) const noexcept {
870 ENTT_ASSERT(base_type::contains(entt), "Invalid entity");
871 }
872
878 [[nodiscard]] stl::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
879 ENTT_ASSERT(base_type::contains(entt), "Invalid entity");
880 return stl::tuple{};
881 }
882
892 void emplace(const entity_type entt, const auto &...) {
894 }
895
902 template<typename... Func>
903 void patch([[maybe_unused]] const entity_type entt, Func &&...func) {
904 ENTT_ASSERT(base_type::contains(entt), "Invalid entity");
905 (stl::forward<Func>(func)(), ...);
906 }
907
913 void insert(stl::input_iterator auto first, stl::input_iterator auto last, const auto &...) {
914 for(; first != last; ++first) {
915 base_type::try_emplace(*first, true);
916 }
917 }
918
926 [[nodiscard]] iterable each() noexcept {
928 }
929
931 [[nodiscard]] const_iterable each() const noexcept {
933 }
934
942 [[nodiscard]] reverse_iterable reach() noexcept {
944 }
945
947 [[nodiscard]] const_reverse_iterable reach() const noexcept {
949 }
950};
951
957template<typename Entity, typename Allocator>
958class basic_storage<Entity, Entity, Allocator>
959 : public basic_sparse_set<Entity, Allocator> {
960 using alloc_traits = stl::allocator_traits<Allocator>;
961 static_assert(stl::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
962 using underlying_iterator = basic_sparse_set<Entity, Allocator>::basic_iterator;
963 using traits_type = entt_traits<Entity>;
964
965 auto from_placeholder() noexcept {
966 const auto entt = traits_type::combine(static_cast<traits_type::entity_type>(placeholder), {});
967 ENTT_ASSERT(entt != null, "No more entities available");
968 placeholder += static_cast<size_type>(entt != null);
969 return entt;
970 }
971
972 auto next() noexcept {
973 entity_type entt = from_placeholder();
974
976 entt = from_placeholder();
977 }
978
979 return entt;
980 }
981
982protected:
984 void pop_all() override {
986 placeholder = {};
987 }
988
994 underlying_iterator try_emplace(const Entity hint, const bool, const void *) override {
995 return base_type::find(generate(hint));
996 }
997
998public:
1000 using allocator_type = Allocator;
1004 using element_type = Entity;
1006 using value_type = void;
1008 using entity_type = Entity;
1010 using size_type = stl::size_t;
1012 using difference_type = stl::ptrdiff_t;
1023
1028
1033 explicit basic_storage(const allocator_type &allocator)
1034 : base_type{type_id<void>(), storage_policy, allocator} {}
1035
1037 basic_storage(const basic_storage &) = delete;
1038
1043 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
1045 : base_type{static_cast<base_type &&>(other)},
1046 placeholder{other.placeholder} {}
1047
1053 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
1054 basic_storage(basic_storage &&other, const allocator_type &allocator)
1055 : base_type{static_cast<base_type &&>(other), allocator},
1056 placeholder{other.placeholder} {}
1057
1059 ~basic_storage() override = default;
1060
1066
1073 placeholder = other.placeholder;
1074 base_type::operator=(stl::move(other));
1075 return *this;
1076 }
1077
1082 void swap(basic_storage &other) noexcept {
1083 using stl::swap;
1084 swap(placeholder, other.placeholder);
1085 base_type::swap(other);
1086 }
1087
1097 void get([[maybe_unused]] const entity_type entt) const noexcept {
1098 ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
1099 }
1100
1106 [[nodiscard]] stl::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
1107 ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
1108 return stl::tuple{};
1109 }
1110
1116 const auto len = base_type::free_list();
1117 const auto entt = (len == base_type::size()) ? next() : base_type::data()[len];
1118 return *base_type::try_emplace(entt, true);
1119 }
1120
1131 if(hint != null && hint != tombstone) {
1132 if(const auto curr = traits_type::construct(traits_type::to_entity(hint), base_type::current(hint)); curr == tombstone || !(base_type::index(curr) < base_type::free_list())) {
1133 return *base_type::try_emplace(hint, true);
1134 }
1135 }
1136
1137 return generate();
1138 }
1139
1146 template<stl::output_iterator<entity_type> It>
1147 void generate(It first, It last) {
1148 for(const auto sz = base_type::size(); first != last && base_type::free_list() != sz; ++first) {
1150 }
1151
1152 for(; first != last; ++first) {
1153 *first = *base_type::try_emplace(next(), true);
1154 }
1155 }
1156
1163 template<typename... Func>
1164 void patch([[maybe_unused]] const entity_type entt, Func &&...func) {
1165 ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
1166 (stl::forward<Func>(func)(), ...);
1167 }
1168
1176 [[nodiscard]] iterable each() noexcept {
1177 return stl::as_const(*this).each();
1178 }
1179
1181 [[nodiscard]] const_iterable each() const noexcept {
1182 const auto it = base_type::cend();
1183 const auto offset = static_cast<difference_type>(base_type::free_list());
1184 return const_iterable{it - offset, it};
1185 }
1186
1194 [[nodiscard]] reverse_iterable reach() noexcept {
1195 return stl::as_const(*this).reach();
1196 }
1197
1199 [[nodiscard]] const_reverse_iterable reach() const noexcept {
1200 const auto it = base_type::crbegin();
1201 const auto offset = static_cast<difference_type>(base_type::free_list());
1202 return const_reverse_iterable{it, it + offset};
1203 }
1204
1212 void start_from(const entity_type hint) {
1213 placeholder = static_cast<size_type>(traits_type::to_entity(hint));
1214 }
1215
1216private:
1217 size_type placeholder{};
1218};
1219
1220} // namespace entt
1221
1222#endif
static constexpr value_type construct(const entity_type entity, const version_type version) noexcept
Definition entity.hpp:145
internal::entt_traits< Type >::entity_type entity_type
Definition entity.hpp:83
static constexpr entity_type to_entity(const value_type value) noexcept
Definition entity.hpp:106
static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept
Definition entity.hpp:163
static constexpr version_type to_version(const value_type value) noexcept
Definition entity.hpp:116
virtual basic_iterator try_emplace(const Entity entt, const bool force_back, const void *=nullptr)
version_type current(const entity_type entt) const noexcept
Returns the contained version for an identifier.
size_type free_list() const noexcept
Returns data on the free list whose meaning depends on the mode.
const_reverse_iterable reach() const noexcept
Returns a reverse iterable object to use to visit a storage.
Definition storage.hpp:1199
stl::size_t size_type
Unsigned integer type.
Definition storage.hpp:1010
stl::ptrdiff_t difference_type
Signed integer type.
Definition storage.hpp:1012
stl::tuple get_as_tuple(const entity_type entt) const noexcept
Returns an empty tuple.
Definition storage.hpp:1106
iterable_adaptor< internal::extended_storage_iterator< typename base_type::reverse_iterator > > reverse_iterable
Extended reverse iterable storage proxy.
Definition storage.hpp:1018
static constexpr deletion_policy storage_policy
Storage deletion policy.
Definition storage.hpp:1022
void get(const entity_type entt) const noexcept
Returns the object assigned to an entity, that is void.
Definition storage.hpp:1097
void value_type
Type of the objects assigned to entities.
Definition storage.hpp:1006
entity_type generate(const entity_type hint)
Creates a new identifier or recycles a destroyed one.
Definition storage.hpp:1130
iterable_adaptor< internal::extended_storage_iterator< typename base_type::const_iterator > > const_iterable
Constant extended iterable storage proxy.
Definition storage.hpp:1016
Entity entity_type
Underlying entity identifier.
Definition storage.hpp:1008
void pop_all() override
Erases all entities of a storage.
Definition storage.hpp:984
~basic_storage() override=default
Default destructor.
underlying_iterator try_emplace(const Entity hint, const bool, const void *) override
Assigns an entity to a storage.
Definition storage.hpp:994
basic_storage & operator=(basic_storage &&other) noexcept
Move assignment operator.
Definition storage.hpp:1072
entity_type generate()
Creates a new identifier or recycles a destroyed one.
Definition storage.hpp:1115
reverse_iterable reach() noexcept
Returns a reverse iterable object to use to visit a storage.
Definition storage.hpp:1194
basic_storage(basic_storage &&other, const allocator_type &allocator)
Allocator-extended move constructor.
Definition storage.hpp:1054
void swap(basic_storage &other) noexcept
Exchanges the contents with those of a given storage.
Definition storage.hpp:1082
const_iterable each() const noexcept
Returns an iterable object to use to visit a storage.
Definition storage.hpp:1181
basic_storage(const allocator_type &allocator)
Constructs an empty container with a given allocator.
Definition storage.hpp:1033
void generate(It first, It last)
Assigns each element in a range an identifier.
Definition storage.hpp:1147
iterable_adaptor< internal::extended_storage_iterator< typename base_type::const_reverse_iterator > > const_reverse_iterable
Constant extended reverse iterable storage proxy.
Definition storage.hpp:1020
iterable_adaptor< internal::extended_storage_iterator< typename base_type::iterator > > iterable
Extended iterable storage proxy.
Definition storage.hpp:1014
basic_sparse_set< Entity, Allocator > base_type
Base type.
Definition storage.hpp:1002
basic_storage(basic_storage &&other) noexcept
Move constructor.
Definition storage.hpp:1044
iterable each() noexcept
Returns an iterable object to use to visit a storage.
Definition storage.hpp:1176
basic_storage(const basic_storage &)=delete
Default copy constructor, deleted on purpose.
void patch(const entity_type entt, Func &&...func)
Updates a given identifier.
Definition storage.hpp:1164
void start_from(const entity_type hint)
Sets the starting identifier for generation.
Definition storage.hpp:1212
basic_storage & operator=(const basic_storage &)=delete
Default copy assignment operator, deleted on purpose.
iterable_adaptor< internal::extended_storage_iterator< typename base_type::reverse_iterator > > reverse_iterable
Extended reverse iterable storage proxy.
Definition storage.hpp:802
basic_storage(const basic_storage &)=delete
Default copy constructor, deleted on purpose.
iterable each() noexcept
Returns an iterable object to use to visit a storage.
Definition storage.hpp:926
void insert(stl::input_iterator auto first, stl::input_iterator auto last, const auto &...)
Assigns entities to a storage.
Definition storage.hpp:913
const_iterable each() const noexcept
Returns an iterable object to use to visit a storage.
Definition storage.hpp:931
void emplace(const entity_type entt, const auto &...)
Assigns an entity to a storage and constructs its object.
Definition storage.hpp:892
stl::tuple get_as_tuple(const entity_type entt) const noexcept
Returns an empty tuple.
Definition storage.hpp:878
void get(const entity_type entt) const noexcept
Returns the object assigned to an entity, that is void.
Definition storage.hpp:869
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
Definition storage.hpp:856
iterable_adaptor< internal::extended_storage_iterator< typename base_type::const_reverse_iterator > > const_reverse_iterable
Constant extended reverse iterable storage proxy.
Definition storage.hpp:804
stl::ptrdiff_t difference_type
Signed integer type.
Definition storage.hpp:796
void value_type
Type of the objects assigned to entities.
Definition storage.hpp:790
basic_storage(basic_storage &&other, const allocator_type &allocator)
Allocator-extended move constructor.
Definition storage.hpp:833
stl::size_t size_type
Unsigned integer type.
Definition storage.hpp:794
basic_storage & operator=(basic_storage &&other) noexcept=default
Move assignment operator.
iterable_adaptor< internal::extended_storage_iterator< typename base_type::iterator > > iterable
Extended iterable storage proxy.
Definition storage.hpp:798
void patch(const entity_type entt, Func &&...func)
Updates the instance assigned to a given entity in-place.
Definition storage.hpp:903
basic_storage & operator=(const basic_storage &)=delete
Default copy assignment operator, deleted on purpose.
static constexpr deletion_policy storage_policy
Storage deletion policy.
Definition storage.hpp:806
const_reverse_iterable reach() const noexcept
Returns a reverse iterable object to use to visit a storage.
Definition storage.hpp:947
Entity entity_type
Underlying entity identifier.
Definition storage.hpp:792
basic_storage(basic_storage &&other) noexcept=default
Move constructor.
iterable_adaptor< internal::extended_storage_iterator< typename base_type::const_iterator > > const_iterable
Constant extended iterable storage proxy.
Definition storage.hpp:800
basic_sparse_set< Entity, typename alloc_traits::template rebind_alloc< Entity > > base_type
Base type.
Definition storage.hpp:786
~basic_storage() override=default
Default destructor.
reverse_iterable reach() noexcept
Returns a reverse iterable object to use to visit a storage.
Definition storage.hpp:942
basic_storage(const allocator_type &allocator)
Constructs an empty container with a given allocator.
Definition storage.hpp:816
const value_type & get(const entity_type entt) const noexcept
Returns the object assigned to an entity.
Definition storage.hpp:632
iterator begin() noexcept
Returns an iterator to the beginning.
Definition storage.hpp:558
const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
Definition storage.hpp:547
basic_storage(const basic_storage &)=delete
Default copy constructor, deleted on purpose.
void pop(underlying_iterator first, underlying_iterator last) override
Erases entities from a storage.
Definition storage.hpp:319
iterable each() noexcept
Returns an iterable object to use to visit a storage.
Definition storage.hpp:744
stl::tuple< value_type & > get_as_tuple(const entity_type entt) noexcept
Returns the object assigned to an entity as a tuple.
Definition storage.hpp:651
const_reverse_iterator crend() const noexcept
Returns a reverse iterator to the end.
Definition storage.hpp:608
const_iterable each() const noexcept
Returns an iterable object to use to visit a storage.
Definition storage.hpp:749
container_type::pointer pointer
Definition storage.hpp:400
value_type & emplace(const entity_type entt, Args &&...args)
Assigns an entity to a storage and constructs its object.
Definition storage.hpp:668
internal::storage_iterator< container_type, traits_type::page_size > iterator
Definition storage.hpp:404
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
Definition storage.hpp:493
const_pointer raw() const noexcept
Direct access to the array of objects.
Definition storage.hpp:531
stl::ptrdiff_t difference_type
Definition storage.hpp:398
iterator end() noexcept
Returns an iterator to the end.
Definition storage.hpp:578
basic_storage(basic_storage &&other, const allocator_type &allocator)
Allocator-extended move constructor.
Definition storage.hpp:450
alloc_traits::template rebind_traits< typename alloc_traits::const_pointer >::const_pointer const_pointer
Definition storage.hpp:402
iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, const value_type &value={})
Assigns one or more entities to a storage and constructs their objects from a given instance.
Definition storage.hpp:706
~basic_storage() override
Default destructor.
Definition storage.hpp:458
stl::size_t size_type
Unsigned integer type.
Definition storage.hpp:396
void reserve(const size_type cap) override
Increases the capacity of a storage.
Definition storage.hpp:505
internal::storage_iterator< const container_type, traits_type::page_size > const_iterator
Definition storage.hpp:406
basic_storage()
Default constructor.
Definition storage.hpp:423
underlying_type base_type
Definition storage.hpp:388
iterable_adaptor< internal::extended_storage_iterator< typename base_type::const_reverse_iterator, const_reverse_iterator > > const_reverse_iterable
Definition storage.hpp:418
iterable_adaptor< internal::extended_storage_iterator< typename base_type::iterator, iterator > > iterable
Definition storage.hpp:412
basic_storage & operator=(const basic_storage &)=delete
Default copy assignment operator, deleted on purpose.
pointer raw() noexcept
Direct access to the array of objects.
Definition storage.hpp:536
value_type & patch(const entity_type entt, Func &&...func)
Updates the instance assigned to a given entity in-place.
Definition storage.hpp:686
reverse_iterator rbegin() noexcept
Returns a reverse iterator to the beginning.
Definition storage.hpp:599
static constexpr deletion_policy storage_policy
Definition storage.hpp:420
const_reverse_iterator crbegin() const noexcept
Returns a reverse iterator to the beginning.
Definition storage.hpp:589
const_reverse_iterable reach() const noexcept
Returns a reverse iterable object to use to visit a storage.
Definition storage.hpp:765
const_iterator cend() const noexcept
Returns an iterator to the end.
Definition storage.hpp:568
underlying_iterator try_emplace(const Entity entt, const bool force_back, const void *value) override
Assigns an entity to a storage.
Definition storage.hpp:368
size_type capacity() const noexcept override
Returns the number of elements that a storage has currently allocated space for.
Definition storage.hpp:517
iterable_adaptor< internal::extended_storage_iterator< typename base_type::const_iterator, const_iterator > > const_iterable
Definition storage.hpp:414
const_reverse_iterator rend() const noexcept
Returns a reverse iterator to the end.
Definition storage.hpp:613
reverse_iterator rend() noexcept
Returns a reverse iterator to the end.
Definition storage.hpp:618
void shrink_to_fit() override
Requests the removal of unused capacity.
Definition storage.hpp:522
iterable_adaptor< internal::extended_storage_iterator< typename base_type::reverse_iterator, reverse_iterator > > reverse_iterable
Definition storage.hpp:416
void swap(basic_storage &other) noexcept
Exchanges the contents with those of a given storage.
Definition storage.hpp:483
const_reverse_iterator rbegin() const noexcept
Returns a reverse iterator to the beginning.
Definition storage.hpp:594
Allocator allocator_type
Allocator type.
Definition storage.hpp:386
void pop_all() override
Erases all entities of a storage.
Definition storage.hpp:341
basic_storage(basic_storage &&other) noexcept
Move constructor.
Definition storage.hpp:441
iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, It from)
Assigns one or more entities to a storage and constructs their objects from a given range.
Definition storage.hpp:728
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
value_type & get(const entity_type entt) noexcept
Returns the object assigned to an entity.
Definition storage.hpp:637
basic_storage & operator=(basic_storage &&other) noexcept
Move assignment operator.
Definition storage.hpp:473
reverse_iterable reach() noexcept
Returns a reverse iterable object to use to visit a storage.
Definition storage.hpp:760
const_iterator begin() const noexcept
Returns an iterator to the beginning.
Definition storage.hpp:553
basic_storage(const allocator_type &allocator)
Constructs an empty storage with a given allocator.
Definition storage.hpp:430
stl::reverse_iterator< iterator > reverse_iterator
Definition storage.hpp:408
stl::reverse_iterator< const_iterator > const_reverse_iterator
Definition storage.hpp:410
const_iterator end() const noexcept
Returns an iterator to the end.
Definition storage.hpp:573
Custom EnTT namespace for the standard template library.
Definition entt.hpp:5
EnTT default namespace.
Definition dense_map.hpp:25
deletion_policy
Storage deletion policy.
Definition fwd.hpp:18
@ swap_only
Swap-only deletion policy.
Definition fwd.hpp:24
constexpr null_t null
Compile-time constant for null entities.
Definition entity.hpp:299
constexpr Type * uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
Definition memory.hpp:219
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
constexpr type_list< Type..., Other... > operator+(type_list< Type... >, type_list< Other... >)
Concatenates multiple type lists.
@ ref
Aliasing mode, non-const reference.
Definition fwd.hpp:19
const type_info & type_id() noexcept
Returns the type info object associated to a given type.
constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept
Fast module utility function (powers of two only).
Definition bit.hpp:19
Common way to access various properties of components.
Definition component.hpp:45
static constexpr stl::size_t page_size
Page size, default is ENTT_PACKED_PAGE for non-empty types.
Definition component.hpp:54
static constexpr bool in_place_delete
Pointer stability, default is false.
Definition component.hpp:52
Entity traits.
Definition entity.hpp:177
Utility class to create an iterable object from a pair of iterators.
Definition iterator.hpp:125