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

961 lines
34 KiB

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