group.hpp 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076
  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/fwd.hpp"
  8. #include "../core/iterator.hpp"
  9. #include "../core/type_info.hpp"
  10. #include "../core/type_traits.hpp"
  11. #include "entity.hpp"
  12. #include "fwd.hpp"
  13. #include "sparse_set.hpp"
  14. #include "storage.hpp"
  15. namespace entt {
  16. /**
  17. * @cond TURN_OFF_DOXYGEN
  18. * Internal details not to be documented.
  19. */
  20. namespace internal {
  21. template<typename, typename, typename>
  22. class extended_group_iterator;
  23. template<typename It, typename... Owned, typename... Get>
  24. class extended_group_iterator<It, owned_t<Owned...>, get_t<Get...>> {
  25. template<typename Type>
  26. auto index_to_element([[maybe_unused]] Type &cpool) const {
  27. if constexpr(Type::traits_type::page_size == 0u) {
  28. return std::make_tuple();
  29. } else {
  30. return std::forward_as_tuple(cpool.rbegin()[it.index()]);
  31. }
  32. }
  33. public:
  34. using iterator_type = It;
  35. using difference_type = std::ptrdiff_t;
  36. using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Owned>().get_as_tuple({})..., std::declval<Get>().get_as_tuple({})...));
  37. using pointer = input_iterator_pointer<value_type>;
  38. using reference = value_type;
  39. using iterator_category = std::input_iterator_tag;
  40. using iterator_concept = std::forward_iterator_tag;
  41. constexpr extended_group_iterator()
  42. : it{},
  43. pools{} {}
  44. extended_group_iterator(iterator_type from, const std::tuple<Owned *..., Get *...> &cpools)
  45. : it{from},
  46. pools{cpools} {}
  47. extended_group_iterator &operator++() noexcept {
  48. return ++it, *this;
  49. }
  50. extended_group_iterator operator++(int) noexcept {
  51. extended_group_iterator orig = *this;
  52. return ++(*this), orig;
  53. }
  54. [[nodiscard]] reference operator*() const noexcept {
  55. return std::tuple_cat(std::make_tuple(*it), index_to_element(*std::get<Owned *>(pools))..., std::get<Get *>(pools)->get_as_tuple(*it)...);
  56. }
  57. [[nodiscard]] pointer operator->() const noexcept {
  58. return operator*();
  59. }
  60. [[nodiscard]] constexpr iterator_type base() const noexcept {
  61. return it;
  62. }
  63. template<typename... Lhs, typename... Rhs>
  64. friend constexpr bool operator==(const extended_group_iterator<Lhs...> &, const extended_group_iterator<Rhs...> &) noexcept;
  65. private:
  66. It it;
  67. std::tuple<Owned *..., Get *...> pools;
  68. };
  69. template<typename... Lhs, typename... Rhs>
  70. [[nodiscard]] constexpr bool operator==(const extended_group_iterator<Lhs...> &lhs, const extended_group_iterator<Rhs...> &rhs) noexcept {
  71. return lhs.it == rhs.it;
  72. }
  73. template<typename... Lhs, typename... Rhs>
  74. [[nodiscard]] constexpr bool operator!=(const extended_group_iterator<Lhs...> &lhs, const extended_group_iterator<Rhs...> &rhs) noexcept {
  75. return !(lhs == rhs);
  76. }
  77. struct group_descriptor {
  78. using size_type = std::size_t;
  79. virtual ~group_descriptor() = default;
  80. virtual size_type owned(const id_type *, const size_type) const noexcept {
  81. return 0u;
  82. }
  83. };
  84. template<typename, typename, typename>
  85. class group_handler;
  86. template<typename... Owned, typename... Get, typename... Exclude>
  87. class group_handler<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> final: public group_descriptor {
  88. // nasty workaround for an issue with the toolset v141 that doesn't accept a fold expression here
  89. static_assert(!std::disjunction_v<std::bool_constant<Owned::traits_type::in_place_delete>...>, "Groups do not support in-place delete");
  90. static_assert(!std::disjunction_v<std::is_const<Owned>..., std::is_const<Get>..., std::is_const<Exclude>...>, "Const storage type not allowed");
  91. using base_type = std::common_type_t<typename Owned::base_type..., typename Get::base_type..., typename Exclude::base_type...>;
  92. using entity_type = typename base_type::entity_type;
  93. void swap_elements(const std::size_t pos, const entity_type entt) {
  94. std::apply([pos, entt](auto *...cpool) { (cpool->swap_elements(cpool->data()[pos], entt), ...); }, pools);
  95. }
  96. void push_on_construct(const entity_type entt) {
  97. if(std::apply([entt, len = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < len) && (other->contains(entt) && ...); }, pools)
  98. && std::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
  99. swap_elements(len++, entt);
  100. }
  101. }
  102. void push_on_destroy(const entity_type entt) {
  103. if(std::apply([entt, len = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < len) && (other->contains(entt) && ...); }, pools)
  104. && std::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
  105. swap_elements(len++, entt);
  106. }
  107. }
  108. void remove_if(const entity_type entt) {
  109. if(std::get<0>(pools)->contains(entt) && (std::get<0>(pools)->index(entt) < len)) {
  110. swap_elements(--len, entt);
  111. }
  112. }
  113. public:
  114. using size_type = typename base_type::size_type;
  115. group_handler(Owned &...opool, Get &...gpool, Exclude &...epool)
  116. : pools{&opool..., &gpool...},
  117. filter{&epool...},
  118. len{} {
  119. std::apply([this](auto *...cpool) { ((cpool->on_construct().template connect<&group_handler::push_on_construct>(*this), cpool->on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, pools);
  120. std::apply([this](auto *...cpool) { ((cpool->on_construct().template connect<&group_handler::remove_if>(*this), cpool->on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, filter);
  121. // we cannot iterate backwards because we want to leave behind valid entities in case of owned types
  122. for(auto *first = std::get<0>(pools)->data(), *last = first + std::get<0>(pools)->size(); first != last; ++first) {
  123. push_on_construct(*first);
  124. }
  125. }
  126. size_type owned(const id_type *elem, const size_type length) const noexcept final {
  127. size_type cnt = 0u;
  128. for(auto pos = 0u; pos < length; ++pos) {
  129. cnt += ((elem[pos] == entt::type_hash<typename Owned::value_type>::value()) || ...);
  130. }
  131. return cnt;
  132. }
  133. [[nodiscard]] size_type length() const noexcept {
  134. return len;
  135. }
  136. template<typename Type>
  137. Type pools_as() const noexcept {
  138. return pools;
  139. }
  140. template<typename Type>
  141. Type filter_as() const noexcept {
  142. return filter;
  143. }
  144. private:
  145. std::tuple<Owned *..., Get *...> pools;
  146. std::tuple<Exclude *...> filter;
  147. std::size_t len;
  148. };
  149. template<typename... Get, typename... Exclude>
  150. class group_handler<owned_t<>, get_t<Get...>, exclude_t<Exclude...>> final: public group_descriptor {
  151. // nasty workaround for an issue with the toolset v141 that doesn't accept a fold expression here
  152. static_assert(!std::disjunction_v<std::is_const<Get>..., std::is_const<Exclude>...>, "Const storage type not allowed");
  153. using base_type = std::common_type_t<typename Get::base_type..., typename Exclude::base_type...>;
  154. using entity_type = typename base_type::entity_type;
  155. void push_on_construct(const entity_type entt) {
  156. if(!elem.contains(entt)
  157. && std::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools)
  158. && std::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
  159. elem.push(entt);
  160. }
  161. }
  162. void push_on_destroy(const entity_type entt) {
  163. if(!elem.contains(entt)
  164. && std::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools)
  165. && std::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
  166. elem.push(entt);
  167. }
  168. }
  169. void remove_if(const entity_type entt) {
  170. elem.remove(entt);
  171. }
  172. public:
  173. using common_type = base_type;
  174. template<typename Alloc>
  175. group_handler(const Alloc &alloc, Get &...gpool, Exclude &...epool)
  176. : pools{&gpool...},
  177. filter{&epool...},
  178. elem{alloc} {
  179. std::apply([this](auto *...cpool) { ((cpool->on_construct().template connect<&group_handler::push_on_construct>(*this), cpool->on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, pools);
  180. std::apply([this](auto *...cpool) { ((cpool->on_construct().template connect<&group_handler::remove_if>(*this), cpool->on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, filter);
  181. for(const auto entity: static_cast<base_type &>(*std::get<0>(pools))) {
  182. push_on_construct(entity);
  183. }
  184. }
  185. common_type &handle() noexcept {
  186. return elem;
  187. }
  188. const common_type &handle() const noexcept {
  189. return elem;
  190. }
  191. template<typename Type>
  192. Type pools_as() const noexcept {
  193. return pools;
  194. }
  195. template<typename Type>
  196. Type filter_as() const noexcept {
  197. return filter;
  198. }
  199. private:
  200. std::tuple<Get *...> pools;
  201. std::tuple<Exclude *...> filter;
  202. base_type elem;
  203. };
  204. } // namespace internal
  205. /**
  206. * Internal details not to be documented.
  207. * @endcond
  208. */
  209. /**
  210. * @brief Group.
  211. *
  212. * Primary template isn't defined on purpose. All the specializations give a
  213. * compile-time error, but for a few reasonable cases.
  214. */
  215. template<typename, typename, typename>
  216. class basic_group;
  217. /**
  218. * @brief Non-owning group.
  219. *
  220. * A non-owning group returns all entities and only the entities that are at
  221. * least in the given storage. Moreover, it's guaranteed that the entity list is
  222. * tightly packed in memory for fast iterations.
  223. *
  224. * @b Important
  225. *
  226. * Iterators aren't invalidated if:
  227. *
  228. * * New elements are added to the storage.
  229. * * The entity currently pointed is modified (for example, components are added
  230. * or removed from it).
  231. * * The entity currently pointed is destroyed.
  232. *
  233. * In all other cases, modifying the pools iterated by the group in any way
  234. * invalidates all the iterators.
  235. *
  236. * @tparam Get Types of storage _observed_ by the group.
  237. * @tparam Exclude Types of storage used to filter the group.
  238. */
  239. template<typename... Get, typename... Exclude>
  240. class basic_group<owned_t<>, get_t<Get...>, exclude_t<Exclude...>> {
  241. using base_type = std::common_type_t<typename Get::base_type..., typename Exclude::base_type...>;
  242. using underlying_type = typename base_type::entity_type;
  243. template<typename Type>
  244. static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Get::value_type..., typename Exclude::value_type...>>;
  245. auto pools() const noexcept {
  246. using return_type = std::tuple<Get *...>;
  247. return descriptor ? descriptor->template pools_as<return_type>() : return_type{};
  248. }
  249. auto filter() const noexcept {
  250. using return_type = std::tuple<Exclude *...>;
  251. return descriptor ? descriptor->template filter_as<return_type>() : return_type{};
  252. }
  253. public:
  254. /*! @brief Underlying entity identifier. */
  255. using entity_type = underlying_type;
  256. /*! @brief Unsigned integer type. */
  257. using size_type = std::size_t;
  258. /*! @brief Common type among all storage types. */
  259. using common_type = base_type;
  260. /*! @brief Random access iterator type. */
  261. using iterator = typename common_type::iterator;
  262. /*! @brief Reversed iterator type. */
  263. using reverse_iterator = typename common_type::reverse_iterator;
  264. /*! @brief Iterable group type. */
  265. using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<>, get_t<Get...>>>;
  266. /*! @brief Group handler type. */
  267. using handler = internal::group_handler<owned_t<>, get_t<std::remove_const_t<Get>...>, exclude_t<std::remove_const_t<Exclude>...>>;
  268. /*! @brief Default constructor to use to create empty, invalid groups. */
  269. basic_group() noexcept
  270. : descriptor{} {}
  271. /**
  272. * @brief Constructs a group from a set of storage classes.
  273. * @param ref A reference to a group handler.
  274. */
  275. basic_group(handler &ref) noexcept
  276. : descriptor{&ref} {}
  277. /**
  278. * @brief Returns the leading storage of a group.
  279. * @return The leading storage of the group.
  280. */
  281. [[nodiscard]] const common_type &handle() const noexcept {
  282. return descriptor->handle();
  283. }
  284. /**
  285. * @brief Returns the storage for a given component type, if any.
  286. * @tparam Type Type of component of which to return the storage.
  287. * @return The storage for the given component type.
  288. */
  289. template<typename Type>
  290. [[nodiscard]] auto *storage() const noexcept {
  291. return storage<index_of<Type>>();
  292. }
  293. /**
  294. * @brief Returns the storage for a given index, if any.
  295. * @tparam Index Index of the storage to return.
  296. * @return The storage for the given index.
  297. */
  298. template<std::size_t Index>
  299. [[nodiscard]] auto *storage() const noexcept {
  300. constexpr auto offset = sizeof...(Get);
  301. if constexpr(Index < offset) {
  302. return std::get<Index>(pools());
  303. } else {
  304. return std::get<Index - offset>(filter());
  305. }
  306. }
  307. /**
  308. * @brief Returns the number of entities that are part of the group.
  309. * @return Number of entities that are part of the group.
  310. */
  311. [[nodiscard]] size_type size() const noexcept {
  312. return *this ? handle().size() : size_type{};
  313. }
  314. /**
  315. * @brief Returns the number of elements that a group has currently
  316. * allocated space for.
  317. * @return Capacity of the group.
  318. */
  319. [[nodiscard]] size_type capacity() const noexcept {
  320. return *this ? handle().capacity() : size_type{};
  321. }
  322. /*! @brief Requests the removal of unused capacity. */
  323. void shrink_to_fit() {
  324. if(*this) {
  325. descriptor->handle().shrink_to_fit();
  326. }
  327. }
  328. /**
  329. * @brief Checks whether a group is empty.
  330. * @return True if the group is empty, false otherwise.
  331. */
  332. [[nodiscard]] bool empty() const noexcept {
  333. return !*this || handle().empty();
  334. }
  335. /**
  336. * @brief Returns an iterator to the first entity of the group.
  337. *
  338. * If the group is empty, the returned iterator will be equal to `end()`.
  339. *
  340. * @return An iterator to the first entity of the group.
  341. */
  342. [[nodiscard]] iterator begin() const noexcept {
  343. return *this ? handle().begin() : iterator{};
  344. }
  345. /**
  346. * @brief Returns an iterator that is past the last entity of the group.
  347. * @return An iterator to the entity following the last entity of the
  348. * group.
  349. */
  350. [[nodiscard]] iterator end() const noexcept {
  351. return *this ? handle().end() : iterator{};
  352. }
  353. /**
  354. * @brief Returns an iterator to the first entity of the reversed group.
  355. *
  356. * If the group is empty, the returned iterator will be equal to `rend()`.
  357. *
  358. * @return An iterator to the first entity of the reversed group.
  359. */
  360. [[nodiscard]] reverse_iterator rbegin() const noexcept {
  361. return *this ? handle().rbegin() : reverse_iterator{};
  362. }
  363. /**
  364. * @brief Returns an iterator that is past the last entity of the reversed
  365. * group.
  366. * @return An iterator to the entity following the last entity of the
  367. * reversed group.
  368. */
  369. [[nodiscard]] reverse_iterator rend() const noexcept {
  370. return *this ? handle().rend() : reverse_iterator{};
  371. }
  372. /**
  373. * @brief Returns the first entity of the group, if any.
  374. * @return The first entity of the group if one exists, the null entity
  375. * otherwise.
  376. */
  377. [[nodiscard]] entity_type front() const noexcept {
  378. const auto it = begin();
  379. return it != end() ? *it : null;
  380. }
  381. /**
  382. * @brief Returns the last entity of the group, if any.
  383. * @return The last entity of the group if one exists, the null entity
  384. * otherwise.
  385. */
  386. [[nodiscard]] entity_type back() const noexcept {
  387. const auto it = rbegin();
  388. return it != rend() ? *it : null;
  389. }
  390. /**
  391. * @brief Finds an entity.
  392. * @param entt A valid identifier.
  393. * @return An iterator to the given entity if it's found, past the end
  394. * iterator otherwise.
  395. */
  396. [[nodiscard]] iterator find(const entity_type entt) const noexcept {
  397. return *this ? handle().find(entt) : iterator{};
  398. }
  399. /**
  400. * @brief Returns the identifier that occupies the given position.
  401. * @param pos Position of the element to return.
  402. * @return The identifier that occupies the given position.
  403. */
  404. [[nodiscard]] entity_type operator[](const size_type pos) const {
  405. return begin()[pos];
  406. }
  407. /**
  408. * @brief Checks if a group is properly initialized.
  409. * @return True if the group is properly initialized, false otherwise.
  410. */
  411. [[nodiscard]] explicit operator bool() const noexcept {
  412. return descriptor != nullptr;
  413. }
  414. /**
  415. * @brief Checks if a group contains an entity.
  416. * @param entt A valid identifier.
  417. * @return True if the group contains the given entity, false otherwise.
  418. */
  419. [[nodiscard]] bool contains(const entity_type entt) const noexcept {
  420. return *this && handle().contains(entt);
  421. }
  422. /**
  423. * @brief Returns the components assigned to the given entity.
  424. * @tparam Type Type of the component to get.
  425. * @tparam Other Other types of components to get.
  426. * @param entt A valid identifier.
  427. * @return The components assigned to the entity.
  428. */
  429. template<typename Type, typename... Other>
  430. [[nodiscard]] decltype(auto) get(const entity_type entt) const {
  431. return get<index_of<Type>, index_of<Other>...>(entt);
  432. }
  433. /**
  434. * @brief Returns the components assigned to the given entity.
  435. * @tparam Index Indexes of the components to get.
  436. * @param entt A valid identifier.
  437. * @return The components assigned to the entity.
  438. */
  439. template<std::size_t... Index>
  440. [[nodiscard]] decltype(auto) get(const entity_type entt) const {
  441. const auto cpools = pools();
  442. if constexpr(sizeof...(Index) == 0) {
  443. return std::apply([entt](auto *...curr) { return std::tuple_cat(curr->get_as_tuple(entt)...); }, cpools);
  444. } else if constexpr(sizeof...(Index) == 1) {
  445. return (std::get<Index>(cpools)->get(entt), ...);
  446. } else {
  447. return std::tuple_cat(std::get<Index>(cpools)->get_as_tuple(entt)...);
  448. }
  449. }
  450. /**
  451. * @brief Iterates entities and components and applies the given function
  452. * object to them.
  453. *
  454. * The function object is invoked for each entity. It is provided with the
  455. * entity itself and a set of references to non-empty components. The
  456. * _constness_ of the components is as requested.<br/>
  457. * The signature of the function must be equivalent to one of the following
  458. * forms:
  459. *
  460. * @code{.cpp}
  461. * void(const entity_type, Type &...);
  462. * void(Type &...);
  463. * @endcode
  464. *
  465. * @note
  466. * Empty types aren't explicitly instantiated and therefore they are never
  467. * returned during iterations.
  468. *
  469. * @tparam Func Type of the function object to invoke.
  470. * @param func A valid function object.
  471. */
  472. template<typename Func>
  473. void each(Func func) const {
  474. for(const auto entt: *this) {
  475. if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
  476. std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt)));
  477. } else {
  478. std::apply(func, get(entt));
  479. }
  480. }
  481. }
  482. /**
  483. * @brief Returns an iterable object to use to _visit_ a group.
  484. *
  485. * The iterable object returns tuples that contain the current entity and a
  486. * set of references to its non-empty components. The _constness_ of the
  487. * components is as requested.
  488. *
  489. * @note
  490. * Empty types aren't explicitly instantiated and therefore they are never
  491. * returned during iterations.
  492. *
  493. * @return An iterable object to use to _visit_ the group.
  494. */
  495. [[nodiscard]] iterable each() const noexcept {
  496. const auto cpools = pools();
  497. return iterable{{begin(), cpools}, {end(), cpools}};
  498. }
  499. /**
  500. * @brief Sort a group according to the given comparison function.
  501. *
  502. * The comparison function object must return `true` if the first element
  503. * is _less_ than the second one, `false` otherwise. The signature of the
  504. * comparison function should be equivalent to one of the following:
  505. *
  506. * @code{.cpp}
  507. * bool(std::tuple<Type &...>, std::tuple<Type &...>);
  508. * bool(const Type &..., const Type &...);
  509. * bool(const Entity, const Entity);
  510. * @endcode
  511. *
  512. * Where `Type` are such that they are iterated by the group.<br/>
  513. * Moreover, the comparison function object shall induce a
  514. * _strict weak ordering_ on the values.
  515. *
  516. * The sort function object must offer a member function template
  517. * `operator()` that accepts three arguments:
  518. *
  519. * * An iterator to the first element of the range to sort.
  520. * * An iterator past the last element of the range to sort.
  521. * * A comparison function to use to compare the elements.
  522. *
  523. * @tparam Type Optional type of component to compare.
  524. * @tparam Other Other optional types of components to compare.
  525. * @tparam Compare Type of comparison function object.
  526. * @tparam Sort Type of sort function object.
  527. * @tparam Args Types of arguments to forward to the sort function object.
  528. * @param compare A valid comparison function object.
  529. * @param algo A valid sort function object.
  530. * @param args Arguments to forward to the sort function object, if any.
  531. */
  532. template<typename Type, typename... Other, typename Compare, typename Sort = std_sort, typename... Args>
  533. void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
  534. sort<index_of<Type>, index_of<Other>...>(std::move(compare), std::move(algo), std::forward<Args>(args)...);
  535. }
  536. /**
  537. * @brief Sort a group according to the given comparison function.
  538. *
  539. * @sa sort
  540. *
  541. * @tparam Index Optional indexes of components to compare.
  542. * @tparam Compare Type of comparison function object.
  543. * @tparam Sort Type of sort function object.
  544. * @tparam Args Types of arguments to forward to the sort function object.
  545. * @param compare A valid comparison function object.
  546. * @param algo A valid sort function object.
  547. * @param args Arguments to forward to the sort function object, if any.
  548. */
  549. template<std::size_t... Index, typename Compare, typename Sort = std_sort, typename... Args>
  550. void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
  551. if(*this) {
  552. if constexpr(sizeof...(Index) == 0) {
  553. static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
  554. descriptor->handle().sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
  555. } else {
  556. auto comp = [&compare, cpools = pools()](const entity_type lhs, const entity_type rhs) {
  557. if constexpr(sizeof...(Index) == 1) {
  558. return compare((std::get<Index>(cpools)->get(lhs), ...), (std::get<Index>(cpools)->get(rhs), ...));
  559. } else {
  560. return compare(std::forward_as_tuple(std::get<Index>(cpools)->get(lhs)...), std::forward_as_tuple(std::get<Index>(cpools)->get(rhs)...));
  561. }
  562. };
  563. descriptor->handle().sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
  564. }
  565. }
  566. }
  567. /**
  568. * @brief Sort entities according to their order in a range.
  569. *
  570. * The shared pool of entities and thus its order is affected by the changes
  571. * to each and every pool that it tracks.
  572. *
  573. * @tparam It Type of input iterator.
  574. * @param first An iterator to the first element of the range of entities.
  575. * @param last An iterator past the last element of the range of entities.
  576. */
  577. template<typename It>
  578. void sort_as(It first, It last) const {
  579. if(*this) {
  580. descriptor->handle().sort_as(first, last);
  581. }
  582. }
  583. /**
  584. * @brief Sort entities according to their order in a range.
  585. * @param other The storage to use to impose the order.
  586. */
  587. [[deprecated("use iterator based sort_as instead")]] void sort_as(const common_type &other) const {
  588. sort_as(other.begin(), other.end());
  589. }
  590. private:
  591. handler *descriptor;
  592. };
  593. /**
  594. * @brief Owning group.
  595. *
  596. * Owning groups returns all entities and only the entities that are at
  597. * least in the given storage. Moreover:
  598. *
  599. * * It's guaranteed that the entity list is tightly packed in memory for fast
  600. * iterations.
  601. * * It's guaranteed that all components in the owned storage are tightly packed
  602. * in memory for even faster iterations and to allow direct access.
  603. * * They stay true to the order of the owned storage and all instances have the
  604. * same order in memory.
  605. *
  606. * The more types of storage are owned, the faster it is to iterate a group.
  607. *
  608. * @b Important
  609. *
  610. * Iterators aren't invalidated if:
  611. *
  612. * * New elements are added to the storage.
  613. * * The entity currently pointed is modified (for example, components are added
  614. * or removed from it).
  615. * * The entity currently pointed is destroyed.
  616. *
  617. * In all other cases, modifying the pools iterated by the group in any way
  618. * invalidates all the iterators.
  619. *
  620. * @tparam Owned Types of storage _owned_ by the group.
  621. * @tparam Get Types of storage _observed_ by the group.
  622. * @tparam Exclude Types of storage used to filter the group.
  623. */
  624. template<typename... Owned, typename... Get, typename... Exclude>
  625. class basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> {
  626. using base_type = std::common_type_t<typename Owned::base_type..., typename Get::base_type..., typename Exclude::base_type...>;
  627. using underlying_type = typename base_type::entity_type;
  628. template<typename Type>
  629. static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Owned::value_type..., typename Get::value_type..., typename Exclude::value_type...>>;
  630. auto pools() const noexcept {
  631. using return_type = std::tuple<Owned *..., Get *...>;
  632. return descriptor ? descriptor->template pools_as<return_type>() : return_type{};
  633. }
  634. auto filter() const noexcept {
  635. using return_type = std::tuple<Exclude *...>;
  636. return descriptor ? descriptor->template filter_as<return_type>() : return_type{};
  637. }
  638. public:
  639. /*! @brief Underlying entity identifier. */
  640. using entity_type = underlying_type;
  641. /*! @brief Unsigned integer type. */
  642. using size_type = std::size_t;
  643. /*! @brief Common type among all storage types. */
  644. using common_type = base_type;
  645. /*! @brief Random access iterator type. */
  646. using iterator = typename common_type::iterator;
  647. /*! @brief Reversed iterator type. */
  648. using reverse_iterator = typename common_type::reverse_iterator;
  649. /*! @brief Iterable group type. */
  650. using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<Owned...>, get_t<Get...>>>;
  651. /*! @brief Group handler type. */
  652. using handler = internal::group_handler<owned_t<std::remove_const_t<Owned>...>, get_t<std::remove_const_t<Get>...>, exclude_t<std::remove_const_t<Exclude>...>>;
  653. /*! @brief Default constructor to use to create empty, invalid groups. */
  654. basic_group() noexcept
  655. : descriptor{} {}
  656. /**
  657. * @brief Constructs a group from a set of storage classes.
  658. * @param ref A reference to a group handler.
  659. */
  660. basic_group(handler &ref) noexcept
  661. : descriptor{&ref} {}
  662. /**
  663. * @brief Returns the leading storage of a group.
  664. * @return The leading storage of the group.
  665. */
  666. [[nodiscard]] const common_type &handle() const noexcept {
  667. return *storage<0>();
  668. }
  669. /**
  670. * @brief Returns the storage for a given component type, if any.
  671. * @tparam Type Type of component of which to return the storage.
  672. * @return The storage for the given component type.
  673. */
  674. template<typename Type>
  675. [[nodiscard]] auto *storage() const noexcept {
  676. return storage<index_of<Type>>();
  677. }
  678. /**
  679. * @brief Returns the storage for a given index, if any.
  680. * @tparam Index Index of the storage to return.
  681. * @return The storage for the given index.
  682. */
  683. template<std::size_t Index>
  684. [[nodiscard]] auto *storage() const noexcept {
  685. constexpr auto offset = sizeof...(Owned) + sizeof...(Get);
  686. if constexpr(Index < offset) {
  687. return std::get<Index>(pools());
  688. } else {
  689. return std::get<Index - offset>(filter());
  690. }
  691. }
  692. /**
  693. * @brief Returns the number of entities that that are part of the group.
  694. * @return Number of entities that that are part of the group.
  695. */
  696. [[nodiscard]] size_type size() const noexcept {
  697. return *this ? descriptor->length() : size_type{};
  698. }
  699. /**
  700. * @brief Checks whether a group is empty.
  701. * @return True if the group is empty, false otherwise.
  702. */
  703. [[nodiscard]] bool empty() const noexcept {
  704. return !*this || !descriptor->length();
  705. }
  706. /**
  707. * @brief Returns an iterator to the first entity of the group.
  708. *
  709. * If the group is empty, the returned iterator will be equal to `end()`.
  710. *
  711. * @return An iterator to the first entity of the group.
  712. */
  713. [[nodiscard]] iterator begin() const noexcept {
  714. return *this ? (handle().end() - descriptor->length()) : iterator{};
  715. }
  716. /**
  717. * @brief Returns an iterator that is past the last entity of the group.
  718. * @return An iterator to the entity following the last entity of the
  719. * group.
  720. */
  721. [[nodiscard]] iterator end() const noexcept {
  722. return *this ? handle().end() : iterator{};
  723. }
  724. /**
  725. * @brief Returns an iterator to the first entity of the reversed group.
  726. *
  727. * If the group is empty, the returned iterator will be equal to `rend()`.
  728. *
  729. * @return An iterator to the first entity of the reversed group.
  730. */
  731. [[nodiscard]] reverse_iterator rbegin() const noexcept {
  732. return *this ? handle().rbegin() : reverse_iterator{};
  733. }
  734. /**
  735. * @brief Returns an iterator that is past the last entity of the reversed
  736. * group.
  737. * @return An iterator to the entity following the last entity of the
  738. * reversed group.
  739. */
  740. [[nodiscard]] reverse_iterator rend() const noexcept {
  741. return *this ? (handle().rbegin() + descriptor->length()) : reverse_iterator{};
  742. }
  743. /**
  744. * @brief Returns the first entity of the group, if any.
  745. * @return The first entity of the group if one exists, the null entity
  746. * otherwise.
  747. */
  748. [[nodiscard]] entity_type front() const noexcept {
  749. const auto it = begin();
  750. return it != end() ? *it : null;
  751. }
  752. /**
  753. * @brief Returns the last entity of the group, if any.
  754. * @return The last entity of the group if one exists, the null entity
  755. * otherwise.
  756. */
  757. [[nodiscard]] entity_type back() const noexcept {
  758. const auto it = rbegin();
  759. return it != rend() ? *it : null;
  760. }
  761. /**
  762. * @brief Finds an entity.
  763. * @param entt A valid identifier.
  764. * @return An iterator to the given entity if it's found, past the end
  765. * iterator otherwise.
  766. */
  767. [[nodiscard]] iterator find(const entity_type entt) const noexcept {
  768. const auto it = *this ? handle().find(entt) : iterator{};
  769. return it >= begin() ? it : iterator{};
  770. }
  771. /**
  772. * @brief Returns the identifier that occupies the given position.
  773. * @param pos Position of the element to return.
  774. * @return The identifier that occupies the given position.
  775. */
  776. [[nodiscard]] entity_type operator[](const size_type pos) const {
  777. return begin()[pos];
  778. }
  779. /**
  780. * @brief Checks if a group is properly initialized.
  781. * @return True if the group is properly initialized, false otherwise.
  782. */
  783. [[nodiscard]] explicit operator bool() const noexcept {
  784. return descriptor != nullptr;
  785. }
  786. /**
  787. * @brief Checks if a group contains an entity.
  788. * @param entt A valid identifier.
  789. * @return True if the group contains the given entity, false otherwise.
  790. */
  791. [[nodiscard]] bool contains(const entity_type entt) const noexcept {
  792. return *this && handle().contains(entt) && (handle().index(entt) < (descriptor->length()));
  793. }
  794. /**
  795. * @brief Returns the components assigned to the given entity.
  796. * @tparam Type Type of the component to get.
  797. * @tparam Other Other types of components to get.
  798. * @param entt A valid identifier.
  799. * @return The components assigned to the entity.
  800. */
  801. template<typename Type, typename... Other>
  802. [[nodiscard]] decltype(auto) get(const entity_type entt) const {
  803. return get<index_of<Type>, index_of<Other>...>(entt);
  804. }
  805. /**
  806. * @brief Returns the components assigned to the given entity.
  807. * @tparam Index Indexes of the components to get.
  808. * @param entt A valid identifier.
  809. * @return The components assigned to the entity.
  810. */
  811. template<std::size_t... Index>
  812. [[nodiscard]] decltype(auto) get(const entity_type entt) const {
  813. const auto cpools = pools();
  814. if constexpr(sizeof...(Index) == 0) {
  815. return std::apply([entt](auto *...curr) { return std::tuple_cat(curr->get_as_tuple(entt)...); }, cpools);
  816. } else if constexpr(sizeof...(Index) == 1) {
  817. return (std::get<Index>(cpools)->get(entt), ...);
  818. } else {
  819. return std::tuple_cat(std::get<Index>(cpools)->get_as_tuple(entt)...);
  820. }
  821. }
  822. /**
  823. * @brief Iterates entities and components and applies the given function
  824. * object to them.
  825. *
  826. * The function object is invoked for each entity. It is provided with the
  827. * entity itself and a set of references to non-empty components. The
  828. * _constness_ of the components is as requested.<br/>
  829. * The signature of the function must be equivalent to one of the following
  830. * forms:
  831. *
  832. * @code{.cpp}
  833. * void(const entity_type, Type &...);
  834. * void(Type &...);
  835. * @endcode
  836. *
  837. * @note
  838. * Empty types aren't explicitly instantiated and therefore they are never
  839. * returned during iterations.
  840. *
  841. * @tparam Func Type of the function object to invoke.
  842. * @param func A valid function object.
  843. */
  844. template<typename Func>
  845. void each(Func func) const {
  846. for(auto args: each()) {
  847. if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
  848. std::apply(func, args);
  849. } else {
  850. std::apply([&func](auto, auto &&...less) { func(std::forward<decltype(less)>(less)...); }, args);
  851. }
  852. }
  853. }
  854. /**
  855. * @brief Returns an iterable object to use to _visit_ a group.
  856. *
  857. * The iterable object returns tuples that contain the current entity and a
  858. * set of references to its non-empty components. The _constness_ of the
  859. * components is as requested.
  860. *
  861. * @note
  862. * Empty types aren't explicitly instantiated and therefore they are never
  863. * returned during iterations.
  864. *
  865. * @return An iterable object to use to _visit_ the group.
  866. */
  867. [[nodiscard]] iterable each() const noexcept {
  868. const auto cpools = pools();
  869. return {{begin(), cpools}, {end(), cpools}};
  870. }
  871. /**
  872. * @brief Sort a group according to the given comparison function.
  873. *
  874. * The comparison function object must return `true` if the first element
  875. * is _less_ than the second one, `false` otherwise. The signature of the
  876. * comparison function should be equivalent to one of the following:
  877. *
  878. * @code{.cpp}
  879. * bool(std::tuple<Type &...>, std::tuple<Type &...>);
  880. * bool(const Type &, const Type &);
  881. * bool(const Entity, const Entity);
  882. * @endcode
  883. *
  884. * Where `Type` are either owned types or not but still such that they are
  885. * iterated by the group.<br/>
  886. * Moreover, the comparison function object shall induce a
  887. * _strict weak ordering_ on the values.
  888. *
  889. * The sort function object must offer a member function template
  890. * `operator()` that accepts three arguments:
  891. *
  892. * * An iterator to the first element of the range to sort.
  893. * * An iterator past the last element of the range to sort.
  894. * * A comparison function to use to compare the elements.
  895. *
  896. * @tparam Type Optional type of component to compare.
  897. * @tparam Other Other optional types of components to compare.
  898. * @tparam Compare Type of comparison function object.
  899. * @tparam Sort Type of sort function object.
  900. * @tparam Args Types of arguments to forward to the sort function object.
  901. * @param compare A valid comparison function object.
  902. * @param algo A valid sort function object.
  903. * @param args Arguments to forward to the sort function object, if any.
  904. */
  905. template<typename Type, typename... Other, typename Compare, typename Sort = std_sort, typename... Args>
  906. void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const {
  907. sort<index_of<Type>, index_of<Other>...>(std::move(compare), std::move(algo), std::forward<Args>(args)...);
  908. }
  909. /**
  910. * @brief Sort a group according to the given comparison function.
  911. *
  912. * @sa sort
  913. *
  914. * @tparam Index Optional indexes of components to compare.
  915. * @tparam Compare Type of comparison function object.
  916. * @tparam Sort Type of sort function object.
  917. * @tparam Args Types of arguments to forward to the sort function object.
  918. * @param compare A valid comparison function object.
  919. * @param algo A valid sort function object.
  920. * @param args Arguments to forward to the sort function object, if any.
  921. */
  922. template<std::size_t... Index, typename Compare, typename Sort = std_sort, typename... Args>
  923. void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const {
  924. const auto cpools = pools();
  925. if constexpr(sizeof...(Index) == 0) {
  926. static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
  927. storage<0>()->sort_n(descriptor->length(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
  928. } else {
  929. auto comp = [&compare, &cpools](const entity_type lhs, const entity_type rhs) {
  930. if constexpr(sizeof...(Index) == 1) {
  931. return compare((std::get<Index>(cpools)->get(lhs), ...), (std::get<Index>(cpools)->get(rhs), ...));
  932. } else {
  933. return compare(std::forward_as_tuple(std::get<Index>(cpools)->get(lhs)...), std::forward_as_tuple(std::get<Index>(cpools)->get(rhs)...));
  934. }
  935. };
  936. storage<0>()->sort_n(descriptor->length(), std::move(comp), std::move(algo), std::forward<Args>(args)...);
  937. }
  938. auto cb = [this](auto *head, auto *...other) {
  939. for(auto next = descriptor->length(); next; --next) {
  940. const auto pos = next - 1;
  941. [[maybe_unused]] const auto entt = head->data()[pos];
  942. (other->swap_elements(other->data()[pos], entt), ...);
  943. }
  944. };
  945. std::apply(cb, cpools);
  946. }
  947. private:
  948. handler *descriptor;
  949. };
  950. } // namespace entt
  951. #endif