EnTT 3.13.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 <cstddef>
6#include <functional>
7#include <iterator>
8#include <memory>
9#include <tuple>
10#include <type_traits>
11#include <utility>
12#include <vector>
13#include "../config/config.h"
14#include "../container/dense_map.hpp"
15#include "../core/algorithm.hpp"
16#include "../core/any.hpp"
17#include "../core/fwd.hpp"
18#include "../core/iterator.hpp"
19#include "../core/memory.hpp"
20#include "../core/type_info.hpp"
21#include "../core/type_traits.hpp"
22#include "../core/utility.hpp"
23#include "entity.hpp"
24#include "fwd.hpp"
25#include "group.hpp"
26#include "mixin.hpp"
27#include "sparse_set.hpp"
28#include "storage.hpp"
29#include "view.hpp"
30
31namespace entt {
32
34namespace internal {
35
36template<typename It>
37class registry_storage_iterator final {
38 template<typename Other>
39 friend class registry_storage_iterator;
40
41 using mapped_type = std::remove_reference_t<decltype(std::declval<It>()->second)>;
42
43public:
44 using value_type = std::pair<id_type, constness_as_t<typename mapped_type::element_type, mapped_type> &>;
45 using pointer = input_iterator_pointer<value_type>;
46 using reference = value_type;
47 using difference_type = std::ptrdiff_t;
48 using iterator_category = std::input_iterator_tag;
49 using iterator_concept = std::random_access_iterator_tag;
50
51 constexpr registry_storage_iterator() noexcept
52 : it{} {}
53
54 constexpr registry_storage_iterator(It iter) noexcept
55 : it{iter} {}
56
57 template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
58 constexpr registry_storage_iterator(const registry_storage_iterator<Other> &other) noexcept
59 : registry_storage_iterator{other.it} {}
60
61 constexpr registry_storage_iterator &operator++() noexcept {
62 return ++it, *this;
63 }
64
65 constexpr registry_storage_iterator operator++(int) noexcept {
66 registry_storage_iterator orig = *this;
67 return ++(*this), orig;
68 }
69
70 constexpr registry_storage_iterator &operator--() noexcept {
71 return --it, *this;
72 }
73
74 constexpr registry_storage_iterator operator--(int) noexcept {
75 registry_storage_iterator orig = *this;
76 return operator--(), orig;
77 }
78
79 constexpr registry_storage_iterator &operator+=(const difference_type value) noexcept {
80 it += value;
81 return *this;
82 }
83
84 constexpr registry_storage_iterator operator+(const difference_type value) const noexcept {
85 registry_storage_iterator copy = *this;
86 return (copy += value);
87 }
88
89 constexpr registry_storage_iterator &operator-=(const difference_type value) noexcept {
90 return (*this += -value);
91 }
92
93 constexpr registry_storage_iterator operator-(const difference_type value) const noexcept {
94 return (*this + -value);
95 }
96
97 [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
98 return {it[value].first, *it[value].second};
99 }
100
101 [[nodiscard]] constexpr reference operator*() const noexcept {
102 return {it->first, *it->second};
103 }
104
105 [[nodiscard]] constexpr pointer operator->() const noexcept {
106 return operator*();
107 }
108
109 template<typename Lhs, typename Rhs>
110 friend constexpr std::ptrdiff_t operator-(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
111
112 template<typename Lhs, typename Rhs>
113 friend constexpr bool operator==(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
114
115 template<typename Lhs, typename Rhs>
116 friend constexpr bool operator<(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
117
118private:
119 It it;
120};
121
122template<typename Lhs, typename Rhs>
123[[nodiscard]] constexpr std::ptrdiff_t operator-(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
124 return lhs.it - rhs.it;
125}
126
127template<typename Lhs, typename Rhs>
128[[nodiscard]] constexpr bool operator==(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
129 return lhs.it == rhs.it;
130}
131
132template<typename Lhs, typename Rhs>
133[[nodiscard]] constexpr bool operator!=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
134 return !(lhs == rhs);
135}
136
137template<typename Lhs, typename Rhs>
138[[nodiscard]] constexpr bool operator<(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
139 return lhs.it < rhs.it;
140}
141
142template<typename Lhs, typename Rhs>
143[[nodiscard]] constexpr bool operator>(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
144 return rhs < lhs;
145}
146
147template<typename Lhs, typename Rhs>
148[[nodiscard]] constexpr bool operator<=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
149 return !(lhs > rhs);
150}
151
152template<typename Lhs, typename Rhs>
153[[nodiscard]] constexpr bool operator>=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
154 return !(lhs < rhs);
155}
156
157template<typename Allocator>
158class registry_context {
159 using alloc_traits = std::allocator_traits<Allocator>;
160 using allocator_type = typename alloc_traits::template rebind_alloc<std::pair<const id_type, basic_any<0u>>>;
161
162public:
163 explicit registry_context(const allocator_type &allocator)
164 : ctx{allocator} {}
165
166 template<typename Type, typename... Args>
167 Type &emplace_as(const id_type id, Args &&...args) {
168 return any_cast<Type &>(ctx.try_emplace(id, std::in_place_type<Type>, std::forward<Args>(args)...).first->second);
169 }
170
171 template<typename Type, typename... Args>
172 Type &emplace(Args &&...args) {
173 return emplace_as<Type>(type_id<Type>().hash(), std::forward<Args>(args)...);
174 }
175
176 template<typename Type>
177 Type &insert_or_assign(const id_type id, Type &&value) {
178 return any_cast<std::remove_cv_t<std::remove_reference_t<Type>> &>(ctx.insert_or_assign(id, std::forward<Type>(value)).first->second);
179 }
180
181 template<typename Type>
182 Type &insert_or_assign(Type &&value) {
183 return insert_or_assign(type_id<Type>().hash(), std::forward<Type>(value));
184 }
185
186 template<typename Type>
187 bool erase(const id_type id = type_id<Type>().hash()) {
188 const auto it = ctx.find(id);
189 return it != ctx.end() && it->second.type() == type_id<Type>() ? (ctx.erase(it), true) : false;
190 }
191
192 template<typename Type>
193 [[nodiscard]] const Type &get(const id_type id = type_id<Type>().hash()) const {
194 return any_cast<const Type &>(ctx.at(id));
195 }
196
197 template<typename Type>
198 [[nodiscard]] Type &get(const id_type id = type_id<Type>().hash()) {
199 return any_cast<Type &>(ctx.at(id));
200 }
201
202 template<typename Type>
203 [[nodiscard]] const Type *find(const id_type id = type_id<Type>().hash()) const {
204 const auto it = ctx.find(id);
205 return it != ctx.cend() ? any_cast<const Type>(&it->second) : nullptr;
206 }
207
208 template<typename Type>
209 [[nodiscard]] Type *find(const id_type id = type_id<Type>().hash()) {
210 const auto it = ctx.find(id);
211 return it != ctx.end() ? any_cast<Type>(&it->second) : nullptr;
212 }
213
214 template<typename Type>
215 [[nodiscard]] bool contains(const id_type id = type_id<Type>().hash()) const {
216 const auto it = ctx.find(id);
217 return it != ctx.cend() && it->second.type() == type_id<Type>();
218 }
219
220private:
221 dense_map<id_type, basic_any<0u>, identity, std::equal_to<id_type>, allocator_type> ctx;
222};
223
224} // namespace internal
232template<typename Entity, typename Allocator>
235
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
239 // std::shared_ptr because of its type erased allocator which is useful here
240 using pool_container_type = dense_map<id_type, std::shared_ptr<base_type>, identity, std::equal_to<id_type>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<base_type>>>>;
241 using group_container_type = dense_map<id_type, std::shared_ptr<internal::group_descriptor>, identity, std::equal_to<id_type>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<internal::group_descriptor>>>>;
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 return entities;
249 } else {
250 auto &cpool = pools[id];
251
252 if(!cpool) {
254 using alloc_type = typename storage_type::allocator_type;
255
256 if constexpr(std::is_void_v<Type> && !std::is_constructible_v<alloc_type, allocator_type>) {
257 // std::allocator<void> has no cross constructors (waiting for C++20)
258 cpool = std::allocate_shared<storage_type>(get_allocator(), alloc_type{});
259 } else {
260 cpool = std::allocate_shared<storage_type>(get_allocator(), get_allocator());
261 }
262
263 cpool->bind(forward_as_any(*this));
264 }
265
266 ENTT_ASSERT(cpool->type() == type_id<Type>(), "Unexpected type");
267 return static_cast<storage_for_type<Type> &>(*cpool);
268 }
269 }
270
271 template<typename Type>
272 [[nodiscard]] const auto *assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) const {
273 static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
274
275 if constexpr(std::is_same_v<Type, entity_type>) {
276 return &entities;
277 } else {
278 if(const auto it = pools.find(id); it != pools.cend()) {
279 ENTT_ASSERT(it->second->type() == type_id<Type>(), "Unexpected type");
280 return static_cast<const storage_for_type<Type> *>(it->second.get());
281 }
282
283 return static_cast<const storage_for_type<Type> *>(nullptr);
284 }
285 }
286
287 void rebind() {
288 entities.bind(forward_as_any(*this));
289
290 for(auto &&curr: pools) {
291 curr.second->bind(forward_as_any(*this));
292 }
293 }
294
295public:
299 using allocator_type = Allocator;
301 using entity_type = typename traits_type::value_type;
303 using version_type = typename traits_type::version_type;
305 using size_type = std::size_t;
309 using context = internal::registry_context<allocator_type>;
314
319 template<typename Type>
321
325
330 explicit basic_registry(const allocator_type &allocator)
331 : basic_registry{0u, allocator} {}
332
338 basic_registry(const size_type count, const allocator_type &allocator = allocator_type{})
339 : vars{allocator},
340 pools{allocator},
341 groups{allocator},
342 entities{allocator} {
343 pools.reserve(count);
344 rebind();
345 }
346
352 : vars{std::move(other.vars)},
353 pools{std::move(other.pools)},
354 groups{std::move(other.groups)},
355 entities{std::move(other.entities)} {
356 rebind();
357 }
358
365 vars = std::move(other.vars);
366 pools = std::move(other.pools);
367 groups = std::move(other.groups);
368 entities = std::move(other.entities);
369
370 rebind();
371
372 return *this;
373 }
374
379 void swap(basic_registry &other) {
380 using std::swap;
381
382 swap(vars, other.vars);
383 swap(pools, other.pools);
384 swap(groups, other.groups);
385 swap(entities, other.entities);
386
387 rebind();
388 other.rebind();
389 }
390
395 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
396 return entities.get_allocator();
397 }
398
407 [[nodiscard]] iterable storage() noexcept {
408 return iterable_adaptor{internal::registry_storage_iterator{pools.begin()}, internal::registry_storage_iterator{pools.end()}};
409 }
410
412 [[nodiscard]] const_iterable storage() const noexcept {
413 return iterable_adaptor{internal::registry_storage_iterator{pools.cbegin()}, internal::registry_storage_iterator{pools.cend()}};
414 }
415
421 [[nodiscard]] common_type *storage(const id_type id) {
422 return const_cast<common_type *>(std::as_const(*this).storage(id));
423 }
424
430 [[nodiscard]] const common_type *storage(const id_type id) const {
431 const auto it = pools.find(id);
432 return it == pools.cend() ? nullptr : it->second.get();
433 }
434
441 template<typename Type>
443 return assure<Type>(id);
444 }
445
452 template<typename Type>
454 return assure<Type>(id);
455 }
456
462 [[nodiscard]] bool valid(const entity_type entt) const {
463 return entities.contains(entt) && (entities.index(entt) < entities.free_list());
464 }
465
472 [[nodiscard]] version_type current(const entity_type entt) const {
473 return entities.current(entt);
474 }
475
480 [[nodiscard]] entity_type create() {
481 return entities.emplace();
482 }
483
493 [[nodiscard]] entity_type create(const entity_type hint) {
494 return entities.emplace(hint);
495 }
496
506 template<typename It>
507 void create(It first, It last) {
508 entities.insert(std::move(first), std::move(last));
509 }
510
522 for(size_type pos = pools.size(); pos; --pos) {
523 pools.begin()[pos - 1u].second->remove(entt);
524 }
525
526 entities.erase(entt);
527 return entities.current(entt);
528 }
529
543 destroy(entt);
544 const auto elem = traits_type::construct(traits_type::to_entity(entt), version);
545 return entities.bump((elem == tombstone) ? traits_type::next(elem) : elem);
546 }
547
557 template<typename It>
558 void destroy(It first, It last) {
559 entities.sort_as(first, last);
560
561 const auto from = entities.cbegin(0);
562 const auto to = from + std::distance(first, last);
563
564 for(auto &&curr: pools) {
565 curr.second->remove(from, to);
566 }
567
568 entities.erase(from, to);
569 }
570
586 template<typename Type, typename... Args>
587 decltype(auto) emplace(const entity_type entt, Args &&...args) {
588 return assure<Type>().emplace(entt, std::forward<Args>(args)...);
589 }
590
602 template<typename Type, typename It>
603 void insert(It first, It last, const Type &value = {}) {
604 assure<Type>().insert(std::move(first), std::move(last), value);
605 }
606
619 template<typename Type, typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<CIt>::value_type, Type>>>
620 void insert(EIt first, EIt last, CIt from) {
621 assure<Type>().insert(first, last, from);
622 }
623
636 template<typename Type, typename... Args>
637 decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args) {
638 if(auto &cpool = assure<Type>(); cpool.contains(entt)) {
639 return cpool.patch(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); });
640 } else {
641 return cpool.emplace(entt, std::forward<Args>(args)...);
642 }
643 }
644
664 template<typename Type, typename... Func>
665 decltype(auto) patch(const entity_type entt, Func &&...func) {
666 return assure<Type>().patch(entt, std::forward<Func>(func)...);
667 }
668
684 template<typename Type, typename... Args>
685 decltype(auto) replace(const entity_type entt, Args &&...args) {
686 return patch<Type>(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); });
687 }
688
696 template<typename Type, typename... Other>
698 return (assure<Type>().remove(entt) + ... + assure<Other>().remove(entt));
699 }
700
713 template<typename Type, typename... Other, typename It>
714 size_type remove(It first, It last) {
715 size_type count{};
716
717 if constexpr(std::is_same_v<It, typename common_type::iterator>) {
718 common_type *cpools[sizeof...(Other) + 1u]{&assure<Type>(), &assure<Other>()...};
719
720 for(size_type pos{}, len = sizeof...(Other) + 1u; pos < len; ++pos) {
721 if constexpr(sizeof...(Other) != 0u) {
722 if(cpools[pos]->data() == first.data()) {
723 std::swap(cpools[pos], cpools[sizeof...(Other)]);
724 }
725 }
726
727 count += cpools[pos]->remove(first, last);
728 }
729 } else {
730 for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
731 count += std::apply([entt = *first](auto &...curr) { return (curr.remove(entt) + ... + 0u); }, cpools);
732 }
733 }
734
735 return count;
736 }
737
749 template<typename Type, typename... Other>
750 void erase(const entity_type entt) {
751 (assure<Type>().erase(entt), (assure<Other>().erase(entt), ...));
752 }
753
765 template<typename Type, typename... Other, typename It>
766 void erase(It first, It last) {
767 if constexpr(std::is_same_v<It, typename common_type::iterator>) {
768 common_type *cpools[sizeof...(Other) + 1u]{&assure<Type>(), &assure<Other>()...};
769
770 for(size_type pos{}, len = sizeof...(Other) + 1u; pos < len; ++pos) {
771 if constexpr(sizeof...(Other) != 0u) {
772 if(cpools[pos]->data() == first.data()) {
773 std::swap(cpools[pos], cpools[sizeof...(Other)]);
774 }
775 }
776
777 cpools[pos]->erase(first, last);
778 }
779 } else {
780 for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
781 std::apply([entt = *first](auto &...curr) { (curr.erase(entt), ...); }, cpools);
782 }
783 }
784 }
785
801 template<typename Func>
802 void erase_if(const entity_type entt, Func func) {
803 for(auto [id, cpool]: storage()) {
804 if(cpool.contains(entt) && func(id, std::as_const(cpool))) {
805 cpool.erase(entt);
806 }
807 }
808 }
809
815 template<typename... Type>
816 void compact() {
817 if constexpr(sizeof...(Type) == 0u) {
818 for(auto &&curr: pools) {
819 curr.second->compact();
820 }
821 } else {
822 (assure<Type>().compact(), ...);
823 }
824 }
825
832 template<typename... Type>
833 [[nodiscard]] bool all_of([[maybe_unused]] const entity_type entt) const {
834 if constexpr(sizeof...(Type) == 1u) {
835 auto *cpool = assure<std::remove_const_t<Type>...>();
836 return cpool && cpool->contains(entt);
837 } else {
838 return (all_of<Type>(entt) && ...);
839 }
840 }
841
849 template<typename... Type>
850 [[nodiscard]] bool any_of([[maybe_unused]] const entity_type entt) const {
851 return (all_of<Type>(entt) || ...);
852 }
853
865 template<typename... Type>
866 [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const {
867 if constexpr(sizeof...(Type) == 1u) {
868 return (assure<std::remove_const_t<Type>>()->get(entt), ...);
869 } else {
870 return std::forward_as_tuple(get<Type>(entt)...);
871 }
872 }
873
875 template<typename... Type>
876 [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) {
877 if constexpr(sizeof...(Type) == 1u) {
878 return (static_cast<storage_for_type<Type> &>(assure<std::remove_const_t<Type>>()).get(entt), ...);
879 } else {
880 return std::forward_as_tuple(get<Type>(entt)...);
881 }
882 }
883
899 template<typename Type, typename... Args>
900 [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entt, Args &&...args) {
901 if(auto &cpool = assure<Type>(); cpool.contains(entt)) {
902 return cpool.get(entt);
903 } else {
904 return cpool.emplace(entt, std::forward<Args>(args)...);
905 }
906 }
907
918 template<typename... Type>
919 [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) const {
920 if constexpr(sizeof...(Type) == 1u) {
921 const auto *cpool = assure<std::remove_const_t<Type>...>();
922 return (cpool && cpool->contains(entt)) ? std::addressof(cpool->get(entt)) : nullptr;
923 } else {
924 return std::make_tuple(try_get<Type>(entt)...);
925 }
926 }
927
929 template<typename... Type>
930 [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) {
931 if constexpr(sizeof...(Type) == 1u) {
932 return (const_cast<Type *>(std::as_const(*this).template try_get<Type>(entt)), ...);
933 } else {
934 return std::make_tuple(try_get<Type>(entt)...);
935 }
936 }
937
942 template<typename... Type>
943 void clear() {
944 if constexpr(sizeof...(Type) == 0u) {
945 for(size_type pos = pools.size(); pos; --pos) {
946 pools.begin()[pos - 1u].second->clear();
947 }
948
949 const auto elem = entities.each();
950 entities.erase(elem.begin().base(), elem.end().base());
951 } else {
952 (assure<Type>().clear(), ...);
953 }
954 }
955
961 [[nodiscard]] bool orphan(const entity_type entt) const {
962 return std::none_of(pools.cbegin(), pools.cend(), [entt](auto &&curr) { return curr.second->contains(entt); });
963 }
964
984 template<typename Type>
985 [[nodiscard]] auto on_construct(const id_type id = type_hash<Type>::value()) {
986 return assure<Type>(id).on_construct();
987 }
988
1008 template<typename Type>
1009 [[nodiscard]] auto on_update(const id_type id = type_hash<Type>::value()) {
1010 return assure<Type>(id).on_update();
1011 }
1012
1032 template<typename Type>
1033 [[nodiscard]] auto on_destroy(const id_type id = type_hash<Type>::value()) {
1034 return assure<Type>(id).on_destroy();
1035 }
1036
1044 template<typename Type, typename... Other, typename... Exclude>
1045 [[nodiscard]] basic_view<get_t<storage_for_type<const Type>, storage_for_type<const Other>...>, exclude_t<storage_for_type<const Exclude>...>>
1047 const auto cpools = std::make_tuple(assure<std::remove_const_t<Type>>(), assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Exclude>>()...);
1049 std::apply([&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }, cpools);
1050 return elem;
1051 }
1052
1054 template<typename Type, typename... Other, typename... Exclude>
1055 [[nodiscard]] basic_view<get_t<storage_for_type<Type>, storage_for_type<Other>...>, exclude_t<storage_for_type<Exclude>...>>
1057 return {assure<std::remove_const_t<Type>>(), assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Exclude>>()...};
1058 }
1059
1067 template<typename... Owned, typename... Get, typename... Exclude>
1068 basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>
1070 using handler_type = typename basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>::handler;
1071
1072 if(auto it = groups.find(type_hash<handler_type>::value()); it != groups.cend()) {
1073 return {*std::static_pointer_cast<handler_type>(it->second)};
1074 }
1075
1076 std::shared_ptr<handler_type> handler{};
1077
1078 if constexpr(sizeof...(Owned) == 0u) {
1079 handler = std::allocate_shared<handler_type>(get_allocator(), get_allocator(), assure<std::remove_const_t<Get>>()..., assure<std::remove_const_t<Exclude>>()...);
1080 } else {
1081 handler = std::allocate_shared<handler_type>(get_allocator(), assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()..., assure<std::remove_const_t<Exclude>>()...);
1082 [[maybe_unused]] const id_type elem[]{type_hash<std::remove_const_t<Owned>>::value()..., type_hash<std::remove_const_t<Get>>::value()..., type_hash<std::remove_const_t<Exclude>>::value()...};
1083 ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [&elem](const auto &data) { return data.second->owned(elem, sizeof...(Owned)) == 0u; }), "Conflicting groups");
1084 }
1085
1086 groups.emplace(type_hash<handler_type>::value(), handler);
1087 return {*handler};
1088 }
1089
1091 template<typename... Owned, typename... Get, typename... Exclude>
1092 basic_group<owned_t<storage_for_type<const Owned>...>, get_t<storage_for_type<const Get>...>, exclude_t<storage_for_type<const Exclude>...>>
1094 using handler_type = typename basic_group<owned_t<storage_for_type<const Owned>...>, get_t<storage_for_type<const Get>...>, exclude_t<storage_for_type<const Exclude>...>>::handler;
1095
1096 if(auto it = groups.find(type_hash<handler_type>::value()); it != groups.cend()) {
1097 return {*std::static_pointer_cast<handler_type>(it->second)};
1098 }
1099
1100 return {};
1101 }
1102
1110 template<typename Type, typename... Other>
1111 [[nodiscard]] bool owned() const {
1113 return std::any_of(groups.cbegin(), groups.cend(), [&elem](auto &&data) { return data.second->owned(elem, 1u + sizeof...(Other)); });
1114 }
1115
1149 template<typename Type, typename Compare, typename Sort = std_sort, typename... Args>
1150 void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
1151 ENTT_ASSERT(!owned<Type>(), "Cannot sort owned storage");
1152 auto &cpool = assure<Type>();
1153
1154 if constexpr(std::is_invocable_v<Compare, decltype(cpool.get({})), decltype(cpool.get({}))>) {
1155 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))); };
1156 cpool.sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
1157 } else {
1158 cpool.sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
1159 }
1160 }
1161
1175 template<typename To, typename From>
1176 void sort() {
1177 ENTT_ASSERT(!owned<To>(), "Cannot sort owned storage");
1178 const base_type &cpool = assure<From>();
1179 assure<To>().sort_as(cpool.begin(), cpool.end());
1180 }
1181
1186 context &ctx() noexcept {
1187 return vars;
1188 }
1189
1191 const context &ctx() const noexcept {
1192 return vars;
1193 }
1194
1195private:
1196 context vars;
1197 pool_container_type pools;
1198 group_container_type groups;
1199 storage_for_type<entity_type> entities;
1200};
1201
1202} // namespace entt
1203
1204#endif
Fast and reliable entity-component system.
Definition registry.hpp:233
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 component.
bool any_of(const entity_type entt) const
Check if an entity is part of at least one given storage.
Definition registry.hpp:850
typename base_type::traits_type traits_type
Entity traits.
Definition registry.hpp:297
decltype(auto) get_or_emplace(const entity_type entt, Args &&...args)
Returns a reference to the given component for an entity.
Definition registry.hpp:900
bool orphan(const entity_type entt) const
Checks if an entity has components assigned.
Definition registry.hpp:961
decltype(auto) replace(const entity_type entt, Args &&...args)
Replaces the given component for an entity.
Definition registry.hpp:685
basic_registry(const size_type count, const allocator_type &allocator=allocator_type{})
Allocates enough memory upon construction to store count pools.
Definition registry.hpp:338
auto on_update(const id_type id=type_hash< Type >::value())
Returns a sink object for the given component.
const common_type * storage(const id_type id) const
Finds the storage associated with a given name, if any.
Definition registry.hpp:430
auto try_get(const entity_type entt) const
Returns pointers to the given components for an entity.
Definition registry.hpp:919
decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args)
Assigns or replaces the given component for an entity.
Definition registry.hpp:637
iterable storage() noexcept
Returns an iterable object to use to visit a registry.
Definition registry.hpp:407
bool valid(const entity_type entt) const
Checks if an identifier refers to a valid entity.
Definition registry.hpp:462
bool all_of(const entity_type entt) const
Check if an entity is part of all the given storage.
Definition registry.hpp:833
void erase_if(const entity_type entt, Func func)
Erases components satisfying specific criteria from an entity.
Definition registry.hpp:802
version_type destroy(const entity_type entt)
Destroys an entity and releases its identifier.
Definition registry.hpp:521
typename traits_type::version_type version_type
Underlying version type.
Definition registry.hpp:303
entity_type create()
Creates a new entity or recycles a destroyed one.
Definition registry.hpp:480
const context & ctx() const noexcept
Returns the context object, that is, a general purpose container.
void sort()
Sorts two pools of components 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:542
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 components.
void create(It first, It last)
Assigns each element in a range an identifier.
Definition registry.hpp:507
bool owned() const
Checks whether the given components belong to any group.
size_type remove(It first, It last)
Removes the given components from all the entities in a range.
Definition registry.hpp:714
entity_type create(const entity_type hint)
Creates a new entity or recycles a destroyed one.
Definition registry.hpp:493
void clear()
Clears a whole registry or the pools for the given components.
Definition registry.hpp:943
decltype(auto) patch(const entity_type entt, Func &&...func)
Patches the given component for an entity.
Definition registry.hpp:665
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 components.
size_type remove(const entity_type entt)
Removes the given components from an entity.
Definition registry.hpp:697
basic_registry & operator=(basic_registry &&other) noexcept
Move assignment operator.
Definition registry.hpp:364
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 components.
auto try_get(const entity_type entt)
Returns pointers to the given components for an entity.
Definition registry.hpp:930
common_type * storage(const id_type id)
Finds the storage associated with a given name, if any.
Definition registry.hpp:421
void destroy(It first, It last)
Destroys all entities in a range and releases their identifiers.
Definition registry.hpp:558
decltype(auto) get(const entity_type entt)
Returns references to the given components for an entity.
Definition registry.hpp:876
void swap(basic_registry &other)
Exchanges the contents with those of a given registry.
Definition registry.hpp:379
void erase(It first, It last)
Erases the given components from all the entities in a range.
Definition registry.hpp:766
Allocator allocator_type
Allocator type.
Definition registry.hpp:299
void sort(Compare compare, Sort algo=Sort{}, Args &&...args)
Sorts the elements of a given component.
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
Definition registry.hpp:395
decltype(auto) emplace(const entity_type entt, Args &&...args)
Assigns the given component to an entity.
Definition registry.hpp:587
basic_registry(const allocator_type &allocator)
Constructs an empty registry with a given allocator.
Definition registry.hpp:330
auto on_construct(const id_type id=type_hash< Type >::value())
Returns a sink object for the given component.
Definition registry.hpp:985
storage_for_type< Type > & storage(const id_type id=type_hash< Type >::value())
Returns the storage for a given component type.
Definition registry.hpp:442
typename traits_type::value_type entity_type
Underlying entity identifier.
Definition registry.hpp:301
decltype(auto) get(const entity_type entt) const
Returns references to the given components for an entity.
Definition registry.hpp:866
std::size_t size_type
Unsigned integer type.
Definition registry.hpp:305
basic_registry(basic_registry &&other) noexcept
Move constructor.
Definition registry.hpp:351
void compact()
Removes all tombstones from a registry or only the pools for the given components.
Definition registry.hpp:816
typename storage_for< Type, Entity, typename alloc_traits::template rebind_alloc< std::remove_const_t< Type > > >::type storage_for_type
Definition registry.hpp:320
const_iterable storage() const noexcept
Returns an iterable object to use to visit a registry.
Definition registry.hpp:412
version_type current(const entity_type entt) const
Returns the actual version for an identifier.
Definition registry.hpp:472
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 components.
void insert(It first, It last, const Type &value={})
Assigns each entity in a range the given component.
Definition registry.hpp:603
const storage_for_type< Type > * storage(const id_type id=type_hash< Type >::value()) const
Returns the storage for a given component type, if any.
Definition registry.hpp:453
void insert(EIt first, EIt last, CIt from)
Assigns each entity in a range the given components.
Definition registry.hpp:620
internal::registry_context< allocator_type > context
Context type.
Definition registry.hpp:309
basic_registry()
Default constructor.
Definition registry.hpp:323
void erase(const entity_type entt)
Erases the given components from an entity.
Definition registry.hpp:750
Basic sparse set implementation.
iterator begin() const noexcept
Returns an iterator to the beginning.
iterator end() const noexcept
Returns an iterator to the end.
entt_traits< Entity > traits_type
Entity traits.
View implementation.
Definition fwd.hpp:38
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.
const_iterator end() const noexcept
Returns an iterator to the end.
EnTT default namespace.
Definition dense_map.hpp:21
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:13
basic_storage< Type > storage
Alias declaration for the most common use case.
Definition fwd.hpp:72
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
Definition entity.hpp:372
constexpr get_t< Type... > get
Variable template for lists of observed components.
Definition fwd.hpp:157
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.
basic_any< Len, Align > forward_as_any(Type &&value)
Forwards its argument and avoids copies for lvalue references.
Definition any.hpp:507
constexpr bool operator==(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
Alias for exclusion lists.
Definition fwd.hpp:130
Alias for lists of observed components.
Definition fwd.hpp:147
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:216
Type hash.
Definition type_info.hpp:92
static constexpr id_type value() noexcept
Returns the numeric representation of a given type.