EnTT  3.9.0
registry.hpp
1 #ifndef ENTT_ENTITY_REGISTRY_HPP
2 #define ENTT_ENTITY_REGISTRY_HPP
3 
4 #include <algorithm>
5 #include <cstddef>
6 #include <iterator>
7 #include <memory>
8 #include <tuple>
9 #include <type_traits>
10 #include <utility>
11 #include <vector>
12 #include "../config/config.h"
13 #include "../container/dense_hash_map.hpp"
14 #include "../core/algorithm.hpp"
15 #include "../core/any.hpp"
16 #include "../core/fwd.hpp"
17 #include "../core/iterator.hpp"
18 #include "../core/type_info.hpp"
19 #include "../core/type_traits.hpp"
20 #include "../core/utility.hpp"
21 #include "component.hpp"
22 #include "entity.hpp"
23 #include "fwd.hpp"
24 #include "group.hpp"
25 #include "runtime_view.hpp"
26 #include "sparse_set.hpp"
27 #include "storage.hpp"
28 #include "utility.hpp"
29 #include "view.hpp"
30 
31 namespace entt {
32 
38 namespace internal {
39 
40 template<typename It>
41 class storage_proxy_iterator {
42  template<typename Other>
43  friend class storage_proxy_iterator;
44 
45  using iterator_traits = std::iterator_traits<It>;
46  using first_type = typename iterator_traits::value_type::first_type;
47  using second_type = typename iterator_traits::value_type::second_type::element_type;
48 
49 public:
50  using value_type = std::pair<first_type, constness_as_t<second_type, std::remove_reference_t<typename iterator_traits::reference>> &>;
51  using pointer = input_iterator_pointer<value_type>;
52  using reference = value_type;
53  using difference_type = typename iterator_traits::difference_type;
54  using iterator_category = std::input_iterator_tag;
55 
56  storage_proxy_iterator() ENTT_NOEXCEPT = default;
57 
58  storage_proxy_iterator(const It iter) ENTT_NOEXCEPT
59  : it{iter} {}
60 
61  template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
62  storage_proxy_iterator(const storage_proxy_iterator<Other> &other)
63  : it{other.it} {}
64 
65  storage_proxy_iterator &operator++() ENTT_NOEXCEPT {
66  return ++it, *this;
67  }
68 
69  storage_proxy_iterator operator++(int) ENTT_NOEXCEPT {
70  storage_proxy_iterator orig = *this;
71  return ++(*this), orig;
72  }
73 
74  storage_proxy_iterator &operator--() ENTT_NOEXCEPT {
75  return --it, *this;
76  }
77 
78  storage_proxy_iterator operator--(int) ENTT_NOEXCEPT {
79  storage_proxy_iterator orig = *this;
80  return operator--(), orig;
81  }
82 
83  storage_proxy_iterator &operator+=(const difference_type value) ENTT_NOEXCEPT {
84  it += value;
85  return *this;
86  }
87 
88  storage_proxy_iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
89  storage_proxy_iterator copy = *this;
90  return (copy += value);
91  }
92 
93  storage_proxy_iterator &operator-=(const difference_type value) ENTT_NOEXCEPT {
94  return (*this += -value);
95  }
96 
97  storage_proxy_iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
98  return (*this + -value);
99  }
100 
101  [[nodiscard]] reference operator[](const difference_type value) const {
102  return {it[value].first, *it[value].second};
103  }
104 
105  [[nodiscard]] reference operator*() const {
106  return {it->first, *it->second};
107  }
108 
109  [[nodiscard]] pointer operator->() const {
110  return operator*();
111  }
112 
113  template<typename ILhs, typename IRhs>
114  friend auto operator-(const storage_proxy_iterator<ILhs> &, const storage_proxy_iterator<IRhs> &) ENTT_NOEXCEPT;
115 
116  template<typename ILhs, typename IRhs>
117  friend bool operator==(const storage_proxy_iterator<ILhs> &, const storage_proxy_iterator<IRhs> &) ENTT_NOEXCEPT;
118 
119  template<typename ILhs, typename IRhs>
120  friend bool operator<(const storage_proxy_iterator<ILhs> &, const storage_proxy_iterator<IRhs> &) ENTT_NOEXCEPT;
121 
122 private:
123  It it;
124 };
125 
126 template<typename ILhs, typename IRhs>
127 [[nodiscard]] auto operator-(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
128  return lhs.it - rhs.it;
129 }
130 
131 template<typename ILhs, typename IRhs>
132 [[nodiscard]] bool operator==(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
133  return lhs.it == rhs.it;
134 }
135 
136 template<typename ILhs, typename IRhs>
137 [[nodiscard]] bool operator!=(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
138  return !(lhs == rhs);
139 }
140 
141 template<typename ILhs, typename IRhs>
142 [[nodiscard]] bool operator<(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
143  return lhs.it < rhs.it;
144 }
145 
146 template<typename ILhs, typename IRhs>
147 [[nodiscard]] bool operator>(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
148  return rhs < lhs;
149 }
150 
151 template<typename ILhs, typename IRhs>
152 [[nodiscard]] bool operator<=(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
153  return !(lhs > rhs);
154 }
155 
156 template<typename ILhs, typename IRhs>
157 [[nodiscard]] bool operator>=(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
158  return !(lhs < rhs);
159 }
160 
161 } // namespace internal
162 
172 template<typename Entity>
176 
177  template<typename Component>
178  using storage_type = typename storage_traits<Entity, Component>::storage_type;
179 
180  template<typename...>
181  struct group_handler;
182 
183  template<typename... Exclude, typename... Get, typename... Owned>
184  struct group_handler<exclude_t<Exclude...>, get_t<Get...>, Owned...> {
185  // nasty workaround for an issue with the toolset v141 that doesn't accept a fold expression here
186  static_assert(!std::disjunction_v<std::bool_constant<component_traits<Owned>::in_place_delete>...>, "Groups do not support in-place delete");
187  std::conditional_t<sizeof...(Owned) == 0, basic_common_type, std::size_t> current{};
188 
189  template<typename Component>
190  void maybe_valid_if(basic_registry &owner, const Entity entt) {
191  [[maybe_unused]] const auto cpools = std::forward_as_tuple(owner.assure<Owned>()...);
192 
193  const auto is_valid = ((std::is_same_v<Component, Owned> || std::get<storage_type<Owned> &>(cpools).contains(entt)) && ...)
194  && ((std::is_same_v<Component, Get> || owner.assure<Get>().contains(entt)) && ...)
195  && ((std::is_same_v<Component, Exclude> || !owner.assure<Exclude>().contains(entt)) && ...);
196 
197  if constexpr(sizeof...(Owned) == 0) {
198  if(is_valid && !current.contains(entt)) {
199  current.emplace(entt);
200  }
201  } else {
202  if(is_valid && !(std::get<0>(cpools).index(entt) < current)) {
203  const auto pos = current++;
204  (std::get<storage_type<Owned> &>(cpools).swap_elements(std::get<storage_type<Owned> &>(cpools).data()[pos], entt), ...);
205  }
206  }
207  }
208 
209  void discard_if([[maybe_unused]] basic_registry &owner, const Entity entt) {
210  if constexpr(sizeof...(Owned) == 0) {
211  current.remove(entt);
212  } else {
213  if(const auto cpools = std::forward_as_tuple(owner.assure<Owned>()...); std::get<0>(cpools).contains(entt) && (std::get<0>(cpools).index(entt) < current)) {
214  const auto pos = --current;
215  (std::get<storage_type<Owned> &>(cpools).swap_elements(std::get<storage_type<Owned> &>(cpools).data()[pos], entt), ...);
216  }
217  }
218  }
219  };
220 
221  struct group_data {
222  std::size_t size;
223  std::unique_ptr<void, void (*)(void *)> group;
224  bool (*owned)(const id_type) ENTT_NOEXCEPT;
225  bool (*get)(const id_type) ENTT_NOEXCEPT;
226  bool (*exclude)(const id_type) ENTT_NOEXCEPT;
227  };
228 
229  template<typename Component>
230  [[nodiscard]] auto &assure(const id_type id = type_hash<Component>::value()) {
231  static_assert(std::is_same_v<Component, std::decay_t<Component>>, "Non-decayed types not allowed");
232  auto &&cpool = pools[id];
233 
234  if(!cpool) {
235  cpool.reset(new storage_type<Component>{});
236  cpool->bind(forward_as_any(*this));
237  }
238 
239  return static_cast<storage_type<Component> &>(*cpool);
240  }
241 
242  template<typename Component>
243  [[nodiscard]] const auto &assure(const id_type id = type_hash<Component>::value()) const {
244  static_assert(std::is_same_v<Component, std::decay_t<Component>>, "Non-decayed types not allowed");
245 
246  if(const auto it = pools.find(id); it != pools.cend()) {
247  return static_cast<const storage_type<Component> &>(*it->second);
248  }
249 
250  static storage_type<Component> placeholder{};
251  return placeholder;
252  }
253 
254  auto generate_identifier(const std::size_t pos) ENTT_NOEXCEPT {
255  ENTT_ASSERT(pos < entity_traits::to_integral(null), "No entities available");
256  return entity_traits::combine(static_cast<typename entity_traits::entity_type>(pos), {});
257  }
258 
259  auto recycle_identifier() ENTT_NOEXCEPT {
260  ENTT_ASSERT(free_list != null, "No entities available");
261  const auto curr = entity_traits::to_entity(free_list);
262  free_list = entity_traits::combine(entity_traits::to_integral(entities[curr]), tombstone);
263  return (entities[curr] = entity_traits::combine(curr, entity_traits::to_integral(entities[curr])));
264  }
265 
266  auto release_entity(const Entity entity, const typename entity_traits::version_type version) {
267  const typename entity_traits::version_type vers = version + (version == entity_traits::to_version(tombstone));
270  return vers;
271  }
272 
273 public:
275  using entity_type = Entity;
279  using size_type = std::size_t;
282 
284  basic_registry() = default;
285 
290  basic_registry(basic_registry &&other) ENTT_NOEXCEPT
291  : pools{std::move(other.pools)},
292  vars{std::move(other.vars)},
293  groups{std::move(other.groups)},
294  entities{std::move(other.entities)},
295  free_list{other.free_list} {
296  for(auto &&curr: pools) {
297  curr.second->bind(forward_as_any(*this));
298  }
299  }
300 
306  basic_registry &operator=(basic_registry &&other) ENTT_NOEXCEPT {
307  pools = std::move(other.pools);
308  vars = std::move(other.vars);
309  groups = std::move(other.groups);
310  entities = std::move(other.entities);
311  free_list = other.free_list;
312 
313  for(auto &&curr: pools) {
314  curr.second->bind(forward_as_any(*this));
315  }
316 
317  return *this;
318  }
319 
328  [[nodiscard]] auto storage() ENTT_NOEXCEPT {
329  return iterable_adaptor{internal::storage_proxy_iterator{pools.begin()}, internal::storage_proxy_iterator{pools.end()}};
330  }
331 
333  [[nodiscard]] auto storage() const ENTT_NOEXCEPT {
334  return iterable_adaptor{internal::storage_proxy_iterator{pools.cbegin()}, internal::storage_proxy_iterator{pools.cend()}};
335  }
336 
343  template<typename Component>
344  [[nodiscard]] decltype(auto) storage(const id_type id = type_hash<Component>::value()) {
345  return assure<Component>(id);
346  }
347 
359  template<typename Component>
360  [[nodiscard]] decltype(auto) storage(const id_type id = type_hash<Component>::value()) const {
361  return assure<Component>(id);
362  }
363 
368  [[nodiscard]] size_type size() const ENTT_NOEXCEPT {
369  return entities.size();
370  }
371 
376  [[nodiscard]] size_type alive() const {
377  auto sz = entities.size();
378 
379  for(auto curr = free_list; curr != null; --sz) {
380  curr = entities[entity_traits::to_entity(curr)];
381  }
382 
383  return sz;
384  }
385 
390  void reserve(const size_type cap) {
391  entities.reserve(cap);
392  }
393 
399  [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT {
400  return entities.capacity();
401  }
402 
407  [[nodiscard]] bool empty() const {
408  return !alive();
409  }
410 
423  [[nodiscard]] const entity_type *data() const ENTT_NOEXCEPT {
424  return entities.data();
425  }
426 
435  [[nodiscard]] entity_type released() const ENTT_NOEXCEPT {
436  return free_list;
437  }
438 
444  [[nodiscard]] bool valid(const entity_type entity) const {
445  const auto pos = size_type(entity_traits::to_entity(entity));
446  return (pos < entities.size() && entities[pos] == entity);
447  }
448 
455  [[nodiscard]] version_type current(const entity_type entity) const {
456  const auto pos = size_type(entity_traits::to_entity(entity));
457  return entity_traits::to_version(pos < entities.size() ? entities[pos] : tombstone);
458  }
459 
464  [[nodiscard]] entity_type create() {
465  return (free_list == null) ? entities.emplace_back(generate_identifier(entities.size())) : recycle_identifier();
466  }
467 
477  [[nodiscard]] entity_type create(const entity_type hint) {
478  const auto length = entities.size();
479 
480  if(hint == null || hint == tombstone) {
481  return create();
482  } else if(const auto req = entity_traits::to_entity(hint); !(req < length)) {
483  entities.resize(size_type(req) + 1u, null);
484 
485  for(auto pos = length; pos < req; ++pos) {
486  release_entity(generate_identifier(pos), {});
487  }
488 
489  return (entities[req] = hint);
490  } else if(const auto curr = entity_traits::to_entity(entities[req]); req == curr) {
491  return create();
492  } else {
493  auto *it = &free_list;
494  for(; entity_traits::to_entity(*it) != req; it = &entities[entity_traits::to_entity(*it)]) {}
496  return (entities[req] = hint);
497  }
498  }
499 
509  template<typename It>
510  void create(It first, It last) {
511  for(; free_list != null && first != last; ++first) {
512  *first = recycle_identifier();
513  }
514 
515  const auto length = entities.size();
516  entities.resize(length + std::distance(first, last), null);
517 
518  for(auto pos = length; first != last; ++first, ++pos) {
519  *first = entities[pos] = generate_identifier(pos);
520  }
521  }
522 
540  template<typename It>
541  void assign(It first, It last, const entity_type destroyed) {
542  ENTT_ASSERT(!alive(), "Entities still alive");
543  entities.assign(first, last);
544  free_list = destroyed;
545  }
546 
560  }
561 
575  ENTT_ASSERT(orphan(entity), "Non-orphan entity");
576  return release_entity(entity, version);
577  }
578 
588  template<typename It>
589  void release(It first, It last) {
590  for(; first != last; ++first) {
591  release(*first, entity_traits::to_version(*first) + 1u);
592  }
593  }
594 
610  }
611 
625  ENTT_ASSERT(valid(entity), "Invalid entity");
626 
627  for(auto &&curr: pools) {
628  curr.second->remove(entity);
629  }
630 
631  return release_entity(entity, version);
632  }
633 
643  template<typename It>
644  void destroy(It first, It last) {
645  if constexpr(is_iterator_type_v<typename basic_common_type::iterator, It>) {
646  for(; first != last; ++first) {
647  destroy(*first, entity_traits::to_version(*first) + 1u);
648  }
649  } else {
650  for(auto &&curr: pools) {
651  curr.second->remove(first, last);
652  }
653 
654  release(first, last);
655  }
656  }
657 
673  template<typename Component, typename... Args>
674  decltype(auto) emplace(const entity_type entity, Args &&...args) {
675  ENTT_ASSERT(valid(entity), "Invalid entity");
676  return assure<Component>().emplace(entity, std::forward<Args>(args)...);
677  }
678 
690  template<typename Component, typename It>
691  void insert(It first, It last, const Component &value = {}) {
692  ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }), "Invalid entity");
693  assure<Component>().insert(first, last, value);
694  }
695 
708  template<typename Component, typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<std::decay_t<typename std::iterator_traits<CIt>::value_type>, Component>>>
709  void insert(EIt first, EIt last, CIt from) {
710  ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }), "Invalid entity");
711  assure<Component>().insert(first, last, from);
712  }
713 
726  template<typename Component, typename... Args>
727  decltype(auto) emplace_or_replace(const entity_type entity, Args &&...args) {
728  ENTT_ASSERT(valid(entity), "Invalid entity");
729  auto &cpool = assure<Component>();
730 
731  return cpool.contains(entity)
732  ? cpool.patch(entity, [&args...](auto &...curr) { ((curr = Component{std::forward<Args>(args)...}), ...); })
733  : cpool.emplace(entity, std::forward<Args>(args)...);
734  }
735 
760  template<typename Component, typename... Func>
761  decltype(auto) patch(const entity_type entity, Func &&...func) {
762  ENTT_ASSERT(valid(entity), "Invalid entity");
763  return assure<Component>().patch(entity, std::forward<Func>(func)...);
764  }
765 
781  template<typename Component, typename... Args>
782  decltype(auto) replace(const entity_type entity, Args &&...args) {
783  ENTT_ASSERT(valid(entity), "Invalid entity");
784  return assure<Component>().patch(entity, [&args...](auto &...curr) { ((curr = Component{std::forward<Args>(args)...}), ...); });
785  }
786 
798  template<typename Component, typename... Other>
800  ENTT_ASSERT(valid(entity), "Invalid entity");
801  return (assure<Component>().remove(entity) + ... + assure<Other>().remove(entity));
802  }
803 
816  template<typename Component, typename... Other, typename It>
817  size_type remove(It first, It last) {
818  size_type count{};
819 
820  for(const auto cpools = std::forward_as_tuple(assure<Component>(), assure<Other>()...); first != last; ++first) {
821  const auto entity = *first;
822  ENTT_ASSERT(valid(entity), "Invalid entity");
823  count += (std::get<storage_type<Component> &>(cpools).remove(entity) + ... + std::get<storage_type<Other> &>(cpools).remove(entity));
824  }
825 
826  return count;
827  }
828 
840  template<typename Component, typename... Other>
841  void erase(const entity_type entity) {
842  ENTT_ASSERT(valid(entity), "Invalid entity");
843  (assure<Component>().erase(entity), (assure<Other>().erase(entity), ...));
844  }
845 
857  template<typename Component, typename... Other, typename It>
858  void erase(It first, It last) {
859  for(const auto cpools = std::forward_as_tuple(assure<Component>(), assure<Other>()...); first != last; ++first) {
860  const auto entity = *first;
861  ENTT_ASSERT(valid(entity), "Invalid entity");
862  (std::get<storage_type<Component> &>(cpools).erase(entity), (std::get<storage_type<Other> &>(cpools).erase(entity), ...));
863  }
864  }
865 
871  template<typename... Component>
872  void compact() {
873  if constexpr(sizeof...(Component) == 0) {
874  for(auto &&curr: pools) {
875  curr.second->compact();
876  }
877  } else {
878  (assure<Component>().compact(), ...);
879  }
880  }
881 
892  template<typename... Component>
893  [[nodiscard]] bool all_of(const entity_type entity) const {
894  ENTT_ASSERT(valid(entity), "Invalid entity");
895  return (assure<std::remove_const_t<Component>>().contains(entity) && ...);
896  }
897 
909  template<typename... Component>
910  [[nodiscard]] bool any_of(const entity_type entity) const {
911  ENTT_ASSERT(valid(entity), "Invalid entity");
912  return (assure<std::remove_const_t<Component>>().contains(entity) || ...);
913  }
914 
926  template<typename... Component>
927  [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entity) const {
928  ENTT_ASSERT(valid(entity), "Invalid entity");
929  return view<Component...>().template get<const Component...>(entity);
930  }
931 
933  template<typename... Component>
934  [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entity) {
935  ENTT_ASSERT(valid(entity), "Invalid entity");
936  return view<Component...>().template get<Component...>(entity);
937  }
938 
954  template<typename Component, typename... Args>
955  [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entity, Args &&...args) {
956  ENTT_ASSERT(valid(entity), "Invalid entity");
957  auto &cpool = assure<Component>();
958  return cpool.contains(entity) ? cpool.get(entity) : cpool.emplace(entity, std::forward<Args>(args)...);
959  }
960 
974  template<typename... Component>
975  [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entity) const {
976  ENTT_ASSERT(valid(entity), "Invalid entity");
977 
978  if constexpr(sizeof...(Component) == 1) {
979  const auto &cpool = assure<std::remove_const_t<Component>...>();
980  return cpool.contains(entity) ? std::addressof(cpool.get(entity)) : nullptr;
981  } else {
982  return std::make_tuple(try_get<Component>(entity)...);
983  }
984  }
985 
987  template<typename... Component>
988  [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entity) {
989  if constexpr(sizeof...(Component) == 1) {
990  return (const_cast<Component *>(std::as_const(*this).template try_get<Component>(entity)), ...);
991  } else {
992  return std::make_tuple(try_get<Component>(entity)...);
993  }
994  }
995 
1000  template<typename... Component>
1001  void clear() {
1002  if constexpr(sizeof...(Component) == 0) {
1003  for(auto &&curr: pools) {
1004  curr.second->clear();
1005  }
1006 
1007  each([this](const auto entity) { release_entity(entity, entity_traits::to_version(entity) + 1u); });
1008  } else {
1009  (assure<Component>().clear(), ...);
1010  }
1011  }
1012 
1027  template<typename Func>
1028  void each(Func func) const {
1029  if(free_list == null) {
1030  for(auto pos = entities.size(); pos; --pos) {
1031  func(entities[pos - 1]);
1032  }
1033  } else {
1034  for(auto pos = entities.size(); pos; --pos) {
1035  if(const auto entity = entities[pos - 1]; entity_traits::to_entity(entity) == (pos - 1)) {
1036  func(entity);
1037  }
1038  }
1039  }
1040  }
1041 
1047  [[nodiscard]] bool orphan(const entity_type entity) const {
1048  ENTT_ASSERT(valid(entity), "Invalid entity");
1049  return std::none_of(pools.cbegin(), pools.cend(), [entity](auto &&curr) { return curr.second->contains(entity); });
1050  }
1051 
1070  template<typename Component>
1071  [[nodiscard]] auto on_construct() {
1072  return assure<Component>().on_construct();
1073  }
1074 
1093  template<typename Component>
1094  [[nodiscard]] auto on_update() {
1095  return assure<Component>().on_update();
1096  }
1097 
1116  template<typename Component>
1117  [[nodiscard]] auto on_destroy() {
1118  return assure<Component>().on_destroy();
1119  }
1120 
1134  template<typename Component, typename... Other, typename... Exclude>
1135  [[nodiscard]] basic_view<Entity, get_t<std::add_const_t<Component>, std::add_const_t<Other>...>, exclude_t<Exclude...>> view(exclude_t<Exclude...> = {}) const {
1136  return {assure<std::remove_const_t<Component>>(), assure<std::remove_const_t<Other>>()..., assure<Exclude>()...};
1137  }
1138 
1140  template<typename Component, typename... Other, typename... Exclude>
1141  [[nodiscard]] basic_view<Entity, get_t<Component, Other...>, exclude_t<Exclude...>> view(exclude_t<Exclude...> = {}) {
1142  return {assure<std::remove_const_t<Component>>(), assure<std::remove_const_t<Other>>()..., assure<Exclude>()...};
1143  }
1144 
1168  template<typename ItComp, typename ItExcl = id_type *>
1169  [[nodiscard]] basic_runtime_view<Entity> runtime_view(ItComp first, ItComp last, ItExcl from = {}, ItExcl to = {}) const {
1170  std::vector<const basic_common_type *> component{};
1171  std::vector<const basic_common_type *> filter{};
1172 
1173  component.reserve(std::distance(first, last));
1174  filter.reserve(std::distance(from, to));
1175 
1176  for(; first != last; ++first) {
1177  const auto it = pools.find(*first);
1178  component.emplace_back(it == pools.cend() ? nullptr : it->second.get());
1179  }
1180 
1181  for(; from != to; ++from) {
1182  const auto it = pools.find(*from);
1183  filter.emplace_back(it == pools.cend() ? nullptr : it->second.get());
1184  }
1185 
1186  return {std::move(component), std::move(filter)};
1187  }
1188 
1213  template<typename... Owned, typename... Get, typename... Exclude>
1214  [[nodiscard]] basic_group<Entity, owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> group(get_t<Get...>, exclude_t<Exclude...> = {}) {
1215  static_assert(sizeof...(Owned) + sizeof...(Get) > 0, "Exclusion-only groups are not supported");
1216  static_assert(sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude) > 1, "Single component groups are not allowed");
1217 
1218  using handler_type = group_handler<exclude_t<std::remove_const_t<Exclude>...>, get_t<std::remove_const_t<Get>...>, std::remove_const_t<Owned>...>;
1219 
1220  const auto cpools = std::forward_as_tuple(assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()...);
1221  constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
1222  handler_type *handler = nullptr;
1223 
1224  auto it = std::find_if(groups.cbegin(), groups.cend(), [size](const auto &gdata) {
1225  return gdata.size == size
1226  && (gdata.owned(type_hash<std::remove_const_t<Owned>>::value()) && ...)
1227  && (gdata.get(type_hash<std::remove_const_t<Get>>::value()) && ...)
1228  && (gdata.exclude(type_hash<Exclude>::value()) && ...);
1229  });
1230 
1231  if(it != groups.cend()) {
1232  handler = static_cast<handler_type *>(it->group.get());
1233  } else {
1234  group_data candidate = {
1235  size,
1236  {new handler_type{}, [](void *instance) { delete static_cast<handler_type *>(instance); }},
1237  []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash<std::remove_const_t<Owned>>::value()) || ...); },
1238  []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash<std::remove_const_t<Get>>::value()) || ...); },
1239  []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash<Exclude>::value()) || ...); },
1240  };
1241 
1242  handler = static_cast<handler_type *>(candidate.group.get());
1243 
1244  const void *maybe_valid_if = nullptr;
1245  const void *discard_if = nullptr;
1246 
1247  if constexpr(sizeof...(Owned) == 0) {
1248  groups.push_back(std::move(candidate));
1249  } else {
1250  [[maybe_unused]] auto has_conflict = [size](const auto &gdata) {
1251  const auto overlapping = (0u + ... + gdata.owned(type_hash<std::remove_const_t<Owned>>::value()));
1252  const auto sz = overlapping + (0u + ... + gdata.get(type_hash<std::remove_const_t<Get>>::value())) + (0u + ... + gdata.exclude(type_hash<Exclude>::value()));
1253  return !overlapping || ((sz == size) || (sz == gdata.size));
1254  };
1255 
1256  ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), std::move(has_conflict)), "Conflicting groups");
1257 
1258  const auto next = std::find_if_not(groups.cbegin(), groups.cend(), [size](const auto &gdata) {
1259  return !(0u + ... + gdata.owned(type_hash<std::remove_const_t<Owned>>::value())) || (size > gdata.size);
1260  });
1261 
1262  const auto prev = std::find_if(std::make_reverse_iterator(next), groups.crend(), [](const auto &gdata) {
1263  return (0u + ... + gdata.owned(type_hash<std::remove_const_t<Owned>>::value()));
1264  });
1265 
1266  maybe_valid_if = (next == groups.cend() ? maybe_valid_if : next->group.get());
1267  discard_if = (prev == groups.crend() ? discard_if : prev->group.get());
1268  groups.insert(next, std::move(candidate));
1269  }
1270 
1271  (on_construct<std::remove_const_t<Owned>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::remove_const_t<Owned>>>(*handler), ...);
1272  (on_construct<std::remove_const_t<Get>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::remove_const_t<Get>>>(*handler), ...);
1273  (on_destroy<Exclude>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<Exclude>>(*handler), ...);
1274 
1275  (on_destroy<std::remove_const_t<Owned>>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
1276  (on_destroy<std::remove_const_t<Get>>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
1277  (on_construct<Exclude>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
1278 
1279  if constexpr(sizeof...(Owned) == 0) {
1280  for(const auto entity: view<Owned..., Get...>(exclude<Exclude...>)) {
1281  handler->current.emplace(entity);
1282  }
1283  } else {
1284  // we cannot iterate backwards because we want to leave behind valid entities in case of owned types
1285  for(auto *first = std::get<0>(cpools).data(), *last = first + std::get<0>(cpools).size(); first != last; ++first) {
1286  handler->template maybe_valid_if<type_list_element_t<0, type_list<std::remove_const_t<Owned>...>>>(*this, *first);
1287  }
1288  }
1289  }
1290 
1291  return {handler->current, std::get<storage_type<std::remove_const_t<Owned>> &>(cpools)..., std::get<storage_type<std::remove_const_t<Get>> &>(cpools)...};
1292  }
1293 
1295  template<typename... Owned, typename... Get, typename... Exclude>
1297  auto it = std::find_if(groups.cbegin(), groups.cend(), [](const auto &gdata) {
1298  return gdata.size == (sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude))
1299  && (gdata.owned(type_hash<std::remove_const_t<Owned>>::value()) && ...)
1300  && (gdata.get(type_hash<std::remove_const_t<Get>>::value()) && ...)
1301  && (gdata.exclude(type_hash<Exclude>::value()) && ...);
1302  });
1303 
1304  if(it == groups.cend()) {
1305  return {};
1306  } else {
1307  using handler_type = group_handler<exclude_t<std::remove_const_t<Exclude>...>, get_t<std::remove_const_t<Get>...>, std::remove_const_t<Owned>...>;
1308  return {static_cast<handler_type *>(it->group.get())->current, assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()...};
1309  }
1310  }
1311 
1313  template<typename... Owned, typename... Exclude>
1314  [[nodiscard]] basic_group<Entity, owned_t<Owned...>, get_t<>, exclude_t<Exclude...>> group(exclude_t<Exclude...> = {}) {
1315  return group<Owned...>(get_t<>{}, exclude<Exclude...>);
1316  }
1317 
1319  template<typename... Owned, typename... Exclude>
1321  return group_if_exists<std::add_const_t<Owned>...>(get_t<>{}, exclude<Exclude...>);
1322  }
1323 
1330  template<typename... Component>
1331  [[nodiscard]] bool sortable() const {
1332  return std::none_of(groups.cbegin(), groups.cend(), [](auto &&gdata) { return (gdata.owned(type_hash<std::remove_const_t<Component>>::value()) || ...); });
1333  }
1334 
1342  template<typename... Owned, typename... Get, typename... Exclude>
1343  [[nodiscard]] bool sortable(const basic_group<Entity, owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> &) ENTT_NOEXCEPT {
1344  constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
1345  auto pred = [size](const auto &gdata) { return (0u + ... + gdata.owned(type_hash<std::remove_const_t<Owned>>::value())) && (size < gdata.size); };
1346  return std::find_if(groups.cbegin(), groups.cend(), std::move(pred)) == groups.cend();
1347  }
1348 
1384  template<typename Component, typename Compare, typename Sort = std_sort, typename... Args>
1385  void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
1386  ENTT_ASSERT(sortable<Component>(), "Cannot sort owned storage");
1387  auto &cpool = assure<Component>();
1388 
1389  if constexpr(std::is_invocable_v<Compare, decltype(cpool.get({})), decltype(cpool.get({}))>) {
1390  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))); };
1391  cpool.sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
1392  } else {
1393  cpool.sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
1394  }
1395  }
1396 
1416  template<typename To, typename From>
1417  void sort() {
1418  ENTT_ASSERT(sortable<To>(), "Cannot sort owned storage");
1419  assure<To>().respect(assure<From>());
1420  }
1421 
1433  template<typename Type, typename... Args>
1434  Type &set(Args &&...args) {
1435  auto &&elem = vars[type_hash<std::remove_const_t<std::remove_reference_t<Type>>>::value()];
1436  elem.template emplace<Type>(std::forward<Args>(args)...);
1437  return any_cast<Type &>(elem);
1438  }
1439 
1444  template<typename Type>
1445  void unset() {
1446  vars.erase(type_hash<std::remove_const_t<std::remove_reference_t<Type>>>::value());
1447  }
1448 
1460  template<typename Type, typename... Args>
1461  [[nodiscard]] Type &ctx_or_set(Args &&...args) {
1462  auto *elem = try_ctx<Type>();
1463  return elem ? *elem : set<Type>(std::forward<Args>(args)...);
1464  }
1465 
1472  template<typename Type>
1473  [[nodiscard]] std::add_const_t<Type> *try_ctx() const {
1474  auto it = vars.find(type_hash<std::remove_const_t<std::remove_reference_t<Type>>>::value());
1475  return it == vars.cend() ? nullptr : any_cast<Type>(&it->second);
1476  }
1477 
1479  template<typename Type>
1480  [[nodiscard]] Type *try_ctx() {
1481  if constexpr(std::is_const_v<Type>) {
1482  return std::as_const(*this).template try_ctx<Type>();
1483  } else {
1484  auto it = vars.find(type_hash<std::remove_const_t<std::remove_reference_t<Type>>>::value());
1485  return it == vars.end() ? nullptr : any_cast<Type>(&it->second);
1486  }
1487  }
1488 
1499  template<typename Type>
1500  [[nodiscard]] std::add_const_t<Type> &ctx() const {
1501  auto *value = try_ctx<Type>();
1502  ENTT_ASSERT(value != nullptr, "Invalid instance");
1503  return *value;
1504  }
1505 
1507  template<typename Type>
1508  [[nodiscard]] Type &ctx() {
1509  auto *value = try_ctx<Type>();
1510  ENTT_ASSERT(value != nullptr, "Invalid instance");
1511  return *value;
1512  }
1513 
1531  template<typename Func>
1532  void ctx(Func func) const {
1533  for(auto &&curr: vars) {
1534  func(curr.second.type());
1535  }
1536  }
1537 
1538 private:
1540  dense_hash_map<id_type, basic_any<0u>, identity> vars{};
1541  std::vector<group_data> groups{};
1542  std::vector<entity_type> entities{};
1543  entity_type free_list{tombstone};
1544 };
1545 
1546 } // namespace entt
1547 
1548 #endif
Group.
Definition: fwd.hpp:26
Fast and reliable entity-component system.
Definition: registry.hpp:173
Type & ctx()
Returns a reference to an object in the context of the registry.
Definition: registry.hpp:1508
size_type capacity() const
Returns the number of entities that a registry has currently allocated space for.
Definition: registry.hpp:399
bool any_of(const entity_type entity) const
Checks if an entity has at least one of the given components.
Definition: registry.hpp:910
basic_registry()=default
Default constructor.
bool orphan(const entity_type entity) const
Checks if an entity has components assigned.
Definition: registry.hpp:1047
bool valid(const entity_type entity) const
Checks if an identifier refers to a valid entity.
Definition: registry.hpp:444
version_type current(const entity_type entity) const
Returns the actual version for an identifier.
Definition: registry.hpp:455
void insert(EIt first, EIt last, CIt from)
Assigns each entity in a range the given components.
Definition: registry.hpp:709
basic_registry & operator=(basic_registry &&other)
Move assignment operator.
Definition: registry.hpp:306
void compact()
Removes all tombstones from a registry or only the pools for the given components.
Definition: registry.hpp:872
void sort()
Sorts two pools of components in the same way.
Definition: registry.hpp:1417
void create(It first, It last)
Assigns each element in a range an identifier.
Definition: registry.hpp:510
void insert(It first, It last, const Component &value={})
Assigns each entity in a range the given component.
Definition: registry.hpp:691
void assign(It first, It last, const entity_type destroyed)
Assigns identifiers to an empty registry.
Definition: registry.hpp:541
decltype(auto) get([[maybe_unused]] const entity_type entity) const
Returns references to the given components for an entity.
Definition: registry.hpp:927
decltype(auto) emplace_or_replace(const entity_type entity, Args &&...args)
Assigns or replaces the given component for an entity.
Definition: registry.hpp:727
version_type release(const entity_type entity)
Releases an identifier.
Definition: registry.hpp:558
bool all_of(const entity_type entity) const
Checks if an entity has all the given components.
Definition: registry.hpp:893
void sort(Compare compare, Sort algo=Sort{}, Args &&...args)
Sorts the elements of a given component.
Definition: registry.hpp:1385
entity_type released() const
Returns the head of the list of released entities.
Definition: registry.hpp:435
decltype(auto) emplace(const entity_type entity, Args &&...args)
Assigns the given component to an entity.
Definition: registry.hpp:674
bool empty() const
Checks whether the registry is empty (no entities still in use).
Definition: registry.hpp:407
basic_group< Entity, owned_t< Owned... >, get_t<>, exclude_t< Exclude... > > group(exclude_t< Exclude... >={})
Returns a group for the given components.
Definition: registry.hpp:1314
size_type remove(It first, It last)
Removes the given components from all the entities in a range.
Definition: registry.hpp:817
basic_view< Entity, get_t< Component, Other... >, exclude_t< Exclude... > > view(exclude_t< Exclude... >={})
Returns a view for the given components.
Definition: registry.hpp:1141
size_type size() const
Returns the number of entities created so far.
Definition: registry.hpp:368
bool sortable() const
Checks whether the given components belong to any group.
Definition: registry.hpp:1331
void release(It first, It last)
Releases all identifiers in a range.
Definition: registry.hpp:589
std::size_t size_type
Unsigned integer type.
Definition: registry.hpp:279
void destroy(It first, It last)
Destroys all entities in a range and releases their identifiers.
Definition: registry.hpp:644
auto storage() const
Returns an iterable object to use to visit a registry.
Definition: registry.hpp:333
size_type alive() const
Returns the number of entities still in use.
Definition: registry.hpp:376
version_type destroy(const entity_type entity)
Destroys an entity and releases its identifier.
Definition: registry.hpp:608
Entity entity_type
Underlying entity identifier.
Definition: registry.hpp:275
typename entity_traits::version_type version_type
Underlying version type.
Definition: registry.hpp:277
std::add_const_t< Type > * try_ctx() const
Returns a pointer to an object in the context of the registry.
Definition: registry.hpp:1473
void each(Func func) const
Iterates all the entities that are still in use.
Definition: registry.hpp:1028
void erase(It first, It last)
Erases the given components from all the entities in a range.
Definition: registry.hpp:858
entity_type create()
Creates a new entity or recycles a destroyed one.
Definition: registry.hpp:464
bool sortable(const basic_group< Entity, owned_t< Owned... >, get_t< Get... >, exclude_t< Exclude... >> &)
Checks whether a group can be sorted.
Definition: registry.hpp:1343
void reserve(const size_type cap)
Increases the capacity (number of entities) of the registry.
Definition: registry.hpp:390
auto try_get([[maybe_unused]] const entity_type entity) const
Returns pointers to the given components for an entity.
Definition: registry.hpp:975
auto storage()
Returns an iterable object to use to visit a registry.
Definition: registry.hpp:328
Type & set(Args &&...args)
Binds an object to the context of the registry.
Definition: registry.hpp:1434
void clear()
Clears a whole registry or the pools for the given components.
Definition: registry.hpp:1001
basic_view< Entity, get_t< std::add_const_t< Component >, std::add_const_t< Other >... >, exclude_t< Exclude... > > view(exclude_t< Exclude... >={}) const
Returns a view for the given components.
Definition: registry.hpp:1135
basic_group< Entity, owned_t< std::add_const_t< Owned >... >, get_t<>, exclude_t< Exclude... > > group_if_exists(exclude_t< Exclude... >={}) const
Returns a group for the given components.
Definition: registry.hpp:1320
size_type remove(const entity_type entity)
Removes the given components from an entity.
Definition: registry.hpp:799
std::add_const_t< Type > & ctx() const
Returns a reference to an object in the context of the registry.
Definition: registry.hpp:1500
void unset()
Unsets a context variable if it exists.
Definition: registry.hpp:1445
auto on_update()
Returns a sink object for the given component.
Definition: registry.hpp:1094
entity_type create(const entity_type hint)
Creates a new entity or recycles a destroyed one.
Definition: registry.hpp:477
Type * try_ctx()
Returns a pointer to an object in the context of the registry.
Definition: registry.hpp:1480
const entity_type * data() const
Direct access to the list of entities of a registry.
Definition: registry.hpp:423
auto try_get([[maybe_unused]] const entity_type entity)
Returns pointers to the given components for an entity.
Definition: registry.hpp:988
basic_registry(basic_registry &&other)
Move constructor.
Definition: registry.hpp:290
void erase(const entity_type entity)
Erases the given components from an entity.
Definition: registry.hpp:841
auto on_destroy()
Returns a sink object for the given component.
Definition: registry.hpp:1117
version_type destroy(const entity_type entity, const version_type version)
Destroys an entity and releases its identifier.
Definition: registry.hpp:624
auto on_construct()
Returns a sink object for the given component.
Definition: registry.hpp:1071
void ctx(Func func) const
Visits a registry and returns the type info for its context variables.
Definition: registry.hpp:1532
basic_runtime_view< Entity > runtime_view(ItComp first, ItComp last, ItExcl from={}, ItExcl to={}) const
Returns a runtime view for the given components.
Definition: registry.hpp:1169
basic_group< Entity, owned_t< std::add_const_t< Owned >... >, get_t< std::add_const_t< Get >... >, exclude_t< Exclude... > > group_if_exists(get_t< Get... >, exclude_t< Exclude... >={}) const
Returns a group for the given components.
Definition: registry.hpp:1296
Type & ctx_or_set(Args &&...args)
Binds an object to the context of the registry.
Definition: registry.hpp:1461
version_type release(const entity_type entity, const version_type version)
Releases an identifier.
Definition: registry.hpp:574
basic_group< Entity, owned_t< Owned... >, get_t< Get... >, exclude_t< Exclude... > > group(get_t< Get... >, exclude_t< Exclude... >={})
Returns a group for the given components.
Definition: registry.hpp:1214
Basic sparse set implementation.
Definition: sparse_set.hpp:174
Basic storage implementation.
Definition: storage.hpp:237
View implementation.
Definition: fwd.hpp:20
Associative container for key-value pairs with unique keys.
Entity traits.
Definition: entity.hpp:62
typename base_type::entity_type entity_type
Underlying entity type.
Definition: entity.hpp:69
static constexpr entity_type to_integral(const value_type value)
Converts an entity to its underlying type.
Definition: entity.hpp:82
static constexpr entity_type to_entity(const value_type value)
Returns the entity part once converted to the underlying type.
Definition: entity.hpp:91
static constexpr value_type construct(const entity_type entity, const version_type version)
Constructs an identifier from its parts.
Definition: entity.hpp:114
static constexpr value_type combine(const entity_type lhs, const entity_type rhs)
Combines two identifiers in a single one.
Definition: entity.hpp:128
typename base_type::version_type version_type
Underlying version type.
Definition: entity.hpp:71
static constexpr version_type to_version(const value_type value)
Returns the version part once converted to the underlying type.
Definition: entity.hpp:100
Mixin type used to add signal support to storage types.
Definition: storage.hpp:949
EnTT default namespace.
constexpr bool operator==(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs)
Compares two hashed strings.
entity
Default entity identifier.
Definition: fwd.hpp:47
std::uint32_t id_type
Alias declaration for type identifiers.
Definition: fwd.hpp:13
constexpr bool operator<=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs)
Compares two hashed strings.
constexpr exclude_t< Type... > exclude
Variable template for exclusion lists.
Definition: utility.hpp:20
constexpr bool operator>=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs)
Compares two hashed strings.
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
Definition: entity.hpp:335
constexpr type_list< Type..., Other... > operator+(type_list< Type... >, type_list< Other... >)
Concatenates multiple type lists.
basic_any< Len, Align > forward_as_any(Type &&value)
Forwards its argument and avoids copies for lvalue references.
Definition: any.hpp:488
constexpr bool operator<(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs)
Compares two hashed strings.
constexpr owned_t< Type... > owned
Variable template for lists of owned components.
Definition: utility.hpp:48
bool operator!=(const basic_any< Len, Align > &lhs, const basic_any< Len, Align > &rhs)
Checks if two wrappers differ in their content.
Definition: any.hpp:406
constexpr bool operator>(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs)
Compares two hashed strings.
Common way to access various properties of components.
Definition: component.hpp:24
Alias for exclusion lists.
Definition: utility.hpp:13
Alias for lists of observed components.
Definition: utility.hpp:27
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:62
const_iterator begin() const
Returns an iterator to the beginning.
Definition: iterator.hpp:86
const_iterator cbegin() const
Returns an iterator to the beginning.
Definition: iterator.hpp:100
Alias for lists of owned components.
Definition: utility.hpp:41
Function object to wrap std::sort in a class type.
Definition: algorithm.hpp:21
Type hash.
Definition: type_info.hpp:100