EnTT 4.0.0
Loading...
Searching...
No Matches
registry.hpp
1#ifndef ENTT_ENTITY_REGISTRY_HPP
2#define ENTT_ENTITY_REGISTRY_HPP
3
4#include <compare>
5#include "../config/config.h"
6#include "../container/dense_map.hpp"
7#include "../core/algorithm.hpp"
8#include "../core/any.hpp"
9#include "../core/concepts.hpp"
10#include "../core/fwd.hpp"
11#include "../core/iterator.hpp"
12#include "../core/memory.hpp"
13#include "../core/type_info.hpp"
14#include "../core/type_traits.hpp"
15#include "../stl/algorithm.hpp"
16#include "../stl/array.hpp"
17#include "../stl/concepts.hpp"
18#include "../stl/cstddef.hpp"
19#include "../stl/functional.hpp"
20#include "../stl/iterator.hpp"
21#include "../stl/memory.hpp"
22#include "../stl/tuple.hpp"
23#include "../stl/type_traits.hpp"
24#include "../stl/utility.hpp"
25#include "entity.hpp"
26#include "fwd.hpp"
27#include "group.hpp"
28#include "mixin.hpp"
29#include "sparse_set.hpp"
30#include "storage.hpp"
31#include "view.hpp"
32
33namespace entt {
34
36namespace internal {
37
38template<typename It>
39class registry_storage_iterator final {
40 template<typename>
41 friend class registry_storage_iterator;
42
43 using mapped_type = stl::remove_reference_t<decltype(stl::declval<It>()->second)>;
44
45public:
46 using value_type = stl::pair<id_type, constness_as_t<typename mapped_type::element_type, mapped_type> &>;
47 using pointer = input_iterator_pointer<value_type>;
48 using reference = value_type;
49 using difference_type = stl::ptrdiff_t;
50 using iterator_category = stl::input_iterator_tag;
51 using iterator_concept = stl::random_access_iterator_tag;
52
53 constexpr registry_storage_iterator() noexcept
54 : it{} {}
55
56 constexpr registry_storage_iterator(It iter) noexcept
57 : it{iter} {}
58
59 template<typename Other>
60 requires (!stl::same_as<It, Other> && stl::constructible_from<It, Other>)
61 constexpr registry_storage_iterator(const registry_storage_iterator<Other> &other) noexcept
62 : registry_storage_iterator{other.it} {}
63
64 constexpr registry_storage_iterator &operator++() noexcept {
65 return ++it, *this;
66 }
67
68 constexpr registry_storage_iterator operator++(int) noexcept {
69 const registry_storage_iterator orig = *this;
70 return ++(*this), orig;
71 }
72
73 constexpr registry_storage_iterator &operator--() noexcept {
74 return --it, *this;
75 }
76
77 constexpr registry_storage_iterator operator--(int) noexcept {
78 const registry_storage_iterator orig = *this;
79 return operator--(), orig;
80 }
81
82 constexpr registry_storage_iterator &operator+=(const difference_type value) noexcept {
83 it += value;
84 return *this;
85 }
86
87 constexpr registry_storage_iterator operator+(const difference_type value) const noexcept {
88 registry_storage_iterator copy = *this;
89 return (copy += value);
90 }
91
92 constexpr registry_storage_iterator &operator-=(const difference_type value) noexcept {
93 return (*this += -value);
94 }
95
96 constexpr registry_storage_iterator operator-(const difference_type value) const noexcept {
97 return (*this + -value);
98 }
99
100 [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
101 return {it[value].first, *it[value].second};
102 }
103
104 [[nodiscard]] constexpr reference operator*() const noexcept {
105 return operator[](0);
106 }
107
108 [[nodiscard]] constexpr pointer operator->() const noexcept {
109 return operator*();
110 }
111
112 template<typename Other>
113 [[nodiscard]] constexpr stl::ptrdiff_t operator-(const registry_storage_iterator<Other> &other) const noexcept {
114 return it - other.it;
115 }
116
117 template<typename Other>
118 [[nodiscard]] constexpr bool operator==(const registry_storage_iterator<Other> &other) const noexcept {
119 return it == other.it;
120 }
121
122 template<typename Other>
123 [[nodiscard]] constexpr auto operator<=>(const registry_storage_iterator<Other> &other) const noexcept {
124 return it <=> other.it;
125 }
126
127private:
128 It it;
129};
130
131template<typename Allocator>
132class registry_context {
133 using alloc_traits = stl::allocator_traits<Allocator>;
134 using allocator_type = alloc_traits::template rebind_alloc<stl::pair<const id_type, basic_any<0u>>>;
135
136public:
137 explicit registry_context(const allocator_type &allocator)
138 : ctx{allocator} {}
139
140 void clear() noexcept {
141 ctx.clear();
142 }
143
144 template<typename Type, typename... Args>
145 Type &emplace_as(const id_type id, Args &&...args) {
146 return any_cast<Type &>(ctx.try_emplace(id, stl::in_place_type<Type>, stl::forward<Args>(args)...).first->second);
147 }
148
149 template<typename Type, typename... Args>
150 Type &emplace(Args &&...args) {
151 return emplace_as<Type>(type_id<Type>().hash(), stl::forward<Args>(args)...);
152 }
153
154 template<typename Type>
155 Type &insert_or_assign(const id_type id, Type &&value) {
156 return any_cast<stl::remove_cvref_t<Type> &>(ctx.insert_or_assign(id, stl::forward<Type>(value)).first->second);
157 }
158
159 template<typename Type>
160 Type &insert_or_assign(Type &&value) {
161 return insert_or_assign(type_id<Type>().hash(), stl::forward<Type>(value));
162 }
163
164 template<typename Type>
165 bool erase(const id_type id = type_id<Type>().hash()) {
166 const auto it = ctx.find(id);
167 return it != ctx.end() && it->second.info() == type_id<Type>() ? (ctx.erase(it), true) : false;
168 }
169
170 template<typename Type>
171 [[nodiscard]] const Type &get(const id_type id = type_id<Type>().hash()) const {
172 return any_cast<const Type &>(ctx.at(id));
173 }
174
175 template<typename Type>
176 [[nodiscard]] Type &get(const id_type id = type_id<Type>().hash()) {
177 return any_cast<Type &>(ctx.at(id));
178 }
179
180 template<typename Type>
181 [[nodiscard]] const Type *find(const id_type id = type_id<Type>().hash()) const {
182 const auto it = ctx.find(id);
183 return it != ctx.cend() ? any_cast<const Type>(&it->second) : nullptr;
184 }
185
186 template<typename Type>
187 [[nodiscard]] Type *find(const id_type id = type_id<Type>().hash()) {
188 const auto it = ctx.find(id);
189 return it != ctx.end() ? any_cast<Type>(&it->second) : nullptr;
190 }
191
192 template<typename Type>
193 [[nodiscard]] bool contains(const id_type id = type_id<Type>().hash()) const {
194 const auto it = ctx.find(id);
195 return it != ctx.cend() && it->second.info() == type_id<Type>();
196 }
197
198private:
199 dense_map<id_type, basic_any<0u>, stl::identity, stl::equal_to<>, allocator_type> ctx;
200};
201
202} // namespace internal
204
210template<typename Entity, typename Allocator>
212 using base_type = basic_sparse_set<Entity, Allocator>;
213 using alloc_traits = stl::allocator_traits<Allocator>;
214 static_assert(stl::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
215 // stl::shared_ptr because of its type erased allocator which is useful here
216 using pool_container_type = dense_map<id_type, stl::shared_ptr<base_type>, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc<stl::pair<const id_type, stl::shared_ptr<base_type>>>>;
217 using group_container_type = dense_map<id_type, stl::shared_ptr<internal::group_descriptor>, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc<stl::pair<const id_type, stl::shared_ptr<internal::group_descriptor>>>>;
218 using traits_type = entt_traits<Entity>;
219
220 template<cvref_unqualified Type>
221 [[nodiscard]] auto &assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) {
222 if constexpr(stl::is_same_v<Type, entity_type>) {
223 ENTT_ASSERT(id == type_hash<Type>::value(), "User entity storage not allowed");
224 return entities;
225 } else {
227
228 if(auto it = pools.find(id); it != pools.cend()) {
229 ENTT_ASSERT(it->second->info() == type_id<Type>(), "Unexpected type");
230 return static_cast<storage_type &>(*it->second);
231 }
232
233 typename pool_container_type::mapped_type cpool = stl::allocate_shared<storage_type>(get_allocator(), get_allocator());
234 pools.emplace(id, cpool);
235 cpool->bind(*this);
236
237 return static_cast<storage_type &>(*cpool);
238 }
239 }
240
241 template<cvref_unqualified Type>
242 [[nodiscard]] const auto *assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) const {
243 if constexpr(stl::is_same_v<Type, entity_type>) {
244 ENTT_ASSERT(id == type_hash<Type>::value(), "User entity storage not allowed");
245 return &entities;
246 } else {
247 if(const auto it = pools.find(id); it != pools.cend()) {
248 ENTT_ASSERT(it->second->info() == type_id<Type>(), "Unexpected type");
249 return static_cast<const storage_for_type<Type> *>(it->second.get());
250 }
251
252 return static_cast<const storage_for_type<Type> *>(nullptr);
253 }
254 }
255
256 void rebind() {
257 entities.bind(*this);
258
259 for(auto &&curr: pools) {
260 curr.second->bind(*this);
261 }
262 }
263
264public:
266 using allocator_type = Allocator;
272 using size_type = stl::size_t;
274 using common_type = base_type;
276 using context = internal::registry_context<allocator_type>;
281
286 template<typename Type>
288
292
297 explicit basic_registry(const allocator_type &allocator)
298 : basic_registry{0u, allocator} {}
299
305 basic_registry(const size_type count, const allocator_type &allocator = allocator_type{})
306 : vars{allocator},
307 pools{allocator},
308 groups{allocator},
309 entities{allocator} {
310 pools.reserve(count);
311 rebind();
312 }
313
316
322 : vars{stl::move(other.vars)},
323 pools{stl::move(other.pools)},
324 groups{stl::move(other.groups)},
325 entities{stl::move(other.entities)} {
326 rebind();
327 }
328
330 ~basic_registry() = default;
331
337
344 swap(other);
345 return *this;
346 }
347
352 void swap(basic_registry &other) noexcept {
353 using stl::swap;
354
355 swap(vars, other.vars);
356 swap(pools, other.pools);
357 swap(groups, other.groups);
358 swap(entities, other.entities);
359
360 rebind();
361 other.rebind();
362 }
363
368 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
369 return entities.get_allocator();
370 }
371
380 [[nodiscard]] iterable storage() noexcept {
381 return iterable{pools.begin(), pools.end()};
382 }
383
385 [[nodiscard]] const_iterable storage() const noexcept {
386 return const_iterable{pools.cbegin(), pools.cend()};
387 }
388
394 [[nodiscard]] common_type *storage(const id_type id) {
395 return const_cast<common_type *>(stl::as_const(*this).storage(id));
396 }
397
403 [[nodiscard]] const common_type *storage(const id_type id) const {
404 const auto it = pools.find(id);
405 return it == pools.cend() ? nullptr : it->second.get();
406 }
407
414 template<typename Type>
416 return assure<stl::remove_const_t<Type>>(id);
417 }
418
425 template<typename Type>
426 [[nodiscard]] const storage_for_type<Type> *storage(const id_type id = type_hash<Type>::value()) const {
427 return assure<stl::remove_const_t<Type>>(id);
428 }
429
435 bool reset(const id_type id) {
436 ENTT_ASSERT(id != type_hash<entity_type>::value(), "Cannot reset entity storage");
437 return !(pools.erase(id) == 0u);
438 }
439
445 [[nodiscard]] bool valid(const entity_type entt) const {
446 return static_cast<size_type>(entities.find(entt).index()) < entities.free_list();
447 }
448
455 [[nodiscard]] version_type current(const entity_type entt) const {
456 return entities.current(entt);
457 }
458
463 [[nodiscard]] entity_type create() {
464 return entities.generate();
465 }
466
476 [[nodiscard]] entity_type create(const entity_type hint) {
477 return entities.generate(hint);
478 }
479
489 template<stl::output_iterator<entity_type> It>
490 void create(It first, It last) {
491 entities.generate(stl::move(first), stl::move(last));
492 }
493
505 for(size_type pos = pools.size(); pos != 0u; --pos) {
506 pools.begin()[static_cast<pool_container_type::difference_type>(pos - 1u)].second->remove(entt);
507 }
508
509 entities.erase(entt);
510 return entities.current(entt);
511 }
512
526 destroy(entt);
527 const auto elem = traits_type::construct(traits_type::to_entity(entt), version);
528 return entities.bump((elem == tombstone) ? traits_type::next(elem) : elem);
529 }
530
539 void destroy(stl::input_iterator auto first, stl::input_iterator auto last) {
540 const auto to = entities.sort_as(first, last);
541 const auto from = entities.cend() - static_cast<common_type::difference_type>(entities.free_list());
542
543 for(auto &&curr: pools) {
544 curr.second->remove(from, to);
545 }
546
547 entities.erase(from, to);
548 }
549
565 template<typename Type, typename... Args>
566 decltype(auto) emplace(const entity_type entt, Args &&...args) {
567 ENTT_ASSERT(valid(entt), "Invalid entity");
568 return assure<Type>().emplace(entt, stl::forward<Args>(args)...);
569 }
570
581 template<typename Type>
582 void insert(stl::input_iterator auto first, stl::input_iterator auto last, const Type &value = {}) {
583 ENTT_ASSERT(stl::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
584 assure<Type>().insert(stl::move(first), stl::move(last), value);
585 }
586
599 template<typename Type, typename EIt, typename CIt>
600 requires stl::same_as<typename stl::iterator_traits<CIt>::value_type, Type>
601 void insert(EIt first, EIt last, CIt from) {
602 ENTT_ASSERT(stl::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
603 assure<Type>().insert(first, last, from);
604 }
605
618 template<typename Type, typename... Args>
619 decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args) {
620 auto &cpool = assure<Type>();
621 ENTT_ASSERT(valid(entt), "Invalid entity");
622 return cpool.contains(entt) ? cpool.patch(entt, [&args...](auto &...curr) { ((curr = Type{stl::forward<Args>(args)...}), ...); }) : cpool.emplace(entt, stl::forward<Args>(args)...);
623 }
624
644 template<typename Type, typename... Func>
645 decltype(auto) patch(const entity_type entt, Func &&...func) {
646 return assure<Type>().patch(entt, stl::forward<Func>(func)...);
647 }
648
664 template<typename Type, typename... Args>
665 decltype(auto) replace(const entity_type entt, Args &&...args) {
666 return patch<Type>(entt, [&args...](auto &...curr) { ((curr = Type{stl::forward<Args>(args)...}), ...); });
667 }
668
676 template<typename Type, typename... Other>
678 return (assure<Type>().remove(entt) + ... + assure<Other>().remove(entt));
679 }
680
693 template<typename Type, typename... Other, stl::input_iterator It>
694 size_type remove(It first, It last) {
695 size_type count{};
696
697 if constexpr(stl::is_same_v<It, typename common_type::iterator>) {
698 stl::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
699
700 for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) {
701 if constexpr(sizeof...(Other) != 0u) {
702 if((*from)->data() == first.data()) {
703 stl::swap((*from), cpools.back());
704 }
705 }
706
707 count += (*from)->remove(first, last);
708 }
709
710 } else {
711 for(auto cpools = stl::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
712 count += stl::apply([entt = *first](auto &...curr) { return (curr.remove(entt) + ... + 0u); }, cpools);
713 }
714 }
715
716 return count;
717 }
718
730 template<typename Type, typename... Other>
731 void erase(const entity_type entt) {
732 (assure<Type>().erase(entt), (assure<Other>().erase(entt), ...));
733 }
734
746 template<typename Type, typename... Other, stl::input_iterator It>
747 void erase(It first, It last) {
748 if constexpr(stl::is_same_v<It, typename common_type::iterator>) {
749 stl::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
750
751 for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) {
752 if constexpr(sizeof...(Other) != 0u) {
753 if((*from)->data() == first.data()) {
754 stl::swap(*from, cpools.back());
755 }
756 }
757
758 (*from)->erase(first, last);
759 }
760 } else {
761 for(auto cpools = stl::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
762 stl::apply([entt = *first](auto &...curr) { (curr.erase(entt), ...); }, cpools);
763 }
764 }
765 }
766
782 template<typename Func>
783 void erase_if(const entity_type entt, Func func) {
784 for(auto [id, cpool]: storage()) {
785 if(cpool.contains(entt) && func(id, stl::as_const(cpool))) {
786 cpool.erase(entt);
787 }
788 }
789 }
790
796 template<typename... Type>
797 void compact() {
798 if constexpr(sizeof...(Type) == 0u) {
799 for(auto &&curr: pools) {
800 curr.second->compact();
801 }
802 } else {
803 (assure<Type>().compact(), ...);
804 }
805 }
806
813 template<typename... Type>
814 [[nodiscard]] bool all_of([[maybe_unused]] const entity_type entt) const {
815 if constexpr(sizeof...(Type) == 1u) {
816 auto *cpool = assure<stl::remove_const_t<Type>...>();
817 return cpool && cpool->contains(entt);
818 } else {
819 return (all_of<Type>(entt) && ...);
820 }
821 }
822
830 template<typename... Type>
831 [[nodiscard]] bool any_of([[maybe_unused]] const entity_type entt) const {
832 return (all_of<Type>(entt) || ...);
833 }
834
846 template<typename... Type>
847 [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const {
848 if constexpr(sizeof...(Type) == 1u) {
849 return (assure<stl::remove_const_t<Type>>()->get(entt), ...);
850 } else {
851 return stl::forward_as_tuple(get<Type>(entt)...);
852 }
853 }
854
856 template<typename... Type>
857 [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) {
858 if constexpr(sizeof...(Type) == 1u) {
859 return (static_cast<storage_for_type<Type> &>(assure<stl::remove_const_t<Type>>()).get(entt), ...);
860 } else {
861 return stl::forward_as_tuple(get<Type>(entt)...);
862 }
863 }
864
880 template<typename Type, typename... Args>
881 [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entt, Args &&...args) {
882 auto &cpool = assure<Type>();
883 ENTT_ASSERT(valid(entt), "Invalid entity");
884 return cpool.contains(entt) ? cpool.get(entt) : cpool.emplace(entt, stl::forward<Args>(args)...);
885 }
886
897 template<typename... Type>
898 [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) const {
899 if constexpr(sizeof...(Type) == 1u) {
900 const auto *cpool = assure<stl::remove_const_t<Type>...>();
901 return (cpool && cpool->contains(entt)) ? stl::addressof(cpool->get(entt)) : nullptr;
902 } else {
903 return stl::make_tuple(try_get<Type>(entt)...);
904 }
905 }
906
908 template<typename... Type>
909 [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) {
910 if constexpr(sizeof...(Type) == 1u) {
911 return (const_cast<Type *>(stl::as_const(*this).template try_get<Type>(entt)), ...);
912 } else {
913 return stl::make_tuple(try_get<Type>(entt)...);
914 }
915 }
916
921 template<typename... Type>
922 void clear() {
923 if constexpr(sizeof...(Type) == 0u) {
924 for(size_type pos = pools.size(); pos; --pos) {
925 pools.begin()[static_cast<pool_container_type::difference_type>(pos - 1u)].second->clear();
926 }
927
928 const auto elem = entities.each();
929 entities.erase(elem.begin().base(), elem.end().base());
930 } else {
931 (assure<Type>().clear(), ...);
932 }
933 }
934
940 [[nodiscard]] bool orphan(const entity_type entt) const {
941 return stl::none_of(pools.cbegin(), pools.cend(), [entt](auto &&curr) { return curr.second->contains(entt); });
942 }
943
963 template<typename Type>
964 [[nodiscard]] auto on_construct(const id_type id = type_hash<Type>::value()) {
965 return assure<Type>(id).on_construct();
966 }
967
987 template<typename Type>
988 [[nodiscard]] auto on_update(const id_type id = type_hash<Type>::value()) {
989 return assure<Type>(id).on_update();
990 }
991
1011 template<typename Type>
1012 [[nodiscard]] auto on_destroy(const id_type id = type_hash<Type>::value()) {
1013 return assure<Type>(id).on_destroy();
1014 }
1015
1023 template<typename Type, typename... Other, typename... Exclude>
1024 [[nodiscard]] basic_view<get_t<storage_for_type<const Type>, storage_for_type<const Other>...>, exclude_t<storage_for_type<const Exclude>...>>
1027 [&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(assure<stl::remove_const_t<Exclude>>()..., assure<stl::remove_const_t<Other>>()..., assure<stl::remove_const_t<Type>>());
1028 return elem;
1029 }
1030
1032 template<typename Type, typename... Other, typename... Exclude>
1033 [[nodiscard]] basic_view<get_t<storage_for_type<Type>, storage_for_type<Other>...>, exclude_t<storage_for_type<Exclude>...>>
1035 return {assure<stl::remove_const_t<Type>>(), assure<stl::remove_const_t<Other>>()..., assure<stl::remove_const_t<Exclude>>()...};
1036 }
1037
1045 template<typename... Owned, typename... Get, typename... Exclude>
1046 basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>
1048 using group_type = basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>;
1049 using handler_type = group_type::handler;
1050
1051 if(auto it = groups.find(group_type::group_id()); it != groups.cend()) {
1052 return {*stl::static_pointer_cast<handler_type>(it->second)};
1053 }
1054
1055 stl::shared_ptr<handler_type> handler{};
1056
1057 if constexpr(sizeof...(Owned) == 0u) {
1058 handler = stl::allocate_shared<handler_type>(get_allocator(), get_allocator(), stl::forward_as_tuple(assure<stl::remove_const_t<Get>>()...), stl::forward_as_tuple(assure<stl::remove_const_t<Exclude>>()...));
1059 } else {
1060 handler = stl::allocate_shared<handler_type>(get_allocator(), stl::forward_as_tuple(assure<stl::remove_const_t<Owned>>()..., assure<stl::remove_const_t<Get>>()...), stl::forward_as_tuple(assure<stl::remove_const_t<Exclude>>()...));
1061 ENTT_ASSERT(stl::all_of(groups.cbegin(), groups.cend(), [](const auto &data) { return !(data.second->owned(type_id<Owned>().hash()) || ...); }), "Conflicting groups");
1062 }
1063
1064 groups.emplace(group_type::group_id(), handler);
1065 return {*handler};
1066 }
1067
1069 template<typename... Owned, typename... Get, typename... Exclude>
1070 [[nodiscard]] basic_group<owned_t<storage_for_type<const Owned>...>, get_t<storage_for_type<const Get>...>, exclude_t<storage_for_type<const Exclude>...>>
1072 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>...>>;
1073 using handler_type = group_type::handler;
1074
1075 if(auto it = groups.find(group_type::group_id()); it != groups.cend()) {
1076 return {*stl::static_pointer_cast<handler_type>(it->second)};
1077 }
1078
1079 return {};
1080 }
1081
1088 template<typename... Type>
1089 [[nodiscard]] bool owned() const {
1090 return stl::any_of(groups.cbegin(), groups.cend(), [](auto &&data) { return (data.second->owned(type_id<Type>().hash()) || ...); });
1091 }
1092
1126 template<typename Type, typename Compare, typename Sort = std_sort, typename... Args>
1127 void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
1128 ENTT_ASSERT(!owned<Type>(), "Cannot sort owned storage");
1129 auto &cpool = assure<Type>();
1130
1131 if constexpr(stl::is_invocable_v<Compare, decltype(cpool.get({})), decltype(cpool.get({}))>) {
1132 auto comp = [&cpool, compare = stl::move(compare)](const auto lhs, const auto rhs) { return compare(stl::as_const(cpool.get(lhs)), stl::as_const(cpool.get(rhs))); };
1133 cpool.sort(stl::move(comp), stl::move(algo), stl::forward<Args>(args)...);
1134 } else {
1135 cpool.sort(stl::move(compare), stl::move(algo), stl::forward<Args>(args)...);
1136 }
1137 }
1138
1152 template<typename To, typename From>
1153 void sort() {
1154 ENTT_ASSERT(!owned<To>(), "Cannot sort owned storage");
1155 const base_type &cpool = assure<From>();
1156 assure<To>().sort_as(cpool.begin(), cpool.end());
1157 }
1158
1163 [[nodiscard]] context &ctx() noexcept {
1164 return vars;
1165 }
1166
1168 [[nodiscard]] const context &ctx() const noexcept {
1169 return vars;
1170 }
1171
1172private:
1173 context vars;
1174 pool_container_type pools;
1175 group_container_type groups;
1176 storage_for_type<entity_type> entities;
1177};
1178
1179} // namespace entt
1180
1181#endif
static constexpr value_type construct(const entity_type entity, const version_type version) noexcept
Definition entity.hpp:145
static constexpr value_type next(const value_type value) noexcept
Definition entity.hpp:130
static constexpr entity_type to_entity(const value_type value) noexcept
Definition entity.hpp:106
internal::entt_traits< Type >::value_type value_type
Definition entity.hpp:81
internal::entt_traits< Type >::version_type version_type
Definition entity.hpp:85
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:831
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:881
bool orphan(const entity_type entt) const
Checks if an entity has elements assigned.
Definition registry.hpp:940
decltype(auto) replace(const entity_type entt, Args &&...args)
Replaces the given element for an entity.
Definition registry.hpp:665
basic_registry(const size_type count, const allocator_type &allocator=allocator_type{})
Allocates enough memory upon construction to store count pools.
Definition registry.hpp:305
auto on_update(const id_type id=type_hash< Type >::value())
Returns a sink object for the given element.
Definition registry.hpp:988
storage_for< Type, Entity, typename alloc_traits::template rebind_alloc< stl::remove_const_t< Type > > >::type storage_for_type
Definition registry.hpp:287
traits_type::version_type version_type
Definition registry.hpp:270
const common_type * storage(const id_type id) const
Finds the storage associated with a given name, if any.
Definition registry.hpp:403
auto try_get(const entity_type entt) const
Returns pointers to the given elements for an entity.
Definition registry.hpp:898
void swap(basic_registry &other) noexcept
Exchanges the contents with those of a given registry.
Definition registry.hpp:352
iterable_adaptor< internal::registry_storage_iterator< typename pool_container_type::iterator > > iterable
Definition registry.hpp:278
decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args)
Assigns or replaces the given element for an entity.
Definition registry.hpp:619
iterable storage() noexcept
Returns an iterable object to use to visit a registry.
Definition registry.hpp:380
bool valid(const entity_type entt) const
Checks if an identifier refers to a valid entity.
Definition registry.hpp:445
bool all_of(const entity_type entt) const
Check if an entity is part of all the given storage.
Definition registry.hpp:814
void erase_if(const entity_type entt, Func func)
Erases elements satisfying specific criteria from an entity.
Definition registry.hpp:783
version_type destroy(const entity_type entt)
Destroys an entity and releases its identifier.
Definition registry.hpp:504
entity_type create()
Creates a new entity or recycles a destroyed one.
Definition registry.hpp:463
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.
void insert(EIt first, EIt last, CIt from)
Assigns each entity in a range the given elements.
Definition registry.hpp:601
version_type destroy(const entity_type entt, const version_type version)
Destroys an entity and releases its identifier.
Definition registry.hpp:525
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.
traits_type::value_type entity_type
Definition registry.hpp:268
void create(It first, It last)
Assigns each element in a range an identifier.
Definition registry.hpp:490
size_type remove(It first, It last)
Removes the given elements from all the entities in a range.
Definition registry.hpp:694
entity_type create(const entity_type hint)
Creates a new entity or recycles a destroyed one.
Definition registry.hpp:476
void clear()
Clears a whole registry or the pools for the given elements.
Definition registry.hpp:922
bool reset(const id_type id)
Discards the storage associated with a given name, if any.
Definition registry.hpp:435
decltype(auto) patch(const entity_type entt, Func &&...func)
Patches the given element for an entity.
Definition registry.hpp:645
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:677
basic_registry & operator=(basic_registry &&other) noexcept
Move assignment operator.
Definition registry.hpp:343
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:909
common_type * storage(const id_type id)
Finds the storage associated with a given name, if any.
Definition registry.hpp:394
decltype(auto) get(const entity_type entt)
Returns references to the given elements for an entity.
Definition registry.hpp:857
void erase(It first, It last)
Erases the given elements from all the entities in a range.
Definition registry.hpp:747
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:368
decltype(auto) emplace(const entity_type entt, Args &&...args)
Assigns the given element to an entity.
Definition registry.hpp:566
void destroy(stl::input_iterator auto first, stl::input_iterator auto last)
Destroys all entities in a range and releases their identifiers.
Definition registry.hpp:539
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:297
auto on_construct(const id_type id=type_hash< Type >::value())
Returns a sink object for the given element.
Definition registry.hpp:964
storage_for_type< Type > & storage(const id_type id=type_hash< Type >::value())
Returns the storage for a given element type.
Definition registry.hpp:415
decltype(auto) get(const entity_type entt) const
Returns references to the given elements for an entity.
Definition registry.hpp:847
basic_registry(basic_registry &&other) noexcept
Move constructor.
Definition registry.hpp:321
void compact()
Removes all tombstones from a registry or only the pools for the given elements.
Definition registry.hpp:797
const_iterable storage() const noexcept
Returns an iterable object to use to visit a registry.
Definition registry.hpp:385
~basic_registry()=default
Default destructor.
version_type current(const entity_type entt) const
Returns the actual version for an identifier.
Definition registry.hpp:455
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:426
void insert(stl::input_iterator auto first, stl::input_iterator auto last, const Type &value={})
Assigns each entity in a range the given element.
Definition registry.hpp:582
basic_registry(const basic_registry &)=delete
Default copy constructor, deleted on purpose.
internal::registry_context< allocator_type > context
Definition registry.hpp:276
iterable_adaptor< internal::registry_storage_iterator< typename pool_container_type::const_iterator > > const_iterable
Definition registry.hpp:280
basic_registry()
Default constructor.
Definition registry.hpp:290
void erase(const entity_type entt)
Erases the given elements from an entity.
Definition registry.hpp:731
Sparse set implementation.
iterator begin() const noexcept
Returns an iterator to the beginning.
iterator end() const noexcept
Returns an iterator to the end.
const_iterator find(const entity_type entt) const noexcept
Finds an entity.
stl::ptrdiff_t difference_type
Signed integer type.
View implementation.
Definition fwd.hpp:48
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.
Custom EnTT namespace for the standard template library.
Definition entt.hpp:5
EnTT default namespace.
Definition dense_map.hpp:25
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.
constexpr owned_t< Type... > owned
Variable template for lists of owned elements.
Definition fwd.hpp:185
const type_info & type_id() noexcept
Returns the type info object associated to a given type.
stl::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:29
Entity traits.
Definition entity.hpp:177
Alias for exclusion lists.
Definition fwd.hpp:141
Alias for lists of observed elements.
Definition fwd.hpp:158
Utility class to create an iterable object from a pair of iterators.
Definition iterator.hpp:125
Function object to wrap stl::sort in a class type.
Definition algorithm.hpp:22
Provides a common way to define storage types.
Definition fwd.hpp:227
static constexpr id_type value() noexcept
Returns the numeric representation of a given type.