EnTT 3.14.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 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 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 template<typename Type, typename... Args>
168 Type &emplace_as(const id_type id, Args &&...args) {
169 return any_cast<Type &>(ctx.try_emplace(id, std::in_place_type<Type>, std::forward<Args>(args)...).first->second);
170 }
171
172 template<typename Type, typename... Args>
173 Type &emplace(Args &&...args) {
174 return emplace_as<Type>(type_id<Type>().hash(), std::forward<Args>(args)...);
175 }
176
177 template<typename Type>
178 Type &insert_or_assign(const id_type id, Type &&value) {
179 return any_cast<std::remove_cv_t<std::remove_reference_t<Type>> &>(ctx.insert_or_assign(id, std::forward<Type>(value)).first->second);
180 }
181
182 template<typename Type>
183 Type &insert_or_assign(Type &&value) {
184 return insert_or_assign(type_id<Type>().hash(), std::forward<Type>(value));
185 }
186
187 template<typename Type>
188 bool erase(const id_type id = type_id<Type>().hash()) {
189 const auto it = ctx.find(id);
190 return it != ctx.end() && it->second.type() == type_id<Type>() ? (ctx.erase(it), true) : false;
191 }
192
193 template<typename Type>
194 [[nodiscard]] const Type &get(const id_type id = type_id<Type>().hash()) const {
195 return any_cast<const Type &>(ctx.at(id));
196 }
197
198 template<typename Type>
199 [[nodiscard]] Type &get(const id_type id = type_id<Type>().hash()) {
200 return any_cast<Type &>(ctx.at(id));
201 }
202
203 template<typename Type>
204 [[nodiscard]] const Type *find(const id_type id = type_id<Type>().hash()) const {
205 const auto it = ctx.find(id);
206 return it != ctx.cend() ? any_cast<const Type>(&it->second) : nullptr;
207 }
208
209 template<typename Type>
210 [[nodiscard]] Type *find(const id_type id = type_id<Type>().hash()) {
211 const auto it = ctx.find(id);
212 return it != ctx.end() ? any_cast<Type>(&it->second) : nullptr;
213 }
214
215 template<typename Type>
216 [[nodiscard]] bool contains(const id_type id = type_id<Type>().hash()) const {
217 const auto it = ctx.find(id);
218 return it != ctx.cend() && it->second.type() == type_id<Type>();
219 }
220
221private:
222 dense_map<id_type, basic_any<0u>, identity, std::equal_to<>, allocator_type> ctx;
223};
224
225} // namespace internal
233template<typename Entity, typename Allocator>
236 using alloc_traits = std::allocator_traits<Allocator>;
237 static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
238 // std::shared_ptr because of its type erased allocator which is useful here
242
243 template<typename Type>
244 [[nodiscard]] auto &assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) {
245 static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
246
247 if constexpr(std::is_same_v<Type, entity_type>) {
248 ENTT_ASSERT(id == type_hash<Type>::value(), "User entity storage not allowed");
249 return entities;
250 } else {
252
253 if(auto it = pools.find(id); it != pools.cend()) {
254 ENTT_ASSERT(it->second->type() == type_id<Type>(), "Unexpected type");
255 return static_cast<storage_type &>(*it->second);
256 }
257
258 using alloc_type = typename storage_type::allocator_type;
260
261 if constexpr(std::is_void_v<Type> && !std::is_constructible_v<alloc_type, allocator_type>) {
262 // std::allocator<void> has no cross constructors (waiting for C++20)
263 cpool = std::allocate_shared<storage_type>(get_allocator(), alloc_type{});
264 } else {
265 cpool = std::allocate_shared<storage_type>(get_allocator(), get_allocator());
266 }
267
268 pools.emplace(id, cpool);
269 cpool->bind(*this);
270
271 return static_cast<storage_type &>(*cpool);
272 }
273 }
274
275 template<typename Type>
276 [[nodiscard]] const auto *assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) const {
277 static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
278
279 if constexpr(std::is_same_v<Type, entity_type>) {
280 ENTT_ASSERT(id == type_hash<Type>::value(), "User entity storage not allowed");
281 return &entities;
282 } else {
283 if(const auto it = pools.find(id); it != pools.cend()) {
284 ENTT_ASSERT(it->second->type() == type_id<Type>(), "Unexpected type");
285 return static_cast<const storage_for_type<Type> *>(it->second.get());
286 }
287
288 return static_cast<const storage_for_type<Type> *>(nullptr);
289 }
290 }
291
292 void rebind() {
293 entities.bind(*this);
294
295 for(auto &&curr: pools) {
296 curr.second->bind(*this);
297 }
298 }
299
300public:
302 using allocator_type = Allocator;
308 using size_type = std::size_t;
312 using context = internal::registry_context<allocator_type>;
317
322 template<typename Type>
324
328
335
342 : vars{allocator},
343 pools{allocator},
344 groups{allocator},
345 entities{allocator} {
346 pools.reserve(count);
347 rebind();
348 }
349
352
358 : vars{std::move(other.vars)},
359 pools{std::move(other.pools)},
360 groups{std::move(other.groups)},
361 entities{std::move(other.entities)} {
362 rebind();
363 }
364
366 ~basic_registry() = default;
367
373
380 swap(other);
381 return *this;
382 }
383
388 void swap(basic_registry &other) noexcept {
389 using std::swap;
390
391 swap(vars, other.vars);
392 swap(pools, other.pools);
393 swap(groups, other.groups);
394 swap(entities, other.entities);
395
396 rebind();
397 other.rebind();
398 }
399
405 return entities.get_allocator();
406 }
407
417 return iterable{pools.begin(), pools.end()};
418 }
419
422 return const_iterable{pools.cbegin(), pools.cend()};
423 }
424
431 return const_cast<common_type *>(std::as_const(*this).storage(id));
432 }
433
439 [[nodiscard]] const common_type *storage(const id_type id) const {
440 const auto it = pools.find(id);
441 return it == pools.cend() ? nullptr : it->second.get();
442 }
443
450 template<typename Type>
454
461 template<typename Type>
463 return assure<Type>(id);
464 }
465
471 bool reset(const id_type id) {
472 ENTT_ASSERT(id != type_hash<entity_type>::value(), "Cannot reset entity storage");
473 return !(pools.erase(id) == 0u);
474 }
475
481 [[nodiscard]] bool valid(const entity_type entt) const {
482 return static_cast<size_type>(entities.find(entt).index()) < entities.free_list();
483 }
484
492 return entities.current(entt);
493 }
494
500 return entities.emplace();
501 }
502
513 return entities.emplace(hint);
514 }
515
525 template<typename It>
526 void create(It first, It last) {
527 entities.insert(std::move(first), std::move(last));
528 }
529
541 for(size_type pos = pools.size(); pos != 0u; --pos) {
542 pools.begin()[pos - 1u].second->remove(entt);
543 }
544
545 entities.erase(entt);
546 return entities.current(entt);
547 }
548
566
576 template<typename It>
577 void destroy(It first, It last) {
578 const auto to = entities.sort_as(first, last);
579 const auto from = entities.cend() - entities.free_list();
580
581 for(auto &&curr: pools) {
582 curr.second->remove(from, to);
583 }
584
585 entities.erase(from, to);
586 }
587
603 template<typename Type, typename... Args>
604 decltype(auto) emplace(const entity_type entt, Args &&...args) {
605 ENTT_ASSERT(valid(entt), "Invalid entity");
606 return assure<Type>().emplace(entt, std::forward<Args>(args)...);
607 }
608
620 template<typename Type, typename It>
621 void insert(It first, It last, const Type &value = {}) {
622 ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
623 assure<Type>().insert(std::move(first), std::move(last), value);
624 }
625
639 void insert(EIt first, EIt last, CIt from) {
640 ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
641 assure<Type>().insert(first, last, from);
642 }
643
656 template<typename Type, typename... Args>
657 decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args) {
658 auto &cpool = assure<Type>();
659 ENTT_ASSERT(valid(entt), "Invalid entity");
660 return cpool.contains(entt) ? cpool.patch(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); }) : cpool.emplace(entt, std::forward<Args>(args)...);
661 }
662
682 template<typename Type, typename... Func>
683 decltype(auto) patch(const entity_type entt, Func &&...func) {
684 return assure<Type>().patch(entt, std::forward<Func>(func)...);
685 }
686
702 template<typename Type, typename... Args>
703 decltype(auto) replace(const entity_type entt, Args &&...args) {
704 return patch<Type>(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); });
705 }
706
714 template<typename Type, typename... Other>
716 return (assure<Type>().remove(entt) + ... + assure<Other>().remove(entt));
717 }
718
731 template<typename Type, typename... Other, typename It>
732 size_type remove(It first, It last) {
733 size_type count{};
734
735 if constexpr(std::is_same_v<It, typename common_type::iterator>) {
736 std::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
737
738 for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) {
739 if constexpr(sizeof...(Other) != 0u) {
740 if((*from)->data() == first.data()) {
741 std::swap((*from), cpools.back());
742 }
743 }
744
745 count += (*from)->remove(first, last);
746 }
747
748 } else {
749 for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
750 count += std::apply([entt = *first](auto &...curr) { return (curr.remove(entt) + ... + 0u); }, cpools);
751 }
752 }
753
754 return count;
755 }
756
768 template<typename Type, typename... Other>
769 void erase(const entity_type entt) {
770 (assure<Type>().erase(entt), (assure<Other>().erase(entt), ...));
771 }
772
784 template<typename Type, typename... Other, typename It>
785 void erase(It first, It last) {
786 if constexpr(std::is_same_v<It, typename common_type::iterator>) {
787 std::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
788
789 for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) {
790 if constexpr(sizeof...(Other) != 0u) {
791 if((*from)->data() == first.data()) {
792 std::swap(*from, cpools.back());
793 }
794 }
795
796 (*from)->erase(first, last);
797 }
798 } else {
799 for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
800 std::apply([entt = *first](auto &...curr) { (curr.erase(entt), ...); }, cpools);
801 }
802 }
803 }
804
820 template<typename Func>
821 void erase_if(const entity_type entt, Func func) {
822 for(auto [id, cpool]: storage()) {
823 if(cpool.contains(entt) && func(id, std::as_const(cpool))) {
824 cpool.erase(entt);
825 }
826 }
827 }
828
834 template<typename... Type>
835 void compact() {
836 if constexpr(sizeof...(Type) == 0u) {
837 for(auto &&curr: pools) {
838 curr.second->compact();
839 }
840 } else {
841 (assure<Type>().compact(), ...);
842 }
843 }
844
851 template<typename... Type>
852 [[nodiscard]] bool all_of([[maybe_unused]] const entity_type entt) const {
853 if constexpr(sizeof...(Type) == 1u) {
854 auto *cpool = assure<std::remove_const_t<Type>...>();
855 return cpool && cpool->contains(entt);
856 } else {
857 return (all_of<Type>(entt) && ...);
858 }
859 }
860
868 template<typename... Type>
869 [[nodiscard]] bool any_of([[maybe_unused]] const entity_type entt) const {
870 return (all_of<Type>(entt) || ...);
871 }
872
884 template<typename... Type>
885 [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const {
886 if constexpr(sizeof...(Type) == 1u) {
887 return (assure<std::remove_const_t<Type>>()->get(entt), ...);
888 } else {
889 return std::forward_as_tuple(get<Type>(entt)...);
890 }
891 }
892
894 template<typename... Type>
895 [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) {
896 if constexpr(sizeof...(Type) == 1u) {
897 return (static_cast<storage_for_type<Type> &>(assure<std::remove_const_t<Type>>()).get(entt), ...);
898 } else {
899 return std::forward_as_tuple(get<Type>(entt)...);
900 }
901 }
902
918 template<typename Type, typename... Args>
919 [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entt, Args &&...args) {
920 auto &cpool = assure<Type>();
921 ENTT_ASSERT(valid(entt), "Invalid entity");
922 return cpool.contains(entt) ? cpool.get(entt) : cpool.emplace(entt, std::forward<Args>(args)...);
923 }
924
935 template<typename... Type>
936 [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) const {
937 if constexpr(sizeof...(Type) == 1u) {
938 const auto *cpool = assure<std::remove_const_t<Type>...>();
939 return (cpool && cpool->contains(entt)) ? std::addressof(cpool->get(entt)) : nullptr;
940 } else {
941 return std::make_tuple(try_get<Type>(entt)...);
942 }
943 }
944
946 template<typename... Type>
947 [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) {
948 if constexpr(sizeof...(Type) == 1u) {
949 return (const_cast<Type *>(std::as_const(*this).template try_get<Type>(entt)), ...);
950 } else {
951 return std::make_tuple(try_get<Type>(entt)...);
952 }
953 }
954
959 template<typename... Type>
960 void clear() {
961 if constexpr(sizeof...(Type) == 0u) {
962 for(size_type pos = pools.size(); pos; --pos) {
963 pools.begin()[pos - 1u].second->clear();
964 }
965
966 const auto elem = entities.each();
967 entities.erase(elem.begin().base(), elem.end().base());
968 } else {
969 (assure<Type>().clear(), ...);
970 }
971 }
972
978 [[nodiscard]] bool orphan(const entity_type entt) const {
979 return std::none_of(pools.cbegin(), pools.cend(), [entt](auto &&curr) { return curr.second->contains(entt); });
980 }
981
1001 template<typename Type>
1002 [[nodiscard]] auto on_construct(const id_type id = type_hash<Type>::value()) {
1003 return assure<Type>(id).on_construct();
1004 }
1005
1025 template<typename Type>
1026 [[nodiscard]] auto on_update(const id_type id = type_hash<Type>::value()) {
1027 return assure<Type>(id).on_update();
1028 }
1029
1049 template<typename Type>
1050 [[nodiscard]] auto on_destroy(const id_type id = type_hash<Type>::value()) {
1051 return assure<Type>(id).on_destroy();
1052 }
1053
1061 template<typename Type, typename... Other, typename... Exclude>
1062 [[nodiscard]] basic_view<get_t<storage_for_type<const Type>, storage_for_type<const Other>...>, exclude_t<storage_for_type<const Exclude>...>>
1065 [&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>>());
1066 return elem;
1067 }
1068
1070 template<typename Type, typename... Other, typename... Exclude>
1071 [[nodiscard]] basic_view<get_t<storage_for_type<Type>, storage_for_type<Other>...>, exclude_t<storage_for_type<Exclude>...>>
1073 return {assure<std::remove_const_t<Type>>(), assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Exclude>>()...};
1074 }
1075
1083 template<typename... Owned, typename... Get, typename... Exclude>
1084 basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>
1086 using group_type = basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>;
1087 using handler_type = typename group_type::handler;
1088
1089 if(auto it = groups.find(group_type::group_id()); it != groups.cend()) {
1090 return {*std::static_pointer_cast<handler_type>(it->second)};
1091 }
1092
1093 std::shared_ptr<handler_type> handler{};
1094
1095 if constexpr(sizeof...(Owned) == 0u) {
1096 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>>()...));
1097 } else {
1098 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>>()...));
1099 ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [](const auto &data) { return !(data.second->owned(type_id<Owned>().hash()) || ...); }), "Conflicting groups");
1100 }
1101
1102 groups.emplace(group_type::group_id(), handler);
1103 return {*handler};
1104 }
1105
1107 template<typename... Owned, typename... Get, typename... Exclude>
1108 [[nodiscard]] basic_group<owned_t<storage_for_type<const Owned>...>, get_t<storage_for_type<const Get>...>, exclude_t<storage_for_type<const Exclude>...>>
1110 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>...>>;
1111 using handler_type = typename group_type::handler;
1112
1113 if(auto it = groups.find(group_type::group_id()); it != groups.cend()) {
1114 return {*std::static_pointer_cast<handler_type>(it->second)};
1115 }
1116
1117 return {};
1118 }
1119
1126 template<typename... Type>
1127 [[nodiscard]] bool owned() const {
1128 return std::any_of(groups.cbegin(), groups.cend(), [](auto &&data) { return (data.second->owned(type_id<Type>().hash()) || ...); });
1129 }
1130
1164 template<typename Type, typename Compare, typename Sort = std_sort, typename... Args>
1165 void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
1166 ENTT_ASSERT(!owned<Type>(), "Cannot sort owned storage");
1167 auto &cpool = assure<Type>();
1168
1169 if constexpr(std::is_invocable_v<Compare, decltype(cpool.get({})), decltype(cpool.get({}))>) {
1170 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))); };
1171 cpool.sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
1172 } else {
1173 cpool.sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
1174 }
1175 }
1176
1190 template<typename To, typename From>
1191 void sort() {
1192 ENTT_ASSERT(!owned<To>(), "Cannot sort owned storage");
1193 const base_type &cpool = assure<From>();
1194 assure<To>().sort_as(cpool.begin(), cpool.end());
1195 }
1196
1201 [[nodiscard]] context &ctx() noexcept {
1202 return vars;
1203 }
1204
1206 [[nodiscard]] const context &ctx() const noexcept {
1207 return vars;
1208 }
1209
1210private:
1211 context vars;
1212 pool_container_type pools;
1213 group_container_type groups;
1214 storage_for_type<entity_type> entities;
1215};
1216
1217} // namespace entt
1218
1219#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
Fast and reliable entity-component system.
Definition registry.hpp:234
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:869
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:919
bool orphan(const entity_type entt) const
Checks if an entity has elements assigned.
Definition registry.hpp:978
decltype(auto) replace(const entity_type entt, Args &&...args)
Replaces the given element for an entity.
Definition registry.hpp:703
basic_registry(const size_type count, const allocator_type &allocator=allocator_type{})
Allocates enough memory upon construction to store count pools.
Definition registry.hpp:341
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:439
auto try_get(const entity_type entt) const
Returns pointers to the given elements for an entity.
Definition registry.hpp:936
void swap(basic_registry &other) noexcept
Exchanges the contents with those of a given registry.
Definition registry.hpp:388
decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args)
Assigns or replaces the given element for an entity.
Definition registry.hpp:657
iterable storage() noexcept
Returns an iterable object to use to visit a registry.
Definition registry.hpp:416
bool valid(const entity_type entt) const
Checks if an identifier refers to a valid entity.
Definition registry.hpp:481
bool all_of(const entity_type entt) const
Check if an entity is part of all the given storage.
Definition registry.hpp:852
void erase_if(const entity_type entt, Func func)
Erases elements satisfying specific criteria from an entity.
Definition registry.hpp:821
version_type destroy(const entity_type entt)
Destroys an entity and releases its identifier.
Definition registry.hpp:540
typename traits_type::version_type version_type
Underlying version type.
Definition registry.hpp:306
entity_type create()
Creates a new entity or recycles a destroyed one.
Definition registry.hpp:499
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:561
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:526
size_type remove(It first, It last)
Removes the given elements from all the entities in a range.
Definition registry.hpp:732
entity_type create(const entity_type hint)
Creates a new entity or recycles a destroyed one.
Definition registry.hpp:512
void clear()
Clears a whole registry or the pools for the given elements.
Definition registry.hpp:960
bool reset(const id_type id)
Discards the storage associated with a given name, if any.
Definition registry.hpp:471
decltype(auto) patch(const entity_type entt, Func &&...func)
Patches the given element for an entity.
Definition registry.hpp:683
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:715
basic_registry & operator=(basic_registry &&other) noexcept
Move assignment operator.
Definition registry.hpp:379
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:947
common_type * storage(const id_type id)
Finds the storage associated with a given name, if any.
Definition registry.hpp:430
void destroy(It first, It last)
Destroys all entities in a range and releases their identifiers.
Definition registry.hpp:577
decltype(auto) get(const entity_type entt)
Returns references to the given elements for an entity.
Definition registry.hpp:895
typename storage_for< Type, Entity, typename alloc_traits::template rebind_alloc< std::remove_const_t< Type > > >::type storage_for_type
Definition registry.hpp:323
void erase(It first, It last)
Erases the given elements from all the entities in a range.
Definition registry.hpp:785
Allocator allocator_type
Allocator type.
Definition registry.hpp:302
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:404
decltype(auto) emplace(const entity_type entt, Args &&...args)
Assigns the given element to an entity.
Definition registry.hpp:604
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:333
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:451
typename traits_type::value_type entity_type
Underlying entity identifier.
Definition registry.hpp:304
decltype(auto) get(const entity_type entt) const
Returns references to the given elements for an entity.
Definition registry.hpp:885
std::size_t size_type
Unsigned integer type.
Definition registry.hpp:308
basic_registry(basic_registry &&other) noexcept
Move constructor.
Definition registry.hpp:357
void compact()
Removes all tombstones from a registry or only the pools for the given elements.
Definition registry.hpp:835
const_iterable storage() const noexcept
Returns an iterable object to use to visit a registry.
Definition registry.hpp:421
~basic_registry()=default
Default destructor.
version_type current(const entity_type entt) const
Returns the actual version for an identifier.
Definition registry.hpp:491
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.
void insert(It first, It last, const Type &value={})
Assigns each entity in a range the given element.
Definition registry.hpp:621
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:462
void insert(EIt first, EIt last, CIt from)
Assigns each entity in a range the given elements.
Definition registry.hpp:639
basic_registry(const basic_registry &)=delete
Default copy constructor, deleted on purpose.
internal::registry_context< allocator_type > context
Context type.
Definition registry.hpp:312
basic_registry()
Default constructor.
Definition registry.hpp:326
void erase(const entity_type entt)
Erases the given elements from an entity.
Definition registry.hpp:769
Sparse set implementation.
iterator begin() const noexcept
Returns an iterator to the beginning.
iterator end() const noexcept
Returns an iterator to the end.
Storage implementation.
Definition storage.hpp:230
View implementation.
Definition fwd.hpp:42
const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
size_type size() const noexcept
Returns the number of elements in a container.
void reserve(const size_type cnt)
Reserves space for at least the specified number of elements and regenerates the hash table.
const_iterator cend() const noexcept
Returns an iterator to the end.
iterator find(const key_type &key)
Finds an element with a given key.
const_iterator begin() const noexcept
Returns an iterator to the beginning.
iterator erase(const_iterator pos)
Removes an element from a given position.
std::pair< iterator, bool > emplace(Args &&...args)
Constructs an element in-place, if the key does not exist.
const_iterator end() const noexcept
Returns an iterator to the end.
EnTT default namespace.
Definition dense_map.hpp:22
constexpr Type make_obj_using_allocator(const Allocator &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:384
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:14
constexpr get_t< Type... > get
Variable template for lists of observed elements.
Definition fwd.hpp:168
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 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 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:141
Alias for lists of observed elements.
Definition fwd.hpp:158
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:227
Type hash.
Definition type_info.hpp:92