EnTT 3.14.0
Loading...
Searching...
No Matches
dense_map.hpp
1#ifndef ENTT_CONTAINER_DENSE_MAP_HPP
2#define ENTT_CONTAINER_DENSE_MAP_HPP
3
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/bit.hpp"
16#include "../core/compressed_pair.hpp"
17#include "../core/iterator.hpp"
18#include "../core/memory.hpp"
19#include "../core/type_traits.hpp"
20#include "fwd.hpp"
21
22namespace entt {
23
25namespace internal {
26
27template<typename Key, typename Type>
28struct dense_map_node final {
29 using value_type = std::pair<Key, Type>;
30
31 template<typename... Args>
32 dense_map_node(const std::size_t pos, Args &&...args)
33 : next{pos},
34 element{std::forward<Args>(args)...} {}
35
36 template<typename Allocator, typename... Args>
37 dense_map_node(std::allocator_arg_t, const Allocator &allocator, const std::size_t pos, Args &&...args)
38 : next{pos},
39 element{entt::make_obj_using_allocator<value_type>(allocator, std::forward<Args>(args)...)} {}
40
41 template<typename Allocator>
42 dense_map_node(std::allocator_arg_t, const Allocator &allocator, const dense_map_node &other)
43 : next{other.next},
44 element{entt::make_obj_using_allocator<value_type>(allocator, other.element)} {}
45
46 template<typename Allocator>
47 dense_map_node(std::allocator_arg_t, const Allocator &allocator, dense_map_node &&other)
48 : next{other.next},
49 element{entt::make_obj_using_allocator<value_type>(allocator, std::move(other.element))} {}
50
51 std::size_t next;
52 value_type element;
53};
54
55template<typename It>
56class dense_map_iterator final {
57 template<typename>
58 friend class dense_map_iterator;
59
60 using first_type = decltype(std::as_const(std::declval<It>()->element.first));
61 using second_type = decltype((std::declval<It>()->element.second));
62
63public:
64 using value_type = std::pair<first_type, second_type>;
66 using reference = value_type;
67 using difference_type = std::ptrdiff_t;
68 using iterator_category = std::input_iterator_tag;
69 using iterator_concept = std::random_access_iterator_tag;
70
71 constexpr dense_map_iterator() noexcept
72 : it{} {}
73
74 constexpr dense_map_iterator(const It iter) noexcept
75 : it{iter} {}
76
77 template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
78 constexpr dense_map_iterator(const dense_map_iterator<Other> &other) noexcept
79 : it{other.it} {}
80
81 constexpr dense_map_iterator &operator++() noexcept {
82 return ++it, *this;
83 }
84
85 constexpr dense_map_iterator operator++(int) noexcept {
86 dense_map_iterator orig = *this;
87 return ++(*this), orig;
88 }
89
90 constexpr dense_map_iterator &operator--() noexcept {
91 return --it, *this;
92 }
93
94 constexpr dense_map_iterator operator--(int) noexcept {
95 dense_map_iterator orig = *this;
96 return operator--(), orig;
97 }
98
99 constexpr dense_map_iterator &operator+=(const difference_type value) noexcept {
100 it += value;
101 return *this;
102 }
103
104 constexpr dense_map_iterator operator+(const difference_type value) const noexcept {
105 dense_map_iterator copy = *this;
106 return (copy += value);
107 }
108
109 constexpr dense_map_iterator &operator-=(const difference_type value) noexcept {
110 return (*this += -value);
111 }
112
113 constexpr dense_map_iterator operator-(const difference_type value) const noexcept {
114 return (*this + -value);
115 }
116
117 [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
118 return {it[value].element.first, it[value].element.second};
119 }
120
121 [[nodiscard]] constexpr pointer operator->() const noexcept {
122 return operator*();
123 }
124
125 [[nodiscard]] constexpr reference operator*() const noexcept {
126 return operator[](0);
127 }
128
129 template<typename Lhs, typename Rhs>
130 friend constexpr std::ptrdiff_t operator-(const dense_map_iterator<Lhs> &, const dense_map_iterator<Rhs> &) noexcept;
131
132 template<typename Lhs, typename Rhs>
133 friend constexpr bool operator==(const dense_map_iterator<Lhs> &, const dense_map_iterator<Rhs> &) noexcept;
134
135 template<typename Lhs, typename Rhs>
136 friend constexpr bool operator<(const dense_map_iterator<Lhs> &, const dense_map_iterator<Rhs> &) noexcept;
137
138private:
139 It it;
140};
141
142template<typename Lhs, typename Rhs>
143[[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
144 return lhs.it - rhs.it;
145}
146
147template<typename Lhs, typename Rhs>
148[[nodiscard]] constexpr bool operator==(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
149 return lhs.it == rhs.it;
150}
151
152template<typename Lhs, typename Rhs>
153[[nodiscard]] constexpr bool operator!=(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
154 return !(lhs == rhs);
155}
156
157template<typename Lhs, typename Rhs>
158[[nodiscard]] constexpr bool operator<(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
159 return lhs.it < rhs.it;
160}
161
162template<typename Lhs, typename Rhs>
163[[nodiscard]] constexpr bool operator>(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
164 return rhs < lhs;
165}
166
167template<typename Lhs, typename Rhs>
168[[nodiscard]] constexpr bool operator<=(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
169 return !(lhs > rhs);
170}
171
172template<typename Lhs, typename Rhs>
173[[nodiscard]] constexpr bool operator>=(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
174 return !(lhs < rhs);
175}
176
177template<typename It>
178class dense_map_local_iterator final {
179 template<typename>
180 friend class dense_map_local_iterator;
181
182 using first_type = decltype(std::as_const(std::declval<It>()->element.first));
183 using second_type = decltype((std::declval<It>()->element.second));
184
185public:
186 using value_type = std::pair<first_type, second_type>;
188 using reference = value_type;
189 using difference_type = std::ptrdiff_t;
190 using iterator_category = std::input_iterator_tag;
191 using iterator_concept = std::forward_iterator_tag;
192
193 constexpr dense_map_local_iterator() noexcept
194 : it{},
195 offset{} {}
196
197 constexpr dense_map_local_iterator(It iter, const std::size_t pos) noexcept
198 : it{iter},
199 offset{pos} {}
200
201 template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
202 constexpr dense_map_local_iterator(const dense_map_local_iterator<Other> &other) noexcept
203 : it{other.it},
204 offset{other.offset} {}
205
206 constexpr dense_map_local_iterator &operator++() noexcept {
207 return offset = it[offset].next, *this;
208 }
209
210 constexpr dense_map_local_iterator operator++(int) noexcept {
211 dense_map_local_iterator orig = *this;
212 return ++(*this), orig;
213 }
214
215 [[nodiscard]] constexpr pointer operator->() const noexcept {
216 return operator*();
217 }
218
219 [[nodiscard]] constexpr reference operator*() const noexcept {
220 return {it[offset].element.first, it[offset].element.second};
221 }
222
223 [[nodiscard]] constexpr std::size_t index() const noexcept {
224 return offset;
225 }
226
227private:
228 It it;
229 std::size_t offset;
230};
231
232template<typename Lhs, typename Rhs>
233[[nodiscard]] constexpr bool operator==(const dense_map_local_iterator<Lhs> &lhs, const dense_map_local_iterator<Rhs> &rhs) noexcept {
234 return lhs.index() == rhs.index();
235}
236
237template<typename Lhs, typename Rhs>
238[[nodiscard]] constexpr bool operator!=(const dense_map_local_iterator<Lhs> &lhs, const dense_map_local_iterator<Rhs> &rhs) noexcept {
239 return !(lhs == rhs);
240}
241
242} // namespace internal
258template<typename Key, typename Type, typename Hash, typename KeyEqual, typename Allocator>
259class dense_map {
260 static constexpr float default_threshold = 0.875f;
261 static constexpr std::size_t minimum_capacity = 8u;
262
263 using node_type = internal::dense_map_node<Key, Type>;
264 using alloc_traits = std::allocator_traits<Allocator>;
265 static_assert(std::is_same_v<typename alloc_traits::value_type, std::pair<const Key, Type>>, "Invalid value type");
266 using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
267 using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
268
269 template<typename Other>
270 [[nodiscard]] std::size_t key_to_bucket(const Other &key) const noexcept {
271 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
272 return fast_mod(static_cast<size_type>(sparse.second()(key)), bucket_count());
273 }
274
275 template<typename Other>
276 [[nodiscard]] auto constrained_find(const Other &key, std::size_t bucket) {
277 for(auto it = begin(bucket), last = end(bucket); it != last; ++it) {
278 if(packed.second()(it->first, key)) {
279 return begin() + static_cast<typename iterator::difference_type>(it.index());
280 }
281 }
282
283 return end();
284 }
285
286 template<typename Other>
287 [[nodiscard]] auto constrained_find(const Other &key, std::size_t bucket) const {
288 for(auto it = cbegin(bucket), last = cend(bucket); it != last; ++it) {
289 if(packed.second()(it->first, key)) {
290 return cbegin() + static_cast<typename iterator::difference_type>(it.index());
291 }
292 }
293
294 return cend();
295 }
296
297 template<typename Other, typename... Args>
298 [[nodiscard]] auto insert_or_do_nothing(Other &&key, Args &&...args) {
299 const auto index = key_to_bucket(key);
300
301 if(auto it = constrained_find(key, index); it != end()) {
302 return std::make_pair(it, false);
303 }
304
305 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)...));
306 sparse.first()[index] = packed.first().size() - 1u;
307 rehash_if_required();
308
309 return std::make_pair(--end(), true);
310 }
311
312 template<typename Other, typename Arg>
313 [[nodiscard]] auto insert_or_overwrite(Other &&key, Arg &&value) {
314 const auto index = key_to_bucket(key);
315
316 if(auto it = constrained_find(key, index); it != end()) {
317 it->second = std::forward<Arg>(value);
318 return std::make_pair(it, false);
319 }
320
321 packed.first().emplace_back(sparse.first()[index], std::forward<Other>(key), std::forward<Arg>(value));
322 sparse.first()[index] = packed.first().size() - 1u;
323 rehash_if_required();
324
325 return std::make_pair(--end(), true);
326 }
327
328 void move_and_pop(const std::size_t pos) {
329 if(const auto last = size() - 1u; pos != last) {
330 size_type *curr = &sparse.first()[key_to_bucket(packed.first().back().element.first)];
331 packed.first()[pos] = std::move(packed.first().back());
332 for(; *curr != last; curr = &packed.first()[*curr].next) {}
333 *curr = pos;
334 }
335
336 packed.first().pop_back();
337 }
338
339 void rehash_if_required() {
340 if(size() > (bucket_count() * max_load_factor())) {
341 rehash(bucket_count() * 2u);
342 }
343 }
344
345public:
347 using allocator_type = Allocator;
349 using key_type = Key;
351 using mapped_type = Type;
353 using value_type = std::pair<const Key, Type>;
355 using size_type = std::size_t;
357 using hasher = Hash;
359 using key_equal = KeyEqual;
361 using iterator = internal::dense_map_iterator<typename packed_container_type::iterator>;
363 using const_iterator = internal::dense_map_iterator<typename packed_container_type::const_iterator>;
365 using local_iterator = internal::dense_map_local_iterator<typename packed_container_type::iterator>;
367 using const_local_iterator = internal::dense_map_local_iterator<typename packed_container_type::const_iterator>;
368
371 : dense_map{minimum_capacity} {}
372
377 explicit dense_map(const allocator_type &allocator)
378 : dense_map{minimum_capacity, hasher{}, key_equal{}, allocator} {}
379
386 dense_map(const size_type cnt, const allocator_type &allocator)
387 : dense_map{cnt, hasher{}, key_equal{}, allocator} {}
388
396 dense_map(const size_type cnt, const hasher &hash, const allocator_type &allocator)
397 : dense_map{cnt, hash, key_equal{}, allocator} {}
398
407 explicit dense_map(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{})
408 : sparse{allocator, hash},
409 packed{allocator, equal} {
410 rehash(cnt);
411 }
412
414 dense_map(const dense_map &) = default;
415
421 dense_map(const dense_map &other, const allocator_type &allocator)
422 : sparse{std::piecewise_construct, std::forward_as_tuple(other.sparse.first(), allocator), std::forward_as_tuple(other.sparse.second())},
423 packed{std::piecewise_construct, std::forward_as_tuple(other.packed.first(), allocator), std::forward_as_tuple(other.packed.second())},
424 threshold{other.threshold} {}
425
427 dense_map(dense_map &&) noexcept = default;
428
434 dense_map(dense_map &&other, const allocator_type &allocator)
435 : sparse{std::piecewise_construct, std::forward_as_tuple(std::move(other.sparse.first()), allocator), std::forward_as_tuple(std::move(other.sparse.second()))},
436 packed{std::piecewise_construct, std::forward_as_tuple(std::move(other.packed.first()), allocator), std::forward_as_tuple(std::move(other.packed.second()))},
437 threshold{other.threshold} {}
438
440 ~dense_map() = default;
441
446 dense_map &operator=(const dense_map &) = default;
447
452 dense_map &operator=(dense_map &&) noexcept = default;
453
458 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
459 return sparse.first().get_allocator();
460 }
461
469 [[nodiscard]] const_iterator cbegin() const noexcept {
470 return packed.first().begin();
471 }
472
474 [[nodiscard]] const_iterator begin() const noexcept {
475 return cbegin();
476 }
477
479 [[nodiscard]] iterator begin() noexcept {
480 return packed.first().begin();
481 }
482
488 [[nodiscard]] const_iterator cend() const noexcept {
489 return packed.first().end();
490 }
491
493 [[nodiscard]] const_iterator end() const noexcept {
494 return cend();
495 }
496
498 [[nodiscard]] iterator end() noexcept {
499 return packed.first().end();
500 }
501
506 [[nodiscard]] bool empty() const noexcept {
507 return packed.first().empty();
508 }
509
514 [[nodiscard]] size_type size() const noexcept {
515 return packed.first().size();
516 }
517
522 [[nodiscard]] size_type max_size() const noexcept {
523 return packed.first().max_size();
524 }
525
527 void clear() noexcept {
528 sparse.first().clear();
529 packed.first().clear();
530 rehash(0u);
531 }
532
540 std::pair<iterator, bool> insert(const value_type &value) {
541 return insert_or_do_nothing(value.first, value.second);
542 }
543
545 std::pair<iterator, bool> insert(value_type &&value) {
546 return insert_or_do_nothing(std::move(value.first), std::move(value.second));
547 }
548
553 template<typename Arg>
554 std::enable_if_t<std::is_constructible_v<value_type, Arg &&>, std::pair<iterator, bool>>
555 insert(Arg &&value) {
556 return insert_or_do_nothing(std::forward<Arg>(value).first, std::forward<Arg>(value).second);
557 }
558
565 template<typename It>
566 void insert(It first, It last) {
567 for(; first != last; ++first) {
568 insert(*first);
569 }
570 }
571
581 template<typename Arg>
582 std::pair<iterator, bool> insert_or_assign(const key_type &key, Arg &&value) {
583 return insert_or_overwrite(key, std::forward<Arg>(value));
584 }
585
587 template<typename Arg>
588 std::pair<iterator, bool> insert_or_assign(key_type &&key, Arg &&value) {
589 return insert_or_overwrite(std::move(key), std::forward<Arg>(value));
590 }
591
605 template<typename... Args>
606 std::pair<iterator, bool> emplace([[maybe_unused]] Args &&...args) {
607 if constexpr(sizeof...(Args) == 0u) {
608 return insert_or_do_nothing(key_type{});
609 } else if constexpr(sizeof...(Args) == 1u) {
610 return insert_or_do_nothing(std::forward<Args>(args).first..., std::forward<Args>(args).second...);
611 } else if constexpr(sizeof...(Args) == 2u) {
612 return insert_or_do_nothing(std::forward<Args>(args)...);
613 } else {
614 auto &node = packed.first().emplace_back(packed.first().size(), std::forward<Args>(args)...);
615 const auto index = key_to_bucket(node.element.first);
616
617 if(auto it = constrained_find(node.element.first, index); it != end()) {
618 packed.first().pop_back();
619 return std::make_pair(it, false);
620 }
621
622 std::swap(node.next, sparse.first()[index]);
623 rehash_if_required();
624
625 return std::make_pair(--end(), true);
626 }
627 }
628
640 template<typename... Args>
641 std::pair<iterator, bool> try_emplace(const key_type &key, Args &&...args) {
642 return insert_or_do_nothing(key, std::forward<Args>(args)...);
643 }
644
646 template<typename... Args>
647 std::pair<iterator, bool> try_emplace(key_type &&key, Args &&...args) {
648 return insert_or_do_nothing(std::move(key), std::forward<Args>(args)...);
649 }
650
657 const auto diff = pos - cbegin();
658 erase(pos->first);
659 return begin() + diff;
660 }
661
669 const auto dist = first - cbegin();
670
671 for(auto from = last - cbegin(); from != dist; --from) {
672 erase(packed.first()[from - 1u].element.first);
673 }
674
675 return (begin() + dist);
676 }
677
684 for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != (std::numeric_limits<size_type>::max)(); curr = &packed.first()[*curr].next) {
685 if(packed.second()(packed.first()[*curr].element.first, key)) {
686 const auto index = *curr;
687 *curr = packed.first()[*curr].next;
688 move_and_pop(index);
689 return 1u;
690 }
691 }
692
693 return 0u;
694 }
695
700 void swap(dense_map &other) noexcept {
701 using std::swap;
702 swap(sparse, other.sparse);
703 swap(packed, other.packed);
704 swap(threshold, other.threshold);
705 }
706
712 [[nodiscard]] mapped_type &at(const key_type &key) {
713 auto it = find(key);
714 ENTT_ASSERT(it != end(), "Invalid key");
715 return it->second;
716 }
717
719 [[nodiscard]] const mapped_type &at(const key_type &key) const {
720 auto it = find(key);
721 ENTT_ASSERT(it != cend(), "Invalid key");
722 return it->second;
723 }
724
730 [[nodiscard]] mapped_type &operator[](const key_type &key) {
731 return insert_or_do_nothing(key).first->second;
732 }
733
739 [[nodiscard]] mapped_type &operator[](key_type &&key) {
740 return insert_or_do_nothing(std::move(key)).first->second;
741 }
742
748 [[nodiscard]] size_type count(const key_type &key) const {
749 return find(key) != end();
750 }
751
758 template<typename Other>
759 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, size_type>>
760 count(const Other &key) const {
761 return find(key) != end();
762 }
763
770 [[nodiscard]] iterator find(const key_type &key) {
771 return constrained_find(key, key_to_bucket(key));
772 }
773
775 [[nodiscard]] const_iterator find(const key_type &key) const {
776 return constrained_find(key, key_to_bucket(key));
777 }
778
787 template<typename Other>
788 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, iterator>>
789 find(const Other &key) {
790 return constrained_find(key, key_to_bucket(key));
791 }
792
794 template<typename Other>
795 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, const_iterator>>
796 find(const Other &key) const {
797 return constrained_find(key, key_to_bucket(key));
798 }
799
806 [[nodiscard]] std::pair<iterator, iterator> equal_range(const key_type &key) {
807 const auto it = find(key);
808 return {it, it + !(it == end())};
809 }
810
812 [[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(const key_type &key) const {
813 const auto it = find(key);
814 return {it, it + !(it == cend())};
815 }
816
825 template<typename Other>
826 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<iterator, iterator>>>
827 equal_range(const Other &key) {
828 const auto it = find(key);
829 return {it, it + !(it == end())};
830 }
831
833 template<typename Other>
834 [[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>>>
835 equal_range(const Other &key) const {
836 const auto it = find(key);
837 return {it, it + !(it == cend())};
838 }
839
845 [[nodiscard]] bool contains(const key_type &key) const {
846 return (find(key) != cend());
847 }
848
856 template<typename Other>
857 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, bool>>
858 contains(const Other &key) const {
859 return (find(key) != cend());
860 }
861
867 [[nodiscard]] const_local_iterator cbegin(const size_type index) const {
868 return {packed.first().begin(), sparse.first()[index]};
869 }
870
876 [[nodiscard]] const_local_iterator begin(const size_type index) const {
877 return cbegin(index);
878 }
879
885 [[nodiscard]] local_iterator begin(const size_type index) {
886 return {packed.first().begin(), sparse.first()[index]};
887 }
888
894 [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const {
895 return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
896 }
897
903 [[nodiscard]] const_local_iterator end(const size_type index) const {
904 return cend(index);
905 }
906
912 [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) {
913 return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
914 }
915
920 [[nodiscard]] size_type bucket_count() const {
921 return sparse.first().size();
922 }
923
928 [[nodiscard]] size_type max_bucket_count() const {
929 return sparse.first().max_size();
930 }
931
937 [[nodiscard]] size_type bucket_size(const size_type index) const {
938 return static_cast<size_type>(std::distance(begin(index), end(index)));
939 }
940
946 [[nodiscard]] size_type bucket(const key_type &key) const {
947 return key_to_bucket(key);
948 }
949
954 [[nodiscard]] float load_factor() const {
955 return size() / static_cast<float>(bucket_count());
956 }
957
962 [[nodiscard]] float max_load_factor() const {
963 return threshold;
964 }
965
970 void max_load_factor(const float value) {
971 ENTT_ASSERT(value > 0.f, "Invalid load factor");
972 threshold = value;
973 rehash(0u);
974 }
975
981 void rehash(const size_type cnt) {
982 auto value = cnt > minimum_capacity ? cnt : minimum_capacity;
983 const auto cap = static_cast<size_type>(size() / max_load_factor());
984 value = value > cap ? value : cap;
985
986 if(const auto sz = next_power_of_two(value); sz != bucket_count()) {
987 sparse.first().resize(sz);
988
989 for(auto &&elem: sparse.first()) {
990 elem = (std::numeric_limits<size_type>::max)();
991 }
992
993 for(size_type pos{}, last = size(); pos < last; ++pos) {
994 const auto index = key_to_bucket(packed.first()[pos].element.first);
995 packed.first()[pos].next = std::exchange(sparse.first()[index], pos);
996 }
997 }
998 }
999
1005 void reserve(const size_type cnt) {
1006 packed.first().reserve(cnt);
1007 rehash(static_cast<size_type>(std::ceil(cnt / max_load_factor())));
1008 }
1009
1014 [[nodiscard]] hasher hash_function() const {
1015 return sparse.second();
1016 }
1017
1022 [[nodiscard]] key_equal key_eq() const {
1023 return packed.second();
1024 }
1025
1026private:
1029 float threshold{default_threshold};
1030};
1031
1032} // namespace entt
1033
1035namespace std {
1036
1037template<typename Key, typename Value, typename Allocator>
1038struct uses_allocator<entt::internal::dense_map_node<Key, Value>, Allocator>
1039 : std::true_type {};
1040
1041} // namespace std
1044#endif
A compressed pair.
Definition fwd.hpp:20
constexpr second_type & second() noexcept
Returns the second element that a pair stores.
constexpr first_type & first() noexcept
Returns the first element that a pair stores.
Associative container for key-value pairs with unique keys.
Definition fwd.hpp:17
local_iterator begin(const size_type index)
Returns an iterator to the beginning of a given bucket.
dense_map & operator=(dense_map &&) noexcept=default
Default move assignment operator.
internal::dense_map_local_iterator< typename packed_container_type::iterator > local_iterator
Input iterator type.
bool contains(const key_type &key) const
Checks if the container contains an element with a given key.
Type mapped_type
Mapped type of the container.
const_iterator begin() const noexcept
Returns an iterator to the beginning.
const_iterator find(const key_type &key) const
Finds an element with a given key.
std::enable_if_t< std::is_constructible_v< value_type, Arg && >, std::pair< iterator, bool > > insert(Arg &&value)
Inserts an element into the container, if the key does not exist.
std::pair< iterator, bool > try_emplace(key_type &&key, Args &&...args)
Inserts in-place if the key does not exist, does nothing if the key exists.
Key key_type
Key type of the container.
dense_map(dense_map &&) noexcept=default
Default move constructor.
std::pair< iterator, bool > insert_or_assign(key_type &&key, Arg &&value)
Inserts an element into the container or assigns to the current element if the key already exists.
dense_map(const allocator_type &allocator)
Constructs an empty container with a given allocator.
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
std::enable_if_t< is_transparent_v< hasher > &&is_transparent_v< key_equal >, std::conditional_t< false, Other, std::pair< const_iterator, const_iterator > > > equal_range(const Other &key) const
Returns a range containing all elements with a given key.
iterator find(const key_type &key)
Finds an element with a given key.
dense_map()
Default constructor.
std::enable_if_t< is_transparent_v< hasher > &&is_transparent_v< key_equal >, std::conditional_t< false, Other, bool > > contains(const Other &key) const
Checks if the container contains an element with a key that compares equivalent to a given value.
float max_load_factor() const
Returns the maximum average number of elements per bucket.
std::enable_if_t< is_transparent_v< hasher > &&is_transparent_v< key_equal >, std::conditional_t< false, Other, iterator > > find(const Other &key)
Finds an element with a key that compares equivalent to a given key.
dense_map & operator=(const dense_map &)=default
Default copy assignment operator.
size_type count(const key_type &key) const
Returns the number of elements matching a key (either 1 or 0).
size_type max_size() const noexcept
Returns the maximum possible number of elements.
const_local_iterator end(const size_type index) const
Returns an iterator to the end of a given bucket.
size_type max_bucket_count() const
Returns the maximum number of buckets.
std::enable_if_t< is_transparent_v< hasher > &&is_transparent_v< key_equal >, std::conditional_t< false, Other, const_iterator > > find(const Other &key) const
Finds an element with a given key.
const_local_iterator cbegin(const size_type index) const
Returns an iterator to the beginning of a given bucket.
size_type bucket_count() const
Returns the number of buckets.
std::size_t size_type
Unsigned integer type.
KeyEqual key_equal
Type of function to use to compare the keys for equality.
dense_map(const size_type cnt, const hasher &hash, const allocator_type &allocator)
Constructs an empty container with a given allocator, hash function and user supplied minimal number ...
iterator erase(const_iterator pos)
Removes an element from a given position.
void max_load_factor(const float value)
Sets the desired maximum average number of elements per bucket.
const mapped_type & at(const key_type &key) const
Accesses a given element with bounds checking.
void reserve(const size_type cnt)
Reserves space for at least the specified number of elements and regenerates the hash table.
const_local_iterator begin(const size_type index) const
Returns an iterator to the beginning of a given bucket.
size_type erase(const key_type &key)
Removes the element associated with a given key.
void swap(dense_map &other) noexcept
Exchanges the contents with those of a given container.
internal::dense_map_iterator< typename packed_container_type::const_iterator > const_iterator
Constant input iterator type.
float load_factor() const
Returns the average number of elements per bucket.
const_iterator end() const noexcept
Returns an iterator to the end.
std::pair< iterator, bool > insert_or_assign(const key_type &key, Arg &&value)
Inserts an element into the container or assigns to the current element if the key already exists.
std::pair< iterator, iterator > equal_range(const key_type &key)
Returns a range containing all elements with a given key.
const_local_iterator cend(const size_type index) const
Returns an iterator to the end of a given bucket.
mapped_type & operator[](const key_type &key)
Accesses or inserts a given element.
const_iterator cend() const noexcept
Returns an iterator to the end.
std::pair< iterator, bool > try_emplace(const key_type &key, Args &&...args)
Inserts in-place if the key does not exist, does nothing if the key exists.
bool empty() const noexcept
Checks whether a container is empty.
std::pair< iterator, bool > emplace(Args &&...args)
Constructs an element in-place, if the key does not exist.
hasher hash_function() const
Returns the function used to hash the keys.
local_iterator end(const size_type index)
Returns an iterator to the end of a given bucket.
std::pair< const Key, Type > value_type
Key-value type of the container.
Hash hasher
Type of function to use to hash the keys.
dense_map(const size_type cnt, const allocator_type &allocator)
Constructs an empty container with a given allocator and user supplied minimal number of buckets.
key_equal key_eq() const
Returns the function used to compare keys for equality.
std::pair< iterator, bool > insert(value_type &&value)
Inserts an element into the container, if the key does not exist.
void insert(It first, It last)
Inserts elements into the container, if their keys do not exist.
size_type bucket(const key_type &key) const
Returns the bucket for a given key.
std::pair< const_iterator, const_iterator > equal_range(const key_type &key) const
Returns a range containing all elements with a given key.
size_type size() const noexcept
Returns the number of elements in a container.
Allocator allocator_type
Allocator type.
dense_map(const dense_map &other, const allocator_type &allocator)
Allocator-extended copy constructor.
std::pair< iterator, bool > insert(const value_type &value)
Inserts an element into the container, if the key does not exist.
internal::dense_map_local_iterator< typename packed_container_type::const_iterator > const_local_iterator
Constant input iterator type.
~dense_map()=default
Default destructor.
void rehash(const size_type cnt)
Reserves at least the specified number of buckets and regenerates the hash table.
const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
std::enable_if_t< is_transparent_v< hasher > &&is_transparent_v< key_equal >, std::conditional_t< false, Other, size_type > > count(const Other &key) const
Returns the number of elements matching a key (either 1 or 0).
dense_map(const dense_map &)=default
Default copy constructor.
size_type bucket_size(const size_type index) const
Returns the number of elements in a given bucket.
dense_map(const size_type cnt, const hasher &hash=hasher{}, const key_equal &equal=key_equal{}, const allocator_type &allocator=allocator_type{})
Constructs an empty container with a given allocator, hash function, compare function and user suppli...
iterator erase(const_iterator first, const_iterator last)
Removes the given elements from a container.
void clear() noexcept
Clears the container.
mapped_type & at(const key_type &key)
Accesses a given element with bounds checking.
mapped_type & operator[](key_type &&key)
Accesses or inserts a given element.
internal::dense_map_iterator< typename packed_container_type::iterator > iterator
Input iterator type.
iterator begin() noexcept
Returns an iterator to the beginning.
std::enable_if_t< is_transparent_v< hasher > &&is_transparent_v< key_equal >, std::conditional_t< false, Other, std::pair< iterator, iterator > > > equal_range(const Other &key)
Returns a range containing all elements that compare equivalent to a given key.
iterator end() noexcept
Returns an iterator to the end.
EnTT default namespace.
Definition dense_map.hpp:22
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
Definition memory.hpp:219
constexpr std::enable_if_t< std::is_unsigned_v< Type >, Type > fast_mod(const Type value, const std::size_t mod) noexcept
Fast module utility function (powers of two only).
Definition bit.hpp:62
constexpr bool is_transparent_v
Helper variable template.
constexpr bool operator<=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
constexpr std::enable_if_t< std::is_unsigned_v< Type >, Type > next_power_of_two(const Type value) noexcept
Computes the smallest power of two greater than or equal to a value (waiting for C++20 and std::bit_c...
Definition bit.hpp:43
constexpr bool operator<(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
constexpr type_list< Type..., Other... > operator+(type_list< Type... >, type_list< Other... >)
Concatenates multiple type lists.
constexpr bool operator!=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
constexpr bool operator>=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
constexpr bool operator>(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
constexpr bool operator==(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
Helper type to use as pointer with input iterators.
Definition iterator.hpp:16