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>
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;
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
378 : dense_map{minimum_capacity, hasher{}, key_equal{}, allocator} {}
379
388
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
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
428
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
453
459 return sparse.first().get_allocator();
460 }
461
470 return packed.first().begin();
471 }
472
475 return cbegin();
476 }
477
480 return packed.first().begin();
481 }
482
489 return packed.first().end();
490 }
491
494 return cend();
495 }
496
499 return packed.first().end();
500 }
501
507 return packed.first().empty();
508 }
509
515 return packed.first().size();
516 }
517
523 return packed.first().max_size();
524 }
525
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
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
731 return insert_or_do_nothing(key).first->second;
732 }
733
740 return insert_or_do_nothing(std::move(key)).first->second;
741 }
742
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
771 return constrained_find(key, key_to_bucket(key));
772 }
773
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>>>
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
868 return {packed.first().begin(), sparse.first()[index]};
869 }
870
877 return cbegin(index);
878 }
879
886 return {packed.first().begin(), sparse.first()[index]};
887 }
888
895 return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
896 }
897
904 return cend(index);
905 }
906
913 return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
914 }
915
921 return sparse.first().size();
922 }
923
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
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
1015 return sparse.second();
1016 }
1017
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.
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.
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...
dense_map(const allocator_type &allocator)
Constructs an empty container with a given allocator.
void clear() noexcept
Clears the container.
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.
mapped_type & operator[](key_type &&key)
Accesses or inserts a given element.
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.
const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
const_local_iterator begin(const size_type index) const
Returns an iterator to the beginning of a given bucket.
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).
size_type size() const noexcept
Returns the number of elements in a container.
std::size_t size_type
Unsigned integer type.
const_local_iterator end(const size_type index) const
Returns an iterator to the end of a given bucket.
void insert(It first, It last)
Inserts elements into the container, if their keys do not exist.
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.
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.
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.
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.
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.
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.
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.
float max_load_factor() const
Returns the maximum average number of elements per bucket.
const_iterator find(const key_type &key) const
Finds an element with a given key.
internal::dense_map_iterator< typename packed_container_type::const_iterator > const_iterator
Constant input iterator type.
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.
std::pair< iterator, bool > insert(value_type &&value)
Inserts an element into the container, if the key does not exist.
iterator find(const key_type &key)
Finds an element with a given key.
std::pair< iterator, iterator > equal_range(const key_type &key)
Returns a range containing all elements 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.
void swap(dense_map &other) noexcept
Exchanges the contents with those of a given container.
dense_map(const dense_map &other, const allocator_type &allocator)
Allocator-extended copy constructor.
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::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.
size_type bucket(const key_type &key) const
Returns the bucket for a given key.
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.
mapped_type & operator[](const key_type &key)
Accesses or inserts a given element.
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
const_local_iterator cbegin(const size_type index) const
Returns an iterator to the beginning of a given bucket.
std::pair< const Key, Type > value_type
Key-value type of the container.
dense_map(const dense_map &)=default
Default copy constructor.
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, bool > emplace(Args &&...args)
Constructs an element in-place, 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.
local_iterator end(const size_type index)
Returns an iterator to the end of a given 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.
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_iterator< typename packed_container_type::iterator > iterator
Input iterator type.
internal::dense_map_local_iterator< typename packed_container_type::iterator > local_iterator
Input iterator type.
dense_map(dense_map &&) noexcept=default
Default move constructor.
internal::dense_map_local_iterator< typename packed_container_type::const_iterator > const_local_iterator
Constant input iterator type.
bool empty() const noexcept
Checks whether a container is empty.
std::pair< iterator, bool > insert(const value_type &value)
Inserts an element into the container, if the key does not exist.
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.
std::pair< const_iterator, const_iterator > equal_range(const key_type &key) const
Returns a range containing all elements with a given key.
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.
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 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