sparse_set.hpp 39 KB

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