registry.hpp 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205
  1. #ifndef ENTT_ENTITY_REGISTRY_HPP
  2. #define ENTT_ENTITY_REGISTRY_HPP
  3. #include <algorithm>
  4. #include <cstddef>
  5. #include <functional>
  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_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/memory.hpp"
  19. #include "../core/type_info.hpp"
  20. #include "../core/type_traits.hpp"
  21. #include "../core/utility.hpp"
  22. #include "entity.hpp"
  23. #include "fwd.hpp"
  24. #include "group.hpp"
  25. #include "mixin.hpp"
  26. #include "sparse_set.hpp"
  27. #include "storage.hpp"
  28. #include "view.hpp"
  29. namespace entt {
  30. /**
  31. * @cond TURN_OFF_DOXYGEN
  32. * Internal details not to be documented.
  33. */
  34. namespace internal {
  35. template<typename It>
  36. class registry_storage_iterator final {
  37. template<typename Other>
  38. friend class registry_storage_iterator;
  39. using mapped_type = std::remove_reference_t<decltype(std::declval<It>()->second)>;
  40. public:
  41. using value_type = std::pair<id_type, constness_as_t<typename mapped_type::element_type, mapped_type> &>;
  42. using pointer = input_iterator_pointer<value_type>;
  43. using reference = value_type;
  44. using difference_type = std::ptrdiff_t;
  45. using iterator_category = std::input_iterator_tag;
  46. using iterator_concept = std::random_access_iterator_tag;
  47. constexpr registry_storage_iterator() noexcept
  48. : it{} {}
  49. constexpr registry_storage_iterator(It iter) noexcept
  50. : it{iter} {}
  51. template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
  52. constexpr registry_storage_iterator(const registry_storage_iterator<Other> &other) noexcept
  53. : registry_storage_iterator{other.it} {}
  54. constexpr registry_storage_iterator &operator++() noexcept {
  55. return ++it, *this;
  56. }
  57. constexpr registry_storage_iterator operator++(int) noexcept {
  58. registry_storage_iterator orig = *this;
  59. return ++(*this), orig;
  60. }
  61. constexpr registry_storage_iterator &operator--() noexcept {
  62. return --it, *this;
  63. }
  64. constexpr registry_storage_iterator operator--(int) noexcept {
  65. registry_storage_iterator orig = *this;
  66. return operator--(), orig;
  67. }
  68. constexpr registry_storage_iterator &operator+=(const difference_type value) noexcept {
  69. it += value;
  70. return *this;
  71. }
  72. constexpr registry_storage_iterator operator+(const difference_type value) const noexcept {
  73. registry_storage_iterator copy = *this;
  74. return (copy += value);
  75. }
  76. constexpr registry_storage_iterator &operator-=(const difference_type value) noexcept {
  77. return (*this += -value);
  78. }
  79. constexpr registry_storage_iterator operator-(const difference_type value) const noexcept {
  80. return (*this + -value);
  81. }
  82. [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
  83. return {it[value].first, *it[value].second};
  84. }
  85. [[nodiscard]] constexpr reference operator*() const noexcept {
  86. return {it->first, *it->second};
  87. }
  88. [[nodiscard]] constexpr pointer operator->() const noexcept {
  89. return operator*();
  90. }
  91. template<typename Lhs, typename Rhs>
  92. friend constexpr std::ptrdiff_t operator-(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
  93. template<typename Lhs, typename Rhs>
  94. friend constexpr bool operator==(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
  95. template<typename Lhs, typename Rhs>
  96. friend constexpr bool operator<(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
  97. private:
  98. It it;
  99. };
  100. template<typename Lhs, typename Rhs>
  101. [[nodiscard]] constexpr std::ptrdiff_t operator-(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
  102. return lhs.it - rhs.it;
  103. }
  104. template<typename Lhs, typename Rhs>
  105. [[nodiscard]] constexpr bool operator==(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
  106. return lhs.it == rhs.it;
  107. }
  108. template<typename Lhs, typename Rhs>
  109. [[nodiscard]] constexpr bool operator!=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
  110. return !(lhs == rhs);
  111. }
  112. template<typename Lhs, typename Rhs>
  113. [[nodiscard]] constexpr bool operator<(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
  114. return lhs.it < rhs.it;
  115. }
  116. template<typename Lhs, typename Rhs>
  117. [[nodiscard]] constexpr bool operator>(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
  118. return rhs < lhs;
  119. }
  120. template<typename Lhs, typename Rhs>
  121. [[nodiscard]] constexpr bool operator<=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
  122. return !(lhs > rhs);
  123. }
  124. template<typename Lhs, typename Rhs>
  125. [[nodiscard]] constexpr bool operator>=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
  126. return !(lhs < rhs);
  127. }
  128. template<typename Allocator>
  129. class registry_context {
  130. using alloc_traits = std::allocator_traits<Allocator>;
  131. using allocator_type = typename alloc_traits::template rebind_alloc<std::pair<const id_type, basic_any<0u>>>;
  132. public:
  133. explicit registry_context(const allocator_type &allocator)
  134. : ctx{allocator} {}
  135. template<typename Type, typename... Args>
  136. Type &emplace_as(const id_type id, Args &&...args) {
  137. return any_cast<Type &>(ctx.try_emplace(id, std::in_place_type<Type>, std::forward<Args>(args)...).first->second);
  138. }
  139. template<typename Type, typename... Args>
  140. Type &emplace(Args &&...args) {
  141. return emplace_as<Type>(type_id<Type>().hash(), std::forward<Args>(args)...);
  142. }
  143. template<typename Type>
  144. Type &insert_or_assign(const id_type id, Type &&value) {
  145. return any_cast<std::remove_cv_t<std::remove_reference_t<Type>> &>(ctx.insert_or_assign(id, std::forward<Type>(value)).first->second);
  146. }
  147. template<typename Type>
  148. Type &insert_or_assign(Type &&value) {
  149. return insert_or_assign(type_id<Type>().hash(), std::forward<Type>(value));
  150. }
  151. template<typename Type>
  152. bool erase(const id_type id = type_id<Type>().hash()) {
  153. const auto it = ctx.find(id);
  154. return it != ctx.end() && it->second.type() == type_id<Type>() ? (ctx.erase(it), true) : false;
  155. }
  156. template<typename Type>
  157. [[nodiscard]] const Type &get(const id_type id = type_id<Type>().hash()) const {
  158. return any_cast<const Type &>(ctx.at(id));
  159. }
  160. template<typename Type>
  161. [[nodiscard]] Type &get(const id_type id = type_id<Type>().hash()) {
  162. return any_cast<Type &>(ctx.at(id));
  163. }
  164. template<typename Type>
  165. [[nodiscard]] const Type *find(const id_type id = type_id<Type>().hash()) const {
  166. const auto it = ctx.find(id);
  167. return it != ctx.cend() ? any_cast<const Type>(&it->second) : nullptr;
  168. }
  169. template<typename Type>
  170. [[nodiscard]] Type *find(const id_type id = type_id<Type>().hash()) {
  171. const auto it = ctx.find(id);
  172. return it != ctx.end() ? any_cast<Type>(&it->second) : nullptr;
  173. }
  174. template<typename Type>
  175. [[nodiscard]] bool contains(const id_type id = type_id<Type>().hash()) const {
  176. const auto it = ctx.find(id);
  177. return it != ctx.cend() && it->second.type() == type_id<Type>();
  178. }
  179. private:
  180. dense_map<id_type, basic_any<0u>, identity, std::equal_to<id_type>, allocator_type> ctx;
  181. };
  182. } // namespace internal
  183. /**
  184. * Internal details not to be documented.
  185. * @endcond
  186. */
  187. /**
  188. * @brief Fast and reliable entity-component system.
  189. * @tparam Entity A valid entity type.
  190. * @tparam Allocator Type of allocator used to manage memory and elements.
  191. */
  192. template<typename Entity, typename Allocator>
  193. class basic_registry {
  194. using base_type = basic_sparse_set<Entity, Allocator>;
  195. using alloc_traits = std::allocator_traits<Allocator>;
  196. static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
  197. // std::shared_ptr because of its type erased allocator which is useful here
  198. 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>>>>;
  199. 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>>>>;
  200. template<typename Type>
  201. [[nodiscard]] auto &assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) {
  202. if constexpr(std::is_same_v<Type, entity_type>) {
  203. return entities;
  204. } else {
  205. static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
  206. auto &cpool = pools[id];
  207. if(!cpool) {
  208. using storage_type = storage_for_type<Type>;
  209. using alloc_type = typename storage_type::allocator_type;
  210. if constexpr(std::is_void_v<Type> && !std::is_constructible_v<alloc_type, allocator_type>) {
  211. // std::allocator<void> has no cross constructors (waiting for C++20)
  212. cpool = std::allocate_shared<storage_type>(get_allocator(), alloc_type{});
  213. } else {
  214. cpool = std::allocate_shared<storage_type>(get_allocator(), get_allocator());
  215. }
  216. cpool->bind(forward_as_any(*this));
  217. }
  218. ENTT_ASSERT(cpool->type() == type_id<Type>(), "Unexpected type");
  219. return static_cast<storage_for_type<Type> &>(*cpool);
  220. }
  221. }
  222. template<typename Type>
  223. [[nodiscard]] const auto *assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) const {
  224. if constexpr(std::is_same_v<Type, entity_type>) {
  225. return &entities;
  226. } else {
  227. static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
  228. if(const auto it = pools.find(id); it != pools.cend()) {
  229. ENTT_ASSERT(it->second->type() == type_id<Type>(), "Unexpected type");
  230. return static_cast<const storage_for_type<Type> *>(it->second.get());
  231. }
  232. return static_cast<const storage_for_type<Type> *>(nullptr);
  233. }
  234. }
  235. void rebind() {
  236. entities.bind(forward_as_any(*this));
  237. for(auto &&curr: pools) {
  238. curr.second->bind(forward_as_any(*this));
  239. }
  240. }
  241. public:
  242. /*! @brief Entity traits. */
  243. using traits_type = typename base_type::traits_type;
  244. /*! @brief Allocator type. */
  245. using allocator_type = Allocator;
  246. /*! @brief Underlying entity identifier. */
  247. using entity_type = typename traits_type::value_type;
  248. /*! @brief Underlying version type. */
  249. using version_type = typename traits_type::version_type;
  250. /*! @brief Unsigned integer type. */
  251. using size_type = std::size_t;
  252. /*! @brief Common type among all storage types. */
  253. using common_type = base_type;
  254. /*! @brief Context type. */
  255. using context = internal::registry_context<allocator_type>;
  256. /**
  257. * @copybrief storage_for
  258. * @tparam Type Storage value type, eventually const.
  259. */
  260. template<typename Type>
  261. using storage_for_type = typename storage_for<Type, Entity, typename alloc_traits::template rebind_alloc<std::remove_const_t<Type>>>::type;
  262. /*! @brief Default constructor. */
  263. basic_registry()
  264. : basic_registry{allocator_type{}} {}
  265. /**
  266. * @brief Constructs an empty registry with a given allocator.
  267. * @param allocator The allocator to use.
  268. */
  269. explicit basic_registry(const allocator_type &allocator)
  270. : basic_registry{0u, allocator} {}
  271. /**
  272. * @brief Allocates enough memory upon construction to store `count` pools.
  273. * @param count The number of pools to allocate memory for.
  274. * @param allocator The allocator to use.
  275. */
  276. basic_registry(const size_type count, const allocator_type &allocator = allocator_type{})
  277. : vars{allocator},
  278. pools{allocator},
  279. groups{allocator},
  280. entities{allocator} {
  281. pools.reserve(count);
  282. rebind();
  283. }
  284. /**
  285. * @brief Move constructor.
  286. * @param other The instance to move from.
  287. */
  288. basic_registry(basic_registry &&other) noexcept
  289. : vars{std::move(other.vars)},
  290. pools{std::move(other.pools)},
  291. groups{std::move(other.groups)},
  292. entities{std::move(other.entities)} {
  293. rebind();
  294. }
  295. /**
  296. * @brief Move assignment operator.
  297. * @param other The instance to move from.
  298. * @return This registry.
  299. */
  300. basic_registry &operator=(basic_registry &&other) noexcept {
  301. vars = std::move(other.vars);
  302. pools = std::move(other.pools);
  303. groups = std::move(other.groups);
  304. entities = std::move(other.entities);
  305. rebind();
  306. return *this;
  307. }
  308. /**
  309. * @brief Exchanges the contents with those of a given registry.
  310. * @param other Registry to exchange the content with.
  311. */
  312. void swap(basic_registry &other) {
  313. using std::swap;
  314. swap(vars, other.vars);
  315. swap(pools, other.pools);
  316. swap(groups, other.groups);
  317. swap(entities, other.entities);
  318. rebind();
  319. other.rebind();
  320. }
  321. /**
  322. * @brief Returns the associated allocator.
  323. * @return The associated allocator.
  324. */
  325. [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
  326. return entities.get_allocator();
  327. }
  328. /**
  329. * @brief Returns an iterable object to use to _visit_ a registry.
  330. *
  331. * The iterable object returns a pair that contains the name and a reference
  332. * to the current storage.
  333. *
  334. * @return An iterable object to use to _visit_ the registry.
  335. */
  336. [[nodiscard]] auto storage() noexcept {
  337. return iterable_adaptor{internal::registry_storage_iterator{pools.begin()}, internal::registry_storage_iterator{pools.end()}};
  338. }
  339. /*! @copydoc storage */
  340. [[nodiscard]] auto storage() const noexcept {
  341. return iterable_adaptor{internal::registry_storage_iterator{pools.cbegin()}, internal::registry_storage_iterator{pools.cend()}};
  342. }
  343. /**
  344. * @brief Finds the storage associated with a given name, if any.
  345. * @param id Name used to map the storage within the registry.
  346. * @return A pointer to the storage if it exists, a null pointer otherwise.
  347. */
  348. [[nodiscard]] common_type *storage(const id_type id) {
  349. return const_cast<common_type *>(std::as_const(*this).storage(id));
  350. }
  351. /**
  352. * @brief Finds the storage associated with a given name, if any.
  353. * @param id Name used to map the storage within the registry.
  354. * @return A pointer to the storage if it exists, a null pointer otherwise.
  355. */
  356. [[nodiscard]] const common_type *storage(const id_type id) const {
  357. const auto it = pools.find(id);
  358. return it == pools.cend() ? nullptr : it->second.get();
  359. }
  360. /**
  361. * @brief Returns the storage for a given component type.
  362. * @tparam Type Type of component of which to return the storage.
  363. * @param id Optional name used to map the storage within the registry.
  364. * @return The storage for the given component type.
  365. */
  366. template<typename Type>
  367. storage_for_type<Type> &storage(const id_type id = type_hash<Type>::value()) {
  368. return assure<Type>(id);
  369. }
  370. /**
  371. * @brief Returns the storage for a given component type, if any.
  372. * @tparam Type Type of component of which to return the storage.
  373. * @param id Optional name used to map the storage within the registry.
  374. * @return The storage for the given component type.
  375. */
  376. template<typename Type>
  377. const storage_for_type<Type> *storage(const id_type id = type_hash<Type>::value()) const {
  378. return assure<Type>(id);
  379. }
  380. /**
  381. * @brief Checks if an identifier refers to a valid entity.
  382. * @param entt An identifier, either valid or not.
  383. * @return True if the identifier is valid, false otherwise.
  384. */
  385. [[nodiscard]] bool valid(const entity_type entt) const {
  386. return entities.contains(entt) && (entities.index(entt) < entities.free_list());
  387. }
  388. /**
  389. * @brief Returns the actual version for an identifier.
  390. * @param entt A valid identifier.
  391. * @return The version for the given identifier if valid, the tombstone
  392. * version otherwise.
  393. */
  394. [[nodiscard]] version_type current(const entity_type entt) const {
  395. return entities.current(entt);
  396. }
  397. /**
  398. * @brief Creates a new entity or recycles a destroyed one.
  399. * @return A valid identifier.
  400. */
  401. [[nodiscard]] entity_type create() {
  402. return entities.emplace();
  403. }
  404. /**
  405. * @copybrief create
  406. *
  407. * If the requested entity isn't in use, the suggested identifier is used.
  408. * Otherwise, a new identifier is generated.
  409. *
  410. * @param hint Required identifier.
  411. * @return A valid identifier.
  412. */
  413. [[nodiscard]] entity_type create(const entity_type hint) {
  414. return entities.emplace(hint);
  415. }
  416. /**
  417. * @brief Assigns each element in a range an identifier.
  418. *
  419. * @sa create
  420. *
  421. * @tparam It Type of forward iterator.
  422. * @param first An iterator to the first element of the range to generate.
  423. * @param last An iterator past the last element of the range to generate.
  424. */
  425. template<typename It>
  426. void create(It first, It last) {
  427. entities.insert(std::move(first), std::move(last));
  428. }
  429. /**
  430. * @brief Destroys an entity and releases its identifier.
  431. *
  432. * @warning
  433. * Adding or removing components to an entity that is being destroyed can
  434. * result in undefined behavior.
  435. *
  436. * @param entt A valid identifier.
  437. * @return The version of the recycled entity.
  438. */
  439. version_type destroy(const entity_type entt) {
  440. for(size_type pos = pools.size(); pos; --pos) {
  441. pools.begin()[pos - 1u].second->remove(entt);
  442. }
  443. entities.erase(entt);
  444. return entities.current(entt);
  445. }
  446. /**
  447. * @brief Destroys an entity and releases its identifier.
  448. *
  449. * The suggested version or the valid version closest to the suggested one
  450. * is used instead of the implicitly generated version.
  451. *
  452. * @sa destroy
  453. *
  454. * @param entt A valid identifier.
  455. * @param version A desired version upon destruction.
  456. * @return The version actually assigned to the entity.
  457. */
  458. version_type destroy(const entity_type entt, const version_type version) {
  459. destroy(entt);
  460. const auto elem = traits_type::construct(traits_type::to_entity(entt), version);
  461. return entities.bump((elem == tombstone) ? traits_type::next(elem) : elem);
  462. }
  463. /**
  464. * @brief Destroys all entities in a range and releases their identifiers.
  465. *
  466. * @sa destroy
  467. *
  468. * @tparam It Type of input iterator.
  469. * @param first An iterator to the first element of the range of entities.
  470. * @param last An iterator past the last element of the range of entities.
  471. */
  472. template<typename It>
  473. void destroy(It first, It last) {
  474. const auto from = entities.each().cbegin().base();
  475. const auto to = from + entities.pack(first, last);
  476. for(size_type pos = pools.size(); pos; --pos) {
  477. pools.begin()[pos - 1u].second->remove(from, to);
  478. }
  479. entities.erase(from, to);
  480. }
  481. /**
  482. * @brief Assigns the given component to an entity.
  483. *
  484. * The component must have a proper constructor or be of aggregate type.
  485. *
  486. * @warning
  487. * Attempting to assign a component to an entity that already owns it
  488. * results in undefined behavior.
  489. *
  490. * @tparam Type Type of component to create.
  491. * @tparam Args Types of arguments to use to construct the component.
  492. * @param entt A valid identifier.
  493. * @param args Parameters to use to initialize the component.
  494. * @return A reference to the newly created component.
  495. */
  496. template<typename Type, typename... Args>
  497. decltype(auto) emplace(const entity_type entt, Args &&...args) {
  498. return assure<Type>().emplace(entt, std::forward<Args>(args)...);
  499. }
  500. /**
  501. * @brief Assigns each entity in a range the given component.
  502. *
  503. * @sa emplace
  504. *
  505. * @tparam Type Type of component to create.
  506. * @tparam It Type of input iterator.
  507. * @param first An iterator to the first element of the range of entities.
  508. * @param last An iterator past the last element of the range of entities.
  509. * @param value An instance of the component to assign.
  510. */
  511. template<typename Type, typename It>
  512. void insert(It first, It last, const Type &value = {}) {
  513. assure<Type>().insert(std::move(first), std::move(last), value);
  514. }
  515. /**
  516. * @brief Assigns each entity in a range the given components.
  517. *
  518. * @sa emplace
  519. *
  520. * @tparam Type Type of component to create.
  521. * @tparam EIt Type of input iterator.
  522. * @tparam CIt Type of input iterator.
  523. * @param first An iterator to the first element of the range of entities.
  524. * @param last An iterator past the last element of the range of entities.
  525. * @param from An iterator to the first element of the range of components.
  526. */
  527. template<typename Type, typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<CIt>::value_type, Type>>>
  528. void insert(EIt first, EIt last, CIt from) {
  529. assure<Type>().insert(first, last, from);
  530. }
  531. /**
  532. * @brief Assigns or replaces the given component for an entity.
  533. *
  534. * @sa emplace
  535. * @sa replace
  536. *
  537. * @tparam Type Type of component to assign or replace.
  538. * @tparam Args Types of arguments to use to construct the component.
  539. * @param entt A valid identifier.
  540. * @param args Parameters to use to initialize the component.
  541. * @return A reference to the newly created component.
  542. */
  543. template<typename Type, typename... Args>
  544. decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args) {
  545. if(auto &cpool = assure<Type>(); cpool.contains(entt)) {
  546. return cpool.patch(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); });
  547. } else {
  548. return cpool.emplace(entt, std::forward<Args>(args)...);
  549. }
  550. }
  551. /**
  552. * @brief Patches the given component for an entity.
  553. *
  554. * The signature of the function should be equivalent to the following:
  555. *
  556. * @code{.cpp}
  557. * void(Type &);
  558. * @endcode
  559. *
  560. * @warning
  561. * Attempting to patch a component of an entity that doesn't own it
  562. * results in undefined behavior.
  563. *
  564. * @tparam Type Type of component to patch.
  565. * @tparam Func Types of the function objects to invoke.
  566. * @param entt A valid identifier.
  567. * @param func Valid function objects.
  568. * @return A reference to the patched component.
  569. */
  570. template<typename Type, typename... Func>
  571. decltype(auto) patch(const entity_type entt, Func &&...func) {
  572. return assure<Type>().patch(entt, std::forward<Func>(func)...);
  573. }
  574. /**
  575. * @brief Replaces the given component for an entity.
  576. *
  577. * The component must have a proper constructor or be of aggregate type.
  578. *
  579. * @warning
  580. * Attempting to replace a component of an entity that doesn't own it
  581. * results in undefined behavior.
  582. *
  583. * @tparam Type Type of component to replace.
  584. * @tparam Args Types of arguments to use to construct the component.
  585. * @param entt A valid identifier.
  586. * @param args Parameters to use to initialize the component.
  587. * @return A reference to the component being replaced.
  588. */
  589. template<typename Type, typename... Args>
  590. decltype(auto) replace(const entity_type entt, Args &&...args) {
  591. return patch<Type>(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); });
  592. }
  593. /**
  594. * @brief Removes the given components from an entity.
  595. * @tparam Type Type of component to remove.
  596. * @tparam Other Other types of components to remove.
  597. * @param entt A valid identifier.
  598. * @return The number of components actually removed.
  599. */
  600. template<typename Type, typename... Other>
  601. size_type remove(const entity_type entt) {
  602. return (assure<Type>().remove(entt) + ... + assure<Other>().remove(entt));
  603. }
  604. /**
  605. * @brief Removes the given components from all the entities in a range.
  606. *
  607. * @sa remove
  608. *
  609. * @tparam Type Type of component to remove.
  610. * @tparam Other Other types of components to remove.
  611. * @tparam It Type of input iterator.
  612. * @param first An iterator to the first element of the range of entities.
  613. * @param last An iterator past the last element of the range of entities.
  614. * @return The number of components actually removed.
  615. */
  616. template<typename Type, typename... Other, typename It>
  617. size_type remove(It first, It last) {
  618. size_type count{};
  619. if constexpr(std::is_same_v<It, typename common_type::iterator>) {
  620. common_type *cpools[sizeof...(Other) + 1u]{&assure<Type>(), &assure<Other>()...};
  621. for(size_type pos{}, len = sizeof...(Other) + 1u; pos < len; ++pos) {
  622. if constexpr(sizeof...(Other) != 0u) {
  623. if(cpools[pos]->data() == first.data()) {
  624. std::swap(cpools[pos], cpools[sizeof...(Other)]);
  625. }
  626. }
  627. count += cpools[pos]->remove(first, last);
  628. }
  629. } else {
  630. for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
  631. count += std::apply([entt = *first](auto &...curr) { return (curr.remove(entt) + ... + 0u); }, cpools);
  632. }
  633. }
  634. return count;
  635. }
  636. /**
  637. * @brief Erases the given components from an entity.
  638. *
  639. * @warning
  640. * Attempting to erase a component from an entity that doesn't own it
  641. * results in undefined behavior.
  642. *
  643. * @tparam Type Types of components to erase.
  644. * @tparam Other Other types of components to erase.
  645. * @param entt A valid identifier.
  646. */
  647. template<typename Type, typename... Other>
  648. void erase(const entity_type entt) {
  649. (assure<Type>().erase(entt), (assure<Other>().erase(entt), ...));
  650. }
  651. /**
  652. * @brief Erases the given components from all the entities in a range.
  653. *
  654. * @sa erase
  655. *
  656. * @tparam Type Types of components to erase.
  657. * @tparam Other Other types of components to erase.
  658. * @tparam It Type of input iterator.
  659. * @param first An iterator to the first element of the range of entities.
  660. * @param last An iterator past the last element of the range of entities.
  661. */
  662. template<typename Type, typename... Other, typename It>
  663. void erase(It first, It last) {
  664. if constexpr(std::is_same_v<It, typename common_type::iterator>) {
  665. common_type *cpools[sizeof...(Other) + 1u]{&assure<Type>(), &assure<Other>()...};
  666. for(size_type pos{}, len = sizeof...(Other) + 1u; pos < len; ++pos) {
  667. if constexpr(sizeof...(Other) != 0u) {
  668. if(cpools[pos]->data() == first.data()) {
  669. std::swap(cpools[pos], cpools[sizeof...(Other)]);
  670. }
  671. }
  672. cpools[pos]->erase(first, last);
  673. }
  674. } else {
  675. for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
  676. std::apply([entt = *first](auto &...curr) { (curr.erase(entt), ...); }, cpools);
  677. }
  678. }
  679. }
  680. /**
  681. * @brief Erases components satisfying specific criteria from an entity.
  682. *
  683. * The function type is equivalent to:
  684. *
  685. * @code{.cpp}
  686. * void(const id_type, typename basic_registry<Entity>::base_type &);
  687. * @endcode
  688. *
  689. * Only storage where the entity exists are passed to the function.
  690. *
  691. * @tparam Func Type of the function object to invoke.
  692. * @param entt A valid identifier.
  693. * @param func A valid function object.
  694. */
  695. template<typename Func>
  696. void erase_if(const entity_type entt, Func func) {
  697. for(auto [id, cpool]: storage()) {
  698. if(cpool.contains(entt) && func(id, std::as_const(cpool))) {
  699. cpool.erase(entt);
  700. }
  701. }
  702. }
  703. /**
  704. * @brief Removes all tombstones from a registry or only the pools for the
  705. * given components.
  706. * @tparam Type Types of components for which to clear all tombstones.
  707. */
  708. template<typename... Type>
  709. void compact() {
  710. if constexpr(sizeof...(Type) == 0u) {
  711. for(auto &&curr: pools) {
  712. curr.second->compact();
  713. }
  714. } else {
  715. (assure<Type>().compact(), ...);
  716. }
  717. }
  718. /**
  719. * @brief Check if an entity is part of all the given storage.
  720. * @tparam Type Type of storage to check for.
  721. * @param entt A valid identifier.
  722. * @return True if the entity is part of all the storage, false otherwise.
  723. */
  724. template<typename... Type>
  725. [[nodiscard]] bool all_of([[maybe_unused]] const entity_type entt) const {
  726. if constexpr(sizeof...(Type) == 1u) {
  727. auto *cpool = assure<std::remove_const_t<Type>...>();
  728. return cpool && cpool->contains(entt);
  729. } else {
  730. return (all_of<Type>(entt) && ...);
  731. }
  732. }
  733. /**
  734. * @brief Check if an entity is part of at least one given storage.
  735. * @tparam Type Type of storage to check for.
  736. * @param entt A valid identifier.
  737. * @return True if the entity is part of at least one storage, false
  738. * otherwise.
  739. */
  740. template<typename... Type>
  741. [[nodiscard]] bool any_of([[maybe_unused]] const entity_type entt) const {
  742. return (all_of<Type>(entt) || ...);
  743. }
  744. /**
  745. * @brief Returns references to the given components for an entity.
  746. *
  747. * @warning
  748. * Attempting to get a component from an entity that doesn't own it results
  749. * in undefined behavior.
  750. *
  751. * @tparam Type Types of components to get.
  752. * @param entt A valid identifier.
  753. * @return References to the components owned by the entity.
  754. */
  755. template<typename... Type>
  756. [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const {
  757. if constexpr(sizeof...(Type) == 1u) {
  758. return (assure<std::remove_const_t<Type>>()->get(entt), ...);
  759. } else {
  760. return std::forward_as_tuple(get<Type>(entt)...);
  761. }
  762. }
  763. /*! @copydoc get */
  764. template<typename... Type>
  765. [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) {
  766. if constexpr(sizeof...(Type) == 1u) {
  767. return (static_cast<storage_for_type<Type> &>(assure<std::remove_const_t<Type>>()).get(entt), ...);
  768. } else {
  769. return std::forward_as_tuple(get<Type>(entt)...);
  770. }
  771. }
  772. /**
  773. * @brief Returns a reference to the given component for an entity.
  774. *
  775. * In case the entity doesn't own the component, the parameters provided are
  776. * used to construct it.
  777. *
  778. * @sa get
  779. * @sa emplace
  780. *
  781. * @tparam Type Type of component to get.
  782. * @tparam Args Types of arguments to use to construct the component.
  783. * @param entt A valid identifier.
  784. * @param args Parameters to use to initialize the component.
  785. * @return Reference to the component owned by the entity.
  786. */
  787. template<typename Type, typename... Args>
  788. [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entt, Args &&...args) {
  789. if(auto &cpool = assure<Type>(); cpool.contains(entt)) {
  790. return cpool.get(entt);
  791. } else {
  792. return cpool.emplace(entt, std::forward<Args>(args)...);
  793. }
  794. }
  795. /**
  796. * @brief Returns pointers to the given components for an entity.
  797. *
  798. * @note
  799. * The registry retains ownership of the pointed-to components.
  800. *
  801. * @tparam Type Types of components to get.
  802. * @param entt A valid identifier.
  803. * @return Pointers to the components owned by the entity.
  804. */
  805. template<typename... Type>
  806. [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) const {
  807. if constexpr(sizeof...(Type) == 1u) {
  808. const auto *cpool = assure<std::remove_const_t<Type>...>();
  809. return (cpool && cpool->contains(entt)) ? std::addressof(cpool->get(entt)) : nullptr;
  810. } else {
  811. return std::make_tuple(try_get<Type>(entt)...);
  812. }
  813. }
  814. /*! @copydoc try_get */
  815. template<typename... Type>
  816. [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) {
  817. if constexpr(sizeof...(Type) == 1u) {
  818. return (const_cast<Type *>(std::as_const(*this).template try_get<Type>(entt)), ...);
  819. } else {
  820. return std::make_tuple(try_get<Type>(entt)...);
  821. }
  822. }
  823. /**
  824. * @brief Clears a whole registry or the pools for the given components.
  825. * @tparam Type Types of components to remove from their entities.
  826. */
  827. template<typename... Type>
  828. void clear() {
  829. if constexpr(sizeof...(Type) == 0u) {
  830. for(size_type pos = pools.size(); pos; --pos) {
  831. pools.begin()[pos - 1u].second->clear();
  832. }
  833. const auto iterable = entities.each();
  834. entities.erase(iterable.begin().base(), iterable.end().base());
  835. } else {
  836. (assure<Type>().clear(), ...);
  837. }
  838. }
  839. /**
  840. * @brief Checks if an entity has components assigned.
  841. * @param entt A valid identifier.
  842. * @return True if the entity has no components assigned, false otherwise.
  843. */
  844. [[nodiscard]] bool orphan(const entity_type entt) const {
  845. return std::none_of(pools.cbegin(), pools.cend(), [entt](auto &&curr) { return curr.second->contains(entt); });
  846. }
  847. /**
  848. * @brief Returns a sink object for the given component.
  849. *
  850. * Use this function to receive notifications whenever a new instance of the
  851. * given component is created and assigned to an entity.<br/>
  852. * The function type for a listener is equivalent to:
  853. *
  854. * @code{.cpp}
  855. * void(basic_registry<Entity> &, Entity);
  856. * @endcode
  857. *
  858. * Listeners are invoked **after** assigning the component to the entity.
  859. *
  860. * @sa sink
  861. *
  862. * @tparam Type Type of component of which to get the sink.
  863. * @param id Optional name used to map the storage within the registry.
  864. * @return A temporary sink object.
  865. */
  866. template<typename Type>
  867. [[nodiscard]] auto on_construct(const id_type id = type_hash<Type>::value()) {
  868. return assure<Type>(id).on_construct();
  869. }
  870. /**
  871. * @brief Returns a sink object for the given component.
  872. *
  873. * Use this function to receive notifications whenever an instance of the
  874. * given component is explicitly updated.<br/>
  875. * The function type for a listener is equivalent to:
  876. *
  877. * @code{.cpp}
  878. * void(basic_registry<Entity> &, Entity);
  879. * @endcode
  880. *
  881. * Listeners are invoked **after** updating the component.
  882. *
  883. * @sa sink
  884. *
  885. * @tparam Type Type of component of which to get the sink.
  886. * @param id Optional name used to map the storage within the registry.
  887. * @return A temporary sink object.
  888. */
  889. template<typename Type>
  890. [[nodiscard]] auto on_update(const id_type id = type_hash<Type>::value()) {
  891. return assure<Type>(id).on_update();
  892. }
  893. /**
  894. * @brief Returns a sink object for the given component.
  895. *
  896. * Use this function to receive notifications whenever an instance of the
  897. * given component is removed from an entity and thus destroyed.<br/>
  898. * The function type for a listener is equivalent to:
  899. *
  900. * @code{.cpp}
  901. * void(basic_registry<Entity> &, Entity);
  902. * @endcode
  903. *
  904. * Listeners are invoked **before** removing the component from the entity.
  905. *
  906. * @sa sink
  907. *
  908. * @tparam Type Type of component of which to get the sink.
  909. * @param id Optional name used to map the storage within the registry.
  910. * @return A temporary sink object.
  911. */
  912. template<typename Type>
  913. [[nodiscard]] auto on_destroy(const id_type id = type_hash<Type>::value()) {
  914. return assure<Type>(id).on_destroy();
  915. }
  916. /**
  917. * @brief Returns a view for the given components.
  918. * @tparam Type Type of component used to construct the view.
  919. * @tparam Other Other types of components used to construct the view.
  920. * @tparam Exclude Types of components used to filter the view.
  921. * @return A newly created view.
  922. */
  923. template<typename Type, typename... Other, typename... Exclude>
  924. [[nodiscard]] basic_view<get_t<storage_for_type<const Type>, storage_for_type<const Other>...>, exclude_t<storage_for_type<const Exclude>...>>
  925. view(exclude_t<Exclude...> = exclude_t{}) const {
  926. const auto cpools = std::make_tuple(assure<std::remove_const_t<Type>>(), assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Exclude>>()...);
  927. basic_view<get_t<storage_for_type<const Type>, storage_for_type<const Other>...>, exclude_t<storage_for_type<const Exclude>...>> elem{};
  928. std::apply([&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }, cpools);
  929. return elem;
  930. }
  931. /*! @copydoc view */
  932. template<typename Type, typename... Other, typename... Exclude>
  933. [[nodiscard]] basic_view<get_t<storage_for_type<Type>, storage_for_type<Other>...>, exclude_t<storage_for_type<Exclude>...>>
  934. view(exclude_t<Exclude...> = exclude_t{}) {
  935. return {assure<std::remove_const_t<Type>>(), assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Exclude>>()...};
  936. }
  937. /**
  938. * @brief Returns a group for the given components.
  939. * @tparam Owned Types of storage _owned_ by the group.
  940. * @tparam Get Types of storage _observed_ by the group, if any.
  941. * @tparam Exclude Types of storage used to filter the group, if any.
  942. * @return A newly created group.
  943. */
  944. template<typename... Owned, typename... Get, typename... Exclude>
  945. basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>
  946. group(get_t<Get...> = get_t{}, exclude_t<Exclude...> = exclude_t{}) {
  947. 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;
  948. if(auto it = groups.find(type_hash<handler_type>::value()); it != groups.cend()) {
  949. return {*std::static_pointer_cast<handler_type>(it->second)};
  950. }
  951. std::shared_ptr<handler_type> handler{};
  952. if constexpr(sizeof...(Owned) == 0u) {
  953. handler = std::allocate_shared<handler_type>(get_allocator(), get_allocator(), assure<std::remove_const_t<Get>>()..., assure<std::remove_const_t<Exclude>>()...);
  954. } else {
  955. 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>>()...);
  956. [[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()...};
  957. ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [&elem](const auto &data) { return data.second->owned(elem, sizeof...(Owned)) == 0u; }), "Conflicting groups");
  958. }
  959. groups.emplace(type_hash<handler_type>::value(), handler);
  960. return {*handler};
  961. }
  962. /*! @copydoc group */
  963. template<typename... Owned, typename... Get, typename... Exclude>
  964. basic_group<owned_t<storage_for_type<const Owned>...>, get_t<storage_for_type<const Get>...>, exclude_t<storage_for_type<const Exclude>...>>
  965. group_if_exists(get_t<Get...> = get_t{}, exclude_t<Exclude...> = exclude_t{}) const {
  966. 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;
  967. if(auto it = groups.find(type_hash<handler_type>::value()); it != groups.cend()) {
  968. return {*std::static_pointer_cast<handler_type>(it->second)};
  969. }
  970. return {};
  971. }
  972. /**
  973. * @brief Checks whether the given components belong to any group.
  974. * @tparam Type Type of component in which one is interested.
  975. * @tparam Other Other types of components in which one is interested.
  976. * @return True if the pools of the given components are _free_, false
  977. * otherwise.
  978. */
  979. template<typename Type, typename... Other>
  980. [[nodiscard]] bool owned() const {
  981. const id_type elem[]{type_hash<std::remove_const_t<Type>>::value(), type_hash<std::remove_const_t<Other>>::value()...};
  982. return std::any_of(groups.cbegin(), groups.cend(), [&elem](auto &&data) { return data.second->owned(elem, 1u + sizeof...(Other)); });
  983. }
  984. /**
  985. * @brief Sorts the elements of a given component.
  986. *
  987. * The comparison function object returns `true` if the first element is
  988. * _less_ than the second one, `false` otherwise. Its signature is also
  989. * equivalent to one of the following:
  990. *
  991. * @code{.cpp}
  992. * bool(const Entity, const Entity);
  993. * bool(const Type &, const Type &);
  994. * @endcode
  995. *
  996. * Moreover, it shall induce a _strict weak ordering_ on the values.<br/>
  997. * The sort function object offers an `operator()` that accepts:
  998. *
  999. * * An iterator to the first element of the range to sort.
  1000. * * An iterator past the last element of the range to sort.
  1001. * * A comparison function object to use to compare the elements.
  1002. *
  1003. * The comparison function object hasn't necessarily the type of the one
  1004. * passed along with the other parameters to this member function.
  1005. *
  1006. * @warning
  1007. * Pools of components owned by a group cannot be sorted.
  1008. *
  1009. * @tparam Type Type of components to sort.
  1010. * @tparam Compare Type of comparison function object.
  1011. * @tparam Sort Type of sort function object.
  1012. * @tparam Args Types of arguments to forward to the sort function object.
  1013. * @param compare A valid comparison function object.
  1014. * @param algo A valid sort function object.
  1015. * @param args Arguments to forward to the sort function object, if any.
  1016. */
  1017. template<typename Type, typename Compare, typename Sort = std_sort, typename... Args>
  1018. void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
  1019. ENTT_ASSERT(!owned<Type>(), "Cannot sort owned storage");
  1020. auto &cpool = assure<Type>();
  1021. if constexpr(std::is_invocable_v<Compare, decltype(cpool.get({})), decltype(cpool.get({}))>) {
  1022. 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))); };
  1023. cpool.sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
  1024. } else {
  1025. cpool.sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
  1026. }
  1027. }
  1028. /**
  1029. * @brief Sorts two pools of components in the same way.
  1030. *
  1031. * Entities and components in `To` which are part of both storage are sorted
  1032. * internally with the order they have in `From`. The others follow in no
  1033. * particular order.
  1034. *
  1035. * @warning
  1036. * Pools of components owned by a group cannot be sorted.
  1037. *
  1038. * @tparam To Type of components to sort.
  1039. * @tparam From Type of components to use to sort.
  1040. */
  1041. template<typename To, typename From>
  1042. void sort() {
  1043. ENTT_ASSERT(!owned<To>(), "Cannot sort owned storage");
  1044. const base_type &cpool = assure<From>();
  1045. assure<To>().sort_as(cpool.begin(), cpool.end());
  1046. }
  1047. /**
  1048. * @brief Returns the context object, that is, a general purpose container.
  1049. * @return The context object, that is, a general purpose container.
  1050. */
  1051. context &ctx() noexcept {
  1052. return vars;
  1053. }
  1054. /*! @copydoc ctx */
  1055. const context &ctx() const noexcept {
  1056. return vars;
  1057. }
  1058. private:
  1059. context vars;
  1060. pool_container_type pools;
  1061. group_container_type groups;
  1062. storage_for_type<entity_type> entities;
  1063. };
  1064. } // namespace entt
  1065. #endif