dense_map.hpp 38 KB

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