dense_set.hpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933
  1. #ifndef ENTT_CONTAINER_DENSE_SET_HPP
  2. #define ENTT_CONTAINER_DENSE_SET_HPP
  3. #include <cmath>
  4. #include <cstddef>
  5. #include <functional>
  6. #include <iterator>
  7. #include <limits>
  8. #include <memory>
  9. #include <tuple>
  10. #include <type_traits>
  11. #include <utility>
  12. #include <vector>
  13. #include "../config/config.h"
  14. #include "../core/compressed_pair.hpp"
  15. #include "../core/memory.hpp"
  16. #include "../core/type_traits.hpp"
  17. #include "fwd.hpp"
  18. namespace entt {
  19. /**
  20. * @cond TURN_OFF_DOXYGEN
  21. * Internal details not to be documented.
  22. */
  23. namespace internal {
  24. template<typename It>
  25. class dense_set_iterator final {
  26. template<typename>
  27. friend class dense_set_iterator;
  28. public:
  29. using value_type = typename It::value_type::second_type;
  30. using pointer = const value_type *;
  31. using reference = const value_type &;
  32. using difference_type = std::ptrdiff_t;
  33. using iterator_category = std::random_access_iterator_tag;
  34. constexpr dense_set_iterator() noexcept
  35. : it{} {}
  36. constexpr dense_set_iterator(const It iter) noexcept
  37. : it{iter} {}
  38. template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
  39. constexpr dense_set_iterator(const dense_set_iterator<Other> &other) noexcept
  40. : it{other.it} {}
  41. constexpr dense_set_iterator &operator++() noexcept {
  42. return ++it, *this;
  43. }
  44. constexpr dense_set_iterator operator++(int) noexcept {
  45. dense_set_iterator orig = *this;
  46. return ++(*this), orig;
  47. }
  48. constexpr dense_set_iterator &operator--() noexcept {
  49. return --it, *this;
  50. }
  51. constexpr dense_set_iterator operator--(int) noexcept {
  52. dense_set_iterator orig = *this;
  53. return operator--(), orig;
  54. }
  55. constexpr dense_set_iterator &operator+=(const difference_type value) noexcept {
  56. it += value;
  57. return *this;
  58. }
  59. constexpr dense_set_iterator operator+(const difference_type value) const noexcept {
  60. dense_set_iterator copy = *this;
  61. return (copy += value);
  62. }
  63. constexpr dense_set_iterator &operator-=(const difference_type value) noexcept {
  64. return (*this += -value);
  65. }
  66. constexpr dense_set_iterator operator-(const difference_type value) const noexcept {
  67. return (*this + -value);
  68. }
  69. [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
  70. return it[value].second;
  71. }
  72. [[nodiscard]] constexpr pointer operator->() const noexcept {
  73. return std::addressof(it->second);
  74. }
  75. [[nodiscard]] constexpr reference operator*() const noexcept {
  76. return *operator->();
  77. }
  78. template<typename Lhs, typename Rhs>
  79. friend constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
  80. template<typename Lhs, typename Rhs>
  81. friend constexpr bool operator==(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
  82. template<typename Lhs, typename Rhs>
  83. friend constexpr bool operator<(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
  84. private:
  85. It it;
  86. };
  87. template<typename Lhs, typename Rhs>
  88. [[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
  89. return lhs.it - rhs.it;
  90. }
  91. template<typename Lhs, typename Rhs>
  92. [[nodiscard]] constexpr bool operator==(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
  93. return lhs.it == rhs.it;
  94. }
  95. template<typename Lhs, typename Rhs>
  96. [[nodiscard]] constexpr bool operator!=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
  97. return !(lhs == rhs);
  98. }
  99. template<typename Lhs, typename Rhs>
  100. [[nodiscard]] constexpr bool operator<(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
  101. return lhs.it < rhs.it;
  102. }
  103. template<typename Lhs, typename Rhs>
  104. [[nodiscard]] constexpr bool operator>(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
  105. return rhs < lhs;
  106. }
  107. template<typename Lhs, typename Rhs>
  108. [[nodiscard]] constexpr bool operator<=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
  109. return !(lhs > rhs);
  110. }
  111. template<typename Lhs, typename Rhs>
  112. [[nodiscard]] constexpr bool operator>=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
  113. return !(lhs < rhs);
  114. }
  115. template<typename It>
  116. class dense_set_local_iterator final {
  117. template<typename>
  118. friend class dense_set_local_iterator;
  119. public:
  120. using value_type = typename It::value_type::second_type;
  121. using pointer = const value_type *;
  122. using reference = const value_type &;
  123. using difference_type = std::ptrdiff_t;
  124. using iterator_category = std::forward_iterator_tag;
  125. constexpr dense_set_local_iterator() noexcept
  126. : it{},
  127. offset{} {}
  128. constexpr dense_set_local_iterator(It iter, const std::size_t pos) noexcept
  129. : it{iter},
  130. offset{pos} {}
  131. template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
  132. constexpr dense_set_local_iterator(const dense_set_local_iterator<Other> &other) noexcept
  133. : it{other.it},
  134. offset{other.offset} {}
  135. constexpr dense_set_local_iterator &operator++() noexcept {
  136. return offset = it[offset].first, *this;
  137. }
  138. constexpr dense_set_local_iterator operator++(int) noexcept {
  139. dense_set_local_iterator orig = *this;
  140. return ++(*this), orig;
  141. }
  142. [[nodiscard]] constexpr pointer operator->() const noexcept {
  143. return std::addressof(it[offset].second);
  144. }
  145. [[nodiscard]] constexpr reference operator*() const noexcept {
  146. return *operator->();
  147. }
  148. [[nodiscard]] constexpr std::size_t index() const noexcept {
  149. return offset;
  150. }
  151. private:
  152. It it;
  153. std::size_t offset;
  154. };
  155. template<typename Lhs, typename Rhs>
  156. [[nodiscard]] constexpr bool operator==(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &rhs) noexcept {
  157. return lhs.index() == rhs.index();
  158. }
  159. template<typename Lhs, typename Rhs>
  160. [[nodiscard]] constexpr bool operator!=(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &rhs) noexcept {
  161. return !(lhs == rhs);
  162. }
  163. } // namespace internal
  164. /**
  165. * Internal details not to be documented.
  166. * @endcond
  167. */
  168. /**
  169. * @brief Associative container for unique objects of a given type.
  170. *
  171. * Internally, elements are organized into buckets. Which bucket an element is
  172. * placed into depends entirely on its hash. Elements with the same hash code
  173. * appear in the same bucket.
  174. *
  175. * @tparam Type Value type of the associative container.
  176. * @tparam Hash Type of function to use to hash the values.
  177. * @tparam KeyEqual Type of function to use to compare the values for equality.
  178. * @tparam Allocator Type of allocator used to manage memory and elements.
  179. */
  180. template<typename Type, typename Hash, typename KeyEqual, typename Allocator>
  181. class dense_set {
  182. static constexpr float default_threshold = 0.875f;
  183. static constexpr std::size_t minimum_capacity = 8u;
  184. using node_type = std::pair<std::size_t, Type>;
  185. using alloc_traits = std::allocator_traits<Allocator>;
  186. static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
  187. using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
  188. using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
  189. template<typename Other>
  190. [[nodiscard]] std::size_t value_to_bucket(const Other &value) const noexcept {
  191. return fast_mod(static_cast<size_type>(sparse.second()(value)), bucket_count());
  192. }
  193. template<typename Other>
  194. [[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) {
  195. for(auto it = begin(bucket), last = end(bucket); it != last; ++it) {
  196. if(packed.second()(*it, value)) {
  197. return begin() + static_cast<typename iterator::difference_type>(it.index());
  198. }
  199. }
  200. return end();
  201. }
  202. template<typename Other>
  203. [[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) const {
  204. for(auto it = cbegin(bucket), last = cend(bucket); it != last; ++it) {
  205. if(packed.second()(*it, value)) {
  206. return cbegin() + static_cast<typename iterator::difference_type>(it.index());
  207. }
  208. }
  209. return cend();
  210. }
  211. template<typename Other>
  212. [[nodiscard]] auto insert_or_do_nothing(Other &&value) {
  213. const auto index = value_to_bucket(value);
  214. if(auto it = constrained_find(value, index); it != end()) {
  215. return std::make_pair(it, false);
  216. }
  217. packed.first().emplace_back(sparse.first()[index], std::forward<Other>(value));
  218. sparse.first()[index] = packed.first().size() - 1u;
  219. rehash_if_required();
  220. return std::make_pair(--end(), true);
  221. }
  222. void move_and_pop(const std::size_t pos) {
  223. if(const auto last = size() - 1u; pos != last) {
  224. size_type *curr = sparse.first().data() + value_to_bucket(packed.first().back().second);
  225. packed.first()[pos] = std::move(packed.first().back());
  226. for(; *curr != last; curr = &packed.first()[*curr].first) {}
  227. *curr = pos;
  228. }
  229. packed.first().pop_back();
  230. }
  231. void rehash_if_required() {
  232. if(size() > (bucket_count() * max_load_factor())) {
  233. rehash(bucket_count() * 2u);
  234. }
  235. }
  236. public:
  237. /*! @brief Key type of the container. */
  238. using key_type = Type;
  239. /*! @brief Value type of the container. */
  240. using value_type = Type;
  241. /*! @brief Unsigned integer type. */
  242. using size_type = std::size_t;
  243. /*! @brief Type of function to use to hash the elements. */
  244. using hasher = Hash;
  245. /*! @brief Type of function to use to compare the elements for equality. */
  246. using key_equal = KeyEqual;
  247. /*! @brief Allocator type. */
  248. using allocator_type = Allocator;
  249. /*! @brief Random access iterator type. */
  250. using iterator = internal::dense_set_iterator<typename packed_container_type::iterator>;
  251. /*! @brief Constant random access iterator type. */
  252. using const_iterator = internal::dense_set_iterator<typename packed_container_type::const_iterator>;
  253. /*! @brief Reverse iterator type. */
  254. using reverse_iterator = std::reverse_iterator<iterator>;
  255. /*! @brief Constant reverse iterator type. */
  256. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  257. /*! @brief Forward iterator type. */
  258. using local_iterator = internal::dense_set_local_iterator<typename packed_container_type::iterator>;
  259. /*! @brief Constant forward iterator type. */
  260. using const_local_iterator = internal::dense_set_local_iterator<typename packed_container_type::const_iterator>;
  261. /*! @brief Default constructor. */
  262. dense_set()
  263. : dense_set{minimum_capacity} {}
  264. /**
  265. * @brief Constructs an empty container with a given allocator.
  266. * @param allocator The allocator to use.
  267. */
  268. explicit dense_set(const allocator_type &allocator)
  269. : dense_set{minimum_capacity, hasher{}, key_equal{}, allocator} {}
  270. /**
  271. * @brief Constructs an empty container with a given allocator and user
  272. * supplied minimal number of buckets.
  273. * @param cnt Minimal number of buckets.
  274. * @param allocator The allocator to use.
  275. */
  276. dense_set(const size_type cnt, const allocator_type &allocator)
  277. : dense_set{cnt, hasher{}, key_equal{}, allocator} {}
  278. /**
  279. * @brief Constructs an empty container with a given allocator, hash
  280. * function and user supplied minimal number of buckets.
  281. * @param cnt Minimal number of buckets.
  282. * @param hash Hash function to use.
  283. * @param allocator The allocator to use.
  284. */
  285. dense_set(const size_type cnt, const hasher &hash, const allocator_type &allocator)
  286. : dense_set{cnt, hash, key_equal{}, allocator} {}
  287. /**
  288. * @brief Constructs an empty container with a given allocator, hash
  289. * function, compare function and user supplied minimal number of buckets.
  290. * @param cnt Minimal number of buckets.
  291. * @param hash Hash function to use.
  292. * @param equal Compare function to use.
  293. * @param allocator The allocator to use.
  294. */
  295. explicit dense_set(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{})
  296. : sparse{allocator, hash},
  297. packed{allocator, equal},
  298. threshold{default_threshold} {
  299. rehash(cnt);
  300. }
  301. /*! @brief Default copy constructor. */
  302. dense_set(const dense_set &) = default;
  303. /**
  304. * @brief Allocator-extended copy constructor.
  305. * @param other The instance to copy from.
  306. * @param allocator The allocator to use.
  307. */
  308. dense_set(const dense_set &other, const allocator_type &allocator)
  309. : sparse{std::piecewise_construct, std::forward_as_tuple(other.sparse.first(), allocator), std::forward_as_tuple(other.sparse.second())},
  310. packed{std::piecewise_construct, std::forward_as_tuple(other.packed.first(), allocator), std::forward_as_tuple(other.packed.second())},
  311. threshold{other.threshold} {}
  312. /*! @brief Default move constructor. */
  313. dense_set(dense_set &&) noexcept(std::is_nothrow_move_constructible_v<compressed_pair<sparse_container_type, hasher>> &&std::is_nothrow_move_constructible_v<compressed_pair<packed_container_type, key_equal>>) = default;
  314. /**
  315. * @brief Allocator-extended move constructor.
  316. * @param other The instance to move from.
  317. * @param allocator The allocator to use.
  318. */
  319. dense_set(dense_set &&other, const allocator_type &allocator)
  320. : sparse{std::piecewise_construct, std::forward_as_tuple(std::move(other.sparse.first()), allocator), std::forward_as_tuple(std::move(other.sparse.second()))},
  321. packed{std::piecewise_construct, std::forward_as_tuple(std::move(other.packed.first()), allocator), std::forward_as_tuple(std::move(other.packed.second()))},
  322. threshold{other.threshold} {}
  323. /**
  324. * @brief Default copy assignment operator.
  325. * @return This container.
  326. */
  327. dense_set &operator=(const dense_set &) = default;
  328. /**
  329. * @brief Default move assignment operator.
  330. * @return This container.
  331. */
  332. dense_set &operator=(dense_set &&) noexcept(std::is_nothrow_move_assignable_v<compressed_pair<sparse_container_type, hasher>> &&std::is_nothrow_move_assignable_v<compressed_pair<packed_container_type, key_equal>>) = default;
  333. /**
  334. * @brief Returns the associated allocator.
  335. * @return The associated allocator.
  336. */
  337. [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
  338. return sparse.first().get_allocator();
  339. }
  340. /**
  341. * @brief Returns an iterator to the beginning.
  342. *
  343. * If the array is empty, the returned iterator will be equal to `end()`.
  344. *
  345. * @return An iterator to the first instance of the internal array.
  346. */
  347. [[nodiscard]] const_iterator cbegin() const noexcept {
  348. return packed.first().begin();
  349. }
  350. /*! @copydoc cbegin */
  351. [[nodiscard]] const_iterator begin() const noexcept {
  352. return cbegin();
  353. }
  354. /*! @copydoc begin */
  355. [[nodiscard]] iterator begin() noexcept {
  356. return packed.first().begin();
  357. }
  358. /**
  359. * @brief Returns an iterator to the end.
  360. * @return An iterator to the element following the last instance of the
  361. * internal array.
  362. */
  363. [[nodiscard]] const_iterator cend() const noexcept {
  364. return packed.first().end();
  365. }
  366. /*! @copydoc cend */
  367. [[nodiscard]] const_iterator end() const noexcept {
  368. return cend();
  369. }
  370. /*! @copydoc end */
  371. [[nodiscard]] iterator end() noexcept {
  372. return packed.first().end();
  373. }
  374. /**
  375. * @brief Returns a reverse iterator to the beginning.
  376. *
  377. * If the array is empty, the returned iterator will be equal to `rend()`.
  378. *
  379. * @return An iterator to the first instance of the reversed internal array.
  380. */
  381. [[nodiscard]] const_reverse_iterator crbegin() const noexcept {
  382. return std::make_reverse_iterator(cend());
  383. }
  384. /*! @copydoc crbegin */
  385. [[nodiscard]] const_reverse_iterator rbegin() const noexcept {
  386. return crbegin();
  387. }
  388. /*! @copydoc rbegin */
  389. [[nodiscard]] reverse_iterator rbegin() noexcept {
  390. return std::make_reverse_iterator(end());
  391. }
  392. /**
  393. * @brief Returns a reverse iterator to the end.
  394. * @return An iterator to the element following the last instance of the
  395. * reversed internal array.
  396. */
  397. [[nodiscard]] const_reverse_iterator crend() const noexcept {
  398. return std::make_reverse_iterator(cbegin());
  399. }
  400. /*! @copydoc crend */
  401. [[nodiscard]] const_reverse_iterator rend() const noexcept {
  402. return crend();
  403. }
  404. /*! @copydoc rend */
  405. [[nodiscard]] reverse_iterator rend() noexcept {
  406. return std::make_reverse_iterator(begin());
  407. }
  408. /**
  409. * @brief Checks whether a container is empty.
  410. * @return True if the container is empty, false otherwise.
  411. */
  412. [[nodiscard]] bool empty() const noexcept {
  413. return packed.first().empty();
  414. }
  415. /**
  416. * @brief Returns the number of elements in a container.
  417. * @return Number of elements in a container.
  418. */
  419. [[nodiscard]] size_type size() const noexcept {
  420. return packed.first().size();
  421. }
  422. /**
  423. * @brief Returns the maximum possible number of elements.
  424. * @return Maximum possible number of elements.
  425. */
  426. [[nodiscard]] size_type max_size() const noexcept {
  427. return packed.first().max_size();
  428. }
  429. /*! @brief Clears the container. */
  430. void clear() noexcept {
  431. sparse.first().clear();
  432. packed.first().clear();
  433. rehash(0u);
  434. }
  435. /**
  436. * @brief Inserts an element into the container, if it does not exist.
  437. * @param value An element to insert into the container.
  438. * @return A pair consisting of an iterator to the inserted element (or to
  439. * the element that prevented the insertion) and a bool denoting whether the
  440. * insertion took place.
  441. */
  442. std::pair<iterator, bool> insert(const value_type &value) {
  443. return insert_or_do_nothing(value);
  444. }
  445. /*! @copydoc insert */
  446. std::pair<iterator, bool> insert(value_type &&value) {
  447. return insert_or_do_nothing(std::move(value));
  448. }
  449. /**
  450. * @brief Inserts elements into the container, if they do not exist.
  451. * @tparam It Type of input iterator.
  452. * @param first An iterator to the first element of the range of elements.
  453. * @param last An iterator past the last element of the range of elements.
  454. */
  455. template<typename It>
  456. void insert(It first, It last) {
  457. for(; first != last; ++first) {
  458. insert(*first);
  459. }
  460. }
  461. /**
  462. * @brief Constructs an element in-place, if it does not exist.
  463. *
  464. * The element is also constructed when the container already has the key,
  465. * in which case the newly constructed object is destroyed immediately.
  466. *
  467. * @tparam Args Types of arguments to forward to the constructor of the
  468. * element.
  469. * @param args Arguments to forward to the constructor of the element.
  470. * @return A pair consisting of an iterator to the inserted element (or to
  471. * the element that prevented the insertion) and a bool denoting whether the
  472. * insertion took place.
  473. */
  474. template<typename... Args>
  475. std::pair<iterator, bool> emplace(Args &&...args) {
  476. if constexpr(((sizeof...(Args) == 1u) && ... && std::is_same_v<std::decay_t<Args>, value_type>)) {
  477. return insert_or_do_nothing(std::forward<Args>(args)...);
  478. } else {
  479. auto &node = packed.first().emplace_back(std::piecewise_construct, std::make_tuple(packed.first().size()), std::forward_as_tuple(std::forward<Args>(args)...));
  480. const auto index = value_to_bucket(node.second);
  481. if(auto it = constrained_find(node.second, index); it != end()) {
  482. packed.first().pop_back();
  483. return std::make_pair(it, false);
  484. }
  485. std::swap(node.first, sparse.first()[index]);
  486. rehash_if_required();
  487. return std::make_pair(--end(), true);
  488. }
  489. }
  490. /**
  491. * @brief Removes an element from a given position.
  492. * @param pos An iterator to the element to remove.
  493. * @return An iterator following the removed element.
  494. */
  495. iterator erase(const_iterator pos) {
  496. const auto diff = pos - cbegin();
  497. erase(*pos);
  498. return begin() + diff;
  499. }
  500. /**
  501. * @brief Removes the given elements from a container.
  502. * @param first An iterator to the first element of the range of elements.
  503. * @param last An iterator past the last element of the range of elements.
  504. * @return An iterator following the last removed element.
  505. */
  506. iterator erase(const_iterator first, const_iterator last) {
  507. const auto dist = first - cbegin();
  508. for(auto from = last - cbegin(); from != dist; --from) {
  509. erase(packed.first()[from - 1u].second);
  510. }
  511. return (begin() + dist);
  512. }
  513. /**
  514. * @brief Removes the element associated with a given value.
  515. * @param value Value of an element to remove.
  516. * @return Number of elements removed (either 0 or 1).
  517. */
  518. size_type erase(const value_type &value) {
  519. for(size_type *curr = sparse.first().data() + value_to_bucket(value); *curr != (std::numeric_limits<size_type>::max)(); curr = &packed.first()[*curr].first) {
  520. if(packed.second()(packed.first()[*curr].second, value)) {
  521. const auto index = *curr;
  522. *curr = packed.first()[*curr].first;
  523. move_and_pop(index);
  524. return 1u;
  525. }
  526. }
  527. return 0u;
  528. }
  529. /**
  530. * @brief Exchanges the contents with those of a given container.
  531. * @param other Container to exchange the content with.
  532. */
  533. void swap(dense_set &other) {
  534. using std::swap;
  535. swap(sparse, other.sparse);
  536. swap(packed, other.packed);
  537. swap(threshold, other.threshold);
  538. }
  539. /**
  540. * @brief Returns the number of elements matching a value (either 1 or 0).
  541. * @param key Key value of an element to search for.
  542. * @return Number of elements matching the key (either 1 or 0).
  543. */
  544. [[nodiscard]] size_type count(const value_type &key) const {
  545. return find(key) != end();
  546. }
  547. /**
  548. * @brief Returns the number of elements matching a key (either 1 or 0).
  549. * @tparam Other Type of the key value of an element to search for.
  550. * @param key Key value of an element to search for.
  551. * @return Number of elements matching the key (either 1 or 0).
  552. */
  553. template<typename Other>
  554. [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, size_type>>
  555. count(const Other &key) const {
  556. return find(key) != end();
  557. }
  558. /**
  559. * @brief Finds an element with a given value.
  560. * @param value Value of an element to search for.
  561. * @return An iterator to an element with the given value. If no such
  562. * element is found, a past-the-end iterator is returned.
  563. */
  564. [[nodiscard]] iterator find(const value_type &value) {
  565. return constrained_find(value, value_to_bucket(value));
  566. }
  567. /*! @copydoc find */
  568. [[nodiscard]] const_iterator find(const value_type &value) const {
  569. return constrained_find(value, value_to_bucket(value));
  570. }
  571. /**
  572. * @brief Finds an element that compares _equivalent_ to a given value.
  573. * @tparam Other Type of an element to search for.
  574. * @param value Value of an element to search for.
  575. * @return An iterator to an element with the given value. If no such
  576. * element is found, a past-the-end iterator is returned.
  577. */
  578. template<typename Other>
  579. [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, iterator>>
  580. find(const Other &value) {
  581. return constrained_find(value, value_to_bucket(value));
  582. }
  583. /*! @copydoc find */
  584. template<typename Other>
  585. [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, const_iterator>>
  586. find(const Other &value) const {
  587. return constrained_find(value, value_to_bucket(value));
  588. }
  589. /**
  590. * @brief Returns a range containing all elements with a given value.
  591. * @param value Value of an element to search for.
  592. * @return A pair of iterators pointing to the first element and past the
  593. * last element of the range.
  594. */
  595. [[nodiscard]] std::pair<iterator, iterator> equal_range(const value_type &value) {
  596. const auto it = find(value);
  597. return {it, it + !(it == end())};
  598. }
  599. /*! @copydoc equal_range */
  600. [[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(const value_type &value) const {
  601. const auto it = find(value);
  602. return {it, it + !(it == cend())};
  603. }
  604. /**
  605. * @brief Returns a range containing all elements that compare _equivalent_
  606. * to a given value.
  607. * @tparam Other Type of an element to search for.
  608. * @param value Value of an element to search for.
  609. * @return A pair of iterators pointing to the first element and past the
  610. * last element of the range.
  611. */
  612. template<typename Other>
  613. [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<iterator, iterator>>>
  614. equal_range(const Other &value) {
  615. const auto it = find(value);
  616. return {it, it + !(it == end())};
  617. }
  618. /*! @copydoc equal_range */
  619. template<typename Other>
  620. [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<const_iterator, const_iterator>>>
  621. equal_range(const Other &value) const {
  622. const auto it = find(value);
  623. return {it, it + !(it == cend())};
  624. }
  625. /**
  626. * @brief Checks if the container contains an element with a given value.
  627. * @param value Value of an element to search for.
  628. * @return True if there is such an element, false otherwise.
  629. */
  630. [[nodiscard]] bool contains(const value_type &value) const {
  631. return (find(value) != cend());
  632. }
  633. /**
  634. * @brief Checks if the container contains an element that compares
  635. * _equivalent_ to a given value.
  636. * @tparam Other Type of an element to search for.
  637. * @param value Value of an element to search for.
  638. * @return True if there is such an element, false otherwise.
  639. */
  640. template<typename Other>
  641. [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, bool>>
  642. contains(const Other &value) const {
  643. return (find(value) != cend());
  644. }
  645. /**
  646. * @brief Returns an iterator to the beginning of a given bucket.
  647. * @param index An index of a bucket to access.
  648. * @return An iterator to the beginning of the given bucket.
  649. */
  650. [[nodiscard]] const_local_iterator cbegin(const size_type index) const {
  651. return {packed.first().begin(), sparse.first()[index]};
  652. }
  653. /**
  654. * @brief Returns an iterator to the beginning of a given bucket.
  655. * @param index An index of a bucket to access.
  656. * @return An iterator to the beginning of the given bucket.
  657. */
  658. [[nodiscard]] const_local_iterator begin(const size_type index) const {
  659. return cbegin(index);
  660. }
  661. /**
  662. * @brief Returns an iterator to the beginning of a given bucket.
  663. * @param index An index of a bucket to access.
  664. * @return An iterator to the beginning of the given bucket.
  665. */
  666. [[nodiscard]] local_iterator begin(const size_type index) {
  667. return {packed.first().begin(), sparse.first()[index]};
  668. }
  669. /**
  670. * @brief Returns an iterator to the end of a given bucket.
  671. * @param index An index of a bucket to access.
  672. * @return An iterator to the end of the given bucket.
  673. */
  674. [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const {
  675. return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
  676. }
  677. /**
  678. * @brief Returns an iterator to the end of a given bucket.
  679. * @param index An index of a bucket to access.
  680. * @return An iterator to the end of the given bucket.
  681. */
  682. [[nodiscard]] const_local_iterator end(const size_type index) const {
  683. return cend(index);
  684. }
  685. /**
  686. * @brief Returns an iterator to the end of a given bucket.
  687. * @param index An index of a bucket to access.
  688. * @return An iterator to the end of the given bucket.
  689. */
  690. [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) {
  691. return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
  692. }
  693. /**
  694. * @brief Returns the number of buckets.
  695. * @return The number of buckets.
  696. */
  697. [[nodiscard]] size_type bucket_count() const {
  698. return sparse.first().size();
  699. }
  700. /**
  701. * @brief Returns the maximum number of buckets.
  702. * @return The maximum number of buckets.
  703. */
  704. [[nodiscard]] size_type max_bucket_count() const {
  705. return sparse.first().max_size();
  706. }
  707. /**
  708. * @brief Returns the number of elements in a given bucket.
  709. * @param index The index of the bucket to examine.
  710. * @return The number of elements in the given bucket.
  711. */
  712. [[nodiscard]] size_type bucket_size(const size_type index) const {
  713. return static_cast<size_type>(std::distance(begin(index), end(index)));
  714. }
  715. /**
  716. * @brief Returns the bucket for a given element.
  717. * @param value The value of the element to examine.
  718. * @return The bucket for the given element.
  719. */
  720. [[nodiscard]] size_type bucket(const value_type &value) const {
  721. return value_to_bucket(value);
  722. }
  723. /**
  724. * @brief Returns the average number of elements per bucket.
  725. * @return The average number of elements per bucket.
  726. */
  727. [[nodiscard]] float load_factor() const {
  728. return size() / static_cast<float>(bucket_count());
  729. }
  730. /**
  731. * @brief Returns the maximum average number of elements per bucket.
  732. * @return The maximum average number of elements per bucket.
  733. */
  734. [[nodiscard]] float max_load_factor() const {
  735. return threshold;
  736. }
  737. /**
  738. * @brief Sets the desired maximum average number of elements per bucket.
  739. * @param value A desired maximum average number of elements per bucket.
  740. */
  741. void max_load_factor(const float value) {
  742. ENTT_ASSERT(value > 0.f, "Invalid load factor");
  743. threshold = value;
  744. rehash(0u);
  745. }
  746. /**
  747. * @brief Reserves at least the specified number of buckets and regenerates
  748. * the hash table.
  749. * @param cnt New number of buckets.
  750. */
  751. void rehash(const size_type cnt) {
  752. auto value = cnt > minimum_capacity ? cnt : minimum_capacity;
  753. const auto cap = static_cast<size_type>(size() / max_load_factor());
  754. value = value > cap ? value : cap;
  755. if(const auto sz = next_power_of_two(value); sz != bucket_count()) {
  756. sparse.first().resize(sz);
  757. for(auto &&elem: sparse.first()) {
  758. elem = (std::numeric_limits<size_type>::max)();
  759. }
  760. for(size_type pos{}, last = size(); pos < last; ++pos) {
  761. const auto index = value_to_bucket(packed.first()[pos].second);
  762. packed.first()[pos].first = std::exchange(sparse.first()[index], pos);
  763. }
  764. }
  765. }
  766. /**
  767. * @brief Reserves space for at least the specified number of elements and
  768. * regenerates the hash table.
  769. * @param cnt New number of elements.
  770. */
  771. void reserve(const size_type cnt) {
  772. packed.first().reserve(cnt);
  773. rehash(static_cast<size_type>(std::ceil(cnt / max_load_factor())));
  774. }
  775. /**
  776. * @brief Returns the function used to hash the elements.
  777. * @return The function used to hash the elements.
  778. */
  779. [[nodiscard]] hasher hash_function() const {
  780. return sparse.second();
  781. }
  782. /**
  783. * @brief Returns the function used to compare elements for equality.
  784. * @return The function used to compare elements for equality.
  785. */
  786. [[nodiscard]] key_equal key_eq() const {
  787. return packed.second();
  788. }
  789. private:
  790. compressed_pair<sparse_container_type, hasher> sparse;
  791. compressed_pair<packed_container_type, key_equal> packed;
  792. float threshold;
  793. };
  794. } // namespace entt
  795. #endif