🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1495 lines
58 KiB

  1. #ifndef ENTT_ENTITY_REGISTRY_HPP
  2. #define ENTT_ENTITY_REGISTRY_HPP
  3. #include <algorithm>
  4. #include <cstddef>
  5. #include <iterator>
  6. #include <memory>
  7. #include <tuple>
  8. #include <type_traits>
  9. #include <utility>
  10. #include <vector>
  11. #include "../config/config.h"
  12. #include "../container/dense_map.hpp"
  13. #include "../core/algorithm.hpp"
  14. #include "../core/any.hpp"
  15. #include "../core/fwd.hpp"
  16. #include "../core/iterator.hpp"
  17. #include "../core/type_info.hpp"
  18. #include "../core/type_traits.hpp"
  19. #include "../core/utility.hpp"
  20. #include "component.hpp"
  21. #include "entity.hpp"
  22. #include "fwd.hpp"
  23. #include "group.hpp"
  24. #include "runtime_view.hpp"
  25. #include "sparse_set.hpp"
  26. #include "storage.hpp"
  27. #include "utility.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 storage_proxy_iterator final {
  37. template<typename Other>
  38. friend class storage_proxy_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. storage_proxy_iterator() ENTT_NOEXCEPT
  47. : it{} {}
  48. storage_proxy_iterator(const It iter) ENTT_NOEXCEPT
  49. : it{iter} {}
  50. template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
  51. storage_proxy_iterator(const storage_proxy_iterator<Other> &other) ENTT_NOEXCEPT
  52. : it{other.it} {}
  53. storage_proxy_iterator &operator++() ENTT_NOEXCEPT {
  54. return ++it, *this;
  55. }
  56. storage_proxy_iterator operator++(int) ENTT_NOEXCEPT {
  57. storage_proxy_iterator orig = *this;
  58. return ++(*this), orig;
  59. }
  60. storage_proxy_iterator &operator--() ENTT_NOEXCEPT {
  61. return --it, *this;
  62. }
  63. storage_proxy_iterator operator--(int) ENTT_NOEXCEPT {
  64. storage_proxy_iterator orig = *this;
  65. return operator--(), orig;
  66. }
  67. storage_proxy_iterator &operator+=(const difference_type value) ENTT_NOEXCEPT {
  68. it += value;
  69. return *this;
  70. }
  71. storage_proxy_iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
  72. storage_proxy_iterator copy = *this;
  73. return (copy += value);
  74. }
  75. storage_proxy_iterator &operator-=(const difference_type value) ENTT_NOEXCEPT {
  76. return (*this += -value);
  77. }
  78. storage_proxy_iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
  79. return (*this + -value);
  80. }
  81. [[nodiscard]] reference operator[](const difference_type value) const ENTT_NOEXCEPT {
  82. return {it[value].first, *it[value].second};
  83. }
  84. [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
  85. return {it->first, *it->second};
  86. }
  87. [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
  88. return operator*();
  89. }
  90. template<typename ILhs, typename IRhs>
  91. friend std::ptrdiff_t operator-(const storage_proxy_iterator<ILhs> &, const storage_proxy_iterator<IRhs> &) ENTT_NOEXCEPT;
  92. template<typename ILhs, typename IRhs>
  93. friend bool operator==(const storage_proxy_iterator<ILhs> &, const storage_proxy_iterator<IRhs> &) ENTT_NOEXCEPT;
  94. template<typename ILhs, typename IRhs>
  95. friend bool operator<(const storage_proxy_iterator<ILhs> &, const storage_proxy_iterator<IRhs> &) ENTT_NOEXCEPT;
  96. private:
  97. It it;
  98. };
  99. template<typename ILhs, typename IRhs>
  100. [[nodiscard]] std::ptrdiff_t operator-(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
  101. return lhs.it - rhs.it;
  102. }
  103. template<typename ILhs, typename IRhs>
  104. [[nodiscard]] bool operator==(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
  105. return lhs.it == rhs.it;
  106. }
  107. template<typename ILhs, typename IRhs>
  108. [[nodiscard]] bool operator!=(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
  109. return !(lhs == rhs);
  110. }
  111. template<typename ILhs, typename IRhs>
  112. [[nodiscard]] bool operator<(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
  113. return lhs.it < rhs.it;
  114. }
  115. template<typename ILhs, typename IRhs>
  116. [[nodiscard]] bool operator>(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
  117. return rhs < lhs;
  118. }
  119. template<typename ILhs, typename IRhs>
  120. [[nodiscard]] bool operator<=(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
  121. return !(lhs > rhs);
  122. }
  123. template<typename ILhs, typename IRhs>
  124. [[nodiscard]] bool operator>=(const storage_proxy_iterator<ILhs> &lhs, const storage_proxy_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
  125. return !(lhs < rhs);
  126. }
  127. struct registry_context {
  128. template<typename Type, typename... Args>
  129. Type &emplace_hint(const id_type id, Args &&...args) {
  130. return any_cast<Type &>(data.try_emplace(id, std::in_place_type<Type>, std::forward<Args>(args)...).first->second);
  131. }
  132. template<typename Type, typename... Args>
  133. Type &emplace(Args &&...args) {
  134. return emplace_hint<Type>(type_id<Type>().hash(), std::forward<Args>(args)...);
  135. }
  136. template<typename Type>
  137. bool erase(const id_type id = type_id<Type>().hash()) {
  138. const auto it = data.find(id);
  139. return it != data.end() && it->second.type() == type_id<Type>() ? (data.erase(it), true) : false;
  140. }
  141. template<typename Type>
  142. [[nodiscard]] std::add_const_t<Type> &at(const id_type id = type_id<Type>().hash()) const {
  143. return any_cast<std::add_const_t<Type> &>(data.at(id));
  144. }
  145. template<typename Type>
  146. [[nodiscard]] Type &at(const id_type id = type_id<Type>().hash()) {
  147. return any_cast<Type &>(data.at(id));
  148. }
  149. template<typename Type>
  150. [[nodiscard]] std::add_const_t<Type> *find(const id_type id = type_id<Type>().hash()) const {
  151. const auto it = data.find(id);
  152. return it != data.cend() ? any_cast<std::add_const_t<Type>>(&it->second) : nullptr;
  153. }
  154. template<typename Type>
  155. [[nodiscard]] Type *find(const id_type id = type_id<Type>().hash()) {
  156. const auto it = data.find(id);
  157. return it != data.end() ? any_cast<Type>(&it->second) : nullptr;
  158. }
  159. template<typename Type>
  160. [[nodiscard]] bool contains(const id_type id = type_id<Type>().hash()) const {
  161. const auto it = data.find(id);
  162. return it != data.end() && it->second.type() == type_id<Type>();
  163. }
  164. private:
  165. dense_map<id_type, basic_any<0u>, identity> data;
  166. };
  167. } // namespace internal
  168. /**
  169. * Internal details not to be documented.
  170. * @endcond
  171. */
  172. /**
  173. * @brief Fast and reliable entity-component system.
  174. * @tparam Entity A valid entity type (see entt_traits for more details).
  175. */
  176. template<typename Entity>
  177. class basic_registry {
  178. using entity_traits = entt_traits<Entity>;
  179. using basic_common_type = basic_sparse_set<Entity>;
  180. template<typename Component>
  181. using storage_type = typename storage_traits<Entity, Component>::storage_type;
  182. template<typename...>
  183. struct group_handler;
  184. template<typename... Exclude, typename... Get, typename... Owned>
  185. struct group_handler<exclude_t<Exclude...>, get_t<Get...>, Owned...> {
  186. // nasty workaround for an issue with the toolset v141 that doesn't accept a fold expression here
  187. static_assert(!std::disjunction_v<std::bool_constant<component_traits<Owned>::in_place_delete>...>, "Groups do not support in-place delete");
  188. std::conditional_t<sizeof...(Owned) == 0, basic_common_type, std::size_t> current{};
  189. template<typename Component>
  190. void maybe_valid_if(basic_registry &owner, const Entity entt) {
  191. [[maybe_unused]] const auto cpools = std::forward_as_tuple(owner.assure<Owned>()...);
  192. const auto is_valid = ((std::is_same_v<Component, Owned> || std::get<storage_type<Owned> &>(cpools).contains(entt)) && ...)
  193. && ((std::is_same_v<Component, Get> || owner.assure<Get>().contains(entt)) && ...)
  194. && ((std::is_same_v<Component, Exclude> || !owner.assure<Exclude>().contains(entt)) && ...);
  195. if constexpr(sizeof...(Owned) == 0) {
  196. if(is_valid && !current.contains(entt)) {
  197. current.emplace(entt);
  198. }
  199. } else {
  200. if(is_valid && !(std::get<0>(cpools).index(entt) < current)) {
  201. const auto pos = current++;
  202. (std::get<storage_type<Owned> &>(cpools).swap_elements(std::get<storage_type<Owned> &>(cpools).data()[pos], entt), ...);
  203. }
  204. }
  205. }
  206. void discard_if([[maybe_unused]] basic_registry &owner, const Entity entt) {
  207. if constexpr(sizeof...(Owned) == 0) {
  208. current.remove(entt);
  209. } else {
  210. if(const auto cpools = std::forward_as_tuple(owner.assure<Owned>()...); std::get<0>(cpools).contains(entt) && (std::get<0>(cpools).index(entt) < current)) {
  211. const auto pos = --current;
  212. (std::get<storage_type<Owned> &>(cpools).swap_elements(std::get<storage_type<Owned> &>(cpools).data()[pos], entt), ...);
  213. }
  214. }
  215. }
  216. };
  217. struct group_data {
  218. std::size_t size;
  219. std::unique_ptr<void, void (*)(void *)> group;
  220. bool (*owned)(const id_type) ENTT_NOEXCEPT;
  221. bool (*get)(const id_type) ENTT_NOEXCEPT;
  222. bool (*exclude)(const id_type) ENTT_NOEXCEPT;
  223. };
  224. template<typename Component>
  225. [[nodiscard]] auto &assure(const id_type id = type_hash<Component>::value()) {
  226. static_assert(std::is_same_v<Component, std::decay_t<Component>>, "Non-decayed types not allowed");
  227. auto &&cpool = pools[id];
  228. if(!cpool) {
  229. cpool.reset(new storage_type<Component>{});
  230. cpool->bind(forward_as_any(*this));
  231. }
  232. ENTT_ASSERT(cpool->type() == type_id<Component>(), "Unexpected type");
  233. return static_cast<storage_type<Component> &>(*cpool);
  234. }
  235. template<typename Component>
  236. [[nodiscard]] const auto &assure(const id_type id = type_hash<Component>::value()) const {
  237. static_assert(std::is_same_v<Component, std::decay_t<Component>>, "Non-decayed types not allowed");
  238. if(const auto it = pools.find(id); it != pools.cend()) {
  239. ENTT_ASSERT(it->second->type() == type_id<Component>(), "Unexpected type");
  240. return static_cast<const storage_type<Component> &>(*it->second);
  241. }
  242. static storage_type<Component> placeholder{};
  243. return placeholder;
  244. }
  245. auto generate_identifier(const std::size_t pos) ENTT_NOEXCEPT {
  246. ENTT_ASSERT(pos < entity_traits::to_entity(null), "No entities available");
  247. return entity_traits::combine(static_cast<typename entity_traits::entity_type>(pos), {});
  248. }
  249. auto recycle_identifier() ENTT_NOEXCEPT {
  250. ENTT_ASSERT(free_list != null, "No entities available");
  251. const auto curr = entity_traits::to_entity(free_list);
  252. free_list = entity_traits::combine(entity_traits::to_integral(entities[curr]), tombstone);
  253. return (entities[curr] = entity_traits::combine(curr, entity_traits::to_integral(entities[curr])));
  254. }
  255. auto release_entity(const Entity entity, const typename entity_traits::version_type version) {
  256. const typename entity_traits::version_type vers = version + (version == entity_traits::to_version(tombstone));
  257. entities[entity_traits::to_entity(entity)] = entity_traits::construct(entity_traits::to_integral(free_list), vers);
  258. free_list = entity_traits::combine(entity_traits::to_integral(entity), tombstone);
  259. return vers;
  260. }
  261. public:
  262. /*! @brief Underlying entity identifier. */
  263. using entity_type = Entity;
  264. /*! @brief Underlying version type. */
  265. using version_type = typename entity_traits::version_type;
  266. /*! @brief Unsigned integer type. */
  267. using size_type = std::size_t;
  268. /*! @brief Common type among all storage types. */
  269. using base_type = basic_common_type;
  270. /*! @brief Context type. */
  271. using context = internal::registry_context;
  272. /*! @brief Default constructor. */
  273. basic_registry()
  274. : pools{},
  275. groups{},
  276. entities{},
  277. free_list{tombstone},
  278. vars{} {}
  279. /**
  280. * @brief Allocates enough memory upon construction to store `count` pools.
  281. * @param count The number of pools to allocate memory for.
  282. */
  283. basic_registry(const size_type count)
  284. : pools{},
  285. groups{},
  286. entities{},
  287. free_list{tombstone},
  288. vars{} {
  289. pools.reserve(count);
  290. }
  291. /**
  292. * @brief Move constructor.
  293. * @param other The instance to move from.
  294. */
  295. basic_registry(basic_registry &&other)
  296. : pools{std::move(other.pools)},
  297. groups{std::move(other.groups)},
  298. entities{std::move(other.entities)},
  299. free_list{other.free_list},
  300. vars{std::move(other.vars)} {
  301. for(auto &&curr: pools) {
  302. curr.second->bind(forward_as_any(*this));
  303. }
  304. }
  305. /**
  306. * @brief Move assignment operator.
  307. * @param other The instance to move from.
  308. * @return This registry.
  309. */
  310. basic_registry &operator=(basic_registry &&other) {
  311. pools = std::move(other.pools);
  312. groups = std::move(other.groups);
  313. entities = std::move(other.entities);
  314. free_list = other.free_list;
  315. vars = std::move(other.vars);
  316. for(auto &&curr: pools) {
  317. curr.second->bind(forward_as_any(*this));
  318. }
  319. return *this;
  320. }
  321. /**
  322. * @brief Returns an iterable object to use to _visit_ a registry.
  323. *
  324. * The iterable object returns a pair that contains the name and a reference
  325. * to the current storage.
  326. *
  327. * @return An iterable object to use to _visit_ the registry.
  328. */
  329. [[nodiscard]] auto storage() ENTT_NOEXCEPT {
  330. return iterable_adaptor{internal::storage_proxy_iterator{pools.begin()}, internal::storage_proxy_iterator{pools.end()}};
  331. }
  332. /*! @copydoc storage */
  333. [[nodiscard]] auto storage() const ENTT_NOEXCEPT {
  334. return iterable_adaptor{internal::storage_proxy_iterator{pools.cbegin()}, internal::storage_proxy_iterator{pools.cend()}};
  335. }
  336. /**
  337. * @brief Finds the storage associated with a given name, if any.
  338. * @param id Name used to map the storage within the registry.
  339. * @return An iterator to the given storage if it's found, past the end
  340. * iterator otherwise.
  341. */
  342. [[nodiscard]] auto storage(const id_type id) {
  343. return internal::storage_proxy_iterator{pools.find(id)};
  344. }
  345. /**
  346. * @brief Finds the storage associated with a given name, if any.
  347. * @param id Name used to map the storage within the registry.
  348. * @return An iterator to the given storage if it's found, past the end
  349. * iterator otherwise.
  350. */
  351. [[nodiscard]] auto storage(const id_type id) const {
  352. return internal::storage_proxy_iterator{pools.find(id)};
  353. }
  354. /**
  355. * @brief Returns the storage for a given component type.
  356. * @tparam Component Type of component of which to return the storage.
  357. * @param id Optional name used to map the storage within the registry.
  358. * @return The storage for the given component type.
  359. */
  360. template<typename Component>
  361. decltype(auto) storage(const id_type id = type_hash<std::remove_const_t<Component>>::value()) {
  362. if constexpr(std::is_const_v<Component>) {
  363. return std::as_const(*this).template storage<std::remove_const_t<Component>>(id);
  364. } else {
  365. return assure<Component>(id);
  366. }
  367. }
  368. /**
  369. * @brief Returns the storage for a given component type.
  370. *
  371. * @warning
  372. * If a storage for the given component doesn't exist yet, a temporary
  373. * placeholder is returned instead.
  374. *
  375. * @tparam Component Type of component of which to return the storage.
  376. * @param id Optional name used to map the storage within the registry.
  377. * @return The storage for the given component type.
  378. */
  379. template<typename Component>
  380. decltype(auto) storage(const id_type id = type_hash<std::remove_const_t<Component>>::value()) const {
  381. return assure<std::remove_const_t<Component>>(id);
  382. }
  383. /**
  384. * @brief Returns the number of entities created so far.
  385. * @return Number of entities created so far.
  386. */
  387. [[nodiscard]] size_type size() const ENTT_NOEXCEPT {
  388. return entities.size();
  389. }
  390. /**
  391. * @brief Returns the number of entities still in use.
  392. * @return Number of entities still in use.
  393. */
  394. [[nodiscard]] size_type alive() const {
  395. auto sz = entities.size();
  396. for(auto curr = free_list; curr != null; --sz) {
  397. curr = entities[entity_traits::to_entity(curr)];
  398. }
  399. return sz;
  400. }
  401. /**
  402. * @brief Increases the capacity (number of entities) of the registry.
  403. * @param cap Desired capacity.
  404. */
  405. void reserve(const size_type cap) {
  406. entities.reserve(cap);
  407. }
  408. /**
  409. * @brief Returns the number of entities that a registry has currently
  410. * allocated space for.
  411. * @return Capacity of the registry.
  412. */
  413. [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT {
  414. return entities.capacity();
  415. }
  416. /**
  417. * @brief Checks whether the registry is empty (no entities still in use).
  418. * @return True if the registry is empty, false otherwise.
  419. */
  420. [[nodiscard]] bool empty() const {
  421. return !alive();
  422. }
  423. /**
  424. * @brief Direct access to the list of entities of a registry.
  425. *
  426. * The returned pointer is such that range `[data(), data() + size())` is
  427. * always a valid range, even if the registry is empty.
  428. *
  429. * @warning
  430. * This list contains both valid and destroyed entities and isn't suitable
  431. * for direct use.
  432. *
  433. * @return A pointer to the array of entities.
  434. */
  435. [[nodiscard]] const entity_type *data() const ENTT_NOEXCEPT {
  436. return entities.data();
  437. }
  438. /**
  439. * @brief Returns the head of the list of released entities.
  440. *
  441. * This function is intended for use in conjunction with `assign`.<br/>
  442. * The returned entity has an invalid identifier in all cases.
  443. *
  444. * @return The head of the list of released entities.
  445. */
  446. [[nodiscard]] entity_type released() const ENTT_NOEXCEPT {
  447. return free_list;
  448. }
  449. /**
  450. * @brief Checks if an identifier refers to a valid entity.
  451. * @param entity An identifier, either valid or not.
  452. * @return True if the identifier is valid, false otherwise.
  453. */
  454. [[nodiscard]] bool valid(const entity_type entity) const {
  455. const auto pos = size_type(entity_traits::to_entity(entity));
  456. return (pos < entities.size() && entities[pos] == entity);
  457. }
  458. /**
  459. * @brief Returns the actual version for an identifier.
  460. * @param entity A valid identifier.
  461. * @return The version for the given identifier if valid, the tombstone
  462. * version otherwise.
  463. */
  464. [[nodiscard]] version_type current(const entity_type entity) const {
  465. const auto pos = size_type(entity_traits::to_entity(entity));
  466. return entity_traits::to_version(pos < entities.size() ? entities[pos] : tombstone);
  467. }
  468. /**
  469. * @brief Creates a new entity or recycles a destroyed one.
  470. * @return A valid identifier.
  471. */
  472. [[nodiscard]] entity_type create() {
  473. return (free_list == null) ? entities.emplace_back(generate_identifier(entities.size())) : recycle_identifier();
  474. }
  475. /**
  476. * @copybrief create
  477. *
  478. * If the requested entity isn't in use, the suggested identifier is used.
  479. * Otherwise, a new identifier is generated.
  480. *
  481. * @param hint Required identifier.
  482. * @return A valid identifier.
  483. */
  484. [[nodiscard]] entity_type create(const entity_type hint) {
  485. const auto length = entities.size();
  486. if(hint == null || hint == tombstone) {
  487. return create();
  488. } else if(const auto req = entity_traits::to_entity(hint); !(req < length)) {
  489. entities.resize(size_type(req) + 1u, null);
  490. for(auto pos = length; pos < req; ++pos) {
  491. release_entity(generate_identifier(pos), {});
  492. }
  493. return (entities[req] = hint);
  494. } else if(const auto curr = entity_traits::to_entity(entities[req]); req == curr) {
  495. return create();
  496. } else {
  497. auto *it = &free_list;
  498. for(; entity_traits::to_entity(*it) != req; it = &entities[entity_traits::to_entity(*it)]) {}
  499. *it = entity_traits::combine(curr, entity_traits::to_integral(*it));
  500. return (entities[req] = hint);
  501. }
  502. }
  503. /**
  504. * @brief Assigns each element in a range an identifier.
  505. *
  506. * @sa create
  507. *
  508. * @tparam It Type of forward iterator.
  509. * @param first An iterator to the first element of the range to generate.
  510. * @param last An iterator past the last element of the range to generate.
  511. */
  512. template<typename It>
  513. void create(It first, It last) {
  514. for(; free_list != null && first != last; ++first) {
  515. *first = recycle_identifier();
  516. }
  517. const auto length = entities.size();
  518. entities.resize(length + std::distance(first, last), null);
  519. for(auto pos = length; first != last; ++first, ++pos) {
  520. *first = entities[pos] = generate_identifier(pos);
  521. }
  522. }
  523. /**
  524. * @brief Assigns identifiers to an empty registry.
  525. *
  526. * This function is intended for use in conjunction with `data`, `size` and
  527. * `destroyed`.<br/>
  528. * Don't try to inject ranges of randomly generated entities nor the _wrong_
  529. * head for the list of destroyed entities. There is no guarantee that a
  530. * registry will continue to work properly in this case.
  531. *
  532. * @warning
  533. * There must be no entities still alive for this to work properly.
  534. *
  535. * @tparam It Type of input iterator.
  536. * @param first An iterator to the first element of the range of entities.
  537. * @param last An iterator past the last element of the range of entities.
  538. * @param destroyed The head of the list of destroyed entities.
  539. */
  540. template<typename It>
  541. void assign(It first, It last, const entity_type destroyed) {
  542. ENTT_ASSERT(!alive(), "Entities still alive");
  543. entities.assign(first, last);
  544. free_list = destroyed;
  545. }
  546. /**
  547. * @brief Releases an identifier.
  548. *
  549. * The version is updated and the identifier can be recycled at any time.
  550. *
  551. * @warning
  552. * Attempting to use an invalid entity results in undefined behavior.
  553. *
  554. * @param entity A valid identifier.
  555. * @return The version of the recycled entity.
  556. */
  557. version_type release(const entity_type entity) {
  558. return release(entity, static_cast<version_type>(entity_traits::to_version(entity) + 1u));
  559. }
  560. /**
  561. * @brief Releases an identifier.
  562. *
  563. * The suggested version or the valid version closest to the suggested one
  564. * is used instead of the implicitly generated version.
  565. *
  566. * @sa release
  567. *
  568. * @param entity A valid identifier.
  569. * @param version A desired version upon destruction.
  570. * @return The version actually assigned to the entity.
  571. */
  572. version_type release(const entity_type entity, const version_type version) {
  573. ENTT_ASSERT(orphan(entity), "Non-orphan entity");
  574. return release_entity(entity, version);
  575. }
  576. /**
  577. * @brief Releases all identifiers in a range.
  578. *
  579. * @sa release
  580. *
  581. * @tparam It Type of input iterator.
  582. * @param first An iterator to the first element of the range of entities.
  583. * @param last An iterator past the last element of the range of entities.
  584. */
  585. template<typename It>
  586. void release(It first, It last) {
  587. for(; first != last; ++first) {
  588. release(*first);
  589. }
  590. }
  591. /**
  592. * @brief Destroys an entity and releases its identifier.
  593. *
  594. * @sa release
  595. *
  596. * @warning
  597. * Adding or removing components to an entity that is being destroyed can
  598. * result in undefined behavior. Attempting to use an invalid entity results
  599. * in undefined behavior.
  600. *
  601. * @param entity A valid identifier.
  602. * @return The version of the recycled entity.
  603. */
  604. version_type destroy(const entity_type entity) {
  605. return destroy(entity, static_cast<version_type>(entity_traits::to_version(entity) + 1u));
  606. }
  607. /**
  608. * @brief Destroys an entity and releases its identifier.
  609. *
  610. * The suggested version or the valid version closest to the suggested one
  611. * is used instead of the implicitly generated version.
  612. *
  613. * @sa destroy
  614. *
  615. * @param entity A valid identifier.
  616. * @param version A desired version upon destruction.
  617. * @return The version actually assigned to the entity.
  618. */
  619. version_type destroy(const entity_type entity, const version_type version) {
  620. ENTT_ASSERT(valid(entity), "Invalid entity");
  621. for(size_type pos = pools.size(); pos; --pos) {
  622. pools.begin()[pos - 1u].second->remove(entity);
  623. }
  624. return release_entity(entity, version);
  625. }
  626. /**
  627. * @brief Destroys all entities in a range and releases their identifiers.
  628. *
  629. * @sa destroy
  630. *
  631. * @tparam It Type of input iterator.
  632. * @param first An iterator to the first element of the range of entities.
  633. * @param last An iterator past the last element of the range of entities.
  634. */
  635. template<typename It>
  636. void destroy(It first, It last) {
  637. for(; first != last; ++first) {
  638. destroy(*first);
  639. }
  640. }
  641. /**
  642. * @brief Assigns the given component to an entity.
  643. *
  644. * The component must have a proper constructor or be of aggregate type.
  645. *
  646. * @warning
  647. * Attempting to use an invalid entity or to assign a component to an entity
  648. * that already owns it results in undefined behavior.
  649. *
  650. * @tparam Component Type of component to create.
  651. * @tparam Args Types of arguments to use to construct the component.
  652. * @param entity A valid identifier.
  653. * @param args Parameters to use to initialize the component.
  654. * @return A reference to the newly created component.
  655. */
  656. template<typename Component, typename... Args>
  657. decltype(auto) emplace(const entity_type entity, Args &&...args) {
  658. ENTT_ASSERT(valid(entity), "Invalid entity");
  659. return assure<Component>().emplace(entity, std::forward<Args>(args)...);
  660. }
  661. /**
  662. * @brief Assigns each entity in a range the given component.
  663. *
  664. * @sa emplace
  665. *
  666. * @tparam Component Type of component to create.
  667. * @tparam It Type of input iterator.
  668. * @param first An iterator to the first element of the range of entities.
  669. * @param last An iterator past the last element of the range of entities.
  670. * @param value An instance of the component to assign.
  671. */
  672. template<typename Component, typename It>
  673. void insert(It first, It last, const Component &value = {}) {
  674. ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }), "Invalid entity");
  675. assure<Component>().insert(first, last, value);
  676. }
  677. /**
  678. * @brief Assigns each entity in a range the given components.
  679. *
  680. * @sa emplace
  681. *
  682. * @tparam Component Type of component to create.
  683. * @tparam EIt Type of input iterator.
  684. * @tparam CIt Type of input iterator.
  685. * @param first An iterator to the first element of the range of entities.
  686. * @param last An iterator past the last element of the range of entities.
  687. * @param from An iterator to the first element of the range of components.
  688. */
  689. template<typename Component, typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<CIt>::value_type, Component>>>
  690. void insert(EIt first, EIt last, CIt from) {
  691. ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }), "Invalid entity");
  692. assure<Component>().insert(first, last, from);
  693. }
  694. /**
  695. * @brief Assigns or replaces the given component for an entity.
  696. *
  697. * @warning
  698. * Attempting to use an invalid entity results in undefined behavior.
  699. *
  700. * @tparam Component Type of component to assign or replace.
  701. * @tparam Args Types of arguments to use to construct the component.
  702. * @param entity A valid identifier.
  703. * @param args Parameters to use to initialize the component.
  704. * @return A reference to the newly created component.
  705. */
  706. template<typename Component, typename... Args>
  707. decltype(auto) emplace_or_replace(const entity_type entity, Args &&...args) {
  708. ENTT_ASSERT(valid(entity), "Invalid entity");
  709. auto &cpool = assure<Component>();
  710. return cpool.contains(entity)
  711. ? cpool.patch(entity, [&args...](auto &...curr) { ((curr = Component{std::forward<Args>(args)...}), ...); })
  712. : cpool.emplace(entity, std::forward<Args>(args)...);
  713. }
  714. /**
  715. * @brief Patches the given component for an entity.
  716. *
  717. * The signature of the function should be equivalent to the following:
  718. *
  719. * @code{.cpp}
  720. * void(Component &);
  721. * @endcode
  722. *
  723. * @note
  724. * Empty types aren't explicitly instantiated and therefore they are never
  725. * returned. However, this function can be used to trigger an update signal
  726. * for them.
  727. *
  728. * @warning
  729. * Attempting to use an invalid entity or to patch a component of an entity
  730. * that doesn't own it results in undefined behavior.
  731. *
  732. * @tparam Component Type of component to patch.
  733. * @tparam Func Types of the function objects to invoke.
  734. * @param entity A valid identifier.
  735. * @param func Valid function objects.
  736. * @return A reference to the patched component.
  737. */
  738. template<typename Component, typename... Func>
  739. decltype(auto) patch(const entity_type entity, Func &&...func) {
  740. ENTT_ASSERT(valid(entity), "Invalid entity");
  741. return assure<Component>().patch(entity, std::forward<Func>(func)...);
  742. }
  743. /**
  744. * @brief Replaces the given component for an entity.
  745. *
  746. * The component must have a proper constructor or be of aggregate type.
  747. *
  748. * @warning
  749. * Attempting to use an invalid entity or to replace a component of an
  750. * entity that doesn't own it results in undefined behavior.
  751. *
  752. * @tparam Component Type of component to replace.
  753. * @tparam Args Types of arguments to use to construct the component.
  754. * @param entity A valid identifier.
  755. * @param args Parameters to use to initialize the component.
  756. * @return A reference to the component being replaced.
  757. */
  758. template<typename Component, typename... Args>
  759. decltype(auto) replace(const entity_type entity, Args &&...args) {
  760. ENTT_ASSERT(valid(entity), "Invalid entity");
  761. return assure<Component>().patch(entity, [&args...](auto &...curr) { ((curr = Component{std::forward<Args>(args)...}), ...); });
  762. }
  763. /**
  764. * @brief Removes the given components from an entity.
  765. *
  766. * @warning
  767. * Attempting to use an invalid entity results in undefined behavior.
  768. *
  769. * @tparam Component Type of component to remove.
  770. * @tparam Other Other types of components to remove.
  771. * @param entity A valid identifier.
  772. * @return The number of components actually removed.
  773. */
  774. template<typename Component, typename... Other>
  775. size_type remove(const entity_type entity) {
  776. ENTT_ASSERT(valid(entity), "Invalid entity");
  777. return (assure<Component>().remove(entity) + ... + assure<Other>().remove(entity));
  778. }
  779. /**
  780. * @brief Removes the given components from all the entities in a range.
  781. *
  782. * @sa remove
  783. *
  784. * @tparam Component Type of component to remove.
  785. * @tparam Other Other types of components to remove.
  786. * @tparam It Type of input iterator.
  787. * @param first An iterator to the first element of the range of entities.
  788. * @param last An iterator past the last element of the range of entities.
  789. * @return The number of components actually removed.
  790. */
  791. template<typename Component, typename... Other, typename It>
  792. size_type remove(It first, It last) {
  793. if constexpr(sizeof...(Other) == 0u) {
  794. ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }), "Invalid entity");
  795. return assure<Component>().remove(std::move(first), std::move(last));
  796. } else {
  797. size_type count{};
  798. for(auto cpools = std::forward_as_tuple(assure<Component>(), assure<Other>()...); first != last; ++first) {
  799. ENTT_ASSERT(valid(*first), "Invalid entity");
  800. count += std::apply([entt = *first](auto &...curr) { return (curr.remove(entt) + ... + 0u); }, cpools);
  801. }
  802. return count;
  803. }
  804. }
  805. /**
  806. * @brief Erases the given components from an entity.
  807. *
  808. * @warning
  809. * Attempting to use an invalid entity or to erase a component from an
  810. * entity that doesn't own it results in undefined behavior.
  811. *
  812. * @tparam Component Types of components to erase.
  813. * @tparam Other Other types of components to erase.
  814. * @param entity A valid identifier.
  815. */
  816. template<typename Component, typename... Other>
  817. void erase(const entity_type entity) {
  818. ENTT_ASSERT(valid(entity), "Invalid entity");
  819. (assure<Component>().erase(entity), (assure<Other>().erase(entity), ...));
  820. }
  821. /**
  822. * @brief Erases the given components from all the entities in a range.
  823. *
  824. * @sa erase
  825. *
  826. * @tparam Component Types of components to erase.
  827. * @tparam Other Other types of components to erase.
  828. * @tparam It Type of input iterator.
  829. * @param first An iterator to the first element of the range of entities.
  830. * @param last An iterator past the last element of the range of entities.
  831. */
  832. template<typename Component, typename... Other, typename It>
  833. void erase(It first, It last) {
  834. if constexpr(sizeof...(Other) == 0u) {
  835. ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }), "Invalid entity");
  836. assure<Component>().erase(std::move(first), std::move(last));
  837. } else {
  838. for(auto cpools = std::forward_as_tuple(assure<Component>(), assure<Other>()...); first != last; ++first) {
  839. ENTT_ASSERT(valid(*first), "Invalid entity");
  840. std::apply([entt = *first](auto &...curr) { (curr.erase(entt), ...); }, cpools);
  841. }
  842. }
  843. }
  844. /**
  845. * @brief Removes all tombstones from a registry or only the pools for the
  846. * given components.
  847. * @tparam Component Types of components for which to clear all tombstones.
  848. */
  849. template<typename... Component>
  850. void compact() {
  851. if constexpr(sizeof...(Component) == 0) {
  852. for(auto &&curr: pools) {
  853. curr.second->compact();
  854. }
  855. } else {
  856. (assure<Component>().compact(), ...);
  857. }
  858. }
  859. /**
  860. * @brief Checks if an entity has all the given components.
  861. *
  862. * @warning
  863. * Attempting to use an invalid entity results in undefined behavior.
  864. *
  865. * @tparam Component Components for which to perform the check.
  866. * @param entity A valid identifier.
  867. * @return True if the entity has all the components, false otherwise.
  868. */
  869. template<typename... Component>
  870. [[nodiscard]] bool all_of(const entity_type entity) const {
  871. ENTT_ASSERT(valid(entity), "Invalid entity");
  872. return (assure<std::remove_const_t<Component>>().contains(entity) && ...);
  873. }
  874. /**
  875. * @brief Checks if an entity has at least one of the given components.
  876. *
  877. * @warning
  878. * Attempting to use an invalid entity results in undefined behavior.
  879. *
  880. * @tparam Component Components for which to perform the check.
  881. * @param entity A valid identifier.
  882. * @return True if the entity has at least one of the given components,
  883. * false otherwise.
  884. */
  885. template<typename... Component>
  886. [[nodiscard]] bool any_of(const entity_type entity) const {
  887. ENTT_ASSERT(valid(entity), "Invalid entity");
  888. return (assure<std::remove_const_t<Component>>().contains(entity) || ...);
  889. }
  890. /**
  891. * @brief Returns references to the given components for an entity.
  892. *
  893. * @warning
  894. * Attempting to use an invalid entity or to get a component from an entity
  895. * that doesn't own it results in undefined behavior.
  896. *
  897. * @tparam Component Types of components to get.
  898. * @param entity A valid identifier.
  899. * @return References to the components owned by the entity.
  900. */
  901. template<typename... Component>
  902. [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entity) const {
  903. ENTT_ASSERT(valid(entity), "Invalid entity");
  904. return view<Component...>().template get<const Component...>(entity);
  905. }
  906. /*! @copydoc get */
  907. template<typename... Component>
  908. [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entity) {
  909. ENTT_ASSERT(valid(entity), "Invalid entity");
  910. return view<Component...>().template get<Component...>(entity);
  911. }
  912. /**
  913. * @brief Returns a reference to the given component for an entity.
  914. *
  915. * In case the entity doesn't own the component, the parameters provided are
  916. * used to construct it.
  917. *
  918. * @warning
  919. * Attempting to use an invalid entity results in undefined behavior.
  920. *
  921. * @tparam Component Type of component to get.
  922. * @tparam Args Types of arguments to use to construct the component.
  923. * @param entity A valid identifier.
  924. * @param args Parameters to use to initialize the component.
  925. * @return Reference to the component owned by the entity.
  926. */
  927. template<typename Component, typename... Args>
  928. [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entity, Args &&...args) {
  929. ENTT_ASSERT(valid(entity), "Invalid entity");
  930. auto &cpool = assure<Component>();
  931. return cpool.contains(entity) ? cpool.get(entity) : cpool.emplace(entity, std::forward<Args>(args)...);
  932. }
  933. /**
  934. * @brief Returns pointers to the given components for an entity.
  935. *
  936. * @warning
  937. * Attempting to use an invalid entity results in undefined behavior.
  938. *
  939. * @note
  940. * The registry retains ownership of the pointed-to components.
  941. *
  942. * @tparam Component Types of components to get.
  943. * @param entity A valid identifier.
  944. * @return Pointers to the components owned by the entity.
  945. */
  946. template<typename... Component>
  947. [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entity) const {
  948. ENTT_ASSERT(valid(entity), "Invalid entity");
  949. if constexpr(sizeof...(Component) == 1) {
  950. const auto &cpool = assure<std::remove_const_t<Component>...>();
  951. return cpool.contains(entity) ? std::addressof(cpool.get(entity)) : nullptr;
  952. } else {
  953. return std::make_tuple(try_get<Component>(entity)...);
  954. }
  955. }
  956. /*! @copydoc try_get */
  957. template<typename... Component>
  958. [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entity) {
  959. if constexpr(sizeof...(Component) == 1) {
  960. return (const_cast<Component *>(std::as_const(*this).template try_get<Component>(entity)), ...);
  961. } else {
  962. return std::make_tuple(try_get<Component>(entity)...);
  963. }
  964. }
  965. /**
  966. * @brief Clears a whole registry or the pools for the given components.
  967. * @tparam Component Types of components to remove from their entities.
  968. */
  969. template<typename... Component>
  970. void clear() {
  971. if constexpr(sizeof...(Component) == 0) {
  972. for(auto &&curr: pools) {
  973. curr.second->clear();
  974. }
  975. each([this](const auto entity) { this->release(entity); });
  976. } else {
  977. (assure<Component>().clear(), ...);
  978. }
  979. }
  980. /**
  981. * @brief Iterates all the entities that are still in use.
  982. *
  983. * The signature of the function should be equivalent to the following:
  984. *
  985. * @code{.cpp}
  986. * void(const Entity);
  987. * @endcode
  988. *
  989. * It's not defined whether entities created during iteration are returned.
  990. *
  991. * @tparam Func Type of the function object to invoke.
  992. * @param func A valid function object.
  993. */
  994. template<typename Func>
  995. void each(Func func) const {
  996. if(free_list == null) {
  997. for(auto pos = entities.size(); pos; --pos) {
  998. func(entities[pos - 1]);
  999. }
  1000. } else {
  1001. for(auto pos = entities.size(); pos; --pos) {
  1002. if(const auto entity = entities[pos - 1]; entity_traits::to_entity(entity) == (pos - 1)) {
  1003. func(entity);
  1004. }
  1005. }
  1006. }
  1007. }
  1008. /**
  1009. * @brief Checks if an entity has components assigned.
  1010. * @param entity A valid identifier.
  1011. * @return True if the entity has no components assigned, false otherwise.
  1012. */
  1013. [[nodiscard]] bool orphan(const entity_type entity) const {
  1014. ENTT_ASSERT(valid(entity), "Invalid entity");
  1015. return std::none_of(pools.cbegin(), pools.cend(), [entity](auto &&curr) { return curr.second->contains(entity); });
  1016. }
  1017. /**
  1018. * @brief Returns a sink object for the given component.
  1019. *
  1020. * Use this function to receive notifications whenever a new instance of the
  1021. * given component is created and assigned to an entity.<br/>
  1022. * The function type for a listener is equivalent to:
  1023. *
  1024. * @code{.cpp}
  1025. * void(basic_registry<Entity> &, Entity);
  1026. * @endcode
  1027. *
  1028. * Listeners are invoked **after** assigning the component to the entity.
  1029. *
  1030. * @sa sink
  1031. *
  1032. * @tparam Component Type of component of which to get the sink.
  1033. * @return A temporary sink object.
  1034. */
  1035. template<typename Component>
  1036. [[nodiscard]] auto on_construct() {
  1037. return assure<Component>().on_construct();
  1038. }
  1039. /**
  1040. * @brief Returns a sink object for the given component.
  1041. *
  1042. * Use this function to receive notifications whenever an instance of the
  1043. * given component is explicitly updated.<br/>
  1044. * The function type for a listener is equivalent to:
  1045. *
  1046. * @code{.cpp}
  1047. * void(basic_registry<Entity> &, Entity);
  1048. * @endcode
  1049. *
  1050. * Listeners are invoked **after** updating the component.
  1051. *
  1052. * @sa sink
  1053. *
  1054. * @tparam Component Type of component of which to get the sink.
  1055. * @return A temporary sink object.
  1056. */
  1057. template<typename Component>
  1058. [[nodiscard]] auto on_update() {
  1059. return assure<Component>().on_update();
  1060. }
  1061. /**
  1062. * @brief Returns a sink object for the given component.
  1063. *
  1064. * Use this function to receive notifications whenever an instance of the
  1065. * given component is removed from an entity and thus destroyed.<br/>
  1066. * The function type for a listener is equivalent to:
  1067. *
  1068. * @code{.cpp}
  1069. * void(basic_registry<Entity> &, Entity);
  1070. * @endcode
  1071. *
  1072. * Listeners are invoked **before** removing the component from the entity.
  1073. *
  1074. * @sa sink
  1075. *
  1076. * @tparam Component Type of component of which to get the sink.
  1077. * @return A temporary sink object.
  1078. */
  1079. template<typename Component>
  1080. [[nodiscard]] auto on_destroy() {
  1081. return assure<Component>().on_destroy();
  1082. }
  1083. /**
  1084. * @brief Returns a view for the given components.
  1085. *
  1086. * Views are created on the fly and share with the registry its internal
  1087. * data structures. Feel free to discard them after the use.<br/>
  1088. * Creating and destroying a view is an incredibly cheap operation. As a
  1089. * rule of thumb, storing a view should never be an option.
  1090. *
  1091. * @tparam Component Type of component used to construct the view.
  1092. * @tparam Other Other types of components used to construct the view.
  1093. * @tparam Exclude Types of components used to filter the view.
  1094. * @return A newly created view.
  1095. */
  1096. template<typename Component, typename... Other, typename... Exclude>
  1097. [[nodiscard]] basic_view<entity_type, get_t<std::add_const_t<Component>, std::add_const_t<Other>...>, exclude_t<Exclude...>> view(exclude_t<Exclude...> = {}) const {
  1098. return {assure<std::remove_const_t<Component>>(), assure<std::remove_const_t<Other>>()..., assure<Exclude>()...};
  1099. }
  1100. /*! @copydoc view */
  1101. template<typename Component, typename... Other, typename... Exclude>
  1102. [[nodiscard]] basic_view<entity_type, get_t<Component, Other...>, exclude_t<Exclude...>> view(exclude_t<Exclude...> = {}) {
  1103. return {assure<std::remove_const_t<Component>>(), assure<std::remove_const_t<Other>>()..., assure<Exclude>()...};
  1104. }
  1105. /**
  1106. * @brief Returns a group for the given components.
  1107. *
  1108. * Groups are created on the fly and share with the registry its internal
  1109. * data structures. Feel free to discard them after the use.<br/>
  1110. * Creating and destroying a group is an incredibly cheap operation. As a
  1111. * rule of thumb, storing a group should never be an option.
  1112. *
  1113. * Groups support exclusion lists and can own types of components. The more
  1114. * types are owned by a group, the faster it is to iterate entities and
  1115. * components.<br/>
  1116. * However, groups also affect some features of the registry such as the
  1117. * creation and destruction of components.
  1118. *
  1119. * @note
  1120. * Pools of components that are owned by a group cannot be sorted anymore.
  1121. * The group takes the ownership of the pools and arrange components so as
  1122. * to iterate them as fast as possible.
  1123. *
  1124. * @tparam Owned Types of components owned by the group.
  1125. * @tparam Get Types of components observed by the group.
  1126. * @tparam Exclude Types of components used to filter the group.
  1127. * @return A newly created group.
  1128. */
  1129. template<typename... Owned, typename... Get, typename... Exclude>
  1130. [[nodiscard]] basic_group<entity_type, owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> group(get_t<Get...>, exclude_t<Exclude...> = {}) {
  1131. static_assert(sizeof...(Owned) + sizeof...(Get) > 0, "Exclusion-only groups are not supported");
  1132. static_assert(sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude) > 1, "Single component groups are not allowed");
  1133. using handler_type = group_handler<exclude_t<std::remove_const_t<Exclude>...>, get_t<std::remove_const_t<Get>...>, std::remove_const_t<Owned>...>;
  1134. const auto cpools = std::forward_as_tuple(assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()...);
  1135. constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
  1136. handler_type *handler = nullptr;
  1137. auto it = std::find_if(groups.cbegin(), groups.cend(), [size](const auto &gdata) {
  1138. return gdata.size == size
  1139. && (gdata.owned(type_hash<std::remove_const_t<Owned>>::value()) && ...)
  1140. && (gdata.get(type_hash<std::remove_const_t<Get>>::value()) && ...)
  1141. && (gdata.exclude(type_hash<Exclude>::value()) && ...);
  1142. });
  1143. if(it != groups.cend()) {
  1144. handler = static_cast<handler_type *>(it->group.get());
  1145. } else {
  1146. group_data candidate = {
  1147. size,
  1148. {new handler_type{}, [](void *instance) { delete static_cast<handler_type *>(instance); }},
  1149. []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash<std::remove_const_t<Owned>>::value()) || ...); },
  1150. []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash<std::remove_const_t<Get>>::value()) || ...); },
  1151. []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash<Exclude>::value()) || ...); },
  1152. };
  1153. handler = static_cast<handler_type *>(candidate.group.get());
  1154. const void *maybe_valid_if = nullptr;
  1155. const void *discard_if = nullptr;
  1156. if constexpr(sizeof...(Owned) == 0) {
  1157. groups.push_back(std::move(candidate));
  1158. } else {
  1159. [[maybe_unused]] auto has_conflict = [size](const auto &gdata) {
  1160. const auto overlapping = (0u + ... + gdata.owned(type_hash<std::remove_const_t<Owned>>::value()));
  1161. const auto sz = overlapping + (0u + ... + gdata.get(type_hash<std::remove_const_t<Get>>::value())) + (0u + ... + gdata.exclude(type_hash<Exclude>::value()));
  1162. return !overlapping || ((sz == size) || (sz == gdata.size));
  1163. };
  1164. ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), std::move(has_conflict)), "Conflicting groups");
  1165. const auto next = std::find_if_not(groups.cbegin(), groups.cend(), [size](const auto &gdata) {
  1166. return !(0u + ... + gdata.owned(type_hash<std::remove_const_t<Owned>>::value())) || (size > gdata.size);
  1167. });
  1168. const auto prev = std::find_if(std::make_reverse_iterator(next), groups.crend(), [](const auto &gdata) {
  1169. return (0u + ... + gdata.owned(type_hash<std::remove_const_t<Owned>>::value()));
  1170. });
  1171. maybe_valid_if = (next == groups.cend() ? maybe_valid_if : next->group.get());
  1172. discard_if = (prev == groups.crend() ? discard_if : prev->group.get());
  1173. groups.insert(next, std::move(candidate));
  1174. }
  1175. (on_construct<std::remove_const_t<Owned>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::remove_const_t<Owned>>>(*handler), ...);
  1176. (on_construct<std::remove_const_t<Get>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::remove_const_t<Get>>>(*handler), ...);
  1177. (on_destroy<Exclude>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<Exclude>>(*handler), ...);
  1178. (on_destroy<std::remove_const_t<Owned>>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
  1179. (on_destroy<std::remove_const_t<Get>>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
  1180. (on_construct<Exclude>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
  1181. if constexpr(sizeof...(Owned) == 0) {
  1182. for(const auto entity: view<Owned..., Get...>(exclude<Exclude...>)) {
  1183. handler->current.emplace(entity);
  1184. }
  1185. } else {
  1186. // we cannot iterate backwards because we want to leave behind valid entities in case of owned types
  1187. for(auto *first = std::get<0>(cpools).data(), *last = first + std::get<0>(cpools).size(); first != last; ++first) {
  1188. handler->template maybe_valid_if<type_list_element_t<0, type_list<std::remove_const_t<Owned>...>>>(*this, *first);
  1189. }
  1190. }
  1191. }
  1192. return {handler->current, std::get<storage_type<std::remove_const_t<Owned>> &>(cpools)..., std::get<storage_type<std::remove_const_t<Get>> &>(cpools)...};
  1193. }
  1194. /*! @copydoc group */
  1195. template<typename... Owned, typename... Get, typename... Exclude>
  1196. [[nodiscard]] basic_group<entity_type, owned_t<std::add_const_t<Owned>...>, get_t<std::add_const_t<Get>...>, exclude_t<Exclude...>> group_if_exists(get_t<Get...>, exclude_t<Exclude...> = {}) const {
  1197. auto it = std::find_if(groups.cbegin(), groups.cend(), [](const auto &gdata) {
  1198. return gdata.size == (sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude))
  1199. && (gdata.owned(type_hash<std::remove_const_t<Owned>>::value()) && ...)
  1200. && (gdata.get(type_hash<std::remove_const_t<Get>>::value()) && ...)
  1201. && (gdata.exclude(type_hash<Exclude>::value()) && ...);
  1202. });
  1203. if(it == groups.cend()) {
  1204. return {};
  1205. } else {
  1206. using handler_type = group_handler<exclude_t<std::remove_const_t<Exclude>...>, get_t<std::remove_const_t<Get>...>, std::remove_const_t<Owned>...>;
  1207. return {static_cast<handler_type *>(it->group.get())->current, assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()...};
  1208. }
  1209. }
  1210. /*! @copydoc group */
  1211. template<typename... Owned, typename... Exclude>
  1212. [[nodiscard]] basic_group<entity_type, owned_t<Owned...>, get_t<>, exclude_t<Exclude...>> group(exclude_t<Exclude...> = {}) {
  1213. return group<Owned...>(get_t<>{}, exclude<Exclude...>);
  1214. }
  1215. /*! @copydoc group */
  1216. template<typename... Owned, typename... Exclude>
  1217. [[nodiscard]] basic_group<entity_type, owned_t<std::add_const_t<Owned>...>, get_t<>, exclude_t<Exclude...>> group_if_exists(exclude_t<Exclude...> = {}) const {
  1218. return group_if_exists<std::add_const_t<Owned>...>(get_t<>{}, exclude<Exclude...>);
  1219. }
  1220. /**
  1221. * @brief Checks whether the given components belong to any group.
  1222. * @tparam Component Types of components in which one is interested.
  1223. * @return True if the pools of the given components are _free_, false
  1224. * otherwise.
  1225. */
  1226. template<typename... Component>
  1227. [[nodiscard]] bool owned() const {
  1228. return std::any_of(groups.cbegin(), groups.cend(), [](auto &&gdata) { return (gdata.owned(type_hash<std::remove_const_t<Component>>::value()) || ...); });
  1229. }
  1230. /**
  1231. * @brief Checks whether a group can be sorted.
  1232. * @tparam Owned Types of components owned by the group.
  1233. * @tparam Get Types of components observed by the group.
  1234. * @tparam Exclude Types of components used to filter the group.
  1235. * @return True if the group can be sorted, false otherwise.
  1236. */
  1237. template<typename... Owned, typename... Get, typename... Exclude>
  1238. [[nodiscard]] bool sortable(const basic_group<entity_type, owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> &) ENTT_NOEXCEPT {
  1239. constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
  1240. auto pred = [size](const auto &gdata) { return (0u + ... + gdata.owned(type_hash<std::remove_const_t<Owned>>::value())) && (size < gdata.size); };
  1241. return std::find_if(groups.cbegin(), groups.cend(), std::move(pred)) == groups.cend();
  1242. }
  1243. /**
  1244. * @brief Sorts the elements of a given component.
  1245. *
  1246. * The order remains valid until a component of the given type is assigned
  1247. * to or removed from an entity.<br/>
  1248. * The comparison function object returns `true` if the first element is
  1249. * _less_ than the second one, `false` otherwise. Its signature is also
  1250. * equivalent to one of the following:
  1251. *
  1252. * @code{.cpp}
  1253. * bool(const Entity, const Entity);
  1254. * bool(const Component &, const Component &);
  1255. * @endcode
  1256. *
  1257. * Moreover, it shall induce a _strict weak ordering_ on the values.<br/>
  1258. * The sort function object offers an `operator()` that accepts:
  1259. *
  1260. * * An iterator to the first element of the range to sort.
  1261. * * An iterator past the last element of the range to sort.
  1262. * * A comparison function object to use to compare the elements.
  1263. *
  1264. * The comparison function object hasn't necessarily the type of the one
  1265. * passed along with the other parameters to this member function.
  1266. *
  1267. * @warning
  1268. * Pools of components owned by a group cannot be sorted.
  1269. *
  1270. * @tparam Component Type of components to sort.
  1271. * @tparam Compare Type of comparison function object.
  1272. * @tparam Sort Type of sort function object.
  1273. * @tparam Args Types of arguments to forward to the sort function object.
  1274. * @param compare A valid comparison function object.
  1275. * @param algo A valid sort function object.
  1276. * @param args Arguments to forward to the sort function object, if any.
  1277. */
  1278. template<typename Component, typename Compare, typename Sort = std_sort, typename... Args>
  1279. void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
  1280. ENTT_ASSERT(!owned<Component>(), "Cannot sort owned storage");
  1281. auto &cpool = assure<Component>();
  1282. if constexpr(std::is_invocable_v<Compare, decltype(cpool.get({})), decltype(cpool.get({}))>) {
  1283. 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))); };
  1284. cpool.sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
  1285. } else {
  1286. cpool.sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
  1287. }
  1288. }
  1289. /**
  1290. * @brief Sorts two pools of components in the same way.
  1291. *
  1292. * Being `To` and `From` the two sets, after invoking this function an
  1293. * iterator for `To` returns elements according to the following rules:
  1294. *
  1295. * * All entities in `To` that are also in `From` are returned first
  1296. * according to the order they have in `From`.
  1297. * * All entities in `To` that are not in `From` are returned in no
  1298. * particular order after all the other entities.
  1299. *
  1300. * Any subsequent change to `From` won't affect the order in `To`.
  1301. *
  1302. * @warning
  1303. * Pools of components owned by a group cannot be sorted.
  1304. *
  1305. * @tparam To Type of components to sort.
  1306. * @tparam From Type of components to use to sort.
  1307. */
  1308. template<typename To, typename From>
  1309. void sort() {
  1310. ENTT_ASSERT(!owned<To>(), "Cannot sort owned storage");
  1311. assure<To>().respect(assure<From>());
  1312. }
  1313. /**
  1314. * @brief Returns the context object, that is, a general purpose container.
  1315. * @return The context object, that is, a general purpose container.
  1316. */
  1317. context &ctx() ENTT_NOEXCEPT {
  1318. return vars;
  1319. }
  1320. /*! @copydoc ctx */
  1321. const context &ctx() const ENTT_NOEXCEPT {
  1322. return vars;
  1323. }
  1324. private:
  1325. dense_map<id_type, std::unique_ptr<base_type>, identity> pools;
  1326. std::vector<group_data> groups;
  1327. std::vector<entity_type> entities;
  1328. entity_type free_list;
  1329. context vars;
  1330. };
  1331. } // namespace entt
  1332. #endif