EnTT 4.0.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 <compare>
5#include "../config/config.h"
6#include "../core/bit.hpp"
7#include "../core/compressed_pair.hpp"
8#include "../core/iterator.hpp"
9#include "../core/memory.hpp"
10#include "../core/type_traits.hpp"
11#include "../stl/bit.hpp"
12#include "../stl/cmath.hpp"
13#include "../stl/concepts.hpp"
14#include "../stl/cstddef.hpp"
15#include "../stl/functional.hpp"
16#include "../stl/iterator.hpp"
17#include "../stl/limits.hpp"
18#include "../stl/memory.hpp"
19#include "../stl/tuple.hpp"
20#include "../stl/type_traits.hpp"
21#include "../stl/utility.hpp"
22#include "../stl/vector.hpp"
23#include "fwd.hpp"
24
25namespace entt {
26
28namespace internal {
29
30static constexpr stl::size_t dense_map_placeholder_position = (stl::numeric_limits<stl::size_t>::max)();
31
32template<typename Key, typename Type>
33struct dense_map_node final {
34 using value_type = stl::pair<Key, Type>;
35
36 template<typename... Args>
37 dense_map_node(const stl::size_t pos, Args &&...args)
38 : next{pos},
39 element{stl::forward<Args>(args)...} {}
40
41 template<typename... Args>
42 dense_map_node(stl::allocator_arg_t, const auto &allocator, const stl::size_t pos, Args &&...args)
43 : next{pos},
44 element{entt::make_obj_using_allocator<value_type>(allocator, stl::forward<Args>(args)...)} {}
45
46 dense_map_node(stl::allocator_arg_t, const auto &allocator, const dense_map_node &other)
47 : next{other.next},
48 element{entt::make_obj_using_allocator<value_type>(allocator, other.element)} {}
49
50 dense_map_node(stl::allocator_arg_t, const auto &allocator, dense_map_node &&other)
51 : next{other.next},
52 element{entt::make_obj_using_allocator<value_type>(allocator, stl::move(other.element))} {}
53
54 stl::size_t next;
55 value_type element;
56};
57
58template<typename It>
59class dense_map_iterator final {
60 template<typename>
61 friend class dense_map_iterator;
62
63 static_assert(stl::is_pointer_v<It>, "Not a pointer type");
64 using first_type = decltype(stl::as_const(stl::declval<It>()->element.first));
65 using second_type = decltype((stl::declval<It>()->element.second));
66
67public:
68 using value_type = stl::pair<first_type, second_type>;
70 using reference = value_type;
71 using difference_type = stl::ptrdiff_t;
72 using iterator_category = stl::input_iterator_tag;
73 using iterator_concept = stl::random_access_iterator_tag;
74
75 constexpr dense_map_iterator() noexcept
76 : it{} {}
77
78 constexpr dense_map_iterator(const It iter) noexcept
79 : it{iter} {}
80
81 template<typename Other>
82 requires (!stl::same_as<It, Other> && stl::constructible_from<It, Other>)
83 constexpr dense_map_iterator(const dense_map_iterator<Other> &other) noexcept
84 : it{other.it} {}
85
86 constexpr dense_map_iterator &operator++() noexcept {
87 return ++it, *this;
88 }
89
90 constexpr dense_map_iterator operator++(int) noexcept {
91 const dense_map_iterator orig = *this;
92 return ++(*this), orig;
93 }
94
95 constexpr dense_map_iterator &operator--() noexcept {
96 return --it, *this;
97 }
98
99 constexpr dense_map_iterator operator--(int) noexcept {
100 const dense_map_iterator orig = *this;
101 return operator--(), orig;
102 }
103
104 constexpr dense_map_iterator &operator+=(const difference_type value) noexcept {
105 it += value;
106 return *this;
107 }
108
109 constexpr dense_map_iterator operator+(const difference_type value) const noexcept {
110 dense_map_iterator copy = *this;
111 return (copy += value);
112 }
113
114 constexpr dense_map_iterator &operator-=(const difference_type value) noexcept {
115 return (*this += -value);
116 }
117
118 constexpr dense_map_iterator operator-(const difference_type value) const noexcept {
119 return (*this + -value);
120 }
121
122 [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
123 return {it[value].element.first, it[value].element.second};
124 }
125
126 [[nodiscard]] constexpr pointer operator->() const noexcept {
127 return operator*();
128 }
129
130 [[nodiscard]] constexpr reference operator*() const noexcept {
131 return operator[](0);
132 }
133
134 template<typename Other>
135 [[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_map_iterator<Other> &other) const noexcept {
136 return it - other.it;
137 }
138
139 template<typename Other>
140 [[nodiscard]] constexpr bool operator==(const dense_map_iterator<Other> &other) const noexcept {
141 return it == other.it;
142 }
143
144 template<typename Other>
145 [[nodiscard]] constexpr auto operator<=>(const dense_map_iterator<Other> &other) const noexcept {
146 return it <=> other.it;
147 }
148
149private:
150 It it;
151};
152
153template<typename It>
154class dense_map_local_iterator final {
155 template<typename>
156 friend class dense_map_local_iterator;
157
158 static_assert(stl::is_pointer_v<It>, "Not a pointer type");
159 using first_type = decltype(stl::as_const(stl::declval<It>()->element.first));
160 using second_type = decltype((stl::declval<It>()->element.second));
161
162public:
163 using value_type = stl::pair<first_type, second_type>;
165 using reference = value_type;
166 using difference_type = stl::ptrdiff_t;
167 using iterator_category = stl::input_iterator_tag;
168 using iterator_concept = stl::forward_iterator_tag;
169
170 constexpr dense_map_local_iterator() noexcept = default;
171
172 constexpr dense_map_local_iterator(It iter, const stl::size_t pos) noexcept
173 : it{iter},
174 offset{pos} {}
175
176 template<typename Other>
177 requires (!stl::same_as<It, Other> && stl::constructible_from<It, Other>)
178 constexpr dense_map_local_iterator(const dense_map_local_iterator<Other> &other) noexcept
179 : it{other.it},
180 offset{other.offset} {}
181
182 constexpr dense_map_local_iterator &operator++() noexcept {
183 return (offset = it[static_cast<difference_type>(offset)].next), *this;
184 }
185
186 constexpr dense_map_local_iterator operator++(int) noexcept {
187 const dense_map_local_iterator orig = *this;
188 return ++(*this), orig;
189 }
190
191 [[nodiscard]] constexpr pointer operator->() const noexcept {
192 return operator*();
193 }
194
195 [[nodiscard]] constexpr reference operator*() const noexcept {
196 const auto idx = static_cast<difference_type>(offset);
197 return {it[idx].element.first, it[idx].element.second};
198 }
199
200 template<typename Other>
201 [[nodiscard]] constexpr bool operator==(const dense_map_local_iterator<Other> &other) const noexcept {
202 return offset == other.offset;
203 }
204
205 [[nodiscard]] constexpr stl::size_t index() const noexcept {
206 return offset;
207 }
208
209private:
210 It it{};
211 stl::size_t offset{dense_map_placeholder_position};
212};
213
214} // namespace internal
216
230template<typename Key, typename Type, typename Hash, typename KeyEqual, typename Allocator>
232 static constexpr float default_threshold = 0.875f;
233 static constexpr stl::size_t minimum_capacity = 8u;
234 static constexpr stl::size_t placeholder_position = internal::dense_map_placeholder_position;
235
236 using node_type = internal::dense_map_node<Key, Type>;
237 using alloc_traits = stl::allocator_traits<Allocator>;
238 static_assert(stl::is_same_v<typename alloc_traits::value_type, stl::pair<const Key, Type>>, "Invalid value type");
239 using sparse_container_type = stl::vector<stl::size_t, typename alloc_traits::template rebind_alloc<stl::size_t>>;
240 using packed_container_type = stl::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
241
242 [[nodiscard]] stl::size_t key_to_bucket(const auto &key) const noexcept {
243 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
244 return fast_mod(static_cast<size_type>(sparse.second()(key)), bucket_count());
245 }
246
247 [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) {
248 for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) {
249 if(packed.second()(packed.first()[offset].element.first, key)) {
250 return begin() + static_cast<iterator::difference_type>(offset);
251 }
252 }
253
254 return end();
255 }
256
257 [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) const {
258 for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) {
259 if(packed.second()(packed.first()[offset].element.first, key)) {
260 return cbegin() + static_cast<const_iterator::difference_type>(offset);
261 }
262 }
263
264 return cend();
265 }
266
267 template<typename Other, typename... Args>
268 [[nodiscard]] auto insert_or_do_nothing(Other &&key, Args &&...args) {
269 const auto index = key_to_bucket(key);
270
271 if(auto it = constrained_find(key, index); it != end()) {
272 return stl::make_pair(it, false);
273 }
274
275 packed.first().emplace_back(sparse.first()[index], stl::piecewise_construct, stl::forward_as_tuple(stl::forward<Other>(key)), stl::forward_as_tuple(stl::forward<Args>(args)...));
276 sparse.first()[index] = packed.first().size() - 1u;
277 rehash_if_required();
278
279 return stl::make_pair(--end(), true);
280 }
281
282 template<typename Other, typename Arg>
283 [[nodiscard]] auto insert_or_overwrite(Other &&key, Arg &&value) {
284 const auto index = key_to_bucket(key);
285
286 if(auto it = constrained_find(key, index); it != end()) {
287 it->second = stl::forward<Arg>(value);
288 return stl::make_pair(it, false);
289 }
290
291 packed.first().emplace_back(sparse.first()[index], stl::forward<Other>(key), stl::forward<Arg>(value));
292 sparse.first()[index] = packed.first().size() - 1u;
293 rehash_if_required();
294
295 return stl::make_pair(--end(), true);
296 }
297
298 void move_and_pop(const stl::size_t pos) {
299 if(const auto last = size() - 1u; pos != last) {
300 size_type *curr = &sparse.first()[key_to_bucket(packed.first().back().element.first)];
301 packed.first()[pos] = stl::move(packed.first().back());
302 for(; *curr != last; curr = &packed.first()[*curr].next) {}
303 *curr = pos;
304 }
305
306 packed.first().pop_back();
307 }
308
309 void rehash_if_required() {
310 if(const auto bc = bucket_count(); size() > static_cast<size_type>(static_cast<float>(bc) * max_load_factor())) {
311 rehash(bc * 2u);
312 }
313 }
314
315public:
317 using allocator_type = Allocator;
319 using key_type = Key;
321 using mapped_type = Type;
323 using value_type = stl::pair<const Key, Type>;
325 using size_type = stl::size_t;
327 using difference_type = stl::ptrdiff_t;
329 using hasher = Hash;
331 using key_equal = KeyEqual;
333 using iterator = internal::dense_map_iterator<typename packed_container_type::pointer>;
335 using const_iterator = internal::dense_map_iterator<typename packed_container_type::const_pointer>;
337 using local_iterator = internal::dense_map_local_iterator<typename packed_container_type::pointer>;
339 using const_local_iterator = internal::dense_map_local_iterator<typename packed_container_type::const_pointer>;
340
343 : dense_map{minimum_capacity} {}
344
349 explicit dense_map(const allocator_type &allocator)
350 : dense_map{minimum_capacity, hasher{}, key_equal{}, allocator} {}
351
358 dense_map(const size_type cnt, const allocator_type &allocator)
359 : dense_map{cnt, hasher{}, key_equal{}, allocator} {}
360
368 dense_map(const size_type cnt, const hasher &hash, const allocator_type &allocator)
369 : dense_map{cnt, hash, key_equal{}, allocator} {}
370
379 explicit dense_map(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{})
380 : sparse{allocator, hash},
381 packed{allocator, equal} {
382 rehash(cnt);
383 }
384
386 dense_map(const dense_map &) = default;
387
393 dense_map(const dense_map &other, const allocator_type &allocator)
394 : sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())},
395 packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())},
396 threshold{other.threshold} {}
397
399 dense_map(dense_map &&) noexcept = default;
400
406 dense_map(dense_map &&other, const allocator_type &allocator)
407 : sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))},
408 packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))},
409 threshold{other.threshold} {}
410
412 ~dense_map() = default;
413
418 dense_map &operator=(const dense_map &) = default;
419
424 dense_map &operator=(dense_map &&) noexcept = default;
425
430 void swap(dense_map &other) noexcept {
431 using stl::swap;
432 swap(sparse, other.sparse);
433 swap(packed, other.packed);
434 swap(threshold, other.threshold);
435 }
436
441 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
442 return sparse.first().get_allocator();
443 }
444
452 [[nodiscard]] const_iterator cbegin() const noexcept {
453 return packed.first().data();
454 }
455
457 [[nodiscard]] const_iterator begin() const noexcept {
458 return cbegin();
459 }
460
462 [[nodiscard]] iterator begin() noexcept {
463 return packed.first().data();
464 }
465
471 [[nodiscard]] const_iterator cend() const noexcept {
472 return packed.first().data() + packed.first().size();
473 }
474
476 [[nodiscard]] const_iterator end() const noexcept {
477 return cend();
478 }
479
481 [[nodiscard]] iterator end() noexcept {
482 return packed.first().data() + packed.first().size();
483 }
484
489 [[nodiscard]] bool empty() const noexcept {
490 return packed.first().empty();
491 }
492
497 [[nodiscard]] size_type size() const noexcept {
498 return packed.first().size();
499 }
500
505 [[nodiscard]] size_type max_size() const noexcept {
506 return packed.first().max_size();
507 }
508
510 void clear() noexcept {
511 sparse.first().clear();
512 packed.first().clear();
513 rehash(0u);
514 }
515
523 stl::pair<iterator, bool> insert(const value_type &value) {
524 return insert_or_do_nothing(value.first, value.second);
525 }
526
528 stl::pair<iterator, bool> insert(value_type &&value) {
529 return insert_or_do_nothing(stl::move(value.first), stl::move(value.second));
530 }
531
536 template<typename Arg>
537 requires stl::constructible_from<value_type, Arg &&>
538 stl::pair<iterator, bool> insert(Arg &&value) {
539 return insert_or_do_nothing(stl::forward<Arg>(value).first, stl::forward<Arg>(value).second);
540 }
541
547 void insert(stl::input_iterator auto first, stl::input_iterator auto last) {
548 for(; first != last; ++first) {
549 insert(*first);
550 }
551 }
552
562 template<typename Arg>
563 stl::pair<iterator, bool> insert_or_assign(const key_type &key, Arg &&value) {
564 return insert_or_overwrite(key, stl::forward<Arg>(value));
565 }
566
568 template<typename Arg>
569 stl::pair<iterator, bool> insert_or_assign(key_type &&key, Arg &&value) {
570 return insert_or_overwrite(stl::move(key), stl::forward<Arg>(value));
571 }
572
586 template<typename... Args>
587 stl::pair<iterator, bool> emplace([[maybe_unused]] Args &&...args) {
588 if constexpr(sizeof...(Args) == 0u) {
589 return insert_or_do_nothing(key_type{});
590 } else if constexpr(sizeof...(Args) == 1u) {
591 return insert_or_do_nothing(stl::forward<Args>(args).first..., stl::forward<Args>(args).second...);
592 } else if constexpr(sizeof...(Args) == 2u) {
593 return insert_or_do_nothing(stl::forward<Args>(args)...);
594 } else {
595 auto &node = packed.first().emplace_back(packed.first().size(), stl::forward<Args>(args)...);
596 const auto index = key_to_bucket(node.element.first);
597
598 if(auto it = constrained_find(node.element.first, index); it != end()) {
599 packed.first().pop_back();
600 return stl::make_pair(it, false);
601 }
602
603 stl::swap(node.next, sparse.first()[index]);
604 rehash_if_required();
605
606 return stl::make_pair(--end(), true);
607 }
608 }
609
621 template<typename... Args>
622 stl::pair<iterator, bool> try_emplace(const key_type &key, Args &&...args) {
623 return insert_or_do_nothing(key, stl::forward<Args>(args)...);
624 }
625
627 template<typename... Args>
628 stl::pair<iterator, bool> try_emplace(key_type &&key, Args &&...args) {
629 return insert_or_do_nothing(stl::move(key), stl::forward<Args>(args)...);
630 }
631
638 const auto diff = pos - cbegin();
639 erase(pos->first);
640 return begin() + diff;
641 }
642
650 const auto dist = first - cbegin();
651
652 for(auto from = last - cbegin(); from != dist; --from) {
653 erase(packed.first()[static_cast<size_type>(from) - 1u].element.first);
654 }
655
656 return (begin() + dist);
657 }
658
665 for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != placeholder_position; curr = &packed.first()[*curr].next) {
666 if(packed.second()(packed.first()[*curr].element.first, key)) {
667 const auto index = *curr;
668 *curr = packed.first()[*curr].next;
669 move_and_pop(index);
670 return 1u;
671 }
672 }
673
674 return 0u;
675 }
676
682 [[nodiscard]] mapped_type &at(const key_type &key) {
683 auto it = find(key);
684 ENTT_ASSERT(it != end(), "Invalid key");
685 return it->second;
686 }
687
689 [[nodiscard]] const mapped_type &at(const key_type &key) const {
690 auto it = find(key);
691 ENTT_ASSERT(it != cend(), "Invalid key");
692 return it->second;
693 }
694
700 [[nodiscard]] mapped_type const &at(const auto &key) const
702 auto it = find(key);
703 ENTT_ASSERT(it != cend(), "Invalid key");
704 return it->second;
705 }
706
708 [[nodiscard]] mapped_type &at(const auto &key)
710 auto it = find(key);
711 ENTT_ASSERT(it != end(), "Invalid key");
712 return it->second;
713 }
714
720 [[nodiscard]] mapped_type &operator[](const key_type &key) {
721 return insert_or_do_nothing(key).first->second;
722 }
723
729 [[nodiscard]] mapped_type &operator[](key_type &&key) {
730 return insert_or_do_nothing(stl::move(key)).first->second;
731 }
732
738 [[nodiscard]] size_type count(const key_type &key) const {
739 return find(key) != end();
740 }
741
747 [[nodiscard]] size_type count(const auto &key) const
749 return find(key) != end();
750 }
751
758 [[nodiscard]] iterator find(const key_type &key) {
759 return constrained_find(key, key_to_bucket(key));
760 }
761
763 [[nodiscard]] const_iterator find(const key_type &key) const {
764 return constrained_find(key, key_to_bucket(key));
765 }
766
774 [[nodiscard]] iterator find(const auto &key)
776 return constrained_find(key, key_to_bucket(key));
777 }
778
780 [[nodiscard]] const_iterator find(const auto &key) const
782 return constrained_find(key, key_to_bucket(key));
783 }
784
791 [[nodiscard]] stl::pair<iterator, iterator> equal_range(const key_type &key) {
792 const auto it = find(key);
793 return {it, it + !(it == end())};
794 }
795
797 [[nodiscard]] stl::pair<const_iterator, const_iterator> equal_range(const key_type &key) const {
798 const auto it = find(key);
799 return {it, it + !(it == cend())};
800 }
801
809 [[nodiscard]] stl::pair<iterator, iterator> equal_range(const auto &key)
811 const auto it = find(key);
812 return {it, it + !(it == end())};
813 }
814
816 [[nodiscard]] stl::pair<const_iterator, const_iterator> equal_range(const auto &key) const
818 const auto it = find(key);
819 return {it, it + !(it == cend())};
820 }
821
827 [[nodiscard]] bool contains(const key_type &key) const {
828 return (find(key) != cend());
829 }
830
837 [[nodiscard]] bool contains(const auto &key) const
839 return (find(key) != cend());
840 }
841
847 [[nodiscard]] const_local_iterator cbegin(const size_type index) const {
848 return {packed.first().data(), sparse.first()[index]};
849 }
850
856 [[nodiscard]] const_local_iterator begin(const size_type index) const {
857 return cbegin(index);
858 }
859
865 [[nodiscard]] local_iterator begin(const size_type index) {
866 return {packed.first().data(), sparse.first()[index]};
867 }
868
874 [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const {
875 return {};
876 }
877
883 [[nodiscard]] const_local_iterator end(const size_type index) const {
884 return cend(index);
885 }
886
892 [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) {
893 return {};
894 }
895
900 [[nodiscard]] size_type bucket_count() const {
901 return sparse.first().size();
902 }
903
908 [[nodiscard]] size_type max_bucket_count() const {
909 return sparse.first().max_size();
910 }
911
917 [[nodiscard]] size_type bucket_size(const size_type index) const {
918 return static_cast<size_type>(stl::distance(begin(index), end(index)));
919 }
920
926 [[nodiscard]] size_type bucket(const key_type &key) const {
927 return key_to_bucket(key);
928 }
929
934 [[nodiscard]] float load_factor() const {
935 return static_cast<float>(size()) / static_cast<float>(bucket_count());
936 }
937
942 [[nodiscard]] float max_load_factor() const {
943 return threshold;
944 }
945
950 void max_load_factor(const float value) {
951 ENTT_ASSERT(value > 0.f, "Invalid load factor");
952 threshold = value;
953 rehash(0u);
954 }
955
961 void rehash(const size_type cnt) {
962 auto value = cnt > minimum_capacity ? cnt : minimum_capacity;
963 const auto cap = static_cast<size_type>(static_cast<float>(size()) / max_load_factor());
964 value = value > cap ? value : cap;
965
966 if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) {
967 sparse.first().resize(sz);
968
969 for(auto &&elem: sparse.first()) {
970 elem = placeholder_position;
971 }
972
973 for(size_type pos{}, last = size(); pos < last; ++pos) {
974 const auto index = key_to_bucket(packed.first()[pos].element.first);
975 packed.first()[pos].next = stl::exchange(sparse.first()[index], pos);
976 }
977 }
978 }
979
985 void reserve(const size_type cnt) {
986 packed.first().reserve(cnt);
987 rehash(static_cast<size_type>(stl::ceil(static_cast<float>(cnt) / max_load_factor())));
988 }
989
994 [[nodiscard]] hasher hash_function() const {
995 return sparse.second();
996 }
997
1002 [[nodiscard]] key_equal key_eq() const {
1003 return packed.second();
1004 }
1005
1006private:
1009 float threshold{default_threshold};
1010};
1011
1012} // namespace entt
1013
1015#include <utility>
1016
1017namespace std {
1018
1019template<typename Key, typename Value, typename Allocator>
1020struct uses_allocator<entt::internal::dense_map_node<Key, Value>, Allocator>
1021 : entt::stl::true_type {};
1022
1023} // namespace std
1025
1026#endif
A compressed pair.
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 find(const auto &key)
Finds an element with a key that compares equivalent to a given key.
dense_map(const allocator_type &allocator)
Constructs an empty container with a given allocator.
void clear() noexcept
Clears the container.
stl::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.
float load_factor() const
Returns the average number of elements per bucket.
size_type erase(const key_type &key)
Removes the element associated with a given key.
bool contains(const auto &key) const
Checks if the container contains an element with a key that compares equivalent to a given value.
stl::ptrdiff_t difference_type
Signed integer type.
stl::pair< const Key, Type > value_type
Key-value type of the container.
mapped_type & operator[](key_type &&key)
Accesses or inserts a given element.
stl::pair< iterator, iterator > equal_range(const key_type &key)
Returns a range containing all elements with a given key.
const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
internal::dense_map_iterator< typename packed_container_type::pointer > iterator
Input iterator type.
const_local_iterator begin(const size_type index) const
Returns an iterator to the beginning of a given bucket.
size_type size() const noexcept
Returns the number of elements in a container.
const_local_iterator end(const size_type index) const
Returns an iterator to the end of a given bucket.
dense_map & operator=(dense_map &&) noexcept=default
Default move assignment operator.
const mapped_type & at(const key_type &key) const
Accesses a given element with bounds checking.
KeyEqual key_equal
Type of function to use to compare the keys for equality.
stl::pair< const_iterator, const_iterator > equal_range(const key_type &key) const
Returns a range containing all elements with a given key.
void insert(stl::input_iterator auto first, stl::input_iterator auto last)
Inserts elements into the container, if their keys do not exist.
size_type max_size() const noexcept
Returns the maximum possible number of elements.
mapped_type & at(const key_type &key)
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.
size_type max_bucket_count() const
Returns the maximum number of buckets.
iterator erase(const_iterator first, const_iterator last)
Removes the given elements from a container.
size_type count(const key_type &key) const
Returns the number of elements matching a key (either 1 or 0).
local_iterator begin(const size_type index)
Returns an iterator to the beginning of a given bucket.
bool contains(const key_type &key) const
Checks if the container contains an element with a given key.
const_iterator cend() const noexcept
Returns an iterator to the end.
stl::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 size_type cnt, const allocator_type &allocator)
Constructs an empty container with a given allocator and user supplied minimal number of buckets.
size_type count(const auto &key) const
Returns the number of elements matching a key (either 1 or 0).
stl::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.
float max_load_factor() const
Returns the maximum average number of elements per bucket.
mapped_type & at(const auto &key)
Accesses a given element with bounds checking.
stl::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.
internal::dense_map_local_iterator< typename packed_container_type::const_pointer > const_local_iterator
Constant input iterator type.
const_iterator find(const key_type &key) const
Finds an element with a given key.
void max_load_factor(const float value)
Sets the desired maximum average number of elements per bucket.
dense_map & operator=(const dense_map &)=default
Default copy assignment operator.
stl::pair< iterator, iterator > equal_range(const auto &key)
Returns a range containing all elements that compare equivalent to a given key.
mapped_type const & at(const auto &key) const
Accesses a given element with bounds checking.
iterator find(const key_type &key)
Finds an element with a given key.
const_iterator begin() const noexcept
Returns an iterator to the beginning.
Type mapped_type
Mapped type of the container.
void rehash(const size_type cnt)
Reserves at least the specified number of buckets and regenerates the hash table.
const_local_iterator cend(const size_type index) const
Returns an iterator to the end of a given bucket.
iterator erase(const_iterator pos)
Removes an element from a given position.
const_iterator find(const auto &key) const
Finds an element with a given key.
dense_map(const dense_map &other, const allocator_type &allocator)
Allocator-extended copy constructor.
size_type bucket(const key_type &key) const
Returns the bucket for a given key.
mapped_type & operator[](const key_type &key)
Accesses or inserts a given element.
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
stl::pair< iterator, bool > emplace(Args &&...args)
Constructs an element in-place, if the key does not exist.
const_local_iterator cbegin(const size_type index) const
Returns an iterator to the beginning of a given bucket.
stl::size_t size_type
Unsigned integer type.
dense_map(const dense_map &)=default
Default copy constructor.
stl::pair< iterator, bool > insert(const value_type &value)
Inserts an element into the container, if the key does not exist.
local_iterator end(const size_type index)
Returns an iterator to the end of a given bucket.
stl::pair< const_iterator, const_iterator > equal_range(const auto &key) const
Returns a range containing all elements with a given key.
key_equal key_eq() const
Returns the function used to compare 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 ...
internal::dense_map_local_iterator< typename packed_container_type::pointer > local_iterator
Input iterator type.
stl::pair< iterator, bool > insert(value_type &&value)
Inserts an element into the container, if the key does not exist.
dense_map(dense_map &&) noexcept=default
Default move constructor.
bool empty() const noexcept
Checks whether a container is empty.
Allocator allocator_type
Allocator type.
size_type bucket_size(const size_type index) const
Returns the number of elements in a given bucket.
Hash hasher
Type of function to use to hash the keys.
Key key_type
Key type of the container.
size_type bucket_count() const
Returns the number of buckets.
dense_map()
Default constructor.
~dense_map()=default
Default destructor.
stl::pair< iterator, bool > insert(Arg &&value)
Inserts an element into the container, if the key does not exist.
hasher hash_function() const
Returns the function used to hash the keys.
const_iterator end() const noexcept
Returns an iterator to the end.
iterator begin() noexcept
Returns an iterator to the beginning.
internal::dense_map_iterator< typename packed_container_type::const_pointer > const_iterator
Constant input iterator type.
iterator end() noexcept
Returns an iterator to the end.
Custom EnTT namespace for the standard template library.
Definition entt.hpp:5
EnTT default namespace.
Definition dense_map.hpp:25
constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
Definition memory.hpp:201
constexpr bool is_transparent_v
Helper variable template.
constexpr type_list< Type..., Other... > operator+(type_list< Type... >, type_list< Other... >)
Concatenates multiple type lists.
constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept
Fast module utility function (powers of two only).
Definition bit.hpp:19
Helper type to use as pointer with input iterators.
Definition iterator.hpp:18