EnTT  3.6.0
registry.hpp
1 #ifndef ENTT_ENTITY_REGISTRY_HPP
2 #define ENTT_ENTITY_REGISTRY_HPP
3 
4 
5 #include <algorithm>
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 "../core/algorithm.hpp"
16 #include "../core/fwd.hpp"
17 #include "../core/type_info.hpp"
18 #include "../core/type_traits.hpp"
19 #include "entity.hpp"
20 #include "fwd.hpp"
21 #include "group.hpp"
22 #include "poly_storage.hpp"
23 #include "runtime_view.hpp"
24 #include "sparse_set.hpp"
25 #include "storage.hpp"
26 #include "utility.hpp"
27 #include "view.hpp"
28 
29 
30 namespace entt {
31 
32 
43 template<typename Entity>
46  using poly_storage_type = typename poly_storage_traits<Entity>::storage_type;
47 
48  template<typename Component>
49  using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Component>>::storage_type, Component>;
50 
51  struct pool_data {
52  poly_storage_type poly;
53  std::unique_ptr<basic_sparse_set<Entity>> pool{};
54  };
55 
56  template<typename...>
57  struct group_handler;
58 
59  template<typename... Exclude, typename... Get, typename... Owned>
60  struct group_handler<exclude_t<Exclude...>, get_t<Get...>, Owned...> {
61  static_assert(std::conjunction_v<std::is_same<Owned, std::decay_t<Owned>>..., std::is_same<Get, std::decay_t<Get>>..., std::is_same<Exclude, std::decay_t<Exclude>>...>, "One or more component types are invalid");
62  std::conditional_t<sizeof...(Owned) == 0, basic_sparse_set<Entity>, std::size_t> current{};
63 
64  template<typename Component>
65  void maybe_valid_if(basic_registry &owner, const Entity entt) {
66  [[maybe_unused]] const auto cpools = std::make_tuple(owner.assure<Owned>()...);
67 
68  const auto is_valid = ((std::is_same_v<Component, Owned> || std::get<storage_type<Owned> *>(cpools)->contains(entt)) && ...)
69  && ((std::is_same_v<Component, Get> || owner.assure<Get>()->contains(entt)) && ...)
70  && ((std::is_same_v<Component, Exclude> || !owner.assure<Exclude>()->contains(entt)) && ...);
71 
72  if constexpr(sizeof...(Owned) == 0) {
73  if(is_valid && !current.contains(entt)) {
74  current.emplace(entt);
75  }
76  } else {
77  if(is_valid && !(std::get<0>(cpools)->index(entt) < current)) {
78  const auto pos = current++;
79  (std::get<storage_type<Owned> *>(cpools)->swap(std::get<storage_type<Owned> *>(cpools)->data()[pos], entt), ...);
80  }
81  }
82  }
83 
84  void discard_if([[maybe_unused]] basic_registry &owner, const Entity entt) {
85  if constexpr(sizeof...(Owned) == 0) {
86  if(current.contains(entt)) {
87  current.remove(entt);
88  }
89  } else {
90  if(const auto cpools = std::make_tuple(owner.assure<Owned>()...); std::get<0>(cpools)->contains(entt) && (std::get<0>(cpools)->index(entt) < current)) {
91  const auto pos = --current;
92  (std::get<storage_type<Owned> *>(cpools)->swap(std::get<storage_type<Owned> *>(cpools)->data()[pos], entt), ...);
93  }
94  }
95  }
96  };
97 
98  struct group_data {
99  std::size_t size;
100  std::unique_ptr<void, void(*)(void *)> group;
101  bool (* owned)(const id_type) ENTT_NOEXCEPT;
102  bool (* get)(const id_type) ENTT_NOEXCEPT;
103  bool (* exclude)(const id_type) ENTT_NOEXCEPT;
104  };
105 
106  struct variable_data {
107  type_info info;
108  std::unique_ptr<void, void(*)(void *)> value;
109  };
110 
111  template<typename Component>
112  [[nodiscard]] storage_type<Component> * assure() {
113  const auto index = type_seq<Component>::value();
114 
115  if(!(index < pools.size())) {
116  pools.resize(size_type(index)+1u);
117  }
118 
119  if(auto &&pdata = pools[index]; !pdata.pool) {
120  pdata.pool.reset(new storage_type<Component>());
121  pdata.poly = std::ref(*static_cast<storage_type<Component> *>(pdata.pool.get()));
122  }
123 
124  return static_cast<storage_type<Component> *>(pools[index].pool.get());
125  }
126 
127  template<typename Component>
128  [[nodiscard]] const storage_type<Component> * assure() const {
129  const auto index = type_seq<Component>::value();
130  return (!(index < pools.size()) || !pools[index].pool) ? nullptr : static_cast<const storage_type<Component> *>(pools[index].pool.get());
131  }
132 
133  Entity generate_identifier() {
134  // traits_type::entity_mask is reserved to allow for null identifiers
135  ENTT_ASSERT(static_cast<typename traits_type::entity_type>(entities.size()) < traits_type::entity_mask);
136  return entities.emplace_back(entity_type{static_cast<typename traits_type::entity_type>(entities.size())});
137  }
138 
139  Entity recycle_identifier() {
140  ENTT_ASSERT(available != null);
141  const auto curr = to_integral(available);
142  const auto version = to_integral(entities[curr]) & (traits_type::version_mask << traits_type::entity_shift);
143  available = entity_type{to_integral(entities[curr]) & traits_type::entity_mask};
144  return entities[curr] = entity_type{curr | version};
145  }
146 
147  void release_entity(const Entity entity, const typename traits_type::version_type version) {
148  const auto entt = to_integral(entity) & traits_type::entity_mask;
149  entities[entt] = entity_type{to_integral(available) | (typename traits_type::entity_type{version} << traits_type::entity_shift)};
150  available = entity_type{entt};
151  }
152 
153 public:
155  using entity_type = Entity;
157  using version_type = typename traits_type::version_type;
159  using size_type = std::size_t;
162 
164  basic_registry() = default;
165 
168 
171 
176  template<typename Component>
177  void prepare() {
178  // suppress the warning due to the [[nodiscard]] attribute
179  static_cast<void>(assure<Component>());
180  }
181 
189  return info.seq() < pools.size() ? pools[info.seq()].poly : poly_storage{};
190  }
191 
193  poly_storage storage(const type_info info) const {
194  // as_ref forces a constness conversion for the underlying pool
195  return info.seq() < pools.size() ? as_ref(pools[info.seq()].poly) : poly_storage{};
196  }
197 
203  template<typename Component>
204  [[nodiscard]] size_type size() const {
205  const auto *cpool = assure<Component>();
206  return cpool ? cpool->size() : size_type{};
207  }
208 
213  [[nodiscard]] size_type size() const ENTT_NOEXCEPT {
214  return entities.size();
215  }
216 
221  [[nodiscard]] size_type alive() const {
222  auto sz = entities.size();
223  auto curr = available;
224 
225  for(; curr != null; --sz) {
226  curr = entities[to_integral(curr) & traits_type::entity_mask];
227  }
228 
229  return sz;
230  }
231 
245  template<typename... Component>
246  void reserve(const size_type cap) {
247  if constexpr(sizeof...(Component) == 0) {
248  entities.reserve(cap);
249  } else {
250  (assure<Component>()->reserve(cap), ...);
251  }
252  }
253 
258  void reserve_pools(const size_t count) {
259  pools.reserve(count);
260  }
261 
267  template<typename Component>
268  [[nodiscard]] size_type capacity() const {
269  const auto *cpool = assure<Component>();
270  return cpool ? cpool->capacity() : size_type{};
271  }
272 
278  [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT {
279  return entities.capacity();
280  }
281 
287  template<typename... Component>
288  void shrink_to_fit() {
289  (assure<Component>()->shrink_to_fit(), ...);
290  }
291 
303  template<typename... Component>
304  [[nodiscard]] bool empty() const {
305  if constexpr(sizeof...(Component) == 0) {
306  return !alive();
307  } else {
308  return [](auto *... cpool) { return ((!cpool || cpool->empty()) && ...); }(assure<Component>()...);
309  }
310  }
311 
329  template<typename Component>
330  [[nodiscard]] const Component * raw() const {
331  const auto *cpool = assure<Component>();
332  return cpool ? cpool->raw() : nullptr;
333  }
334 
336  template<typename Component>
337  [[nodiscard]] Component * raw() {
338  return assure<Component>()->raw();
339  }
340 
354  template<typename Component>
355  [[nodiscard]] const entity_type * data() const {
356  const auto *cpool = assure<Component>();
357  return cpool ? cpool->data() : nullptr;
358  }
359 
372  [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT {
373  return entities.data();
374  }
375 
384  [[nodiscard]] entity_type destroyed() const ENTT_NOEXCEPT {
385  return available;
386  }
387 
393  [[nodiscard]] bool valid(const entity_type entity) const {
394  const auto pos = size_type(to_integral(entity) & traits_type::entity_mask);
395  return (pos < entities.size() && entities[pos] == entity);
396  }
397 
403  [[nodiscard]] static entity_type entity(const entity_type entity) ENTT_NOEXCEPT {
404  return entity_type{to_integral(entity) & traits_type::entity_mask};
405  }
406 
412  [[nodiscard]] static version_type version(const entity_type entity) ENTT_NOEXCEPT {
413  return version_type(to_integral(entity) >> traits_type::entity_shift);
414  }
415 
427  [[nodiscard]] version_type current(const entity_type entity) const {
428  const auto pos = size_type(to_integral(entity) & traits_type::entity_mask);
429  ENTT_ASSERT(pos < entities.size());
430  return version(entities[pos]);
431  }
432 
444  return available == null ? generate_identifier() : recycle_identifier();
445  }
446 
458  [[nodiscard]] entity_type create(const entity_type hint) {
459  ENTT_ASSERT(hint != null);
461 
462  if(const auto req = (to_integral(hint) & traits_type::entity_mask); !(req < entities.size())) {
463  entities.reserve(size_type(req) + 1u);
464 
465  for(auto pos = entities.size(); pos < req; ++pos) {
466  release_entity(generate_identifier(), {});
467  }
468 
469  entt = entities.emplace_back(hint);
470  } else if(const auto curr = (to_integral(entities[req]) & traits_type::entity_mask); req == curr) {
471  entt = create();
472  } else {
473  auto *it = &available;
474  for(; (to_integral(*it) & traits_type::entity_mask) != req; it = &entities[to_integral(*it) & traits_type::entity_mask]);
475  *it = entity_type{curr | (to_integral(*it) & (traits_type::version_mask << traits_type::entity_shift))};
476  entt = entities[req] = hint;
477  }
478 
479  return entt;
480  }
481 
491  template<typename It>
492  void create(It first, It last) {
493  for(; available != null && first != last; ++first) {
494  *first = recycle_identifier();
495  }
496 
497  for(; first != last; ++first) {
498  *first = generate_identifier();
499  }
500  }
501 
519  template<typename It>
520  void assign(It first, It last, const entity_type destroyed) {
521  ENTT_ASSERT(std::all_of(pools.cbegin(), pools.cend(), [](auto &&pdata) { return !pdata.pool || pdata.pool->empty(); }));
522  entities.assign(first, last);
523  available = destroyed;
524  }
525 
536  void destroy(const entity_type entity) {
537  destroy(entity, static_cast<typename traits_type::version_type>(version(entity) + 1u));
538  }
539 
553  release_entity(entity, version);
554  }
555 
565  template<typename It>
566  void destroy(It first, It last) {
567  for(; first != last; ++first) {
568  destroy(*first);
569  }
570  }
571 
589  template<typename Component, typename... Args>
590  decltype(auto) emplace(const entity_type entity, Args &&... args) {
591  ENTT_ASSERT(valid(entity));
592  return assure<Component>()->emplace(*this, entity, std::forward<Args>(args)...);
593  }
594 
606  template<typename Component, typename It>
607  void insert(It first, It last, const Component &value = {}) {
608  ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }));
609  assure<Component>()->insert(*this, first, last, value);
610  }
611 
625  template<typename Component, typename EIt, typename CIt>
626  void insert(EIt first, EIt last, CIt from, CIt to) {
627  static_assert(std::is_constructible_v<Component, typename std::iterator_traits<CIt>::value_type>, "Invalid value type");
628  ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }));
629  assure<Component>()->insert(*this, first, last, from, to);
630  }
631 
652  template<typename Component, typename... Args>
653  decltype(auto) emplace_or_replace(const entity_type entity, Args &&... args) {
654  ENTT_ASSERT(valid(entity));
655  auto *cpool = assure<Component>();
656 
657  return cpool->contains(entity)
658  ? cpool->patch(*this, entity, [&args...](auto &curr) { curr = Component{std::forward<Args>(args)...}; })
659  : cpool->emplace(*this, entity, std::forward<Args>(args)...);
660  }
661 
686  template<typename Component, typename... Func>
687  decltype(auto) patch(const entity_type entity, Func &&... func) {
688  ENTT_ASSERT(valid(entity));
689  return assure<Component>()->patch(*this, entity, std::forward<Func>(func)...);
690  }
691 
709  template<typename Component, typename... Args>
710  decltype(auto) replace(const entity_type entity, Args &&... args) {
711  return assure<Component>()->patch(*this, entity, [&args...](auto &curr) { curr = Component{std::forward<Args>(args)...}; });
712  }
713 
724  template<typename... Component>
725  void remove(const entity_type entity) {
726  ENTT_ASSERT(valid(entity));
727  static_assert(sizeof...(Component) > 0);
728  (assure<Component>()->remove(*this, entity), ...);
729  }
730 
741  template<typename... Component, typename It>
742  void remove(It first, It last) {
743  ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }));
744  static_assert(sizeof...(Component) > 0);
745  (assure<Component>()->remove(*this, first, last), ...);
746  }
747 
766  template<typename... Component>
768  ENTT_ASSERT(valid(entity));
769 
770  return ([this, entity](auto *cpool) {
771  return cpool->contains(entity) ? (cpool->remove(*this, entity), true) : false;
772  }(assure<Component>()) + ... + size_type{});
773  }
774 
790  ENTT_ASSERT(valid(entity));
791  entity_type wrap[1u]{entity};
792 
793  for(auto pos = pools.size(); pos; --pos) {
794  if(auto &pdata = pools[pos-1]; pdata.pool && pdata.pool->contains(entity)) {
795  pdata.poly->remove(*this, std::begin(wrap), std::end(wrap));
796  }
797  }
798  }
799 
810  template<typename... Component>
811  [[nodiscard]] bool has(const entity_type entity) const {
812  ENTT_ASSERT(valid(entity));
813  return [entity](auto *... cpool) { return ((cpool && cpool->contains(entity)) && ...); }(assure<Component>()...);
814  }
815 
827  template<typename... Component>
828  [[nodiscard]] bool any(const entity_type entity) const {
829  ENTT_ASSERT(valid(entity));
830  return (has<Component>(entity) || ...);
831  }
832 
844  template<typename... Component>
845  [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entity) const {
846  ENTT_ASSERT(valid(entity));
847 
848  if constexpr(sizeof...(Component) == 1) {
849  return (assure<Component>()->get(entity), ...);
850  } else {
851  return std::forward_as_tuple(assure<Component>()->get(entity)...);
852  }
853  }
854 
856  template<typename... Component>
857  [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entity) {
858  ENTT_ASSERT(valid(entity));
859 
860  if constexpr(sizeof...(Component) == 1) {
861  return (assure<Component>()->get(entity), ...);
862  } else {
863  return std::forward_as_tuple(assure<Component>()->get(entity)...);
864  }
865  }
866 
889  template<typename Component, typename... Args>
890  [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entity, Args &&... args) {
891  ENTT_ASSERT(valid(entity));
892  auto *cpool = assure<Component>();
893  return cpool->contains(entity) ? cpool->get(entity) : cpool->emplace(*this, entity, std::forward<Args>(args)...);
894  }
895 
909  template<typename... Component>
910  [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entity) const {
911  ENTT_ASSERT(valid(entity));
912 
913  if constexpr(sizeof...(Component) == 1) {
914  auto *cpool = assure<Component...>();
915  return (cpool && cpool->contains(entity)) ? &cpool->get(entity) : nullptr;
916  } else {
917  return std::make_tuple(try_get<Component>(entity)...);
918  }
919  }
920 
922  template<typename... Component>
923  [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entity) {
924  ENTT_ASSERT(valid(entity));
925 
926  if constexpr(sizeof...(Component) == 1) {
927  auto *cpool = assure<Component...>();
928  return cpool->contains(entity) ? &cpool->get(entity) : nullptr;
929  } else {
930  return std::make_tuple(try_get<Component>(entity)...);
931  }
932  }
933 
938  template<typename... Component>
939  void clear() {
940  if constexpr(sizeof...(Component) == 0) {
941  for(auto pos = pools.size(); pos; --pos) {
942  if(auto &pdata = pools[pos-1]; pdata.pool) {
943  pdata.poly->remove(*this, pdata.pool->rbegin(), pdata.pool->rend());
944  }
945  }
946 
947  for(auto pos = entities.size(); pos; --pos) {
948  if(const auto entt = entities[pos - 1]; (to_integral(entt) & traits_type::entity_mask) == (pos - 1)) {
949  release_entity(entt, version(entt) + 1u);
950  }
951  }
952  } else {
953  ([this](auto *cpool) {
954  cpool->remove(*this, cpool->basic_sparse_set<entity_type>::begin(), cpool->basic_sparse_set<entity_type>::end());
955  }(assure<Component>()), ...);
956  }
957  }
958 
976  template<typename Func>
977  void each(Func func) const {
978  if(available == null) {
979  for(auto pos = entities.size(); pos; --pos) {
980  func(entities[pos-1]);
981  }
982  } else {
983  for(auto pos = entities.size(); pos; --pos) {
984  if(const auto entt = entities[pos - 1]; (to_integral(entt) & traits_type::entity_mask) == (pos - 1)) {
985  func(entt);
986  }
987  }
988  }
989  }
990 
996  [[nodiscard]] bool orphan(const entity_type entity) const {
997  ENTT_ASSERT(valid(entity));
998  return std::none_of(pools.cbegin(), pools.cend(), [entity](auto &&pdata) { return pdata.pool && pdata.pool->contains(entity); });
999  }
1000 
1017  template<typename Func>
1018  void orphans(Func func) const {
1019  each([this, &func](const auto entity) {
1020  if(orphan(entity)) {
1021  func(entity);
1022  }
1023  });
1024  }
1025 
1046  template<typename Component>
1047  [[nodiscard]] auto on_construct() {
1048  return assure<Component>()->on_construct();
1049  }
1050 
1069  template<typename Component>
1070  [[nodiscard]] auto on_update() {
1071  return assure<Component>()->on_update();
1072  }
1073 
1094  template<typename Component>
1095  [[nodiscard]] auto on_destroy() {
1096  return assure<Component>()->on_destroy();
1097  }
1098 
1131  template<typename... Component, typename... Exclude>
1132  [[nodiscard]] basic_view<Entity, exclude_t<Exclude...>, Component...> view(exclude_t<Exclude...> = {}) const {
1133  static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported");
1134  using view_type = basic_view<Entity, exclude_t<Exclude...>, Component...>;
1135  return [](auto *... cpools) { return (cpools && ...) ? view_type{*cpools...} : view_type{}; }(assure<std::decay_t<Component>>()..., assure<Exclude>()...);
1136  }
1137 
1139  template<typename... Component, typename... Exclude>
1140  [[nodiscard]] basic_view<Entity, exclude_t<Exclude...>, Component...> view(exclude_t<Exclude...> = {}) {
1141  static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported");
1142  return { *assure<std::decay_t<Component>>()..., *assure<Exclude>()... };
1143  }
1144 
1173  template<typename ItComp, typename ItExcl = id_type *>
1174  [[nodiscard]] basic_runtime_view<Entity> runtime_view(ItComp first, ItComp last, ItExcl from = {}, ItExcl to = {}) const {
1175  std::vector<const basic_sparse_set<Entity> *> component(std::distance(first, last));
1176  std::vector<const basic_sparse_set<Entity> *> filter(std::distance(from, to));
1177 
1178  std::transform(first, last, component.begin(), [this](const auto ctype) {
1179  const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto &&pdata) { return pdata.poly && pdata.poly->value_type().hash() == ctype; });
1180  return it == pools.cend() ? nullptr : it->pool.get();
1181  });
1182 
1183  std::transform(from, to, filter.begin(), [this](const auto ctype) {
1184  const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto &&pdata) { return pdata.poly && pdata.poly->value_type().hash() == ctype; });
1185  return it == pools.cend() ? nullptr : it->pool.get();
1186  });
1187 
1188  return { std::move(component), std::move(filter) };
1189  }
1190 
1218  template<typename... Owned, typename... Get, typename... Exclude>
1219  [[nodiscard]] basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> group(get_t<Get...>, exclude_t<Exclude...> = {}) {
1220  static_assert(sizeof...(Owned) + sizeof...(Get) > 0, "Exclusion-only groups are not supported");
1221  static_assert(sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude) > 1, "Single component groups are not allowed");
1222 
1223  using handler_type = group_handler<exclude_t<Exclude...>, get_t<std::decay_t<Get>...>, std::decay_t<Owned>...>;
1224 
1225  const auto cpools = std::make_tuple(assure<std::decay_t<Owned>>()..., assure<std::decay_t<Get>>()...);
1226  constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
1227  handler_type *handler = nullptr;
1228 
1229  if(auto it = std::find_if(groups.cbegin(), groups.cend(), [size](const auto &gdata) {
1230  return gdata.size == size
1231  && (gdata.owned(type_hash<std::decay_t<Owned>>::value()) && ...)
1232  && (gdata.get(type_hash<std::decay_t<Get>>::value()) && ...)
1233  && (gdata.exclude(type_hash<Exclude>::value()) && ...);
1234  }); it != groups.cend())
1235  {
1236  handler = static_cast<handler_type *>(it->group.get());
1237  }
1238 
1239  if(!handler) {
1240  group_data candidate = {
1241  size,
1242  { new handler_type{}, [](void *instance) { delete static_cast<handler_type *>(instance); } },
1243  []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash<std::decay_t<Owned>>::value()) || ...); },
1244  []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash<std::decay_t<Get>>::value()) || ...); },
1245  []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash<Exclude>::value()) || ...); },
1246  };
1247 
1248  handler = static_cast<handler_type *>(candidate.group.get());
1249 
1250  const void *maybe_valid_if = nullptr;
1251  const void *discard_if = nullptr;
1252 
1253  if constexpr(sizeof...(Owned) == 0) {
1254  groups.push_back(std::move(candidate));
1255  } else {
1256  ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [size](const auto &gdata) {
1257  const auto overlapping = (0u + ... + gdata.owned(type_hash<std::decay_t<Owned>>::value()));
1258  const auto sz = overlapping + (0u + ... + gdata.get(type_hash<std::decay_t<Get>>::value())) + (0u + ... + gdata.exclude(type_hash<Exclude>::value()));
1259  return !overlapping || ((sz == size) || (sz == gdata.size));
1260  }));
1261 
1262  const auto next = std::find_if_not(groups.cbegin(), groups.cend(), [size](const auto &gdata) {
1263  return !(0u + ... + gdata.owned(type_hash<std::decay_t<Owned>>::value())) || (size > gdata.size);
1264  });
1265 
1266  const auto prev = std::find_if(std::make_reverse_iterator(next), groups.crend(), [](const auto &gdata) {
1267  return (0u + ... + gdata.owned(type_hash<std::decay_t<Owned>>::value()));
1268  });
1269 
1270  maybe_valid_if = (next == groups.cend() ? maybe_valid_if : next->group.get());
1271  discard_if = (prev == groups.crend() ? discard_if : prev->group.get());
1272  groups.insert(next, std::move(candidate));
1273  }
1274 
1275  (on_construct<std::decay_t<Owned>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::decay_t<Owned>>>(*handler), ...);
1276  (on_construct<std::decay_t<Get>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::decay_t<Get>>>(*handler), ...);
1277  (on_destroy<Exclude>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<Exclude>>(*handler), ...);
1278 
1279  (on_destroy<std::decay_t<Owned>>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
1280  (on_destroy<std::decay_t<Get>>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
1281  (on_construct<Exclude>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
1282 
1283  if constexpr(sizeof...(Owned) == 0) {
1284  for(const auto entity: view<Owned..., Get...>(exclude<Exclude...>)) {
1285  handler->current.emplace(entity);
1286  }
1287  } else {
1288  // we cannot iterate backwards because we want to leave behind valid entities in case of owned types
1289  for(auto *first = std::get<0>(cpools)->data(), *last = first + std::get<0>(cpools)->size(); first != last; ++first) {
1290  handler->template maybe_valid_if<type_list_element_t<0, type_list<std::decay_t<Owned>...>>>(*this, *first);
1291  }
1292  }
1293  }
1294 
1295  return { handler->current, *std::get<storage_type<std::decay_t<Owned>> *>(cpools)..., *std::get<storage_type<std::decay_t<Get>> *>(cpools)... };
1296  }
1297 
1308  template<typename... Owned, typename... Get, typename... Exclude>
1309  [[nodiscard]] basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> group_if_exists(get_t<Get...>, exclude_t<Exclude...> = {}) const {
1310  static_assert(std::conjunction_v<std::is_const<Owned>..., std::is_const<Get>...>, "Invalid non-const type");
1311 
1312  if(auto it = std::find_if(groups.cbegin(), groups.cend(), [](const auto &gdata) {
1313  return gdata.size == (sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude))
1314  && (gdata.owned(type_hash<std::decay_t<Owned>>::value()) && ...)
1315  && (gdata.get(type_hash<std::decay_t<Get>>::value()) && ...)
1316  && (gdata.exclude(type_hash<Exclude>::value()) && ...);
1317  }); it == groups.cend())
1318  {
1319  return {};
1320  } else {
1321  using handler_type = group_handler<exclude_t<Exclude...>, get_t<std::decay_t<Get>...>, std::decay_t<Owned>...>;
1322  return { static_cast<handler_type *>(it->group.get())->current, *assure<std::decay_t<Owned>>()... , *assure<std::decay_t<Get>>()... };
1323  }
1324  }
1325 
1335  template<typename... Owned, typename... Exclude>
1336  [[nodiscard]] basic_group<Entity, exclude_t<Exclude...>, get_t<>, Owned...> group(exclude_t<Exclude...> = {}) {
1337  return group<Owned...>(get_t<>{}, exclude<Exclude...>);
1338  }
1339 
1349  template<typename... Owned, typename... Exclude>
1350  [[nodiscard]] basic_group<Entity, exclude_t<Exclude...>, get_t<>, Owned...> group_if_exists(exclude_t<Exclude...> = {}) const {
1351  return group_if_exists<Owned...>(get_t<>{}, exclude<Exclude...>);
1352  }
1353 
1360  template<typename... Component>
1361  [[nodiscard]] bool sortable() const {
1362  return std::none_of(groups.cbegin(), groups.cend(), [](auto &&gdata) { return (gdata.owned(type_hash<std::decay_t<Component>>::value()) || ...); });
1363  }
1364 
1372  template<typename... Owned, typename... Get, typename... Exclude>
1373  [[nodiscard]] bool sortable(const basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> &) ENTT_NOEXCEPT {
1374  constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
1375  return std::find_if(groups.cbegin(), groups.cend(), [size](const auto &gdata) {
1376  return (0u + ... + gdata.owned(type_hash<std::decay_t<Owned>>::value())) && (size < gdata.size);
1377  }) == groups.cend();
1378  }
1379 
1425  template<typename Component, typename Compare, typename Sort = std_sort, typename... Args>
1426  void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
1427  ENTT_ASSERT(sortable<Component>());
1428  assure<Component>()->sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
1429  }
1430 
1464  template<typename To, typename From>
1465  void sort() {
1466  ENTT_ASSERT(sortable<To>());
1467  assure<To>()->respect(*assure<From>());
1468  }
1469 
1491  template<typename Func>
1492  void visit(entity_type entity, Func func) const {
1493  for(auto pos = pools.size(); pos; --pos) {
1494  if(const auto &pdata = pools[pos-1]; pdata.pool && pdata.pool->contains(entity)) {
1495  func(pdata.poly->value_type());
1496  }
1497  }
1498  }
1499 
1520  template<typename Func>
1521  void visit(Func func) const {
1522  for(auto pos = pools.size(); pos; --pos) {
1523  if(const auto &pdata = pools[pos-1]; pdata.pool) {
1524  func(pdata.poly->value_type());
1525  }
1526  }
1527  }
1528 
1540  template<typename Type, typename... Args>
1541  Type & set(Args &&... args) {
1542  unset<Type>();
1543  vars.push_back(variable_data{type_id<Type>(), { new Type{std::forward<Args>(args)...}, [](void *instance) { delete static_cast<Type *>(instance); } }});
1544  return *static_cast<Type *>(vars.back().value.get());
1545  }
1546 
1551  template<typename Type>
1552  void unset() {
1553  vars.erase(std::remove_if(vars.begin(), vars.end(), [](auto &&var) {
1554  return var.info.hash() == type_hash<Type>::value();
1555  }), vars.end());
1556  }
1557 
1569  template<typename Type, typename... Args>
1570  [[nodiscard]] Type & ctx_or_set(Args &&... args) {
1571  auto *value = try_ctx<Type>();
1572  return value ? *value : set<Type>(std::forward<Args>(args)...);
1573  }
1574 
1581  template<typename Type>
1582  [[nodiscard]] const Type * try_ctx() const {
1583  auto it = std::find_if(vars.cbegin(), vars.cend(), [](auto &&var) { return var.info.hash() == type_hash<Type>::value(); });
1584  return it == vars.cend() ? nullptr : static_cast<const Type *>(it->value.get());
1585  }
1586 
1588  template<typename Type>
1589  [[nodiscard]] Type * try_ctx() {
1590  return const_cast<Type *>(std::as_const(*this).template try_ctx<Type>());
1591  }
1592 
1603  template<typename Type>
1604  [[nodiscard]] const Type & ctx() const {
1605  const auto *instance = try_ctx<Type>();
1606  ENTT_ASSERT(instance);
1607  return *instance;
1608  }
1609 
1611  template<typename Type>
1612  [[nodiscard]] Type & ctx() {
1613  return const_cast<Type &>(std::as_const(*this).template ctx<Type>());
1614  }
1615 
1637  template<typename Func>
1638  void ctx(Func func) const {
1639  for(auto pos = vars.size(); pos; --pos) {
1640  func(vars[pos-1].info);
1641  }
1642  }
1643 
1644 private:
1645  std::vector<pool_data> pools{};
1646  std::vector<group_data> groups{};
1647  std::vector<entity_type> entities{};
1648  std::vector<variable_data> vars{};
1649  entity_type available{null};
1650 };
1651 
1652 
1653 }
1654 
1655 
1656 #endif
entt::basic_registry::storage
poly_storage storage(const type_info info)
Returns a poly storage for a given type.
Definition: registry.hpp:188
entt::basic_registry::raw
Component * raw()
Direct access to the list of components of a given pool.
Definition: registry.hpp:337
entt::basic_registry::remove_if_exists
size_type remove_if_exists(const entity_type entity)
Removes the given components from an entity.
Definition: registry.hpp:767
entt::basic_registry::clear
void clear()
Clears a whole registry or the pools for the given components.
Definition: registry.hpp:939
entt::basic_registry::create
entity_type create()
Creates a new entity and returns it.
Definition: registry.hpp:443
entt::basic_registry::entity
static entity_type entity(const entity_type entity) noexcept
Returns the entity identifier without the version.
Definition: registry.hpp:403
entt::basic_registry::ctx_or_set
Type & ctx_or_set(Args &&... args)
Binds an object to the context of the registry.
Definition: registry.hpp:1570
entt::basic_registry::set
Type & set(Args &&... args)
Binds an object to the context of the registry.
Definition: registry.hpp:1541
entt::type_seq::value
static id_type value() noexcept
Returns the sequential identifier of a given type.
Definition: type_info.hpp:96
entt::basic_registry::operator=
basic_registry & operator=(basic_registry &&)=default
Default move assignment operator.
entt::basic_registry::data
const entity_type * data() const
Direct access to the list of entities of a given pool.
Definition: registry.hpp:355
entt::basic_registry::sort
void sort()
Sorts two pools of components in the same way.
Definition: registry.hpp:1465
entt::exclude
constexpr exclude_t< Type... > exclude
Variable template for exclusion lists.
Definition: utility.hpp:24
entt::basic_registry::group
basic_group< Entity, exclude_t< Exclude... >, get_t< Get... >, Owned... > group(get_t< Get... >, exclude_t< Exclude... >={})
Returns a group for the given components.
Definition: registry.hpp:1219
entt::basic_registry::alive
size_type alive() const
Returns the number of entities still in use.
Definition: registry.hpp:221
entt::basic_registry::destroy
void destroy(const entity_type entity, const version_type version)
Destroys an entity.
Definition: registry.hpp:551
entt::basic_registry::create
entity_type create(const entity_type hint)
Creates a new entity and returns it.
Definition: registry.hpp:458
entt::to_integral
constexpr auto to_integral(const Entity entity) noexcept
Converts an entity type to its underlying type.
Definition: entity.hpp:93
entt::basic_registry::shrink_to_fit
void shrink_to_fit()
Requests the removal of unused capacity for the given components.
Definition: registry.hpp:288
entt::basic_registry::group_if_exists
basic_group< Entity, exclude_t< Exclude... >, get_t<>, Owned... > group_if_exists(exclude_t< Exclude... >={}) const
Returns a group for the given components.
Definition: registry.hpp:1350
entt::basic_registry::prepare
void prepare()
Prepares a pool for the given type if required.
Definition: registry.hpp:177
entt::basic_registry::ctx
const Type & ctx() const
Returns a reference to an object in the context of the registry.
Definition: registry.hpp:1604
entt::basic_registry::sortable
bool sortable() const
Checks whether the given components belong to any group.
Definition: registry.hpp:1361
entt::basic_registry::on_update
auto on_update()
Returns a sink object for the given component.
Definition: registry.hpp:1070
entt::get
constexpr get_t< Type... > get
Variable template for lists of observed components.
Definition: utility.hpp:40
entt::basic_registry::visit
void visit(Func func) const
Visits a registry and returns the type info for its components.
Definition: registry.hpp:1521
entt::basic_runtime_view
Runtime view.
Definition: runtime_view.hpp:57
entt::exclude_t
Alias for exclusion lists.
Definition: utility.hpp:16
entt::basic_registry::remove
void remove(It first, It last)
Removes the given components from all the entities in a range.
Definition: registry.hpp:742
entt::basic_registry::assign
void assign(It first, It last, const entity_type destroyed)
Assigns entities to an empty registry.
Definition: registry.hpp:520
entt::basic_registry::capacity
size_type capacity() const noexcept
Returns the number of entities that a registry has currently allocated space for.
Definition: registry.hpp:278
entt::type_hash
Type hash.
Definition: type_info.hpp:108
entt::basic_registry::version
static version_type version(const entity_type entity) noexcept
Returns the version stored along with an entity identifier.
Definition: registry.hpp:412
entt::poly_storage_traits
Defines the poly storage type associate with a given entity type.
Definition: poly_storage.hpp:74
entt::basic_registry::destroy
void destroy(const entity_type entity)
Destroys an entity.
Definition: registry.hpp:536
entt::basic_registry::view
basic_view< Entity, exclude_t< Exclude... >, Component... > view(exclude_t< Exclude... >={})
Returns a view for the given components.
Definition: registry.hpp:1140
entt::id_type
std::uint32_t id_type
Alias declaration for type identifiers.
Definition: fwd.hpp:12
entt::basic_registry::size
size_type size() const
Returns the number of existing components of the given type.
Definition: registry.hpp:204
entt::basic_group
Group.
Definition: fwd.hpp:32
entt::basic_registry::empty
bool empty() const
Checks whether the registry or the pools of the given components are empty.
Definition: registry.hpp:304
entt::basic_registry::on_construct
auto on_construct()
Returns a sink object for the given component.
Definition: registry.hpp:1047
entt::basic_registry< entity_type >::poly_storage
typename poly_storage_traits< entity_type >::storage_type poly_storage
Poly storage type.
Definition: registry.hpp:161
entt::basic_registry::create
void create(It first, It last)
Assigns each element in a range an entity.
Definition: registry.hpp:492
entt::basic_registry::each
void each(Func func) const
Iterates all the entities that are still in use.
Definition: registry.hpp:977
entt::basic_registry::orphan
bool orphan(const entity_type entity) const
Checks if an entity has components assigned.
Definition: registry.hpp:996
entt::basic_registry::orphans
void orphans(Func func) const
Iterates orphans and applies them the given function object.
Definition: registry.hpp:1018
entt::basic_registry::visit
void visit(entity_type entity, Func func) const
Visits an entity and returns the type info for its components.
Definition: registry.hpp:1492
entt::basic_registry::try_ctx
const Type * try_ctx() const
Returns a pointer to an object in the context of the registry.
Definition: registry.hpp:1582
entt::basic_registry::basic_registry
basic_registry()=default
Default constructor.
entt::basic_registry::insert
void insert(EIt first, EIt last, CIt from, CIt to)
Assigns each entity in a range the given components.
Definition: registry.hpp:626
entt::basic_registry::group_if_exists
basic_group< Entity, exclude_t< Exclude... >, get_t< Get... >, Owned... > group_if_exists(get_t< Get... >, exclude_t< Exclude... >={}) const
Returns a group for the given components.
Definition: registry.hpp:1309
entt
EnTT default namespace.
Definition: algorithm.hpp:13
entt::basic_registry::emplace
decltype(auto) emplace(const entity_type entity, Args &&... args)
Assigns the given component to an entity.
Definition: registry.hpp:590
entt::basic_registry::size
size_type size() const noexcept
Returns the number of entities created so far.
Definition: registry.hpp:213
entt::basic_sparse_set
Basic sparse set implementation.
Definition: sparse_set.hpp:43
entt::basic_registry::sortable
bool sortable(const basic_group< Entity, exclude_t< Exclude... >, get_t< Get... >, Owned... > &) noexcept
Checks whether a group can be sorted.
Definition: registry.hpp:1373
entt::basic_registry::insert
void insert(It first, It last, const Component &value={})
Assigns each entity in a range the given component.
Definition: registry.hpp:607
entt::poly
Static polymorphism made simple and within everyone's reach.
Definition: poly.hpp:176
entt::basic_registry::on_destroy
auto on_destroy()
Returns a sink object for the given component.
Definition: registry.hpp:1095
entt::get_t
Alias for lists of observed components.
Definition: utility.hpp:32
entt::basic_registry::any
bool any(const entity_type entity) const
Checks if an entity has at least one of the given components.
Definition: registry.hpp:828
entt::basic_registry::current
version_type current(const entity_type entity) const
Returns the actual version for an entity identifier.
Definition: registry.hpp:427
entt::basic_registry::basic_registry
basic_registry(basic_registry &&)=default
Default move constructor.
entt::basic_registry::capacity
size_type capacity() const
Returns the capacity of the pool for the given component.
Definition: registry.hpp:268
entt::basic_registry::reserve
void reserve(const size_type cap)
Increases the capacity of the registry or of the pools for the given components.
Definition: registry.hpp:246
entt::type_info::seq
id_type seq() const noexcept
Type sequential identifier.
Definition: type_info.hpp:186
entt::basic_registry::storage
poly_storage storage(const type_info info) const
Returns a poly storage for a given type.
Definition: registry.hpp:193
entt::basic_registry::destroyed
entity_type destroyed() const noexcept
Returns the head of the list of destroyed entities.
Definition: registry.hpp:384
entt::basic_registry::emplace_or_replace
decltype(auto) emplace_or_replace(const entity_type entity, Args &&... args)
Assigns or replaces the given component for an entity.
Definition: registry.hpp:653
entt::basic_registry
Fast and reliable entity-component system.
Definition: registry.hpp:44
entt::basic_registry::view
basic_view< Entity, exclude_t< Exclude... >, Component... > view(exclude_t< Exclude... >={}) const
Returns a view for the given components.
Definition: registry.hpp:1132
entt::basic_registry::get
decltype(auto) get([[maybe_unused]] const entity_type entity) const
Returns references to the given components for an entity.
Definition: registry.hpp:845
entt::basic_registry::try_get
auto try_get([[maybe_unused]] const entity_type entity)
Returns pointers to the given components for an entity.
Definition: registry.hpp:923
entt::type_info
Implementation specific information about a type.
Definition: type_info.hpp:141
entt::entt_traits
Entity traits.
Definition: entity.hpp:21
entt::basic_registry::has
bool has(const entity_type entity) const
Checks if an entity has all the given components.
Definition: registry.hpp:811
entt::basic_registry::data
const entity_type * data() const noexcept
Direct access to the list of entities of a registry.
Definition: registry.hpp:372
entt::basic_registry::group
basic_group< Entity, exclude_t< Exclude... >, get_t<>, Owned... > group(exclude_t< Exclude... >={})
Returns a group for the given components.
Definition: registry.hpp:1336
entt::basic_registry::runtime_view
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:1174
entt::basic_registry::reserve_pools
void reserve_pools(const size_t count)
Reserves enough space to store count pools.
Definition: registry.hpp:258
entt::basic_registry::destroy
void destroy(It first, It last)
Destroys all the entities in a range.
Definition: registry.hpp:566
entt::basic_registry::ctx
void ctx(Func func) const
Visits a registry and returns the type info for its context variables.
Definition: registry.hpp:1638
entt::basic_registry::valid
bool valid(const entity_type entity) const
Checks if an entity identifier refers to a valid entity.
Definition: registry.hpp:393
entt::basic_view
View.
Definition: fwd.hpp:24
entt::basic_registry::try_get
auto try_get([[maybe_unused]] const entity_type entity) const
Returns pointers to the given components for an entity.
Definition: registry.hpp:910
entt::basic_registry::remove_all
void remove_all(const entity_type entity)
Removes all the components from an entity and makes it orphaned.
Definition: registry.hpp:789
entt::basic_registry::ctx
Type & ctx()
Returns a reference to an object in the context of the registry.
Definition: registry.hpp:1612
entt::basic_registry::size_type
std::size_t size_type
Unsigned integer type.
Definition: registry.hpp:159
entt::basic_registry::sort
void sort(Compare compare, Sort algo=Sort{}, Args &&... args)
Sorts the pool of entities for the given component.
Definition: registry.hpp:1426
entt::entity
entity
Default entity identifier.
Definition: fwd.hpp:60
entt::constness_as_t
typename constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
Definition: type_traits.hpp:549
entt::basic_registry::raw
const Component * raw() const
Direct access to the list of components of a given pool.
Definition: registry.hpp:330
entt::basic_registry::unset
void unset()
Unsets a context variable if it exists.
Definition: registry.hpp:1552
entt::basic_registry::entity_type
Entity entity_type
Underlying entity identifier.
Definition: registry.hpp:155
entt::std_sort
Function object to wrap std::sort in a class type.
Definition: algorithm.hpp:24
entt::basic_registry::remove
void remove(const entity_type entity)
Removes the given components from an entity.
Definition: registry.hpp:725
entt::basic_registry::try_ctx
Type * try_ctx()
Returns a pointer to an object in the context of the registry.
Definition: registry.hpp:1589
entt::basic_registry< entity_type >::version_type
typename traits_type::version_type version_type
Underlying version type.
Definition: registry.hpp:157