sparse_set.hpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. #ifndef ENTT_ENTITY_SPARSE_SET_HPP
  2. #define ENTT_ENTITY_SPARSE_SET_HPP
  3. #include <cstddef>
  4. #include <iterator>
  5. #include <memory>
  6. #include <type_traits>
  7. #include <utility>
  8. #include "../config/config.h"
  9. #include "../core/algorithm.hpp"
  10. #include "../core/fwd.hpp"
  11. #include "entity.hpp"
  12. #include "fwd.hpp"
  13. namespace entt {
  14. /**
  15. * @brief Basic sparse set implementation.
  16. *
  17. * Sparse set or packed array or whatever is the name users give it.<br/>
  18. * Two arrays: an _external_ one and an _internal_ one; a _sparse_ one and a
  19. * _packed_ one; one used for direct access through contiguous memory, the other
  20. * one used to get the data through an extra level of indirection.<br/>
  21. * This is largely used by the registry to offer users the fastest access ever
  22. * to the components. Views and groups in general are almost entirely designed
  23. * around sparse sets.
  24. *
  25. * This type of data structure is widely documented in the literature and on the
  26. * web. This is nothing more than a customized implementation suitable for the
  27. * purpose of the framework.
  28. *
  29. * @note
  30. * Internal data structures arrange elements to maximize performance. There are
  31. * no guarantees that entities are returned in the insertion order when iterate
  32. * a sparse set. Do not make assumption on the order in any case.
  33. *
  34. * @tparam Entity A valid entity type (see entt_traits for more details).
  35. * @tparam Allocator Type of allocator used to manage memory and elements.
  36. */
  37. template<typename Entity, typename Allocator>
  38. class basic_sparse_set {
  39. static constexpr auto growth_factor = 1.5;
  40. using traits_type = entt_traits<Entity>;
  41. using alloc_type = typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>;
  42. using alloc_traits = std::allocator_traits<alloc_type>;
  43. using alloc_pointer = typename alloc_traits::pointer;
  44. using alloc_const_pointer = typename alloc_traits::const_pointer;
  45. using bucket_alloc_type = typename std::allocator_traits<Allocator>::template rebind_alloc<alloc_pointer>;
  46. using bucket_alloc_traits = std::allocator_traits<bucket_alloc_type>;
  47. using bucket_alloc_pointer = typename bucket_alloc_traits::pointer;
  48. static_assert(alloc_traits::propagate_on_container_move_assignment::value);
  49. static_assert(bucket_alloc_traits::propagate_on_container_move_assignment::value);
  50. class sparse_set_iterator final {
  51. friend class basic_sparse_set<Entity>;
  52. using index_type = typename traits_type::difference_type;
  53. sparse_set_iterator(const alloc_const_pointer *ref, const index_type idx) ENTT_NOEXCEPT
  54. : packed{ref}, index{idx}
  55. {}
  56. public:
  57. using difference_type = index_type;
  58. using value_type = Entity;
  59. using pointer = const value_type *;
  60. using reference = const value_type &;
  61. using iterator_category = std::random_access_iterator_tag;
  62. sparse_set_iterator() ENTT_NOEXCEPT = default;
  63. sparse_set_iterator & operator++() ENTT_NOEXCEPT {
  64. return --index, *this;
  65. }
  66. sparse_set_iterator operator++(int) ENTT_NOEXCEPT {
  67. iterator orig = *this;
  68. return ++(*this), orig;
  69. }
  70. sparse_set_iterator & operator--() ENTT_NOEXCEPT {
  71. return ++index, *this;
  72. }
  73. sparse_set_iterator operator--(int) ENTT_NOEXCEPT {
  74. sparse_set_iterator orig = *this;
  75. return operator--(), orig;
  76. }
  77. sparse_set_iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
  78. index -= value;
  79. return *this;
  80. }
  81. sparse_set_iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
  82. sparse_set_iterator copy = *this;
  83. return (copy += value);
  84. }
  85. sparse_set_iterator & operator-=(const difference_type value) ENTT_NOEXCEPT {
  86. return (*this += -value);
  87. }
  88. sparse_set_iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
  89. return (*this + -value);
  90. }
  91. difference_type operator-(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  92. return other.index - index;
  93. }
  94. [[nodiscard]] reference operator[](const difference_type value) const {
  95. const auto pos = size_type(index-value-1u);
  96. return (*packed)[pos];
  97. }
  98. [[nodiscard]] bool operator==(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  99. return other.index == index;
  100. }
  101. [[nodiscard]] bool operator!=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  102. return !(*this == other);
  103. }
  104. [[nodiscard]] bool operator<(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  105. return index > other.index;
  106. }
  107. [[nodiscard]] bool operator>(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  108. return index < other.index;
  109. }
  110. [[nodiscard]] bool operator<=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  111. return !(*this > other);
  112. }
  113. [[nodiscard]] bool operator>=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  114. return !(*this < other);
  115. }
  116. [[nodiscard]] pointer operator->() const {
  117. const auto pos = size_type(index-1u);
  118. return std::addressof((*packed)[pos]);
  119. }
  120. [[nodiscard]] reference operator*() const {
  121. return *operator->();
  122. }
  123. private:
  124. const alloc_const_pointer *packed;
  125. index_type index;
  126. };
  127. [[nodiscard]] static auto page(const Entity entt) ENTT_NOEXCEPT {
  128. return size_type{(to_integral(entt) & traits_type::entity_mask) / page_size};
  129. }
  130. [[nodiscard]] static auto offset(const Entity entt) ENTT_NOEXCEPT {
  131. return size_type{to_integral(entt) & (page_size - 1)};
  132. }
  133. [[nodiscard]] auto assure_page(const std::size_t idx) {
  134. if(!(idx < bucket)) {
  135. const size_type sz = idx + 1u;
  136. const auto old = std::exchange(sparse, bucket_alloc_traits::allocate(bucket_allocator, sz));
  137. std::uninitialized_fill(sparse + bucket, sparse + sz, alloc_pointer{});
  138. if(const auto curr = std::exchange(bucket, sz); curr) {
  139. for(size_type pos{}; pos < curr; ++pos) {
  140. bucket_alloc_traits::construct(bucket_allocator, std::addressof(sparse[pos]), std::move(old[pos]));
  141. bucket_alloc_traits::destroy(bucket_allocator, std::addressof(old[pos]));
  142. }
  143. bucket_alloc_traits::deallocate(bucket_allocator, old, curr);
  144. }
  145. }
  146. if(!sparse[idx]) {
  147. sparse[idx] = alloc_traits::allocate(allocator, page_size);
  148. std::uninitialized_fill(sparse[idx], sparse[idx] + page_size, null);
  149. }
  150. return sparse[idx];
  151. }
  152. void maybe_release_pages() {
  153. if(!count && bucket) {
  154. for(size_type pos{}; pos < bucket; ++pos) {
  155. if(sparse[pos]) {
  156. std::destroy(sparse[pos], sparse[pos] + page_size);
  157. alloc_traits::deallocate(allocator, sparse[pos], page_size);
  158. }
  159. bucket_alloc_traits::destroy(bucket_allocator, std::addressof(sparse[pos]));
  160. }
  161. bucket_alloc_traits::deallocate(bucket_allocator, sparse, std::exchange(bucket, 0u));
  162. }
  163. }
  164. void maybe_resize_packed(const std::size_t req) {
  165. if(const auto length = std::exchange(reserved, req); !reserved) {
  166. if(length) {
  167. std::destroy(packed, packed + std::exchange(count, 0u));
  168. alloc_traits::deallocate(allocator, packed, length);
  169. }
  170. } else if(reserved != length) {
  171. ENTT_ASSERT(!(req < count), "Invalid request");
  172. auto old = std::exchange(packed, alloc_traits::allocate(allocator, reserved));
  173. for(size_type pos{}; pos < count; ++pos) {
  174. alloc_traits::construct(allocator, std::addressof(packed[pos]), std::move(old[pos]));
  175. alloc_traits::destroy(allocator, std::addressof(old[pos]));
  176. }
  177. alloc_traits::deallocate(allocator, old, length);
  178. }
  179. }
  180. void push_back(const Entity entt) {
  181. ENTT_ASSERT(count != reserved, "No more space left");
  182. assure_page(page(entt))[offset(entt)] = entity_type{static_cast<typename traits_type::entity_type>(count)};
  183. alloc_traits::construct(allocator, std::addressof(packed[count]), entt);
  184. // exception safety guarantee requires to update this after construction
  185. ++count;
  186. }
  187. void pop(const Entity entt, void *ud) {
  188. ENTT_ASSERT(contains(entt), "Set does not contain entity");
  189. // last chance to use the entity for derived classes and mixins, if any
  190. about_to_erase(entt, ud);
  191. auto &ref = sparse[page(entt)][offset(entt)];
  192. const auto pos = size_type{to_integral(ref)};
  193. const auto last = --count;
  194. packed[pos] = std::exchange(packed[last], entt);
  195. sparse[page(packed[pos])][offset(packed[pos])] = ref;
  196. // no risks when pos == count, accessing packed is no longer required
  197. alloc_traits::destroy(allocator, std::addressof(packed[last]));
  198. ref = null;
  199. // don't expect exceptions here, instead allow for nosy destructors
  200. swap_and_pop(pos);
  201. }
  202. protected:
  203. /**
  204. * @brief Swaps two entities in the internal packed array.
  205. * @param lhs A valid position of an entity within storage.
  206. * @param rhs A valid position of an entity within storage.
  207. */
  208. virtual void swap_at([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) {}
  209. /**
  210. * @brief Attempts to erase an entity from the internal packed array.
  211. * @param pos A valid position of an entity within storage.
  212. */
  213. virtual void swap_and_pop([[maybe_unused]] const std::size_t pos) {}
  214. /**
  215. * @brief Last chance to use an entity that is about to be erased.
  216. * @param entity A valid entity identifier.
  217. * @param ud Optional user data that are forwarded as-is to derived classes.
  218. */
  219. virtual void about_to_erase([[maybe_unused]] const Entity entity, [[maybe_unused]] void *ud) {}
  220. public:
  221. /*! @brief Allocator type. */
  222. using allocator_type = alloc_type;
  223. /*! @brief Underlying entity identifier. */
  224. using entity_type = Entity;
  225. /*! @brief Unsigned integer type. */
  226. using size_type = std::size_t;
  227. /*! @brief Pointer type to contained entities. */
  228. using pointer = alloc_const_pointer;
  229. /*! @brief Random access iterator type. */
  230. using iterator = sparse_set_iterator;
  231. /*! @brief Reverse iterator type. */
  232. using reverse_iterator = pointer;
  233. /**
  234. * @brief Default constructor.
  235. * @param alloc Allocator to use (possibly default-constructed).
  236. */
  237. explicit basic_sparse_set(const allocator_type &alloc = {})
  238. : allocator{alloc},
  239. bucket_allocator{alloc},
  240. sparse{},
  241. packed{},
  242. bucket{},
  243. count{},
  244. reserved{}
  245. {}
  246. /**
  247. * @brief Move constructor.
  248. * @param other The instance to move from.
  249. */
  250. basic_sparse_set(basic_sparse_set &&other) ENTT_NOEXCEPT
  251. : allocator{std::move(other.allocator)},
  252. bucket_allocator{std::move(other.bucket_allocator)},
  253. sparse{std::exchange(other.sparse, bucket_alloc_pointer{})},
  254. packed{std::exchange(other.packed, alloc_pointer{})},
  255. bucket{std::exchange(other.bucket, 0u)},
  256. count{std::exchange(other.count, 0u)},
  257. reserved{std::exchange(other.reserved, 0u)}
  258. {}
  259. /*! @brief Default destructor. */
  260. virtual ~basic_sparse_set() {
  261. maybe_resize_packed(0u);
  262. maybe_release_pages();
  263. }
  264. /**
  265. * @brief Move assignment operator.
  266. * @param other The instance to move from.
  267. * @return This sparse set.
  268. */
  269. basic_sparse_set & operator=(basic_sparse_set &&other) ENTT_NOEXCEPT {
  270. maybe_resize_packed(0u);
  271. maybe_release_pages();
  272. allocator = std::move(other.allocator);
  273. bucket_allocator = std::move(other.bucket_allocator);
  274. sparse = std::exchange(other.sparse, bucket_alloc_pointer{});
  275. packed = std::exchange(other.packed, alloc_pointer{});
  276. bucket = std::exchange(other.bucket, 0u);
  277. count = std::exchange(other.count, 0u);
  278. reserved = std::exchange(other.reserved, 0u);
  279. return *this;
  280. }
  281. /**
  282. * @brief Increases the capacity of a sparse set.
  283. *
  284. * If the new capacity is greater than the current capacity, new storage is
  285. * allocated, otherwise the method does nothing.
  286. *
  287. * @param cap Desired capacity.
  288. */
  289. void reserve(const size_type cap) {
  290. if(cap > reserved) {
  291. maybe_resize_packed(cap);
  292. }
  293. }
  294. /**
  295. * @brief Returns the number of elements that a sparse set has currently
  296. * allocated space for.
  297. * @return Capacity of the sparse set.
  298. */
  299. [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT {
  300. return reserved;
  301. }
  302. /*! @brief Requests the removal of unused capacity. */
  303. void shrink_to_fit() {
  304. maybe_resize_packed(count);
  305. maybe_release_pages();
  306. }
  307. /**
  308. * @brief Returns the extent of a sparse set.
  309. *
  310. * The extent of a sparse set is also the size of the internal sparse array.
  311. * There is no guarantee that the internal packed array has the same size.
  312. * Usually the size of the internal sparse array is equal or greater than
  313. * the one of the internal packed array.
  314. *
  315. * @return Extent of the sparse set.
  316. */
  317. [[nodiscard]] size_type extent() const ENTT_NOEXCEPT {
  318. return bucket * page_size;
  319. }
  320. /**
  321. * @brief Returns the number of elements in a sparse set.
  322. *
  323. * The number of elements is also the size of the internal packed array.
  324. * There is no guarantee that the internal sparse array has the same size.
  325. * Usually the size of the internal sparse array is equal or greater than
  326. * the one of the internal packed array.
  327. *
  328. * @return Number of elements.
  329. */
  330. [[nodiscard]] size_type size() const ENTT_NOEXCEPT {
  331. return count;
  332. }
  333. /**
  334. * @brief Checks whether a sparse set is empty.
  335. * @return True if the sparse set is empty, false otherwise.
  336. */
  337. [[nodiscard]] bool empty() const ENTT_NOEXCEPT {
  338. return (count == size_type{});
  339. }
  340. /**
  341. * @brief Direct access to the internal packed array.
  342. * @return A pointer to the internal packed array.
  343. */
  344. [[nodiscard]] pointer data() const ENTT_NOEXCEPT {
  345. return packed;
  346. }
  347. /**
  348. * @brief Returns an iterator to the beginning.
  349. *
  350. * The returned iterator points to the first entity of the internal packed
  351. * array. If the sparse set is empty, the returned iterator will be equal to
  352. * `end()`.
  353. *
  354. * @return An iterator to the first entity of the internal packed array.
  355. */
  356. [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
  357. return iterator{&packed, static_cast<typename traits_type::difference_type>(count)};
  358. }
  359. /**
  360. * @brief Returns an iterator to the end.
  361. *
  362. * The returned iterator points to the element following the last entity in
  363. * the internal packed array. Attempting to dereference the returned
  364. * iterator results in undefined behavior.
  365. *
  366. * @return An iterator to the element following the last entity of the
  367. * internal packed array.
  368. */
  369. [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
  370. return iterator{&packed, {}};
  371. }
  372. /**
  373. * @brief Returns a reverse iterator to the beginning.
  374. *
  375. * The returned iterator points to the first entity of the reversed internal
  376. * packed array. If the sparse set is empty, the returned iterator will be
  377. * equal to `rend()`.
  378. *
  379. * @return An iterator to the first entity of the reversed internal packed
  380. * array.
  381. */
  382. [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
  383. return data();
  384. }
  385. /**
  386. * @brief Returns a reverse iterator to the end.
  387. *
  388. * The returned iterator points to the element following the last entity in
  389. * the reversed internal packed array. Attempting to dereference the
  390. * returned iterator results in undefined behavior.
  391. *
  392. * @return An iterator to the element following the last entity of the
  393. * reversed internal packed array.
  394. */
  395. [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
  396. return rbegin() + count;
  397. }
  398. /**
  399. * @brief Finds an entity.
  400. * @param entt A valid entity identifier.
  401. * @return An iterator to the given entity if it's found, past the end
  402. * iterator otherwise.
  403. */
  404. [[nodiscard]] iterator find(const entity_type entt) const {
  405. return contains(entt) ? --(end() - index(entt)) : end();
  406. }
  407. /**
  408. * @brief Checks if a sparse set contains an entity.
  409. * @param entt A valid entity identifier.
  410. * @return True if the sparse set contains the entity, false otherwise.
  411. */
  412. [[nodiscard]] bool contains(const entity_type entt) const {
  413. const auto curr = page(entt);
  414. // testing against null permits to avoid accessing the packed array
  415. return (curr < bucket && sparse[curr] && sparse[curr][offset(entt)] != null);
  416. }
  417. /**
  418. * @brief Returns the position of an entity in a sparse set.
  419. *
  420. * @warning
  421. * Attempting to get the position of an entity that doesn't belong to the
  422. * sparse set results in undefined behavior.
  423. *
  424. * @param entt A valid entity identifier.
  425. * @return The position of the entity in the sparse set.
  426. */
  427. [[nodiscard]] size_type index(const entity_type entt) const {
  428. ENTT_ASSERT(contains(entt), "Set does not contain entity");
  429. return size_type{to_integral(sparse[page(entt)][offset(entt)])};
  430. }
  431. /**
  432. * @brief Returns the entity at specified location, with bounds checking.
  433. * @param pos The position for which to return the entity.
  434. * @return The entity at specified location if any, a null entity otherwise.
  435. */
  436. [[nodiscard]] entity_type at(const size_type pos) const {
  437. return pos < count ? packed[pos] : null;
  438. }
  439. /**
  440. * @brief Returns the entity at specified location, without bounds checking.
  441. * @param pos The position for which to return the entity.
  442. * @return The entity at specified location.
  443. */
  444. [[nodiscard]] entity_type operator[](const size_type pos) const {
  445. ENTT_ASSERT(pos < count, "Position is out of bounds");
  446. return packed[pos];
  447. }
  448. /**
  449. * @brief Assigns an entity to a sparse set.
  450. *
  451. * @warning
  452. * Attempting to assign an entity that already belongs to the sparse set
  453. * results in undefined behavior.
  454. *
  455. * @param entt A valid entity identifier.
  456. */
  457. void emplace(const entity_type entt) {
  458. ENTT_ASSERT(!contains(entt), "Set already contains entity");
  459. if(count == reserved) {
  460. const size_type sz(reserved * growth_factor);
  461. maybe_resize_packed(sz + !(sz > reserved));
  462. }
  463. push_back(entt);
  464. }
  465. /**
  466. * @brief Assigns one or more entities to a sparse set.
  467. *
  468. * @warning
  469. * Attempting to assign an entity that already belongs to the sparse set
  470. * results in undefined behavior.
  471. *
  472. * @tparam It Type of input iterator.
  473. * @param first An iterator to the first element of the range of entities.
  474. * @param last An iterator past the last element of the range of entities.
  475. * @return The number of elements assigned to the sparse set.
  476. */
  477. template<typename It>
  478. size_type insert(It first, It last) {
  479. const auto length = std::distance(first, last);
  480. reserve(count + length);
  481. for(; first != last; ++first) {
  482. ENTT_ASSERT(!contains(*first), "Set already contains entity");
  483. push_back(*first);
  484. }
  485. return length;
  486. }
  487. /**
  488. * @brief Erases an entity from a sparse set.
  489. *
  490. * @warning
  491. * Attempting to erase an entity that doesn't belong to the sparse set
  492. * results in undefined behavior.
  493. *
  494. * @param entt A valid entity identifier.
  495. * @param ud Optional user data that are forwarded as-is to derived classes.
  496. */
  497. void erase(const entity_type entt, void *ud = nullptr) {
  498. pop(entt, ud);
  499. }
  500. /**
  501. * @brief Erases multiple entities from a set.
  502. * @tparam It Type of input iterator.
  503. * @param first An iterator to the first element of the range of entities.
  504. * @param last An iterator past the last element of the range of entities.
  505. * @param ud Optional user data that are forwarded as-is to derived classes.
  506. */
  507. template<typename It>
  508. void erase(It first, It last, void *ud = nullptr) {
  509. for(; first != last; ++first) {
  510. pop(*first, ud);
  511. }
  512. }
  513. /**
  514. * @brief Removes an entity from a sparse set if it exists.
  515. * @param entt A valid entity identifier.
  516. * @param ud Optional user data that are forwarded as-is to derived classes.
  517. * @return True if the entity is actually removed, false otherwise.
  518. */
  519. bool remove(const entity_type entt, void *ud = nullptr) {
  520. return contains(entt) ? (pop(entt, ud), true) : false;
  521. }
  522. /**
  523. * @brief Removes multiple entities from a sparse set if they exist.
  524. * @tparam It Type of input iterator.
  525. * @param first An iterator to the first element of the range of entities.
  526. * @param last An iterator past the last element of the range of entities.
  527. * @param ud Optional user data that are forwarded as-is to derived classes.
  528. * @return The number of entities actually removed.
  529. */
  530. template<typename It>
  531. size_type remove(It first, It last, void *ud = nullptr) {
  532. size_type found{};
  533. for(; first != last; ++first) {
  534. found += remove(*first, ud);
  535. }
  536. return found;
  537. }
  538. /**
  539. * @copybrief swap_at
  540. *
  541. * For what it's worth, this function affects both the internal sparse array
  542. * and the internal packed array. Users should not care of that anyway.
  543. *
  544. * @warning
  545. * Attempting to swap entities that don't belong to the sparse set results
  546. * in undefined behavior.
  547. *
  548. * @param lhs A valid entity identifier.
  549. * @param rhs A valid entity identifier.
  550. */
  551. void swap(const entity_type lhs, const entity_type rhs) {
  552. const auto from = index(lhs);
  553. const auto to = index(rhs);
  554. // derived classes first for a bare-minimum exception safety guarantee
  555. swap_at(from, to);
  556. std::swap(sparse[page(lhs)][offset(lhs)], sparse[page(rhs)][offset(rhs)]);
  557. std::swap(packed[from], packed[to]);
  558. }
  559. /**
  560. * @brief Sort the first count elements according to the given comparison
  561. * function.
  562. *
  563. * The comparison function object must return `true` if the first element
  564. * is _less_ than the second one, `false` otherwise. The signature of the
  565. * comparison function should be equivalent to the following:
  566. *
  567. * @code{.cpp}
  568. * bool(const Entity, const Entity);
  569. * @endcode
  570. *
  571. * Moreover, the comparison function object shall induce a
  572. * _strict weak ordering_ on the values.
  573. *
  574. * The sort function object must offer a member function template
  575. * `operator()` that accepts three arguments:
  576. *
  577. * * An iterator to the first element of the range to sort.
  578. * * An iterator past the last element of the range to sort.
  579. * * A comparison function to use to compare the elements.
  580. *
  581. * @tparam Compare Type of comparison function object.
  582. * @tparam Sort Type of sort function object.
  583. * @tparam Args Types of arguments to forward to the sort function object.
  584. * @param length Number of elements to sort.
  585. * @param compare A valid comparison function object.
  586. * @param algo A valid sort function object.
  587. * @param args Arguments to forward to the sort function object, if any.
  588. */
  589. template<typename Compare, typename Sort = std_sort, typename... Args>
  590. void sort_n(const size_type length, Compare compare, Sort algo = Sort{}, Args &&... args) {
  591. ENTT_ASSERT(!(length > count), "Length exceeds the number of elements");
  592. algo(std::make_reverse_iterator(packed + length), std::make_reverse_iterator(packed), std::move(compare), std::forward<Args>(args)...);
  593. for(size_type pos{}; pos < length; ++pos) {
  594. auto curr = pos;
  595. auto next = index(packed[curr]);
  596. while(curr != next) {
  597. const auto idx = index(packed[next]);
  598. const auto entt = packed[curr];
  599. swap_at(next, idx);
  600. sparse[page(entt)][offset(entt)] = entity_type{static_cast<typename traits_type::entity_type>(curr)};
  601. curr = next;
  602. next = idx;
  603. }
  604. }
  605. }
  606. /**
  607. * @brief Sort all elements according to the given comparison function.
  608. *
  609. * @sa sort_n
  610. *
  611. * @tparam Compare Type of comparison function object.
  612. * @tparam Sort Type of sort function object.
  613. * @tparam Args Types of arguments to forward to the sort function object.
  614. * @param compare A valid comparison function object.
  615. * @param algo A valid sort function object.
  616. * @param args Arguments to forward to the sort function object, if any.
  617. */
  618. template<typename Compare, typename Sort = std_sort, typename... Args>
  619. void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
  620. sort_n(count, std::move(compare), std::move(algo), std::forward<Args>(args)...);
  621. }
  622. /**
  623. * @brief Sort entities according to their order in another sparse set.
  624. *
  625. * Entities that are part of both the sparse sets are ordered internally
  626. * according to the order they have in `other`. All the other entities goes
  627. * to the end of the list and there are no guarantees on their order.<br/>
  628. * In other terms, this function can be used to impose the same order on two
  629. * sets by using one of them as a master and the other one as a slave.
  630. *
  631. * Iterating the sparse set with a couple of iterators returns elements in
  632. * the expected order after a call to `respect`. See `begin` and `end` for
  633. * more details.
  634. *
  635. * @param other The sparse sets that imposes the order of the entities.
  636. */
  637. void respect(const basic_sparse_set &other) {
  638. const auto to = other.end();
  639. auto from = other.begin();
  640. size_type pos = count - 1;
  641. while(pos && from != to) {
  642. if(contains(*from)) {
  643. if(*from != packed[pos]) {
  644. swap(packed[pos], *from);
  645. }
  646. --pos;
  647. }
  648. ++from;
  649. }
  650. }
  651. /**
  652. * @brief Clears a sparse set.
  653. * @param ud Optional user data that are forwarded as-is to derived classes.
  654. */
  655. void clear(void *ud = nullptr) ENTT_NOEXCEPT {
  656. erase(begin(), end(), ud);
  657. }
  658. private:
  659. alloc_type allocator;
  660. bucket_alloc_type bucket_allocator;
  661. bucket_alloc_pointer sparse;
  662. alloc_pointer packed;
  663. std::size_t bucket;
  664. std::size_t count;
  665. std::size_t reserved;
  666. };
  667. }
  668. #endif