EnTT 3.16.0
Loading...
Searching...
No Matches
registry.hpp
1#ifndef ENTT_ENTITY_REGISTRY_HPP
2#define ENTT_ENTITY_REGISTRY_HPP
3
4#include <algorithm>
5#include <array>
6#include <cstddef>
7#include <functional>
8#include <iterator>
9#include <memory>
10#include <tuple>
11#include <type_traits>
12#include <utility>
13#include <vector>
14#include "../config/config.h"
15#include "../container/dense_map.hpp"
16#include "../core/algorithm.hpp"
17#include "../core/any.hpp"
18#include "../core/fwd.hpp"
19#include "../core/iterator.hpp"
20#include "../core/memory.hpp"
21#include "../core/type_info.hpp"
22#include "../core/type_traits.hpp"
23#include "../core/utility.hpp"
24#include "entity.hpp"
25#include "fwd.hpp"
26#include "group.hpp"
27#include "mixin.hpp"
28#include "sparse_set.hpp"
29#include "storage.hpp"
30#include "view.hpp"
31
32namespace entt {
33
35namespace internal {
36
37template<typename It>
38class registry_storage_iterator final {
39 template<typename Other>
40 friend class registry_storage_iterator;
41
42 using mapped_type = std::remove_reference_t<decltype(std::declval<It>()->second)>;
43
44public:
45 using value_type = std::pair<id_type, constness_as_t<typename mapped_type::element_type, mapped_type> &>;
46 using pointer = input_iterator_pointer<value_type>;
47 using reference = value_type;
48 using difference_type = std::ptrdiff_t;
49 using iterator_category = std::input_iterator_tag;
50 using iterator_concept = std::random_access_iterator_tag;
51
52 constexpr registry_storage_iterator() noexcept
53 : it{} {}
54
55 constexpr registry_storage_iterator(It iter) noexcept
56 : it{iter} {}
57
58 template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
59 constexpr registry_storage_iterator(const registry_storage_iterator<Other> &other) noexcept
60 : registry_storage_iterator{other.it} {}
61
62 constexpr registry_storage_iterator &operator++() noexcept {
63 return ++it, *this;
64 }
65
66 constexpr registry_storage_iterator operator++(int) noexcept {
67 const registry_storage_iterator orig = *this;
68 return ++(*this), orig;
69 }
70
71 constexpr registry_storage_iterator &operator--() noexcept {
72 return --it, *this;
73 }
74
75 constexpr registry_storage_iterator operator--(int) noexcept {
76 const registry_storage_iterator orig = *this;
77 return operator--(), orig;
78 }
79
80 constexpr registry_storage_iterator &operator+=(const difference_type value) noexcept {
81 it += value;
82 return *this;
83 }
84
85 constexpr registry_storage_iterator operator+(const difference_type value) const noexcept {
86 registry_storage_iterator copy = *this;
87 return (copy += value);
88 }
89
90 constexpr registry_storage_iterator &operator-=(const difference_type value) noexcept {
91 return (*this += -value);
92 }
93
94 constexpr registry_storage_iterator operator-(const difference_type value) const noexcept {
95 return (*this + -value);
96 }
97
98 [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
99 return {it[value].first, *it[value].second};
100 }
101
102 [[nodiscard]] constexpr reference operator*() const noexcept {
103 return operator[](0);
104 }
105
106 [[nodiscard]] constexpr pointer operator->() const noexcept {
107 return operator*();
108 }
109
110 template<typename Lhs, typename Rhs>
111 friend constexpr std::ptrdiff_t operator-(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
112
113 template<typename Lhs, typename Rhs>
114 friend constexpr bool operator==(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
115
116 template<typename Lhs, typename Rhs>
117 friend constexpr bool operator<(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
118
119private:
120 It it;
121};
122
123template<typename Lhs, typename Rhs>
124[[nodiscard]] constexpr std::ptrdiff_t operator-(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
125 return lhs.it - rhs.it;
126}
127
128template<typename Lhs, typename Rhs>
129[[nodiscard]] constexpr bool operator==(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
130 return lhs.it == rhs.it;
131}
132
133template<typename Lhs, typename Rhs>
134[[nodiscard]] constexpr bool operator!=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
135 return !(lhs == rhs);
136}
137
138template<typename Lhs, typename Rhs>
139[[nodiscard]] constexpr bool operator<(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
140 return lhs.it < rhs.it;
141}
142
143template<typename Lhs, typename Rhs>
144[[nodiscard]] constexpr bool operator>(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
145 return rhs < lhs;
146}
147
148template<typename Lhs, typename Rhs>
149[[nodiscard]] constexpr bool operator<=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
150 return !(lhs > rhs);
151}
152
153template<typename Lhs, typename Rhs>
154[[nodiscard]] constexpr bool operator>=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
155 return !(lhs < rhs);
156}
157
158template<typename Allocator>
159class registry_context {
160 using alloc_traits = std::allocator_traits<Allocator>;
161 using allocator_type = typename alloc_traits::template rebind_alloc<std::pair<const id_type, basic_any<0u>>>;
162
163public:
164 explicit registry_context(const allocator_type &allocator)
165 : ctx{allocator} {}
166
167 void clear() noexcept {
168 ctx.clear();
169 }
170
171 template<typename Type, typename... Args>
172 Type &emplace_as(const id_type id, Args &&...args) {
173 return any_cast<Type &>(ctx.try_emplace(id, std::in_place_type<Type>, std::forward<Args>(args)...).first->second);
174 }
175
176 template<typename Type, typename... Args>
177 Type &emplace(Args &&...args) {
178 return emplace_as<Type>(type_id<Type>().hash(), std::forward<Args>(args)...);
179 }
180
181 template<typename Type>
182 Type &insert_or_assign(const id_type id, Type &&value) {
183 return any_cast<std::remove_const_t<std::remove_reference_t<Type>> &>(ctx.insert_or_assign(id, std::forward<Type>(value)).first->second);
184 }
185
186 template<typename Type>
187 Type &insert_or_assign(Type &&value) {
188 return insert_or_assign(type_id<Type>().hash(), std::forward<Type>(value));
189 }
190
191 template<typename Type>
192 bool erase(const id_type id = type_id<Type>().hash()) {
193 const auto it = ctx.find(id);
194 return it != ctx.end() && it->second.info() == type_id<Type>() ? (ctx.erase(it), true) : false;
195 }
196
197 template<typename Type>
198 [[nodiscard]] const Type &get(const id_type id = type_id<Type>().hash()) const {
199 return any_cast<const Type &>(ctx.at(id));
200 }
201
202 template<typename Type>
203 [[nodiscard]] Type &get(const id_type id = type_id<Type>().hash()) {
204 return any_cast<Type &>(ctx.at(id));
205 }
206
207 template<typename Type>
208 [[nodiscard]] const Type *find(const id_type id = type_id<Type>().hash()) const {
209 const auto it = ctx.find(id);
210 return it != ctx.cend() ? any_cast<const Type>(&it->second) : nullptr;
211 }
212
213 template<typename Type>
214 [[nodiscard]] Type *find(const id_type id = type_id<Type>().hash()) {
215 const auto it = ctx.find(id);
216 return it != ctx.end() ? any_cast<Type>(&it->second) : nullptr;
217 }
218
219 template<typename Type>
220 [[nodiscard]] bool contains(const id_type id = type_id<Type>().hash()) const {
221 const auto it = ctx.find(id);
222 return it != ctx.cend() && it->second.info() == type_id<Type>();
223 }
224
225private:
226 dense_map<id_type, basic_any<0u>, identity, std::equal_to<>, allocator_type> ctx;
227};
228
229} // namespace internal
231
237template<typename Entity, typename Allocator>
239 using base_type = basic_sparse_set<Entity, Allocator>;
240 using alloc_traits = std::allocator_traits<Allocator>;
241 static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
242 // std::shared_ptr because of its type erased allocator which is useful here
243 using pool_container_type = dense_map<id_type, std::shared_ptr<base_type>, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<base_type>>>>;
244 using group_container_type = dense_map<id_type, std::shared_ptr<internal::group_descriptor>, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<internal::group_descriptor>>>>;
245 using traits_type = entt_traits<Entity>;
246
247 template<typename Type>
248 [[nodiscard]] auto &assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) {
249 static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
250
251 if constexpr(std::is_same_v<Type, entity_type>) {
252 ENTT_ASSERT(id == type_hash<Type>::value(), "User entity storage not allowed");
253 return entities;
254 } else {
256
257 if(auto it = pools.find(id); it != pools.cend()) {
258 ENTT_ASSERT(it->second->info() == type_id<Type>(), "Unexpected type");
259 return static_cast<storage_type &>(*it->second);
260 }
261
262 using alloc_type = typename storage_type::allocator_type;
263 typename pool_container_type::mapped_type cpool{};
264
265 if constexpr(std::is_void_v<Type> && !std::is_constructible_v<alloc_type, allocator_type>) {
266 // std::allocator<void> has no cross constructors (waiting for C++20)
267 cpool = std::allocate_shared<storage_type>(get_allocator(), alloc_type{});
268 } else {
269 cpool = std::allocate_shared<storage_type>(get_allocator(), get_allocator());
270 }
271
272 pools.emplace(id, cpool);
273 cpool->bind(*this);
274
275 return static_cast<storage_type &>(*cpool);
276 }
277 }
278
279 template<typename Type>
280 [[nodiscard]] const auto *assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) const {
281 static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
282
283 if constexpr(std::is_same_v<Type, entity_type>) {
284 ENTT_ASSERT(id == type_hash<Type>::value(), "User entity storage not allowed");
285 return &entities;
286 } else {
287 if(const auto it = pools.find(id); it != pools.cend()) {
288 ENTT_ASSERT(it->second->info() == type_id<Type>(), "Unexpected type");
289 return static_cast<const storage_for_type<Type> *>(it->second.get());
290 }
291
292 return static_cast<const storage_for_type<Type> *>(nullptr);
293 }
294 }
295
296 void rebind() {
297 entities.bind(*this);
298
299 for(auto &&curr: pools) {
300 curr.second->bind(*this);
301 }
302 }
303
304public:
306 using allocator_type = Allocator;
312 using size_type = std::size_t;
314 using common_type = base_type;
316 using context = internal::registry_context<allocator_type>;
321
326 template<typename Type>
328
332
337 explicit basic_registry(const allocator_type &allocator)
338 : basic_registry{0u, allocator} {}
339
345 basic_registry(const size_type count, const allocator_type &allocator = allocator_type{})
346 : vars{allocator},
347 pools{allocator},
348 groups{allocator},
349 entities{allocator} {
350 pools.reserve(count);
351 rebind();
352 }
353
356
362 : vars{std::move(other.vars)},
363 pools{std::move(other.pools)},
364 groups{std::move(other.groups)},
365 entities{std::move(other.entities)} {
366 rebind();
367 }
368
370 ~basic_registry() = default;
371
377
384 swap(other);
385 return *this;
386 }
387
392 void swap(basic_registry &other) noexcept {
393 using std::swap;
394
395 swap(vars, other.vars);
396 swap(pools, other.pools);
397 swap(groups, other.groups);
398 swap(entities, other.entities);
399
400 rebind();
401 other.rebind();
402 }
403
408 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
409 return entities.get_allocator();
410 }
411
420 [[nodiscard]] iterable storage() noexcept {
421 return iterable{pools.begin(), pools.end()};
422 }
423
425 [[nodiscard]] const_iterable storage() const noexcept {
426 return const_iterable{pools.cbegin(), pools.cend()};
427 }
428
434 [[nodiscard]] common_type *storage(const id_type id) {
435 return const_cast<common_type *>(std::as_const(*this).storage(id));
436 }
437
443 [[nodiscard]] const common_type *storage(const id_type id) const {
444 const auto it = pools.find(id);
445 return it == pools.cend() ? nullptr : it->second.get();
446 }
447
454 template<typename Type>
456 return assure<std::remove_const_t<Type>>(id);
457 }
458
465 template<typename Type>
466 [[nodiscard]] const storage_for_type<Type> *storage(const id_type id = type_hash<Type>::value()) const {
467 return assure<std::remove_const_t<Type>>(id);
468 }
469
475 bool reset(const id_type id) {
476 ENTT_ASSERT(id != type_hash<entity_type>::value(), "Cannot reset entity storage");
477 return !(pools.erase(id) == 0u);
478 }
479
485 [[nodiscard]] bool valid(const entity_type entt) const {
486 return static_cast<size_type>(entities.find(entt).index()) < entities.free_list();
487 }
488
495 [[nodiscard]] version_type current(const entity_type entt) const {
496 return entities.current(entt);
497 }
498
503 [[nodiscard]] entity_type create() {
504 return entities.generate();
505 }
506
516 [[nodiscard]] entity_type create(const entity_type hint) {
517 return entities.generate(hint);
518 }
519
529 template<typename It>
530 void create(It first, It last) {
531 entities.generate(std::move(first), std::move(last));
532 }
533
545 for(size_type pos = pools.size(); pos != 0u; --pos) {
546 pools.begin()[static_cast<typename pool_container_type::difference_type>(pos - 1u)].second->remove(entt);
547 }
548
549 entities.erase(entt);
550 return entities.current(entt);
551 }
552
566 destroy(entt);
567 const auto elem = traits_type::construct(traits_type::to_entity(entt), version);
568 return entities.bump((elem == tombstone) ? traits_type::next(elem) : elem);
569 }
570
580 template<typename It>
581 void destroy(It first, It last) {
582 const auto to = entities.sort_as(first, last);
583 const auto from = entities.cend() - static_cast<typename common_type::difference_type>(entities.free_list());
584
585 for(auto &&curr: pools) {
586 curr.second->remove(from, to);
587 }
588
589 entities.erase(from, to);
590 }
591
607 template<typename Type, typename... Args>
608 decltype(auto) emplace(const entity_type entt, Args &&...args) {
609 ENTT_ASSERT(valid(entt), "Invalid entity");
610 return assure<Type>().emplace(entt, std::forward<Args>(args)...);
611 }
612
623 template<typename Type, typename It>
624 void insert(It first, It last) {
625 ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
626 assure<Type>().insert(std::move(first), std::move(last));
627 }
628
640 template<typename Type, typename It>
641 void insert(It first, It last, const Type &value) {
642 ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
643 assure<Type>().insert(std::move(first), std::move(last), value);
644 }
645
658 template<typename Type, typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<CIt>::value_type, Type>>>
659 void insert(EIt first, EIt last, CIt from) {
660 ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
661 assure<Type>().insert(first, last, from);
662 }
663
676 template<typename Type, typename... Args>
677 decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args) {
678 auto &cpool = assure<Type>();
679 ENTT_ASSERT(valid(entt), "Invalid entity");
680 return cpool.contains(entt) ? cpool.patch(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); }) : cpool.emplace(entt, std::forward<Args>(args)...);
681 }
682
702 template<typename Type, typename... Func>
703 decltype(auto) patch(const entity_type entt, Func &&...func) {
704 return assure<Type>().patch(entt, std::forward<Func>(func)...);
705 }
706
722 template<typename Type, typename... Args>
723 decltype(auto) replace(const entity_type entt, Args &&...args) {
724 return patch<Type>(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); });
725 }
726
734 template<typename Type, typename... Other>
736 return (assure<Type>().remove(entt) + ... + assure<Other>().remove(entt));
737 }
738
751 template<typename Type, typename... Other, typename It>
752 size_type remove(It first, It last) {
753 size_type count{};
754
755 if constexpr(std::is_same_v<It, typename common_type::iterator>) {
756 std::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
757
758 for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) {
759 if constexpr(sizeof...(Other) != 0u) {
760 if((*from)->data() == first.data()) {
761 std::swap((*from), cpools.back());
762 }
763 }
764
765 count += (*from)->remove(first, last);
766 }
767
768 } else {
769 for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
770 count += std::apply([entt = *first](auto &...curr) { return (curr.remove(entt) + ... + 0u); }, cpools);
771 }
772 }
773
774 return count;
775 }
776
788 template<typename Type, typename... Other>
789 void erase(const entity_type entt) {
790 (assure<Type>().erase(entt), (assure<Other>().erase(entt), ...));
791 }
792
804 template<typename Type, typename... Other, typename It>
805 void erase(It first, It last) {
806 if constexpr(std::is_same_v<It, typename common_type::iterator>) {
807 std::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
808
809 for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) {
810 if constexpr(sizeof...(Other) != 0u) {
811 if((*from)->data() == first.data()) {
812 std::swap(*from, cpools.back());
813 }
814 }
815
816 (*from)->erase(first, last);
817 }
818 } else {
819 for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
820 std::apply([entt = *first](auto &...curr) { (curr.erase(entt), ...); }, cpools);
821 }
822 }
823 }
824
840 template<typename Func>
841 void erase_if(const entity_type entt, Func func) {
842 for(auto [id, cpool]: storage()) {
843 if(cpool.contains(entt) && func(id, std::as_const(cpool))) {
844 cpool.erase(entt);
845 }
846 }
847 }
848
854 template<typename... Type>
855 void compact() {
856 if constexpr(sizeof...(Type) == 0u) {
857 for(auto &&curr: pools) {
858 curr.second->compact();
859 }
860 } else {
861 (assure<Type>().compact(), ...);
862 }
863 }
864
871 template<typename... Type>
872 [[nodiscard]] bool all_of([[maybe_unused]] const entity_type entt) const {
873 if constexpr(sizeof...(Type) == 1u) {
874 auto *cpool = assure<std::remove_const_t<Type>...>();
875 return cpool && cpool->contains(entt);
876 } else {
877 return (all_of<Type>(entt) && ...);
878 }
879 }
880
888 template<typename... Type>
889 [[nodiscard]] bool any_of([[maybe_unused]] const entity_type entt) const {
890 return (all_of<Type>(entt) || ...);
891 }
892
904 template<typename... Type>
905 [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const {
906 if constexpr(sizeof...(Type) == 1u) {
907 return (assure<std::remove_const_t<Type>>()->get(entt), ...);
908 } else {
909 return std::forward_as_tuple(get<Type>(entt)...);
910 }
911 }
912
914 template<typename... Type>
915 [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) {
916 if constexpr(sizeof...(Type) == 1u) {
917 return (static_cast<storage_for_type<Type> &>(assure<std::remove_const_t<Type>>()).get(entt), ...);
918 } else {
919 return std::forward_as_tuple(get<Type>(entt)...);
920 }
921 }
922
938 template<typename Type, typename... Args>
939 [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entt, Args &&...args) {
940 auto &cpool = assure<Type>();
941 ENTT_ASSERT(valid(entt), "Invalid entity");
942 return cpool.contains(entt) ? cpool.get(entt) : cpool.emplace(entt, std::forward<Args>(args)...);
943 }
944
955 template<typename... Type>
956 [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) const {
957 if constexpr(sizeof...(Type) == 1u) {
958 const auto *cpool = assure<std::remove_const_t<Type>...>();
959 return (cpool && cpool->contains(entt)) ? std::addressof(cpool->get(entt)) : nullptr;
960 } else {
961 return std::make_tuple(try_get<Type>(entt)...);
962 }
963 }
964
966 template<typename... Type>
967 [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) {
968 if constexpr(sizeof...(Type) == 1u) {
969 return (const_cast<Type *>(std::as_const(*this).template try_get<Type>(entt)), ...);
970 } else {
971 return std::make_tuple(try_get<Type>(entt)...);
972 }
973 }
974
979 template<typename... Type>
980 void clear() {
981 if constexpr(sizeof...(Type) == 0u) {
982 for(size_type pos = pools.size(); pos; --pos) {
983 pools.begin()[static_cast<typename pool_container_type::difference_type>(pos - 1u)].second->clear();
984 }
985
986 const auto elem = entities.each();
987 entities.erase(elem.begin().base(), elem.end().base());
988 } else {
989 (assure<Type>().clear(), ...);
990 }
991 }
992
998 [[nodiscard]] bool orphan(const entity_type entt) const {
999 return std::none_of(pools.cbegin(), pools.cend(), [entt](auto &&curr) { return curr.second->contains(entt); });
1000 }
1001
1021 template<typename Type>
1022 [[nodiscard]] auto on_construct(const id_type id = type_hash<Type>::value()) {
1023 return assure<Type>(id).on_construct();
1024 }
1025
1045 template<typename Type>
1046 [[nodiscard]] auto on_update(const id_type id = type_hash<Type>::value()) {
1047 return assure<Type>(id).on_update();
1048 }
1049
1069 template<typename Type>
1070 [[nodiscard]] auto on_destroy(const id_type id = type_hash<Type>::value()) {
1071 return assure<Type>(id).on_destroy();
1072 }
1073
1081 template<typename Type, typename... Other, typename... Exclude>
1082 [[nodiscard]] basic_view<get_t<storage_for_type<const Type>, storage_for_type<const Other>...>, exclude_t<storage_for_type<const Exclude>...>>
1085 [&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(assure<std::remove_const_t<Exclude>>()..., assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Type>>());
1086 return elem;
1087 }
1088
1090 template<typename Type, typename... Other, typename... Exclude>
1091 [[nodiscard]] basic_view<get_t<storage_for_type<Type>, storage_for_type<Other>...>, exclude_t<storage_for_type<Exclude>...>>
1093 return {assure<std::remove_const_t<Type>>(), assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Exclude>>()...};
1094 }
1095
1103 template<typename... Owned, typename... Get, typename... Exclude>
1104 basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>
1106 using group_type = basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>;
1107 using handler_type = typename group_type::handler;
1108
1109 if(auto it = groups.find(group_type::group_id()); it != groups.cend()) {
1110 return {*std::static_pointer_cast<handler_type>(it->second)};
1111 }
1112
1113 std::shared_ptr<handler_type> handler{};
1114
1115 if constexpr(sizeof...(Owned) == 0u) {
1116 handler = std::allocate_shared<handler_type>(get_allocator(), get_allocator(), std::forward_as_tuple(assure<std::remove_const_t<Get>>()...), std::forward_as_tuple(assure<std::remove_const_t<Exclude>>()...));
1117 } else {
1118 handler = std::allocate_shared<handler_type>(get_allocator(), std::forward_as_tuple(assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()...), std::forward_as_tuple(assure<std::remove_const_t<Exclude>>()...));
1119 ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [](const auto &data) { return !(data.second->owned(type_id<Owned>().hash()) || ...); }), "Conflicting groups");
1120 }
1121
1122 groups.emplace(group_type::group_id(), handler);
1123 return {*handler};
1124 }
1125
1127 template<typename... Owned, typename... Get, typename... Exclude>
1128 [[nodiscard]] basic_group<owned_t<storage_for_type<const Owned>...>, get_t<storage_for_type<const Get>...>, exclude_t<storage_for_type<const Exclude>...>>
1130 using group_type = basic_group<owned_t<storage_for_type<const Owned>...>, get_t<storage_for_type<const Get>...>, exclude_t<storage_for_type<const Exclude>...>>;
1131 using handler_type = typename group_type::handler;
1132
1133 if(auto it = groups.find(group_type::group_id()); it != groups.cend()) {
1134 return {*std::static_pointer_cast<handler_type>(it->second)};
1135 }
1136
1137 return {};
1138 }
1139
1146 template<typename... Type>
1147 [[nodiscard]] bool owned() const {
1148 return std::any_of(groups.cbegin(), groups.cend(), [](auto &&data) { return (data.second->owned(type_id<Type>().hash()) || ...); });
1149 }
1150
1184 template<typename Type, typename Compare, typename Sort = std_sort, typename... Args>
1185 void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
1186 ENTT_ASSERT(!owned<Type>(), "Cannot sort owned storage");
1187 auto &cpool = assure<Type>();
1188
1189 if constexpr(std::is_invocable_v<Compare, decltype(cpool.get({})), decltype(cpool.get({}))>) {
1190 auto comp = [&cpool, compare = std::move(compare)](const auto lhs, const auto rhs) { return compare(std::as_const(cpool.get(lhs)), std::as_const(cpool.get(rhs))); };
1191 cpool.sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
1192 } else {
1193 cpool.sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
1194 }
1195 }
1196
1210 template<typename To, typename From>
1211 void sort() {
1212 ENTT_ASSERT(!owned<To>(), "Cannot sort owned storage");
1213 const base_type &cpool = assure<From>();
1214 assure<To>().sort_as(cpool.begin(), cpool.end());
1215 }
1216
1221 [[nodiscard]] context &ctx() noexcept {
1222 return vars;
1223 }
1224
1226 [[nodiscard]] const context &ctx() const noexcept {
1227 return vars;
1228 }
1229
1230private:
1231 context vars;
1232 pool_container_type pools;
1233 group_container_type groups;
1234 storage_for_type<entity_type> entities;
1235};
1236
1237} // namespace entt
1238
1239#endif
static constexpr value_type construct(const entity_type entity, const version_type version) noexcept
Constructs an identifier from its parts.
Definition entity.hpp:131
static constexpr value_type next(const value_type value) noexcept
Returns the successor of a given identifier.
Definition entity.hpp:116
static constexpr entity_type to_entity(const value_type value) noexcept
Returns the entity part once converted to the underlying type.
Definition entity.hpp:94
typename Traits::value_type value_type
Value type.
Definition entity.hpp:69
typename Traits::version_type version_type
Underlying version type.
Definition entity.hpp:73
context & ctx() noexcept
Returns the context object, that is, a general purpose container.
auto on_destroy(const id_type id=type_hash< Type >::value())
Returns a sink object for the given element.
bool any_of(const entity_type entt) const
Check if an entity is part of at least one given storage.
Definition registry.hpp:889
bool owned() const
Checks whether the given elements belong to any group.
decltype(auto) get_or_emplace(const entity_type entt, Args &&...args)
Returns a reference to the given element for an entity.
Definition registry.hpp:939
bool orphan(const entity_type entt) const
Checks if an entity has elements assigned.
Definition registry.hpp:998
decltype(auto) replace(const entity_type entt, Args &&...args)
Replaces the given element for an entity.
Definition registry.hpp:723
basic_registry(const size_type count, const allocator_type &allocator=allocator_type{})
Allocates enough memory upon construction to store count pools.
Definition registry.hpp:345
auto on_update(const id_type id=type_hash< Type >::value())
Returns a sink object for the given element.
const common_type * storage(const id_type id) const
Finds the storage associated with a given name, if any.
Definition registry.hpp:443
auto try_get(const entity_type entt) const
Returns pointers to the given elements for an entity.
Definition registry.hpp:956
void swap(basic_registry &other) noexcept
Exchanges the contents with those of a given registry.
Definition registry.hpp:392
iterable_adaptor< internal::registry_storage_iterator< typename pool_container_type::iterator > > iterable
Definition registry.hpp:318
decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args)
Assigns or replaces the given element for an entity.
Definition registry.hpp:677
void insert(It first, It last)
Assigns each entity in a range the given element.
Definition registry.hpp:624
iterable storage() noexcept
Returns an iterable object to use to visit a registry.
Definition registry.hpp:420
bool valid(const entity_type entt) const
Checks if an identifier refers to a valid entity.
Definition registry.hpp:485
bool all_of(const entity_type entt) const
Check if an entity is part of all the given storage.
Definition registry.hpp:872
void erase_if(const entity_type entt, Func func)
Erases elements satisfying specific criteria from an entity.
Definition registry.hpp:841
version_type destroy(const entity_type entt)
Destroys an entity and releases its identifier.
Definition registry.hpp:544
typename traits_type::version_type version_type
Definition registry.hpp:310
entity_type create()
Creates a new entity or recycles a destroyed one.
Definition registry.hpp:503
const context & ctx() const noexcept
Returns the context object, that is, a general purpose container.
void sort()
Sorts two pools of elements in the same way.
version_type destroy(const entity_type entt, const version_type version)
Destroys an entity and releases its identifier.
Definition registry.hpp:565
basic_view< get_t< storage_for_type< const Type >, storage_for_type< const Other >... >, exclude_t< storage_for_type< const Exclude >... > > view(exclude_t< Exclude... >=exclude_t{}) const
Returns a view for the given elements.
void create(It first, It last)
Assigns each element in a range an identifier.
Definition registry.hpp:530
size_type remove(It first, It last)
Removes the given elements from all the entities in a range.
Definition registry.hpp:752
entity_type create(const entity_type hint)
Creates a new entity or recycles a destroyed one.
Definition registry.hpp:516
void clear()
Clears a whole registry or the pools for the given elements.
Definition registry.hpp:980
bool reset(const id_type id)
Discards the storage associated with a given name, if any.
Definition registry.hpp:475
decltype(auto) patch(const entity_type entt, Func &&...func)
Patches the given element for an entity.
Definition registry.hpp:703
basic_group< owned_t< storage_for_type< const Owned >... >, get_t< storage_for_type< const Get >... >, exclude_t< storage_for_type< const Exclude >... > > group_if_exists(get_t< Get... >=get_t{}, exclude_t< Exclude... >=exclude_t{}) const
Returns a group for the given elements.
size_type remove(const entity_type entt)
Removes the given elements from an entity.
Definition registry.hpp:735
basic_registry & operator=(basic_registry &&other) noexcept
Move assignment operator.
Definition registry.hpp:383
basic_view< get_t< storage_for_type< Type >, storage_for_type< Other >... >, exclude_t< storage_for_type< Exclude >... > > view(exclude_t< Exclude... >=exclude_t{})
Returns a view for the given elements.
auto try_get(const entity_type entt)
Returns pointers to the given elements for an entity.
Definition registry.hpp:967
common_type * storage(const id_type id)
Finds the storage associated with a given name, if any.
Definition registry.hpp:434
void destroy(It first, It last)
Destroys all entities in a range and releases their identifiers.
Definition registry.hpp:581
decltype(auto) get(const entity_type entt)
Returns references to the given elements for an entity.
Definition registry.hpp:915
typename storage_for< Type, Entity, typename alloc_traits::template rebind_alloc< std::remove_const_t< Type > > >::type storage_for_type
Definition registry.hpp:327
void erase(It first, It last)
Erases the given elements from all the entities in a range.
Definition registry.hpp:805
void sort(Compare compare, Sort algo=Sort{}, Args &&...args)
Sorts the elements of a given element.
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
Definition registry.hpp:408
decltype(auto) emplace(const entity_type entt, Args &&...args)
Assigns the given element to an entity.
Definition registry.hpp:608
basic_registry & operator=(const basic_registry &)=delete
Default copy assignment operator, deleted on purpose.
basic_registry(const allocator_type &allocator)
Constructs an empty registry with a given allocator.
Definition registry.hpp:337
auto on_construct(const id_type id=type_hash< Type >::value())
Returns a sink object for the given element.
storage_for_type< Type > & storage(const id_type id=type_hash< Type >::value())
Returns the storage for a given element type.
Definition registry.hpp:455
void insert(It first, It last, const Type &value)
Assigns each entity in a range the given element.
Definition registry.hpp:641
typename traits_type::value_type entity_type
Definition registry.hpp:308
decltype(auto) get(const entity_type entt) const
Returns references to the given elements for an entity.
Definition registry.hpp:905
basic_registry(basic_registry &&other) noexcept
Move constructor.
Definition registry.hpp:361
void compact()
Removes all tombstones from a registry or only the pools for the given elements.
Definition registry.hpp:855
const_iterable storage() const noexcept
Returns an iterable object to use to visit a registry.
Definition registry.hpp:425
~basic_registry()=default
Default destructor.
version_type current(const entity_type entt) const
Returns the actual version for an identifier.
Definition registry.hpp:495
basic_group< owned_t< storage_for_type< Owned >... >, get_t< storage_for_type< Get >... >, exclude_t< storage_for_type< Exclude >... > > group(get_t< Get... >=get_t{}, exclude_t< Exclude... >=exclude_t{})
Returns a group for the given elements.
const storage_for_type< Type > * storage(const id_type id=type_hash< Type >::value()) const
Returns the storage for a given element type, if any.
Definition registry.hpp:466
void insert(EIt first, EIt last, CIt from)
Assigns each entity in a range the given elements.
Definition registry.hpp:659
basic_registry(const basic_registry &)=delete
Default copy constructor, deleted on purpose.
internal::registry_context< allocator_type > context
Definition registry.hpp:316
iterable_adaptor< internal::registry_storage_iterator< typename pool_container_type::const_iterator > > const_iterable
Definition registry.hpp:320
basic_registry()
Default constructor.
Definition registry.hpp:330
void erase(const entity_type entt)
Erases the given elements from an entity.
Definition registry.hpp:789
Sparse set implementation.
iterator begin() const noexcept
Returns an iterator to the beginning.
iterator end() const noexcept
Returns an iterator to the end.
std::ptrdiff_t difference_type
Signed integer type.
const_iterator find(const entity_type entt) const noexcept
Finds an entity.
View implementation.
Definition fwd.hpp:47
Associative container for key-value pairs with unique keys.
void reserve(const size_type cnt)
Reserves space for at least the specified number of elements and regenerates the hash table.
EnTT default namespace.
Definition dense_map.hpp:22
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:29
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
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.
constexpr type_list< Type..., Other... > operator+(type_list< Type... >, type_list< Other... >)
Concatenates multiple type lists.
constexpr owned_t< Type... > owned
Variable template for lists of owned elements.
Definition fwd.hpp:184
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.
const type_info & type_id() noexcept
Returns the type info object associated to a given type.
constexpr bool operator>(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
constexpr bool operator==(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
Entity traits.
Definition entity.hpp:163
Alias for exclusion lists.
Definition fwd.hpp:140
Alias for lists of observed elements.
Definition fwd.hpp:157
Identity function object (waiting for C++20).
Definition utility.hpp:10
Utility class to create an iterable object from a pair of iterators.
Definition iterator.hpp:141
Function object to wrap std::sort in a class type.
Definition algorithm.hpp:21
Provides a common way to define storage types.
Definition fwd.hpp:226
static constexpr id_type value() noexcept
Returns the numeric representation of a given type.