sparse_set.hpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938
  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 <vector>
  9. #include "../config/config.h"
  10. #include "../core/algorithm.hpp"
  11. #include "../core/any.hpp"
  12. #include "../core/memory.hpp"
  13. #include "../core/type_info.hpp"
  14. #include "entity.hpp"
  15. #include "fwd.hpp"
  16. namespace entt {
  17. /**
  18. * @cond TURN_OFF_DOXYGEN
  19. * Internal details not to be documented.
  20. */
  21. namespace internal {
  22. template<typename Container>
  23. struct sparse_set_iterator final {
  24. using value_type = typename Container::value_type;
  25. using pointer = typename Container::const_pointer;
  26. using reference = typename Container::const_reference;
  27. using difference_type = typename Container::difference_type;
  28. using iterator_category = std::random_access_iterator_tag;
  29. sparse_set_iterator() ENTT_NOEXCEPT = default;
  30. sparse_set_iterator(const Container &ref, const difference_type idx) ENTT_NOEXCEPT
  31. : packed{std::addressof(ref)},
  32. offset{idx} {}
  33. sparse_set_iterator &operator++() ENTT_NOEXCEPT {
  34. return --offset, *this;
  35. }
  36. sparse_set_iterator operator++(int) ENTT_NOEXCEPT {
  37. sparse_set_iterator orig = *this;
  38. return ++(*this), orig;
  39. }
  40. sparse_set_iterator &operator--() ENTT_NOEXCEPT {
  41. return ++offset, *this;
  42. }
  43. sparse_set_iterator operator--(int) ENTT_NOEXCEPT {
  44. sparse_set_iterator orig = *this;
  45. return operator--(), orig;
  46. }
  47. sparse_set_iterator &operator+=(const difference_type value) ENTT_NOEXCEPT {
  48. offset -= value;
  49. return *this;
  50. }
  51. sparse_set_iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
  52. sparse_set_iterator copy = *this;
  53. return (copy += value);
  54. }
  55. sparse_set_iterator &operator-=(const difference_type value) ENTT_NOEXCEPT {
  56. return (*this += -value);
  57. }
  58. sparse_set_iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
  59. return (*this + -value);
  60. }
  61. [[nodiscard]] reference operator[](const difference_type value) const {
  62. return packed->data()[index() - value];
  63. }
  64. [[nodiscard]] pointer operator->() const {
  65. return packed->data() + index();
  66. }
  67. [[nodiscard]] reference operator*() const {
  68. return *operator->();
  69. }
  70. [[nodiscard]] difference_type index() const ENTT_NOEXCEPT {
  71. return offset - 1;
  72. }
  73. private:
  74. const Container *packed;
  75. difference_type offset;
  76. };
  77. template<typename Type, typename Other>
  78. [[nodiscard]] auto operator-(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
  79. return rhs.index() - lhs.index();
  80. }
  81. template<typename Type, typename Other>
  82. [[nodiscard]] bool operator==(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
  83. return lhs.index() == rhs.index();
  84. }
  85. template<typename Type, typename Other>
  86. [[nodiscard]] bool operator!=(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
  87. return !(lhs == rhs);
  88. }
  89. template<typename Type, typename Other>
  90. [[nodiscard]] bool operator<(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
  91. return lhs.index() > rhs.index();
  92. }
  93. template<typename Type, typename Other>
  94. [[nodiscard]] bool operator>(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
  95. return lhs.index() < rhs.index();
  96. }
  97. template<typename Type, typename Other>
  98. [[nodiscard]] bool operator<=(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
  99. return !(lhs > rhs);
  100. }
  101. template<typename Type, typename Other>
  102. [[nodiscard]] bool operator>=(const sparse_set_iterator<Type> &lhs, const sparse_set_iterator<Other> &rhs) ENTT_NOEXCEPT {
  103. return !(lhs < rhs);
  104. }
  105. } // namespace internal
  106. /**
  107. * Internal details not to be documented.
  108. * @endcond
  109. */
  110. /*! @brief Sparse set deletion policy. */
  111. enum class deletion_policy : std::uint8_t {
  112. /*! @brief Swap-and-pop deletion policy. */
  113. swap_and_pop = 0u,
  114. /*! @brief In-place deletion policy. */
  115. in_place = 1u
  116. };
  117. /**
  118. * @brief Basic sparse set implementation.
  119. *
  120. * Sparse set or packed array or whatever is the name users give it.<br/>
  121. * Two arrays: an _external_ one and an _internal_ one; a _sparse_ one and a
  122. * _packed_ one; one used for direct access through contiguous memory, the other
  123. * one used to get the data through an extra level of indirection.<br/>
  124. * This is largely used by the registry to offer users the fastest access ever
  125. * to the components. Views and groups in general are almost entirely designed
  126. * around sparse sets.
  127. *
  128. * This type of data structure is widely documented in the literature and on the
  129. * web. This is nothing more than a customized implementation suitable for the
  130. * purpose of the framework.
  131. *
  132. * @note
  133. * Internal data structures arrange elements to maximize performance. There are
  134. * no guarantees that entities are returned in the insertion order when iterate
  135. * a sparse set. Do not make assumption on the order in any case.
  136. *
  137. * @tparam Entity A valid entity type (see entt_traits for more details).
  138. * @tparam Allocator Type of allocator used to manage memory and elements.
  139. */
  140. template<typename Entity, typename Allocator>
  141. class basic_sparse_set {
  142. using alloc_traits = std::allocator_traits<Allocator>;
  143. static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>);
  144. using entity_traits = entt_traits<Entity>;
  145. using sparse_container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
  146. using packed_container_type = std::vector<Entity, Allocator>;
  147. [[nodiscard]] auto sparse_ptr(const Entity entt) const {
  148. const auto pos = static_cast<size_type>(entity_traits::to_entity(entt));
  149. const auto page = pos / entity_traits::page_size;
  150. return (page < sparse.size() && sparse[page]) ? (sparse[page] + fast_mod(pos, entity_traits::page_size)) : nullptr;
  151. }
  152. [[nodiscard]] auto &sparse_ref(const Entity entt) const {
  153. ENTT_ASSERT(sparse_ptr(entt), "Invalid element");
  154. const auto pos = static_cast<size_type>(entity_traits::to_entity(entt));
  155. return sparse[pos / entity_traits::page_size][fast_mod(pos, entity_traits::page_size)];
  156. }
  157. [[nodiscard]] auto &assure_at_least(const Entity entt) {
  158. const auto pos = static_cast<size_type>(entity_traits::to_entity(entt));
  159. const auto page = pos / entity_traits::page_size;
  160. if(!(page < sparse.size())) {
  161. sparse.resize(page + 1u, nullptr);
  162. }
  163. if(!sparse[page]) {
  164. auto page_allocator{packed.get_allocator()};
  165. sparse[page] = alloc_traits::allocate(page_allocator, entity_traits::page_size);
  166. std::uninitialized_fill(sparse[page], sparse[page] + entity_traits::page_size, null);
  167. }
  168. auto &elem = sparse[page][fast_mod(pos, entity_traits::page_size)];
  169. ENTT_ASSERT(entity_traits::to_version(elem) == entity_traits::to_version(tombstone), "Slot not available");
  170. return elem;
  171. }
  172. void release_sparse_pages() {
  173. auto page_allocator{packed.get_allocator()};
  174. for(auto &&page: sparse) {
  175. if(page != nullptr) {
  176. std::destroy(page, page + entity_traits::page_size);
  177. alloc_traits::deallocate(page_allocator, page, entity_traits::page_size);
  178. page = nullptr;
  179. }
  180. }
  181. }
  182. private:
  183. virtual const void *get_at(const std::size_t) const {
  184. return nullptr;
  185. }
  186. virtual void swap_at(const std::size_t, const std::size_t) {}
  187. virtual void move_element(const std::size_t, const std::size_t) {}
  188. protected:
  189. /*! @brief Random access iterator type. */
  190. using basic_iterator = internal::sparse_set_iterator<packed_container_type>;
  191. /**
  192. * @brief Erases entities from a sparse set.
  193. * @param first An iterator to the first element of the range of entities.
  194. * @param last An iterator past the last element of the range of entities.
  195. */
  196. virtual void swap_and_pop(basic_iterator first, basic_iterator last) {
  197. for(; first != last; ++first) {
  198. sparse_ref(packed.back()) = entity_traits::combine(static_cast<typename entity_traits::entity_type>(first.index()), entity_traits::to_integral(packed.back()));
  199. const auto entt = std::exchange(packed[first.index()], packed.back());
  200. // unnecessary but it helps to detect nasty bugs
  201. ENTT_ASSERT((packed.back() = tombstone, true), "");
  202. // lazy self-assignment guard
  203. sparse_ref(entt) = null;
  204. packed.pop_back();
  205. }
  206. }
  207. /**
  208. * @brief Erases entities from a sparse set.
  209. * @param first An iterator to the first element of the range of entities.
  210. * @param last An iterator past the last element of the range of entities.
  211. */
  212. virtual void in_place_pop(basic_iterator first, basic_iterator last) {
  213. for(; first != last; ++first) {
  214. sparse_ref(*first) = null;
  215. packed[first.index()] = std::exchange(free_list, entity_traits::combine(static_cast<typename entity_traits::entity_type>(first.index()), entity_traits::reserved));
  216. }
  217. }
  218. /**
  219. * @brief Assigns an entity to a sparse set.
  220. * @param entt A valid identifier.
  221. * @param force_back Force back insertion.
  222. * @return Iterator pointing to the emplaced element.
  223. */
  224. virtual basic_iterator try_emplace(const Entity entt, const bool force_back, const void * = nullptr) {
  225. ENTT_ASSERT(!contains(entt), "Set already contains entity");
  226. if(auto &elem = assure_at_least(entt); free_list == null || force_back) {
  227. packed.push_back(entt);
  228. elem = entity_traits::combine(static_cast<typename entity_traits::entity_type>(packed.size() - 1u), entity_traits::to_integral(entt));
  229. return begin();
  230. } else {
  231. const auto pos = static_cast<size_type>(entity_traits::to_entity(free_list));
  232. elem = entity_traits::combine(entity_traits::to_integral(free_list), entity_traits::to_integral(entt));
  233. free_list = std::exchange(packed[pos], entt);
  234. return --(end() - pos);
  235. }
  236. }
  237. public:
  238. /*! @brief Allocator type. */
  239. using allocator_type = Allocator;
  240. /*! @brief Underlying entity identifier. */
  241. using entity_type = Entity;
  242. /*! @brief Underlying version type. */
  243. using version_type = typename entity_traits::version_type;
  244. /*! @brief Unsigned integer type. */
  245. using size_type = typename packed_container_type::size_type;
  246. /*! @brief Pointer type to contained entities. */
  247. using pointer = typename packed_container_type::const_pointer;
  248. /*! @brief Random access iterator type. */
  249. using iterator = basic_iterator;
  250. /*! @brief Constant random access iterator type. */
  251. using const_iterator = iterator;
  252. /*! @brief Reverse iterator type. */
  253. using reverse_iterator = std::reverse_iterator<iterator>;
  254. /*! @brief Constant reverse iterator type. */
  255. using const_reverse_iterator = reverse_iterator;
  256. /*! @brief Default constructor. */
  257. basic_sparse_set()
  258. : basic_sparse_set{type_id<void>()} {}
  259. /**
  260. * @brief Constructs an empty container with a given allocator.
  261. * @param allocator The allocator to use.
  262. */
  263. explicit basic_sparse_set(const allocator_type &allocator)
  264. : basic_sparse_set{type_id<void>(), deletion_policy::swap_and_pop, allocator} {}
  265. /**
  266. * @brief Constructs an empty container with the given policy and allocator.
  267. * @param pol Type of deletion policy.
  268. * @param allocator The allocator to use (possibly default-constructed).
  269. */
  270. explicit basic_sparse_set(deletion_policy pol, const allocator_type &allocator = {})
  271. : basic_sparse_set{type_id<void>(), pol, allocator} {}
  272. /**
  273. * @brief Constructs an empty container with the given value type, policy
  274. * and allocator.
  275. * @param value Returned value type, if any.
  276. * @param pol Type of deletion policy.
  277. * @param allocator The allocator to use (possibly default-constructed).
  278. */
  279. explicit basic_sparse_set(const type_info &value, deletion_policy pol = deletion_policy::swap_and_pop, const allocator_type &allocator = {})
  280. : sparse{allocator},
  281. packed{allocator},
  282. info{&value},
  283. free_list{tombstone},
  284. mode{pol} {}
  285. /**
  286. * @brief Move constructor.
  287. * @param other The instance to move from.
  288. */
  289. basic_sparse_set(basic_sparse_set &&other) ENTT_NOEXCEPT
  290. : sparse{std::move(other.sparse)},
  291. packed{std::move(other.packed)},
  292. info{other.info},
  293. free_list{std::exchange(other.free_list, tombstone)},
  294. mode{other.mode} {}
  295. /**
  296. * @brief Allocator-extended move constructor.
  297. * @param other The instance to move from.
  298. * @param allocator The allocator to use.
  299. */
  300. basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator) ENTT_NOEXCEPT
  301. : sparse{std::move(other.sparse), allocator},
  302. packed{std::move(other.packed), allocator},
  303. info{other.info},
  304. free_list{std::exchange(other.free_list, tombstone)},
  305. mode{other.mode} {
  306. ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.get_allocator() == other.packed.get_allocator(), "Copying a sparse set is not allowed");
  307. }
  308. /*! @brief Default destructor. */
  309. virtual ~basic_sparse_set() {
  310. release_sparse_pages();
  311. }
  312. /**
  313. * @brief Move assignment operator.
  314. * @param other The instance to move from.
  315. * @return This sparse set.
  316. */
  317. basic_sparse_set &operator=(basic_sparse_set &&other) ENTT_NOEXCEPT {
  318. ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.get_allocator() == other.packed.get_allocator(), "Copying a sparse set is not allowed");
  319. release_sparse_pages();
  320. sparse = std::move(other.sparse);
  321. packed = std::move(other.packed);
  322. info = other.info;
  323. free_list = std::exchange(other.free_list, tombstone);
  324. mode = other.mode;
  325. return *this;
  326. }
  327. /**
  328. * @brief Exchanges the contents with those of a given sparse set.
  329. * @param other Sparse set to exchange the content with.
  330. */
  331. void swap(basic_sparse_set &other) {
  332. using std::swap;
  333. swap(sparse, other.sparse);
  334. swap(packed, other.packed);
  335. swap(info, other.info);
  336. swap(free_list, other.free_list);
  337. swap(mode, other.mode);
  338. }
  339. /**
  340. * @brief Returns the associated allocator.
  341. * @return The associated allocator.
  342. */
  343. [[nodiscard]] constexpr allocator_type get_allocator() const ENTT_NOEXCEPT {
  344. return packed.get_allocator();
  345. }
  346. /**
  347. * @brief Returns the deletion policy of a sparse set.
  348. * @return The deletion policy of the sparse set.
  349. */
  350. [[nodiscard]] deletion_policy policy() const ENTT_NOEXCEPT {
  351. return mode;
  352. }
  353. /**
  354. * @brief Increases the capacity of a sparse set.
  355. *
  356. * If the new capacity is greater than the current capacity, new storage is
  357. * allocated, otherwise the method does nothing.
  358. *
  359. * @param cap Desired capacity.
  360. */
  361. virtual void reserve(const size_type cap) {
  362. packed.reserve(cap);
  363. }
  364. /**
  365. * @brief Returns the number of elements that a sparse set has currently
  366. * allocated space for.
  367. * @return Capacity of the sparse set.
  368. */
  369. [[nodiscard]] virtual size_type capacity() const ENTT_NOEXCEPT {
  370. return packed.capacity();
  371. }
  372. /*! @brief Requests the removal of unused capacity. */
  373. virtual void shrink_to_fit() {
  374. packed.shrink_to_fit();
  375. }
  376. /**
  377. * @brief Returns the extent of a sparse set.
  378. *
  379. * The extent of a sparse set is also the size of the internal sparse array.
  380. * There is no guarantee that the internal packed array has the same size.
  381. * Usually the size of the internal sparse array is equal or greater than
  382. * the one of the internal packed array.
  383. *
  384. * @return Extent of the sparse set.
  385. */
  386. [[nodiscard]] size_type extent() const ENTT_NOEXCEPT {
  387. return sparse.size() * entity_traits::page_size;
  388. }
  389. /**
  390. * @brief Returns the number of elements in a sparse set.
  391. *
  392. * The number of elements is also the size of the internal packed array.
  393. * There is no guarantee that the internal sparse array has the same size.
  394. * Usually the size of the internal sparse array is equal or greater than
  395. * the one of the internal packed array.
  396. *
  397. * @return Number of elements.
  398. */
  399. [[nodiscard]] size_type size() const ENTT_NOEXCEPT {
  400. return packed.size();
  401. }
  402. /**
  403. * @brief Checks whether a sparse set is empty.
  404. * @return True if the sparse set is empty, false otherwise.
  405. */
  406. [[nodiscard]] bool empty() const ENTT_NOEXCEPT {
  407. return packed.empty();
  408. }
  409. /**
  410. * @brief Direct access to the internal packed array.
  411. * @return A pointer to the internal packed array.
  412. */
  413. [[nodiscard]] pointer data() const ENTT_NOEXCEPT {
  414. return packed.data();
  415. }
  416. /**
  417. * @brief Returns an iterator to the beginning.
  418. *
  419. * The returned iterator points to the first entity of the internal packed
  420. * array. If the sparse set is empty, the returned iterator will be equal to
  421. * `end()`.
  422. *
  423. * @return An iterator to the first entity of the sparse set.
  424. */
  425. [[nodiscard]] const_iterator begin() const ENTT_NOEXCEPT {
  426. const auto pos = static_cast<typename iterator::difference_type>(packed.size());
  427. return iterator{packed, pos};
  428. }
  429. /*! @copydoc begin */
  430. [[nodiscard]] const_iterator cbegin() const ENTT_NOEXCEPT {
  431. return begin();
  432. }
  433. /**
  434. * @brief Returns an iterator to the end.
  435. *
  436. * The returned iterator points to the element following the last entity in
  437. * a sparse set. Attempting to dereference the returned iterator results in
  438. * undefined behavior.
  439. *
  440. * @return An iterator to the element following the last entity of a sparse
  441. * set.
  442. */
  443. [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
  444. return iterator{packed, {}};
  445. }
  446. /*! @copydoc end */
  447. [[nodiscard]] const_iterator cend() const ENTT_NOEXCEPT {
  448. return end();
  449. }
  450. /**
  451. * @brief Returns a reverse iterator to the beginning.
  452. *
  453. * The returned iterator points to the first entity of the reversed internal
  454. * packed array. If the sparse set is empty, the returned iterator will be
  455. * equal to `rend()`.
  456. *
  457. * @return An iterator to the first entity of the reversed internal packed
  458. * array.
  459. */
  460. [[nodiscard]] const_reverse_iterator rbegin() const ENTT_NOEXCEPT {
  461. return std::make_reverse_iterator(end());
  462. }
  463. /*! @copydoc rbegin */
  464. [[nodiscard]] const_reverse_iterator crbegin() const ENTT_NOEXCEPT {
  465. return rbegin();
  466. }
  467. /**
  468. * @brief Returns a reverse iterator to the end.
  469. *
  470. * The returned iterator points to the element following the last entity in
  471. * the reversed sparse set. Attempting to dereference the returned iterator
  472. * results in undefined behavior.
  473. *
  474. * @return An iterator to the element following the last entity of the
  475. * reversed sparse set.
  476. */
  477. [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
  478. return std::make_reverse_iterator(begin());
  479. }
  480. /*! @copydoc rend */
  481. [[nodiscard]] const_reverse_iterator crend() const ENTT_NOEXCEPT {
  482. return rend();
  483. }
  484. /**
  485. * @brief Finds an entity.
  486. * @param entt A valid identifier.
  487. * @return An iterator to the given entity if it's found, past the end
  488. * iterator otherwise.
  489. */
  490. [[nodiscard]] iterator find(const entity_type entt) const ENTT_NOEXCEPT {
  491. return contains(entt) ? --(end() - index(entt)) : end();
  492. }
  493. /**
  494. * @brief Checks if a sparse set contains an entity.
  495. * @param entt A valid identifier.
  496. * @return True if the sparse set contains the entity, false otherwise.
  497. */
  498. [[nodiscard]] bool contains(const entity_type entt) const ENTT_NOEXCEPT {
  499. const auto elem = sparse_ptr(entt);
  500. constexpr auto cap = entity_traits::to_entity(null);
  501. // testing versions permits to avoid accessing the packed array
  502. return elem && (((~cap & entity_traits::to_integral(entt)) ^ entity_traits::to_integral(*elem)) < cap);
  503. }
  504. /**
  505. * @brief Returns the contained version for an identifier.
  506. * @param entt A valid identifier.
  507. * @return The version for the given identifier if present, the tombstone
  508. * version otherwise.
  509. */
  510. [[nodiscard]] version_type current(const entity_type entt) const {
  511. const auto elem = sparse_ptr(entt);
  512. constexpr auto fallback = entity_traits::to_version(tombstone);
  513. return elem ? entity_traits::to_version(*elem) : fallback;
  514. }
  515. /**
  516. * @brief Returns the position of an entity in a sparse set.
  517. *
  518. * @warning
  519. * Attempting to get the position of an entity that doesn't belong to the
  520. * sparse set results in undefined behavior.
  521. *
  522. * @param entt A valid identifier.
  523. * @return The position of the entity in the sparse set.
  524. */
  525. [[nodiscard]] size_type index(const entity_type entt) const ENTT_NOEXCEPT {
  526. ENTT_ASSERT(contains(entt), "Set does not contain entity");
  527. return static_cast<size_type>(entity_traits::to_entity(sparse_ref(entt)));
  528. }
  529. /**
  530. * @brief Returns the entity at specified location, with bounds checking.
  531. * @param pos The position for which to return the entity.
  532. * @return The entity at specified location if any, a null entity otherwise.
  533. */
  534. [[nodiscard]] entity_type at(const size_type pos) const ENTT_NOEXCEPT {
  535. return pos < packed.size() ? packed[pos] : null;
  536. }
  537. /**
  538. * @brief Returns the entity at specified location, without bounds checking.
  539. * @param pos The position for which to return the entity.
  540. * @return The entity at specified location.
  541. */
  542. [[nodiscard]] entity_type operator[](const size_type pos) const ENTT_NOEXCEPT {
  543. ENTT_ASSERT(pos < packed.size(), "Position is out of bounds");
  544. return packed[pos];
  545. }
  546. /**
  547. * @brief Returns the element assigned to an entity, if any.
  548. *
  549. * @warning
  550. * Attempting to use an entity that doesn't belong to the sparse set results
  551. * in undefined behavior.
  552. *
  553. * @param entt A valid identifier.
  554. * @return An opaque pointer to the element assigned to the entity, if any.
  555. */
  556. const void *get(const entity_type entt) const ENTT_NOEXCEPT {
  557. return get_at(index(entt));
  558. }
  559. /*! @copydoc get */
  560. void *get(const entity_type entt) ENTT_NOEXCEPT {
  561. return const_cast<void *>(std::as_const(*this).get(entt));
  562. }
  563. /**
  564. * @brief Assigns an entity to a sparse set.
  565. *
  566. * @warning
  567. * Attempting to assign an entity that already belongs to the sparse set
  568. * results in undefined behavior.
  569. *
  570. * @param entt A valid identifier.
  571. * @param value Optional opaque value to forward to mixins, if any.
  572. * @return Iterator pointing to the emplaced element in case of success, the
  573. * `end()` iterator otherwise.
  574. */
  575. iterator emplace(const entity_type entt, const void *value = nullptr) {
  576. return try_emplace(entt, false, value);
  577. }
  578. /**
  579. * @brief Assigns one or more entities to a sparse set.
  580. *
  581. * @warning
  582. * Attempting to assign an entity that already belongs to the sparse set
  583. * results in undefined behavior.
  584. *
  585. * @tparam It Type of input iterator.
  586. * @param first An iterator to the first element of the range of entities.
  587. * @param last An iterator past the last element of the range of entities.
  588. * @return Iterator pointing to the first element inserted in case of
  589. * success, the `end()` iterator otherwise.
  590. */
  591. template<typename It>
  592. iterator insert(It first, It last) {
  593. for(auto it = first; it != last; ++it) {
  594. try_emplace(*it, true);
  595. }
  596. return first == last ? end() : find(*first);
  597. }
  598. /**
  599. * @brief Erases an entity from a sparse set.
  600. *
  601. * @warning
  602. * Attempting to erase an entity that doesn't belong to the sparse set
  603. * results in undefined behavior.
  604. *
  605. * @param entt A valid identifier.
  606. */
  607. void erase(const entity_type entt) {
  608. const auto it = --(end() - index(entt));
  609. (mode == deletion_policy::in_place) ? in_place_pop(it, it + 1u) : swap_and_pop(it, it + 1u);
  610. }
  611. /**
  612. * @brief Erases entities from a set.
  613. *
  614. * @sa erase
  615. *
  616. * @tparam It Type of input iterator.
  617. * @param first An iterator to the first element of the range of entities.
  618. * @param last An iterator past the last element of the range of entities.
  619. */
  620. template<typename It>
  621. void erase(It first, It last) {
  622. if constexpr(std::is_same_v<It, basic_iterator>) {
  623. (mode == deletion_policy::in_place) ? in_place_pop(first, last) : swap_and_pop(first, last);
  624. } else {
  625. for(; first != last; ++first) {
  626. erase(*first);
  627. }
  628. }
  629. }
  630. /**
  631. * @brief Removes an entity from a sparse set if it exists.
  632. * @param entt A valid identifier.
  633. * @return True if the entity is actually removed, false otherwise.
  634. */
  635. bool remove(const entity_type entt) {
  636. return contains(entt) && (erase(entt), true);
  637. }
  638. /**
  639. * @brief Removes entities from a sparse set if they exist.
  640. * @tparam It Type of input iterator.
  641. * @param first An iterator to the first element of the range of entities.
  642. * @param last An iterator past the last element of the range of entities.
  643. * @return The number of entities actually removed.
  644. */
  645. template<typename It>
  646. size_type remove(It first, It last) {
  647. size_type count{};
  648. for(; first != last; ++first) {
  649. count += remove(*first);
  650. }
  651. return count;
  652. }
  653. /*! @brief Removes all tombstones from the packed array of a sparse set. */
  654. void compact() {
  655. size_type from = packed.size();
  656. for(; from && packed[from - 1u] == tombstone; --from) {}
  657. for(auto *it = &free_list; *it != null && from; it = std::addressof(packed[entity_traits::to_entity(*it)])) {
  658. if(const size_type to = entity_traits::to_entity(*it); to < from) {
  659. --from;
  660. move_element(from, to);
  661. std::swap(packed[from], packed[to]);
  662. const auto entity = static_cast<typename entity_traits::entity_type>(to);
  663. sparse_ref(packed[to]) = entity_traits::combine(entity, entity_traits::to_integral(packed[to]));
  664. *it = entity_traits::combine(static_cast<typename entity_traits::entity_type>(from), entity_traits::reserved);
  665. for(; from && packed[from - 1u] == tombstone; --from) {}
  666. }
  667. }
  668. free_list = tombstone;
  669. packed.resize(from);
  670. }
  671. /**
  672. * @brief Swaps two entities in a sparse set.
  673. *
  674. * For what it's worth, this function affects both the internal sparse array
  675. * and the internal packed array. Users should not care of that anyway.
  676. *
  677. * @warning
  678. * Attempting to swap entities that don't belong to the sparse set results
  679. * in undefined behavior.
  680. *
  681. * @param lhs A valid identifier.
  682. * @param rhs A valid identifier.
  683. */
  684. void swap_elements(const entity_type lhs, const entity_type rhs) {
  685. ENTT_ASSERT(contains(lhs) && contains(rhs), "Set does not contain entities");
  686. auto &entt = sparse_ref(lhs);
  687. auto &other = sparse_ref(rhs);
  688. const auto from = entity_traits::to_entity(entt);
  689. const auto to = entity_traits::to_entity(other);
  690. // basic no-leak guarantee (with invalid state) if swapping throws
  691. swap_at(static_cast<size_type>(from), static_cast<size_type>(to));
  692. entt = entity_traits::combine(to, entity_traits::to_integral(packed[from]));
  693. other = entity_traits::combine(from, entity_traits::to_integral(packed[to]));
  694. std::swap(packed[from], packed[to]);
  695. }
  696. /**
  697. * @brief Sort the first count elements according to the given comparison
  698. * function.
  699. *
  700. * The comparison function object must return `true` if the first element
  701. * is _less_ than the second one, `false` otherwise. The signature of the
  702. * comparison function should be equivalent to the following:
  703. *
  704. * @code{.cpp}
  705. * bool(const Entity, const Entity);
  706. * @endcode
  707. *
  708. * Moreover, the comparison function object shall induce a
  709. * _strict weak ordering_ on the values.
  710. *
  711. * The sort function object must offer a member function template
  712. * `operator()` that accepts three arguments:
  713. *
  714. * * An iterator to the first element of the range to sort.
  715. * * An iterator past the last element of the range to sort.
  716. * * A comparison function to use to compare the elements.
  717. *
  718. * @tparam Compare Type of comparison function object.
  719. * @tparam Sort Type of sort function object.
  720. * @tparam Args Types of arguments to forward to the sort function object.
  721. * @param length Number of elements to sort.
  722. * @param compare A valid comparison function object.
  723. * @param algo A valid sort function object.
  724. * @param args Arguments to forward to the sort function object, if any.
  725. */
  726. template<typename Compare, typename Sort = std_sort, typename... Args>
  727. void sort_n(const size_type length, Compare compare, Sort algo = Sort{}, Args &&...args) {
  728. ENTT_ASSERT(!(length > packed.size()), "Length exceeds the number of elements");
  729. ENTT_ASSERT(free_list == null, "Partial sorting with tombstones is not supported");
  730. algo(packed.rend() - length, packed.rend(), std::move(compare), std::forward<Args>(args)...);
  731. for(size_type pos{}; pos < length; ++pos) {
  732. auto curr = pos;
  733. auto next = index(packed[curr]);
  734. while(curr != next) {
  735. const auto idx = index(packed[next]);
  736. const auto entt = packed[curr];
  737. swap_at(next, idx);
  738. const auto entity = static_cast<typename entity_traits::entity_type>(curr);
  739. sparse_ref(entt) = entity_traits::combine(entity, entity_traits::to_integral(packed[curr]));
  740. curr = std::exchange(next, idx);
  741. }
  742. }
  743. }
  744. /**
  745. * @brief Sort all elements according to the given comparison function.
  746. *
  747. * @sa sort_n
  748. *
  749. * @tparam Compare Type of comparison function object.
  750. * @tparam Sort Type of sort function object.
  751. * @tparam Args Types of arguments to forward to the sort function object.
  752. * @param compare A valid comparison function object.
  753. * @param algo A valid sort function object.
  754. * @param args Arguments to forward to the sort function object, if any.
  755. */
  756. template<typename Compare, typename Sort = std_sort, typename... Args>
  757. void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
  758. compact();
  759. sort_n(packed.size(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
  760. }
  761. /**
  762. * @brief Sort entities according to their order in another sparse set.
  763. *
  764. * Entities that are part of both the sparse sets are ordered internally
  765. * according to the order they have in `other`. All the other entities goes
  766. * to the end of the list and there are no guarantees on their order.<br/>
  767. * In other terms, this function can be used to impose the same order on two
  768. * sets by using one of them as a master and the other one as a slave.
  769. *
  770. * Iterating the sparse set with a couple of iterators returns elements in
  771. * the expected order after a call to `respect`. See `begin` and `end` for
  772. * more details.
  773. *
  774. * @param other The sparse sets that imposes the order of the entities.
  775. */
  776. void respect(const basic_sparse_set &other) {
  777. compact();
  778. const auto to = other.end();
  779. auto from = other.begin();
  780. for(size_type pos = packed.size() - 1; pos && from != to; ++from) {
  781. if(contains(*from)) {
  782. if(*from != packed[pos]) {
  783. // basic no-leak guarantee (with invalid state) if swapping throws
  784. swap_elements(packed[pos], *from);
  785. }
  786. --pos;
  787. }
  788. }
  789. }
  790. /*! @brief Clears a sparse set. */
  791. void clear() {
  792. if(const auto last = end(); free_list == null) {
  793. in_place_pop(begin(), last);
  794. } else {
  795. for(auto &&entity: *this) {
  796. // tombstone filter on itself
  797. if(const auto it = find(entity); it != last) {
  798. in_place_pop(it, it + 1u);
  799. }
  800. }
  801. }
  802. free_list = tombstone;
  803. packed.clear();
  804. }
  805. /**
  806. * @brief Returned value type, if any.
  807. * @return Returned value type, if any.
  808. */
  809. const type_info &type() const ENTT_NOEXCEPT {
  810. return *info;
  811. }
  812. /*! @brief Forwards variables to mixins, if any. */
  813. virtual void bind(any) ENTT_NOEXCEPT {}
  814. private:
  815. sparse_container_type sparse;
  816. packed_container_type packed;
  817. const type_info *info;
  818. entity_type free_list;
  819. deletion_policy mode;
  820. };
  821. } // namespace entt
  822. #endif