🛠️🐜 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.

905 lines
34 KiB

  1. #ifndef ENTT_ENTITY_GROUP_HPP
  2. #define ENTT_ENTITY_GROUP_HPP
  3. #include <tuple>
  4. #include <type_traits>
  5. #include <utility>
  6. #include "../config/config.h"
  7. #include "../core/iterator.hpp"
  8. #include "../core/type_traits.hpp"
  9. #include "component.hpp"
  10. #include "entity.hpp"
  11. #include "fwd.hpp"
  12. #include "sparse_set.hpp"
  13. #include "storage.hpp"
  14. #include "utility.hpp"
  15. namespace entt {
  16. /**
  17. * @brief Group.
  18. *
  19. * Primary template isn't defined on purpose. All the specializations give a
  20. * compile-time error, but for a few reasonable cases.
  21. */
  22. template<typename, typename, typename, typename>
  23. class basic_group;
  24. /**
  25. * @brief Non-owning group.
  26. *
  27. * A non-owning group returns all entities and only the entities that have at
  28. * least the given components. Moreover, it's guaranteed that the entity list
  29. * is tightly packed in memory for fast iterations.
  30. *
  31. * @b Important
  32. *
  33. * Iterators aren't invalidated if:
  34. *
  35. * * New instances of the given components are created and assigned to entities.
  36. * * The entity currently pointed is modified (as an example, if one of the
  37. * given components is removed from the entity to which the iterator points).
  38. * * The entity currently pointed is destroyed.
  39. *
  40. * In all other cases, modifying the pools iterated by the group in any way
  41. * invalidates all the iterators and using them results in undefined behavior.
  42. *
  43. * @note
  44. * Groups share references to the underlying data structures of the registry
  45. * that generated them. Therefore any change to the entities and to the
  46. * components made by means of the registry are immediately reflected by all the
  47. * groups.<br/>
  48. * Moreover, sorting a non-owning group affects all the instances of the same
  49. * group (it means that users don't have to call `sort` on each instance to sort
  50. * all of them because they _share_ entities and components).
  51. *
  52. * @warning
  53. * Lifetime of a group must not overcome that of the registry that generated it.
  54. * In any other case, attempting to use a group results in undefined behavior.
  55. *
  56. * @tparam Entity A valid entity type (see entt_traits for more details).
  57. * @tparam Get Type of components observed by the group.
  58. * @tparam Exclude Types of components used to filter the group.
  59. */
  60. template<typename Entity, typename... Get, typename... Exclude>
  61. class basic_group<Entity, owned_t<>, get_t<Get...>, exclude_t<Exclude...>> {
  62. /*! @brief A registry is allowed to create groups. */
  63. friend class basic_registry<Entity>;
  64. template<typename Comp>
  65. using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Comp>>::storage_type, Comp>;
  66. using basic_common_type = std::common_type_t<typename storage_type<Get>::base_type...>;
  67. struct extended_group_iterator final {
  68. using difference_type = std::ptrdiff_t;
  69. using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_group>().get({})));
  70. using pointer = input_iterator_pointer<value_type>;
  71. using reference = value_type;
  72. using iterator_category = std::input_iterator_tag;
  73. extended_group_iterator() = default;
  74. extended_group_iterator(typename basic_common_type::iterator from, const std::tuple<storage_type<Get> *...> &args)
  75. : it{from},
  76. pools{args} {}
  77. extended_group_iterator &operator++() ENTT_NOEXCEPT {
  78. return ++it, *this;
  79. }
  80. extended_group_iterator operator++(int) ENTT_NOEXCEPT {
  81. extended_group_iterator orig = *this;
  82. return ++(*this), orig;
  83. }
  84. [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
  85. const auto entt = *it;
  86. return std::tuple_cat(std::make_tuple(entt), std::get<storage_type<Get> *>(pools)->get_as_tuple(entt)...);
  87. }
  88. [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
  89. return operator*();
  90. }
  91. [[nodiscard]] bool operator==(const extended_group_iterator &other) const ENTT_NOEXCEPT {
  92. return other.it == it;
  93. }
  94. [[nodiscard]] bool operator!=(const extended_group_iterator &other) const ENTT_NOEXCEPT {
  95. return !(*this == other);
  96. }
  97. private:
  98. typename basic_common_type::iterator it;
  99. std::tuple<storage_type<Get> *...> pools;
  100. };
  101. basic_group(basic_common_type &ref, storage_type<Get> &...gpool) ENTT_NOEXCEPT
  102. : handler{&ref},
  103. pools{&gpool...} {}
  104. public:
  105. /*! @brief Underlying entity identifier. */
  106. using entity_type = Entity;
  107. /*! @brief Unsigned integer type. */
  108. using size_type = std::size_t;
  109. /*! @brief Common type among all storage types. */
  110. using base_type = basic_common_type;
  111. /*! @brief Random access iterator type. */
  112. using iterator = typename base_type::iterator;
  113. /*! @brief Reversed iterator type. */
  114. using reverse_iterator = typename base_type::reverse_iterator;
  115. /*! @brief Iterable group type. */
  116. using iterable = iterable_adaptor<extended_group_iterator>;
  117. /*! @brief Default constructor to use to create empty, invalid groups. */
  118. basic_group() ENTT_NOEXCEPT
  119. : handler{} {}
  120. /**
  121. * @brief Returns a const reference to the underlying handler.
  122. * @return A const reference to the underlying handler.
  123. */
  124. const base_type &handle() const ENTT_NOEXCEPT {
  125. return *handler;
  126. }
  127. /**
  128. * @brief Returns the storage for a given component type.
  129. * @tparam Comp Type of component of which to return the storage.
  130. * @return The storage for the given component type.
  131. */
  132. template<typename Comp>
  133. [[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
  134. return *std::get<storage_type<Comp> *>(pools);
  135. }
  136. /**
  137. * @brief Returns the storage for a given component type.
  138. * @tparam Comp Index of component of which to return the storage.
  139. * @return The storage for the given component type.
  140. */
  141. template<std::size_t Comp>
  142. [[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
  143. return *std::get<Comp>(pools);
  144. }
  145. /**
  146. * @brief Returns the number of entities that have the given components.
  147. * @return Number of entities that have the given components.
  148. */
  149. [[nodiscard]] size_type size() const ENTT_NOEXCEPT {
  150. return *this ? handler->size() : size_type{};
  151. }
  152. /**
  153. * @brief Returns the number of elements that a group has currently
  154. * allocated space for.
  155. * @return Capacity of the group.
  156. */
  157. [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT {
  158. return *this ? handler->capacity() : size_type{};
  159. }
  160. /*! @brief Requests the removal of unused capacity. */
  161. void shrink_to_fit() {
  162. if(*this) {
  163. handler->shrink_to_fit();
  164. }
  165. }
  166. /**
  167. * @brief Checks whether a group is empty.
  168. * @return True if the group is empty, false otherwise.
  169. */
  170. [[nodiscard]] bool empty() const ENTT_NOEXCEPT {
  171. return !*this || handler->empty();
  172. }
  173. /**
  174. * @brief Returns an iterator to the first entity of the group.
  175. *
  176. * The returned iterator points to the first entity of the group. If the
  177. * group is empty, the returned iterator will be equal to `end()`.
  178. *
  179. * @return An iterator to the first entity of the group.
  180. */
  181. [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
  182. return *this ? handler->begin() : iterator{};
  183. }
  184. /**
  185. * @brief Returns an iterator that is past the last entity of the group.
  186. *
  187. * The returned iterator points to the entity following the last entity of
  188. * the group. Attempting to dereference the returned iterator results in
  189. * undefined behavior.
  190. *
  191. * @return An iterator to the entity following the last entity of the
  192. * group.
  193. */
  194. [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
  195. return *this ? handler->end() : iterator{};
  196. }
  197. /**
  198. * @brief Returns an iterator to the first entity of the reversed group.
  199. *
  200. * The returned iterator points to the first entity of the reversed group.
  201. * If the group is empty, the returned iterator will be equal to `rend()`.
  202. *
  203. * @return An iterator to the first entity of the reversed group.
  204. */
  205. [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
  206. return *this ? handler->rbegin() : reverse_iterator{};
  207. }
  208. /**
  209. * @brief Returns an iterator that is past the last entity of the reversed
  210. * group.
  211. *
  212. * The returned iterator points to the entity following the last entity of
  213. * the reversed group. Attempting to dereference the returned iterator
  214. * results in undefined behavior.
  215. *
  216. * @return An iterator to the entity following the last entity of the
  217. * reversed group.
  218. */
  219. [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
  220. return *this ? handler->rend() : reverse_iterator{};
  221. }
  222. /**
  223. * @brief Returns the first entity of the group, if any.
  224. * @return The first entity of the group if one exists, the null entity
  225. * otherwise.
  226. */
  227. [[nodiscard]] entity_type front() const ENTT_NOEXCEPT {
  228. const auto it = begin();
  229. return it != end() ? *it : null;
  230. }
  231. /**
  232. * @brief Returns the last entity of the group, if any.
  233. * @return The last entity of the group if one exists, the null entity
  234. * otherwise.
  235. */
  236. [[nodiscard]] entity_type back() const ENTT_NOEXCEPT {
  237. const auto it = rbegin();
  238. return it != rend() ? *it : null;
  239. }
  240. /**
  241. * @brief Finds an entity.
  242. * @param entt A valid identifier.
  243. * @return An iterator to the given entity if it's found, past the end
  244. * iterator otherwise.
  245. */
  246. [[nodiscard]] iterator find(const entity_type entt) const ENTT_NOEXCEPT {
  247. const auto it = *this ? handler->find(entt) : iterator{};
  248. return it != end() && *it == entt ? it : end();
  249. }
  250. /**
  251. * @brief Returns the identifier that occupies the given position.
  252. * @param pos Position of the element to return.
  253. * @return The identifier that occupies the given position.
  254. */
  255. [[nodiscard]] entity_type operator[](const size_type pos) const {
  256. return begin()[pos];
  257. }
  258. /**
  259. * @brief Checks if a group is properly initialized.
  260. * @return True if the group is properly initialized, false otherwise.
  261. */
  262. [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
  263. return handler != nullptr;
  264. }
  265. /**
  266. * @brief Checks if a group contains an entity.
  267. * @param entt A valid identifier.
  268. * @return True if the group contains the given entity, false otherwise.
  269. */
  270. [[nodiscard]] bool contains(const entity_type entt) const ENTT_NOEXCEPT {
  271. return *this && handler->contains(entt);
  272. }
  273. /**
  274. * @brief Returns the components assigned to the given entity.
  275. *
  276. * Prefer this function instead of `registry::get` during iterations. It has
  277. * far better performance than its counterpart.
  278. *
  279. * @warning
  280. * Attempting to use an invalid component type results in a compilation
  281. * error. Attempting to use an entity that doesn't belong to the group
  282. * results in undefined behavior.
  283. *
  284. * @tparam Comp Types of components to get.
  285. * @param entt A valid identifier.
  286. * @return The components assigned to the entity.
  287. */
  288. template<typename... Comp>
  289. [[nodiscard]] decltype(auto) get(const entity_type entt) const {
  290. ENTT_ASSERT(contains(entt), "Group does not contain entity");
  291. if constexpr(sizeof...(Comp) == 0) {
  292. return std::tuple_cat(std::get<storage_type<Get> *>(pools)->get_as_tuple(entt)...);
  293. } else if constexpr(sizeof...(Comp) == 1) {
  294. return (std::get<storage_type<Comp> *>(pools)->get(entt), ...);
  295. } else {
  296. return std::tuple_cat(std::get<storage_type<Comp> *>(pools)->get_as_tuple(entt)...);
  297. }
  298. }
  299. /**
  300. * @brief Iterates entities and components and applies the given function
  301. * object to them.
  302. *
  303. * The function object is invoked for each entity. It is provided with the
  304. * entity itself and a set of references to non-empty components. The
  305. * _constness_ of the components is as requested.<br/>
  306. * The signature of the function must be equivalent to one of the following
  307. * forms:
  308. *
  309. * @code{.cpp}
  310. * void(const entity_type, Type &...);
  311. * void(Type &...);
  312. * @endcode
  313. *
  314. * @note
  315. * Empty types aren't explicitly instantiated and therefore they are never
  316. * returned during iterations.
  317. *
  318. * @tparam Func Type of the function object to invoke.
  319. * @param func A valid function object.
  320. */
  321. template<typename Func>
  322. void each(Func func) const {
  323. for(const auto entt: *this) {
  324. if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
  325. std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt)));
  326. } else {
  327. std::apply(func, get(entt));
  328. }
  329. }
  330. }
  331. /**
  332. * @brief Returns an iterable object to use to _visit_ a group.
  333. *
  334. * The iterable object returns tuples that contain the current entity and a
  335. * set of references to its non-empty components. The _constness_ of the
  336. * components is as requested.
  337. *
  338. * @note
  339. * Empty types aren't explicitly instantiated and therefore they are never
  340. * returned during iterations.
  341. *
  342. * @return An iterable object to use to _visit_ the group.
  343. */
  344. [[nodiscard]] iterable each() const ENTT_NOEXCEPT {
  345. return handler ? iterable{extended_group_iterator{handler->begin(), pools}, extended_group_iterator{handler->end(), pools}}
  346. : iterable{extended_group_iterator{{}, pools}, extended_group_iterator{{}, pools}};
  347. }
  348. /**
  349. * @brief Sort a group according to the given comparison function.
  350. *
  351. * Sort the group so that iterating it with a couple of iterators returns
  352. * entities and components in the expected order. See `begin` and `end` for
  353. * more details.
  354. *
  355. * The comparison function object must return `true` if the first element
  356. * is _less_ than the second one, `false` otherwise. The signature of the
  357. * comparison function should be equivalent to one of the following:
  358. *
  359. * @code{.cpp}
  360. * bool(std::tuple<Component &...>, std::tuple<Component &...>);
  361. * bool(const Component &..., const Component &...);
  362. * bool(const Entity, const Entity);
  363. * @endcode
  364. *
  365. * Where `Component` are such that they are iterated by the group.<br/>
  366. * Moreover, the comparison function object shall induce a
  367. * _strict weak ordering_ on the values.
  368. *
  369. * The sort function object must offer a member function template
  370. * `operator()` that accepts three arguments:
  371. *
  372. * * An iterator to the first element of the range to sort.
  373. * * An iterator past the last element of the range to sort.
  374. * * A comparison function to use to compare the elements.
  375. *
  376. * @tparam Comp Optional types of components to compare.
  377. * @tparam Compare Type of comparison function object.
  378. * @tparam Sort Type of sort function object.
  379. * @tparam Args Types of arguments to forward to the sort function object.
  380. * @param compare A valid comparison function object.
  381. * @param algo A valid sort function object.
  382. * @param args Arguments to forward to the sort function object, if any.
  383. */
  384. template<typename... Comp, typename Compare, typename Sort = std_sort, typename... Args>
  385. void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
  386. if(*this) {
  387. if constexpr(sizeof...(Comp) == 0) {
  388. static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
  389. handler->sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
  390. } else {
  391. auto comp = [this, &compare](const entity_type lhs, const entity_type rhs) {
  392. if constexpr(sizeof...(Comp) == 1) {
  393. return compare((std::get<storage_type<Comp> *>(pools)->get(lhs), ...), (std::get<storage_type<Comp> *>(pools)->get(rhs), ...));
  394. } else {
  395. return compare(std::forward_as_tuple(std::get<storage_type<Comp> *>(pools)->get(lhs)...), std::forward_as_tuple(std::get<storage_type<Comp> *>(pools)->get(rhs)...));
  396. }
  397. };
  398. handler->sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
  399. }
  400. }
  401. }
  402. /**
  403. * @brief Sort the shared pool of entities according to the given component.
  404. *
  405. * Non-owning groups of the same type share with the registry a pool of
  406. * entities with its own order that doesn't depend on the order of any pool
  407. * of components. Users can order the underlying data structure so that it
  408. * respects the order of the pool of the given component.
  409. *
  410. * @note
  411. * The shared pool of entities and thus its order is affected by the changes
  412. * to each and every pool that it tracks. Therefore changes to those pools
  413. * can quickly ruin the order imposed to the pool of entities shared between
  414. * the non-owning groups.
  415. *
  416. * @tparam Comp Type of component to use to impose the order.
  417. */
  418. template<typename Comp>
  419. void sort() const {
  420. if(*this) {
  421. handler->respect(*std::get<storage_type<Comp> *>(pools));
  422. }
  423. }
  424. private:
  425. base_type *const handler;
  426. const std::tuple<storage_type<Get> *...> pools;
  427. };
  428. /**
  429. * @brief Owning group.
  430. *
  431. * Owning groups return all entities and only the entities that have at least
  432. * the given components. Moreover:
  433. *
  434. * * It's guaranteed that the entity list is tightly packed in memory for fast
  435. * iterations.
  436. * * It's guaranteed that the lists of owned components are tightly packed in
  437. * memory for even faster iterations and to allow direct access.
  438. * * They stay true to the order of the owned components and all instances have
  439. * the same order in memory.
  440. *
  441. * The more types of components are owned by a group, the faster it is to
  442. * iterate them.
  443. *
  444. * @b Important
  445. *
  446. * Iterators aren't invalidated if:
  447. *
  448. * * New instances of the given components are created and assigned to entities.
  449. * * The entity currently pointed is modified (as an example, if one of the
  450. * given components is removed from the entity to which the iterator points).
  451. * * The entity currently pointed is destroyed.
  452. *
  453. * In all other cases, modifying the pools iterated by the group in any way
  454. * invalidates all the iterators and using them results in undefined behavior.
  455. *
  456. * @note
  457. * Groups share references to the underlying data structures of the registry
  458. * that generated them. Therefore any change to the entities and to the
  459. * components made by means of the registry are immediately reflected by all the
  460. * groups.
  461. * Moreover, sorting an owning group affects all the instance of the same group
  462. * (it means that users don't have to call `sort` on each instance to sort all
  463. * of them because they share the underlying data structure).
  464. *
  465. * @warning
  466. * Lifetime of a group must not overcome that of the registry that generated it.
  467. * In any other case, attempting to use a group results in undefined behavior.
  468. *
  469. * @tparam Entity A valid entity type (see entt_traits for more details).
  470. * @tparam Owned Types of components owned by the group.
  471. * @tparam Get Types of components observed by the group.
  472. * @tparam Exclude Types of components used to filter the group.
  473. */
  474. template<typename Entity, typename... Owned, typename... Get, typename... Exclude>
  475. class basic_group<Entity, owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> {
  476. /*! @brief A registry is allowed to create groups. */
  477. friend class basic_registry<Entity>;
  478. template<typename Comp>
  479. using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Comp>>::storage_type, Comp>;
  480. using basic_common_type = std::common_type_t<typename storage_type<Owned>::base_type..., typename storage_type<Get>::base_type...>;
  481. class extended_group_iterator final {
  482. template<typename Type>
  483. auto index_to_element(storage_type<Type> &cpool) const {
  484. if constexpr(ignore_as_empty_v<std::remove_const_t<Type>>) {
  485. return std::make_tuple();
  486. } else {
  487. return std::forward_as_tuple(cpool.rbegin()[it.index()]);
  488. }
  489. }
  490. public:
  491. using difference_type = std::ptrdiff_t;
  492. using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_group>().get({})));
  493. using pointer = input_iterator_pointer<value_type>;
  494. using reference = value_type;
  495. using iterator_category = std::input_iterator_tag;
  496. extended_group_iterator() = default;
  497. template<typename... Other>
  498. extended_group_iterator(typename basic_common_type::iterator from, const std::tuple<storage_type<Owned> *..., storage_type<Get> *...> &cpools)
  499. : it{from},
  500. pools{cpools} {}
  501. extended_group_iterator &operator++() ENTT_NOEXCEPT {
  502. return ++it, *this;
  503. }
  504. extended_group_iterator operator++(int) ENTT_NOEXCEPT {
  505. extended_group_iterator orig = *this;
  506. return ++(*this), orig;
  507. }
  508. [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
  509. return std::tuple_cat(
  510. std::make_tuple(*it),
  511. index_to_element<Owned>(*std::get<storage_type<Owned> *>(pools))...,
  512. std::get<storage_type<Get> *>(pools)->get_as_tuple(*it)...);
  513. }
  514. [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
  515. return operator*();
  516. }
  517. [[nodiscard]] bool operator==(const extended_group_iterator &other) const ENTT_NOEXCEPT {
  518. return other.it == it;
  519. }
  520. [[nodiscard]] bool operator!=(const extended_group_iterator &other) const ENTT_NOEXCEPT {
  521. return !(*this == other);
  522. }
  523. private:
  524. typename basic_common_type::iterator it;
  525. std::tuple<storage_type<Owned> *..., storage_type<Get> *...> pools;
  526. };
  527. basic_group(const std::size_t &extent, storage_type<Owned> &...opool, storage_type<Get> &...gpool) ENTT_NOEXCEPT
  528. : pools{&opool..., &gpool...},
  529. length{&extent} {}
  530. public:
  531. /*! @brief Underlying entity identifier. */
  532. using entity_type = Entity;
  533. /*! @brief Unsigned integer type. */
  534. using size_type = std::size_t;
  535. /*! @brief Common type among all storage types. */
  536. using base_type = basic_common_type;
  537. /*! @brief Random access iterator type. */
  538. using iterator = typename base_type::iterator;
  539. /*! @brief Reversed iterator type. */
  540. using reverse_iterator = typename base_type::reverse_iterator;
  541. /*! @brief Iterable group type. */
  542. using iterable = iterable_adaptor<extended_group_iterator>;
  543. /*! @brief Default constructor to use to create empty, invalid groups. */
  544. basic_group() ENTT_NOEXCEPT
  545. : length{} {}
  546. /**
  547. * @brief Returns the storage for a given component type.
  548. * @tparam Comp Type of component of which to return the storage.
  549. * @return The storage for the given component type.
  550. */
  551. template<typename Comp>
  552. [[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
  553. return *std::get<storage_type<Comp> *>(pools);
  554. }
  555. /**
  556. * @brief Returns the storage for a given component type.
  557. * @tparam Comp Index of component of which to return the storage.
  558. * @return The storage for the given component type.
  559. */
  560. template<std::size_t Comp>
  561. [[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
  562. return *std::get<Comp>(pools);
  563. }
  564. /**
  565. * @brief Returns the number of entities that have the given components.
  566. * @return Number of entities that have the given components.
  567. */
  568. [[nodiscard]] size_type size() const ENTT_NOEXCEPT {
  569. return *this ? *length : size_type{};
  570. }
  571. /**
  572. * @brief Checks whether a group is empty.
  573. * @return True if the group is empty, false otherwise.
  574. */
  575. [[nodiscard]] bool empty() const ENTT_NOEXCEPT {
  576. return !*this || !*length;
  577. }
  578. /**
  579. * @brief Returns an iterator to the first entity of the group.
  580. *
  581. * The returned iterator points to the first entity of the group. If the
  582. * group is empty, the returned iterator will be equal to `end()`.
  583. *
  584. * @return An iterator to the first entity of the group.
  585. */
  586. [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
  587. return *this ? (std::get<0>(pools)->base_type::end() - *length) : iterator{};
  588. }
  589. /**
  590. * @brief Returns an iterator that is past the last entity of the group.
  591. *
  592. * The returned iterator points to the entity following the last entity of
  593. * the group. Attempting to dereference the returned iterator results in
  594. * undefined behavior.
  595. *
  596. * @return An iterator to the entity following the last entity of the
  597. * group.
  598. */
  599. [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
  600. return *this ? std::get<0>(pools)->base_type::end() : iterator{};
  601. }
  602. /**
  603. * @brief Returns an iterator to the first entity of the reversed group.
  604. *
  605. * The returned iterator points to the first entity of the reversed group.
  606. * If the group is empty, the returned iterator will be equal to `rend()`.
  607. *
  608. * @return An iterator to the first entity of the reversed group.
  609. */
  610. [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
  611. return *this ? std::get<0>(pools)->base_type::rbegin() : reverse_iterator{};
  612. }
  613. /**
  614. * @brief Returns an iterator that is past the last entity of the reversed
  615. * group.
  616. *
  617. * The returned iterator points to the entity following the last entity of
  618. * the reversed group. Attempting to dereference the returned iterator
  619. * results in undefined behavior.
  620. *
  621. * @return An iterator to the entity following the last entity of the
  622. * reversed group.
  623. */
  624. [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
  625. return *this ? (std::get<0>(pools)->base_type::rbegin() + *length) : reverse_iterator{};
  626. }
  627. /**
  628. * @brief Returns the first entity of the group, if any.
  629. * @return The first entity of the group if one exists, the null entity
  630. * otherwise.
  631. */
  632. [[nodiscard]] entity_type front() const ENTT_NOEXCEPT {
  633. const auto it = begin();
  634. return it != end() ? *it : null;
  635. }
  636. /**
  637. * @brief Returns the last entity of the group, if any.
  638. * @return The last entity of the group if one exists, the null entity
  639. * otherwise.
  640. */
  641. [[nodiscard]] entity_type back() const ENTT_NOEXCEPT {
  642. const auto it = rbegin();
  643. return it != rend() ? *it : null;
  644. }
  645. /**
  646. * @brief Finds an entity.
  647. * @param entt A valid identifier.
  648. * @return An iterator to the given entity if it's found, past the end
  649. * iterator otherwise.
  650. */
  651. [[nodiscard]] iterator find(const entity_type entt) const ENTT_NOEXCEPT {
  652. const auto it = *this ? std::get<0>(pools)->find(entt) : iterator{};
  653. return it != end() && it >= begin() && *it == entt ? it : end();
  654. }
  655. /**
  656. * @brief Returns the identifier that occupies the given position.
  657. * @param pos Position of the element to return.
  658. * @return The identifier that occupies the given position.
  659. */
  660. [[nodiscard]] entity_type operator[](const size_type pos) const {
  661. return begin()[pos];
  662. }
  663. /**
  664. * @brief Checks if a group is properly initialized.
  665. * @return True if the group is properly initialized, false otherwise.
  666. */
  667. [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
  668. return length != nullptr;
  669. }
  670. /**
  671. * @brief Checks if a group contains an entity.
  672. * @param entt A valid identifier.
  673. * @return True if the group contains the given entity, false otherwise.
  674. */
  675. [[nodiscard]] bool contains(const entity_type entt) const ENTT_NOEXCEPT {
  676. return *this && std::get<0>(pools)->contains(entt) && (std::get<0>(pools)->index(entt) < (*length));
  677. }
  678. /**
  679. * @brief Returns the components assigned to the given entity.
  680. *
  681. * Prefer this function instead of `registry::get` during iterations. It has
  682. * far better performance than its counterpart.
  683. *
  684. * @warning
  685. * Attempting to use an invalid component type results in a compilation
  686. * error. Attempting to use an entity that doesn't belong to the group
  687. * results in undefined behavior.
  688. *
  689. * @tparam Comp Types of components to get.
  690. * @param entt A valid identifier.
  691. * @return The components assigned to the entity.
  692. */
  693. template<typename... Comp>
  694. [[nodiscard]] decltype(auto) get(const entity_type entt) const {
  695. ENTT_ASSERT(contains(entt), "Group does not contain entity");
  696. if constexpr(sizeof...(Comp) == 0) {
  697. return std::tuple_cat(std::get<storage_type<Owned> *>(pools)->get_as_tuple(entt)..., std::get<storage_type<Get> *>(pools)->get_as_tuple(entt)...);
  698. } else if constexpr(sizeof...(Comp) == 1) {
  699. return (std::get<storage_type<Comp> *>(pools)->get(entt), ...);
  700. } else {
  701. return std::tuple_cat(std::get<storage_type<Comp> *>(pools)->get_as_tuple(entt)...);
  702. }
  703. }
  704. /**
  705. * @brief Iterates entities and components and applies the given function
  706. * object to them.
  707. *
  708. * The function object is invoked for each entity. It is provided with the
  709. * entity itself and a set of references to non-empty components. The
  710. * _constness_ of the components is as requested.<br/>
  711. * The signature of the function must be equivalent to one of the following
  712. * forms:
  713. *
  714. * @code{.cpp}
  715. * void(const entity_type, Type &...);
  716. * void(Type &...);
  717. * @endcode
  718. *
  719. * @note
  720. * Empty types aren't explicitly instantiated and therefore they are never
  721. * returned during iterations.
  722. *
  723. * @tparam Func Type of the function object to invoke.
  724. * @param func A valid function object.
  725. */
  726. template<typename Func>
  727. void each(Func func) const {
  728. for(auto args: each()) {
  729. if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
  730. std::apply(func, args);
  731. } else {
  732. std::apply([&func](auto, auto &&...less) { func(std::forward<decltype(less)>(less)...); }, args);
  733. }
  734. }
  735. }
  736. /**
  737. * @brief Returns an iterable object to use to _visit_ a group.
  738. *
  739. * The iterable object returns tuples that contain the current entity and a
  740. * set of references to its non-empty components. The _constness_ of the
  741. * components is as requested.
  742. *
  743. * @note
  744. * Empty types aren't explicitly instantiated and therefore they are never
  745. * returned during iterations.
  746. *
  747. * @return An iterable object to use to _visit_ the group.
  748. */
  749. [[nodiscard]] iterable each() const ENTT_NOEXCEPT {
  750. iterator last = length ? std::get<0>(pools)->basic_common_type::end() : iterator{};
  751. return {extended_group_iterator{last - *length, pools}, extended_group_iterator{last, pools}};
  752. }
  753. /**
  754. * @brief Sort a group according to the given comparison function.
  755. *
  756. * Sort the group so that iterating it with a couple of iterators returns
  757. * entities and components in the expected order. See `begin` and `end` for
  758. * more details.
  759. *
  760. * The comparison function object must return `true` if the first element
  761. * is _less_ than the second one, `false` otherwise. The signature of the
  762. * comparison function should be equivalent to one of the following:
  763. *
  764. * @code{.cpp}
  765. * bool(std::tuple<Component &...>, std::tuple<Component &...>);
  766. * bool(const Component &, const Component &);
  767. * bool(const Entity, const Entity);
  768. * @endcode
  769. *
  770. * Where `Component` are either owned types or not but still such that they
  771. * are iterated by the group.<br/>
  772. * Moreover, the comparison function object shall induce a
  773. * _strict weak ordering_ on the values.
  774. *
  775. * The sort function object must offer a member function template
  776. * `operator()` that accepts three arguments:
  777. *
  778. * * An iterator to the first element of the range to sort.
  779. * * An iterator past the last element of the range to sort.
  780. * * A comparison function to use to compare the elements.
  781. *
  782. * @tparam Comp Optional types of components to compare.
  783. * @tparam Compare Type of comparison function object.
  784. * @tparam Sort Type of sort function object.
  785. * @tparam Args Types of arguments to forward to the sort function object.
  786. * @param compare A valid comparison function object.
  787. * @param algo A valid sort function object.
  788. * @param args Arguments to forward to the sort function object, if any.
  789. */
  790. template<typename... Comp, typename Compare, typename Sort = std_sort, typename... Args>
  791. void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const {
  792. auto *cpool = std::get<0>(pools);
  793. if constexpr(sizeof...(Comp) == 0) {
  794. static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
  795. cpool->sort_n(*length, std::move(compare), std::move(algo), std::forward<Args>(args)...);
  796. } else {
  797. auto comp = [this, &compare](const entity_type lhs, const entity_type rhs) {
  798. if constexpr(sizeof...(Comp) == 1) {
  799. return compare((std::get<storage_type<Comp> *>(pools)->get(lhs), ...), (std::get<storage_type<Comp> *>(pools)->get(rhs), ...));
  800. } else {
  801. return compare(std::forward_as_tuple(std::get<storage_type<Comp> *>(pools)->get(lhs)...), std::forward_as_tuple(std::get<storage_type<Comp> *>(pools)->get(rhs)...));
  802. }
  803. };
  804. cpool->sort_n(*length, std::move(comp), std::move(algo), std::forward<Args>(args)...);
  805. }
  806. [this](auto *head, auto *...other) {
  807. for(auto next = *length; next; --next) {
  808. const auto pos = next - 1;
  809. [[maybe_unused]] const auto entt = head->data()[pos];
  810. (other->swap_elements(other->data()[pos], entt), ...);
  811. }
  812. }(std::get<storage_type<Owned> *>(pools)...);
  813. }
  814. private:
  815. const std::tuple<storage_type<Owned> *..., storage_type<Get> *...> pools;
  816. const size_type *const length;
  817. };
  818. } // namespace entt
  819. #endif