🛠️🐜 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.

988 lines
35 KiB

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