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

823 lines
28 KiB

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