sparse_set.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. #ifndef ENTT_ENTITY_SPARSE_SET_HPP
  2. #define ENTT_ENTITY_SPARSE_SET_HPP
  3. #include <iterator>
  4. #include <utility>
  5. #include <vector>
  6. #include <memory>
  7. #include <cstddef>
  8. #include <type_traits>
  9. #include "../config/config.h"
  10. #include "../core/algorithm.hpp"
  11. #include "entity.hpp"
  12. #include "fwd.hpp"
  13. namespace entt {
  14. /**
  15. * @brief Basic sparse set implementation.
  16. *
  17. * Sparse set or packed array or whatever is the name users give it.<br/>
  18. * Two arrays: an _external_ one and an _internal_ one; a _sparse_ one and a
  19. * _packed_ one; one used for direct access through contiguous memory, the other
  20. * one used to get the data through an extra level of indirection.<br/>
  21. * This is largely used by the registry to offer users the fastest access ever
  22. * to the components. Views and groups in general are almost entirely designed
  23. * around sparse sets.
  24. *
  25. * This type of data structure is widely documented in the literature and on the
  26. * web. This is nothing more than a customized implementation suitable for the
  27. * purpose of the framework.
  28. *
  29. * @note
  30. * Internal data structures arrange elements to maximize performance. There are
  31. * no guarantees that entities are returned in the insertion order when iterate
  32. * a sparse set. Do not make assumption on the order in any case.
  33. *
  34. * @tparam Entity A valid entity type (see entt_traits for more details).
  35. */
  36. template<typename Entity>
  37. class basic_sparse_set {
  38. static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two");
  39. static constexpr auto entt_per_page = ENTT_PAGE_SIZE / sizeof(Entity);
  40. using traits_type = entt_traits<Entity>;
  41. using page_type = std::unique_ptr<Entity[]>;
  42. class sparse_set_iterator final {
  43. friend class basic_sparse_set<Entity>;
  44. using packed_type = std::vector<Entity>;
  45. using index_type = typename traits_type::difference_type;
  46. sparse_set_iterator(const packed_type &ref, const index_type idx) ENTT_NOEXCEPT
  47. : packed{&ref}, index{idx}
  48. {}
  49. public:
  50. using difference_type = index_type;
  51. using value_type = Entity;
  52. using pointer = const value_type *;
  53. using reference = const value_type &;
  54. using iterator_category = std::random_access_iterator_tag;
  55. sparse_set_iterator() ENTT_NOEXCEPT = default;
  56. sparse_set_iterator & operator++() ENTT_NOEXCEPT {
  57. return --index, *this;
  58. }
  59. sparse_set_iterator operator++(int) ENTT_NOEXCEPT {
  60. iterator orig = *this;
  61. return ++(*this), orig;
  62. }
  63. sparse_set_iterator & operator--() ENTT_NOEXCEPT {
  64. return ++index, *this;
  65. }
  66. sparse_set_iterator operator--(int) ENTT_NOEXCEPT {
  67. sparse_set_iterator orig = *this;
  68. return operator--(), orig;
  69. }
  70. sparse_set_iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
  71. index -= value;
  72. return *this;
  73. }
  74. sparse_set_iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
  75. sparse_set_iterator copy = *this;
  76. return (copy += value);
  77. }
  78. sparse_set_iterator & operator-=(const difference_type value) ENTT_NOEXCEPT {
  79. return (*this += -value);
  80. }
  81. sparse_set_iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
  82. return (*this + -value);
  83. }
  84. difference_type operator-(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  85. return other.index - index;
  86. }
  87. [[nodiscard]] reference operator[](const difference_type value) const {
  88. const auto pos = size_type(index-value-1u);
  89. return (*packed)[pos];
  90. }
  91. [[nodiscard]] bool operator==(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  92. return other.index == index;
  93. }
  94. [[nodiscard]] bool operator!=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  95. return !(*this == other);
  96. }
  97. [[nodiscard]] bool operator<(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  98. return index > other.index;
  99. }
  100. [[nodiscard]] bool operator>(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  101. return index < other.index;
  102. }
  103. [[nodiscard]] bool operator<=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  104. return !(*this > other);
  105. }
  106. [[nodiscard]] bool operator>=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
  107. return !(*this < other);
  108. }
  109. [[nodiscard]] pointer operator->() const {
  110. const auto pos = size_type(index-1u);
  111. return &(*packed)[pos];
  112. }
  113. [[nodiscard]] reference operator*() const {
  114. return *operator->();
  115. }
  116. private:
  117. const packed_type *packed;
  118. index_type index;
  119. };
  120. [[nodiscard]] auto page(const Entity entt) const ENTT_NOEXCEPT {
  121. return size_type{(to_integral(entt) & traits_type::entity_mask) / entt_per_page};
  122. }
  123. [[nodiscard]] auto offset(const Entity entt) const ENTT_NOEXCEPT {
  124. return size_type{to_integral(entt) & (entt_per_page - 1)};
  125. }
  126. [[nodiscard]] page_type & assure(const std::size_t pos) {
  127. if(!(pos < sparse.size())) {
  128. sparse.resize(pos+1);
  129. }
  130. if(!sparse[pos]) {
  131. sparse[pos].reset(new entity_type[entt_per_page]);
  132. // null is safe in all cases for our purposes
  133. for(auto *first = sparse[pos].get(), *last = first + entt_per_page; first != last; ++first) {
  134. *first = null;
  135. }
  136. }
  137. return sparse[pos];
  138. }
  139. virtual void swap_at(const std::size_t, const std::size_t) {}
  140. virtual void swap_and_pop(const std::size_t) {}
  141. virtual void clear_all() {}
  142. public:
  143. /*! @brief Underlying entity identifier. */
  144. using entity_type = Entity;
  145. /*! @brief Unsigned integer type. */
  146. using size_type = std::size_t;
  147. /*! @brief Random access iterator type. */
  148. using iterator = sparse_set_iterator;
  149. /*! @brief Reverse iterator type. */
  150. using reverse_iterator = const entity_type *;
  151. /*! @brief Default constructor. */
  152. basic_sparse_set() = default;
  153. /*! @brief Default move constructor. */
  154. basic_sparse_set(basic_sparse_set &&) = default;
  155. /*! @brief Default destructor. */
  156. virtual ~basic_sparse_set() = default;
  157. /*! @brief Default move assignment operator. @return This sparse set. */
  158. basic_sparse_set & operator=(basic_sparse_set &&) = default;
  159. /**
  160. * @brief Increases the capacity of a sparse set.
  161. *
  162. * If the new capacity is greater than the current capacity, new storage is
  163. * allocated, otherwise the method does nothing.
  164. *
  165. * @param cap Desired capacity.
  166. */
  167. void reserve(const size_type cap) {
  168. packed.reserve(cap);
  169. }
  170. /**
  171. * @brief Returns the number of elements that a sparse set has currently
  172. * allocated space for.
  173. * @return Capacity of the sparse set.
  174. */
  175. [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT {
  176. return packed.capacity();
  177. }
  178. /*! @brief Requests the removal of unused capacity. */
  179. void shrink_to_fit() {
  180. // conservative approach
  181. if(packed.empty()) {
  182. sparse.clear();
  183. }
  184. sparse.shrink_to_fit();
  185. packed.shrink_to_fit();
  186. }
  187. /**
  188. * @brief Returns the extent of a sparse set.
  189. *
  190. * The extent of a sparse set is also the size of the internal sparse array.
  191. * There is no guarantee that the internal packed array has the same size.
  192. * Usually the size of the internal sparse array is equal or greater than
  193. * the one of the internal packed array.
  194. *
  195. * @return Extent of the sparse set.
  196. */
  197. [[nodiscard]] size_type extent() const ENTT_NOEXCEPT {
  198. return sparse.size() * entt_per_page;
  199. }
  200. /**
  201. * @brief Returns the number of elements in a sparse set.
  202. *
  203. * The number of elements is also the size of the internal packed array.
  204. * There is no guarantee that the internal sparse array has the same size.
  205. * Usually the size of the internal sparse array is equal or greater than
  206. * the one of the internal packed array.
  207. *
  208. * @return Number of elements.
  209. */
  210. [[nodiscard]] size_type size() const ENTT_NOEXCEPT {
  211. return packed.size();
  212. }
  213. /**
  214. * @brief Checks whether a sparse set is empty.
  215. * @return True if the sparse set is empty, false otherwise.
  216. */
  217. [[nodiscard]] bool empty() const ENTT_NOEXCEPT {
  218. return packed.empty();
  219. }
  220. /**
  221. * @brief Direct access to the internal packed array.
  222. *
  223. * The returned pointer is such that range `[data(), data() + size())` is
  224. * always a valid range, even if the container is empty.
  225. *
  226. * @note
  227. * Entities are in the reverse order as returned by the `begin`/`end`
  228. * iterators.
  229. *
  230. * @return A pointer to the internal packed array.
  231. */
  232. [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT {
  233. return packed.data();
  234. }
  235. /**
  236. * @brief Returns an iterator to the beginning.
  237. *
  238. * The returned iterator points to the first entity of the internal packed
  239. * array. If the sparse set is empty, the returned iterator will be equal to
  240. * `end()`.
  241. *
  242. * @return An iterator to the first entity of the internal packed array.
  243. */
  244. [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
  245. const typename traits_type::difference_type pos = packed.size();
  246. return iterator{packed, pos};
  247. }
  248. /**
  249. * @brief Returns an iterator to the end.
  250. *
  251. * The returned iterator points to the element following the last entity in
  252. * the internal packed array. Attempting to dereference the returned
  253. * iterator results in undefined behavior.
  254. *
  255. * @return An iterator to the element following the last entity of the
  256. * internal packed array.
  257. */
  258. [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
  259. return iterator{packed, {}};
  260. }
  261. /**
  262. * @brief Returns a reverse iterator to the beginning.
  263. *
  264. * The returned iterator points to the first entity of the reversed internal
  265. * packed array. If the sparse set is empty, the returned iterator will be
  266. * equal to `rend()`.
  267. *
  268. * @return An iterator to the first entity of the reversed internal packed
  269. * array.
  270. */
  271. [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
  272. return packed.data();
  273. }
  274. /**
  275. * @brief Returns a reverse iterator to the end.
  276. *
  277. * The returned iterator points to the element following the last entity in
  278. * the reversed internal packed array. Attempting to dereference the
  279. * returned iterator results in undefined behavior.
  280. *
  281. * @return An iterator to the element following the last entity of the
  282. * reversed internal packed array.
  283. */
  284. [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
  285. return rbegin() + packed.size();
  286. }
  287. /**
  288. * @brief Finds an entity.
  289. * @param entt A valid entity identifier.
  290. * @return An iterator to the given entity if it's found, past the end
  291. * iterator otherwise.
  292. */
  293. [[nodiscard]] iterator find(const entity_type entt) const {
  294. return contains(entt) ? --(end() - index(entt)) : end();
  295. }
  296. /**
  297. * @brief Checks if a sparse set contains an entity.
  298. * @param entt A valid entity identifier.
  299. * @return True if the sparse set contains the entity, false otherwise.
  300. */
  301. [[nodiscard]] bool contains(const entity_type entt) const {
  302. const auto curr = page(entt);
  303. // testing against null permits to avoid accessing the packed array
  304. return (curr < sparse.size() && sparse[curr] && sparse[curr][offset(entt)] != null);
  305. }
  306. /**
  307. * @brief Returns the position of an entity in a sparse set.
  308. *
  309. * @warning
  310. * Attempting to get the position of an entity that doesn't belong to the
  311. * sparse set results in undefined behavior.
  312. *
  313. * @param entt A valid entity identifier.
  314. * @return The position of the entity in the sparse set.
  315. */
  316. [[nodiscard]] size_type index(const entity_type entt) const {
  317. ENTT_ASSERT(contains(entt));
  318. return size_type{to_integral(sparse[page(entt)][offset(entt)])};
  319. }
  320. /**
  321. * @brief Assigns an entity to a sparse set.
  322. *
  323. * @warning
  324. * Attempting to assign an entity that already belongs to the sparse set
  325. * results in undefined behavior.
  326. *
  327. * @param entt A valid entity identifier.
  328. */
  329. void emplace(const entity_type entt) {
  330. ENTT_ASSERT(!contains(entt));
  331. assure(page(entt))[offset(entt)] = entity_type{static_cast<typename traits_type::entity_type>(packed.size())};
  332. packed.push_back(entt);
  333. }
  334. /**
  335. * @brief Assigns one or more entities to a sparse set.
  336. *
  337. * @warning
  338. * Attempting to assign an entity that already belongs to the sparse set
  339. * results in undefined behavior.
  340. *
  341. * @tparam It Type of input iterator.
  342. * @param first An iterator to the first element of the range of entities.
  343. * @param last An iterator past the last element of the range of entities.
  344. */
  345. template<typename It>
  346. void insert(It first, It last) {
  347. auto next = static_cast<typename traits_type::entity_type>(packed.size());
  348. packed.insert(packed.end(), first, last);
  349. for(; first != last; ++first) {
  350. ENTT_ASSERT(!contains(*first));
  351. assure(page(*first))[offset(*first)] = entity_type{next++};
  352. }
  353. }
  354. /**
  355. * @brief Removes an entity from a sparse set.
  356. *
  357. * @warning
  358. * Attempting to remove an entity that doesn't belong to the sparse set
  359. * results in undefined behavior.
  360. *
  361. * @param entt A valid entity identifier.
  362. */
  363. void remove(const entity_type entt) {
  364. ENTT_ASSERT(contains(entt));
  365. auto &ref = sparse[page(entt)][offset(entt)];
  366. const auto pos = size_type{to_integral(ref)};
  367. const auto other = packed.back();
  368. sparse[page(other)][offset(other)] = ref;
  369. packed[pos] = other;
  370. ref = null;
  371. packed.pop_back();
  372. swap_and_pop(pos);
  373. }
  374. /**
  375. * @brief Removes multiple entities from a pool.
  376. * @tparam It Type of input iterator.
  377. * @param first An iterator to the first element of the range of entities.
  378. * @param last An iterator past the last element of the range of entities.
  379. */
  380. template<typename It>
  381. void remove(It first, It last) {
  382. if(std::distance(first, last) == std::distance(packed.begin(), packed.end())) {
  383. // no validity check, let it be misused
  384. clear();
  385. } else {
  386. for(; first != last; ++first) {
  387. remove(*first);
  388. }
  389. }
  390. }
  391. /**
  392. * @brief Swaps two entities in the internal packed array.
  393. *
  394. * For what it's worth, this function affects both the internal sparse array
  395. * and the internal packed array. Users should not care of that anyway.
  396. *
  397. * @warning
  398. * Attempting to swap entities that don't belong to the sparse set results
  399. * in undefined behavior.
  400. *
  401. * @param lhs A valid entity identifier.
  402. * @param rhs A valid entity identifier.
  403. */
  404. void swap(const entity_type lhs, const entity_type rhs) {
  405. const auto from = index(lhs);
  406. const auto to = index(rhs);
  407. std::swap(sparse[page(lhs)][offset(lhs)], sparse[page(rhs)][offset(rhs)]);
  408. std::swap(packed[from], packed[to]);
  409. swap_at(from, to);
  410. }
  411. /**
  412. * @brief Sort the first count elements according to the given comparison
  413. * function.
  414. *
  415. * The comparison function object must return `true` if the first element
  416. * is _less_ than the second one, `false` otherwise. The signature of the
  417. * comparison function should be equivalent to the following:
  418. *
  419. * @code{.cpp}
  420. * bool(const Entity, const Entity);
  421. * @endcode
  422. *
  423. * Moreover, the comparison function object shall induce a
  424. * _strict weak ordering_ on the values.
  425. *
  426. * The sort function object must offer a member function template
  427. * `operator()` that accepts three arguments:
  428. *
  429. * * An iterator to the first element of the range to sort.
  430. * * An iterator past the last element of the range to sort.
  431. * * A comparison function to use to compare the elements.
  432. *
  433. * @tparam Compare Type of comparison function object.
  434. * @tparam Sort Type of sort function object.
  435. * @tparam Args Types of arguments to forward to the sort function object.
  436. * @param count Number of elements to sort.
  437. * @param compare A valid comparison function object.
  438. * @param algo A valid sort function object.
  439. * @param args Arguments to forward to the sort function object, if any.
  440. */
  441. template<typename Compare, typename Sort = std_sort, typename... Args>
  442. void sort_n(const size_type count, Compare compare, Sort algo = Sort{}, Args &&... args) {
  443. ENTT_ASSERT(!(count > size()));
  444. algo(packed.rend() - count, packed.rend(), std::move(compare), std::forward<Args>(args)...);
  445. for(size_type pos{}; pos < count; ++pos) {
  446. auto curr = pos;
  447. auto next = index(packed[curr]);
  448. while(curr != next) {
  449. swap_at(next, index(packed[next]));
  450. sparse[page(packed[curr])][offset(packed[curr])] = entity_type{static_cast<typename traits_type::entity_type>(curr)};
  451. curr = next;
  452. next = index(packed[curr]);
  453. }
  454. }
  455. }
  456. /**
  457. * @brief Sort all elements according to the given comparison function.
  458. *
  459. * @sa sort_n
  460. *
  461. * @tparam Compare Type of comparison function object.
  462. * @tparam Sort Type of sort function object.
  463. * @tparam Args Types of arguments to forward to the sort function object.
  464. * @param compare A valid comparison function object.
  465. * @param algo A valid sort function object.
  466. * @param args Arguments to forward to the sort function object, if any.
  467. */
  468. template<typename Compare, typename Sort = std_sort, typename... Args>
  469. void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
  470. sort_n(size(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
  471. }
  472. /**
  473. * @brief Sort entities according to their order in another sparse set.
  474. *
  475. * Entities that are part of both the sparse sets are ordered internally
  476. * according to the order they have in `other`. All the other entities goes
  477. * to the end of the list and there are no guarantees on their order.<br/>
  478. * In other terms, this function can be used to impose the same order on two
  479. * sets by using one of them as a master and the other one as a slave.
  480. *
  481. * Iterating the sparse set with a couple of iterators returns elements in
  482. * the expected order after a call to `respect`. See `begin` and `end` for
  483. * more details.
  484. *
  485. * @param other The sparse sets that imposes the order of the entities.
  486. */
  487. void respect(const basic_sparse_set &other) {
  488. const auto to = other.end();
  489. auto from = other.begin();
  490. size_type pos = packed.size() - 1;
  491. while(pos && from != to) {
  492. if(contains(*from)) {
  493. if(*from != packed[pos]) {
  494. swap(packed[pos], *from);
  495. }
  496. --pos;
  497. }
  498. ++from;
  499. }
  500. }
  501. /*! @brief Clears a sparse set. */
  502. void clear() ENTT_NOEXCEPT {
  503. sparse.clear();
  504. packed.clear();
  505. clear_all();
  506. }
  507. private:
  508. std::vector<page_type> sparse;
  509. std::vector<entity_type> packed;
  510. };
  511. }
  512. #endif