EnTT 3.16.0
Loading...
Searching...
No Matches
dense_set.hpp
1#ifndef ENTT_CONTAINER_DENSE_SET_HPP
2#define ENTT_CONTAINER_DENSE_SET_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/type_traits.hpp"
18#include "fwd.hpp"
19
20namespace entt {
21
23namespace internal {
24
25static constexpr std::size_t dense_set_placeholder_position = (std::numeric_limits<std::size_t>::max)();
26
27template<typename It>
28class dense_set_iterator final {
29 template<typename>
30 friend class dense_set_iterator;
31
32public:
33 using value_type = typename It::value_type::second_type;
34 using pointer = const value_type *;
35 using reference = const value_type &;
36 using difference_type = std::ptrdiff_t;
37 using iterator_category = std::random_access_iterator_tag;
38
39 constexpr dense_set_iterator() noexcept
40 : it{} {}
41
42 constexpr dense_set_iterator(const It iter) noexcept
43 : it{iter} {}
44
45 template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
46 constexpr dense_set_iterator(const dense_set_iterator<Other> &other) noexcept
47 : it{other.it} {}
48
49 constexpr dense_set_iterator &operator++() noexcept {
50 return ++it, *this;
51 }
52
53 constexpr dense_set_iterator operator++(int) noexcept {
54 const dense_set_iterator orig = *this;
55 return ++(*this), orig;
56 }
57
58 constexpr dense_set_iterator &operator--() noexcept {
59 return --it, *this;
60 }
61
62 constexpr dense_set_iterator operator--(int) noexcept {
63 const dense_set_iterator orig = *this;
64 return operator--(), orig;
65 }
66
67 constexpr dense_set_iterator &operator+=(const difference_type value) noexcept {
68 it += value;
69 return *this;
70 }
71
72 constexpr dense_set_iterator operator+(const difference_type value) const noexcept {
73 dense_set_iterator copy = *this;
74 return (copy += value);
75 }
76
77 constexpr dense_set_iterator &operator-=(const difference_type value) noexcept {
78 return (*this += -value);
79 }
80
81 constexpr dense_set_iterator operator-(const difference_type value) const noexcept {
82 return (*this + -value);
83 }
84
85 [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
86 return it[value].second;
87 }
88
89 [[nodiscard]] constexpr pointer operator->() const noexcept {
90 return std::addressof(operator[](0));
91 }
92
93 [[nodiscard]] constexpr reference operator*() const noexcept {
94 return operator[](0);
95 }
96
97 template<typename Lhs, typename Rhs>
98 friend constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
99
100 template<typename Lhs, typename Rhs>
101 friend constexpr bool operator==(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
102
103 template<typename Lhs, typename Rhs>
104 friend constexpr bool operator<(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
105
106private:
107 It it;
108};
109
110template<typename Lhs, typename Rhs>
111[[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
112 return lhs.it - rhs.it;
113}
114
115template<typename Lhs, typename Rhs>
116[[nodiscard]] constexpr bool operator==(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
117 return lhs.it == rhs.it;
118}
119
120template<typename Lhs, typename Rhs>
121[[nodiscard]] constexpr bool operator!=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
122 return !(lhs == rhs);
123}
124
125template<typename Lhs, typename Rhs>
126[[nodiscard]] constexpr bool operator<(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
127 return lhs.it < rhs.it;
128}
129
130template<typename Lhs, typename Rhs>
131[[nodiscard]] constexpr bool operator>(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
132 return rhs < lhs;
133}
134
135template<typename Lhs, typename Rhs>
136[[nodiscard]] constexpr bool operator<=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
137 return !(lhs > rhs);
138}
139
140template<typename Lhs, typename Rhs>
141[[nodiscard]] constexpr bool operator>=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
142 return !(lhs < rhs);
143}
144
145template<typename It>
146class dense_set_local_iterator final {
147 template<typename>
148 friend class dense_set_local_iterator;
149
150public:
151 using value_type = typename It::value_type::second_type;
152 using pointer = const value_type *;
153 using reference = const value_type &;
154 using difference_type = std::ptrdiff_t;
155 using iterator_category = std::forward_iterator_tag;
156
157 constexpr dense_set_local_iterator() noexcept = default;
158
159 constexpr dense_set_local_iterator(It iter, const std::size_t pos) noexcept
160 : it{iter},
161 offset{pos} {}
162
163 template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
164 constexpr dense_set_local_iterator(const dense_set_local_iterator<Other> &other) noexcept
165 : it{other.it},
166 offset{other.offset} {}
167
168 constexpr dense_set_local_iterator &operator++() noexcept {
169 return offset = it[static_cast<typename It::difference_type>(offset)].first, *this;
170 }
171
172 constexpr dense_set_local_iterator operator++(int) noexcept {
173 const dense_set_local_iterator orig = *this;
174 return ++(*this), orig;
175 }
176
177 [[nodiscard]] constexpr pointer operator->() const noexcept {
178 return std::addressof(it[static_cast<typename It::difference_type>(offset)].second);
179 }
180
181 [[nodiscard]] constexpr reference operator*() const noexcept {
182 return *operator->();
183 }
184
185 [[nodiscard]] constexpr std::size_t index() const noexcept {
186 return offset;
187 }
188
189private:
190 It it{};
191 std::size_t offset{dense_set_placeholder_position};
192};
193
194template<typename Lhs, typename Rhs>
195[[nodiscard]] constexpr bool operator==(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &rhs) noexcept {
196 return lhs.index() == rhs.index();
197}
198
199template<typename Lhs, typename Rhs>
200[[nodiscard]] constexpr bool operator!=(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &rhs) noexcept {
201 return !(lhs == rhs);
202}
203
204} // namespace internal
206
219template<typename Type, typename Hash, typename KeyEqual, typename Allocator>
221 static constexpr float default_threshold = 0.875f;
222 static constexpr std::size_t minimum_capacity = 8u;
223 static constexpr std::size_t placeholder_position = internal::dense_set_placeholder_position;
224
225 using node_type = std::pair<std::size_t, Type>;
226 using alloc_traits = std::allocator_traits<Allocator>;
227 static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
228 using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
229 using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
230
231 template<typename Other>
232 [[nodiscard]] std::size_t value_to_bucket(const Other &value) const noexcept {
233 return fast_mod(static_cast<size_type>(sparse.second()(value)), bucket_count());
234 }
235
236 template<typename Other>
237 [[nodiscard]] auto constrained_find(const Other &value, const std::size_t bucket) {
238 for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) {
239 if(packed.second()(packed.first()[offset].second, value)) {
240 return begin() + static_cast<typename iterator::difference_type>(offset);
241 }
242 }
243
244 return end();
245 }
246
247 template<typename Other>
248 [[nodiscard]] auto constrained_find(const Other &value, const std::size_t bucket) const {
249 for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) {
250 if(packed.second()(packed.first()[offset].second, value)) {
251 return cbegin() + static_cast<typename const_iterator::difference_type>(offset);
252 }
253 }
254
255 return cend();
256 }
257
258 template<typename Other>
259 [[nodiscard]] auto insert_or_do_nothing(Other &&value) {
260 const auto index = value_to_bucket(value);
261
262 if(auto it = constrained_find(value, index); it != end()) {
263 return std::make_pair(it, false);
264 }
265
266 packed.first().emplace_back(sparse.first()[index], std::forward<Other>(value));
267 sparse.first()[index] = packed.first().size() - 1u;
268 rehash_if_required();
269
270 return std::make_pair(--end(), true);
271 }
272
273 void move_and_pop(const std::size_t pos) {
274 if(const auto last = size() - 1u; pos != last) {
275 size_type *curr = &sparse.first()[value_to_bucket(packed.first().back().second)];
276 packed.first()[pos] = std::move(packed.first().back());
277 for(; *curr != last; curr = &packed.first()[*curr].first) {}
278 *curr = pos;
279 }
280
281 packed.first().pop_back();
282 }
283
284 void rehash_if_required() {
285 if(const auto bc = bucket_count(); size() > static_cast<size_type>(static_cast<float>(bc) * max_load_factor())) {
286 rehash(bc * 2u);
287 }
288 }
289
290public:
292 using allocator_type = Allocator;
294 using key_type = Type;
296 using value_type = Type;
298 using size_type = std::size_t;
300 using difference_type = std::ptrdiff_t;
302 using hasher = Hash;
304 using key_equal = KeyEqual;
306 using iterator = internal::dense_set_iterator<typename packed_container_type::iterator>;
308 using const_iterator = internal::dense_set_iterator<typename packed_container_type::const_iterator>;
310 using reverse_iterator = std::reverse_iterator<iterator>;
312 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
314 using local_iterator = internal::dense_set_local_iterator<typename packed_container_type::iterator>;
316 using const_local_iterator = internal::dense_set_local_iterator<typename packed_container_type::const_iterator>;
317
320 : dense_set{minimum_capacity} {}
321
326 explicit dense_set(const allocator_type &allocator)
327 : dense_set{minimum_capacity, hasher{}, key_equal{}, allocator} {}
328
335 dense_set(const size_type cnt, const allocator_type &allocator)
336 : dense_set{cnt, hasher{}, key_equal{}, allocator} {}
337
345 dense_set(const size_type cnt, const hasher &hash, const allocator_type &allocator)
346 : dense_set{cnt, hash, key_equal{}, allocator} {}
347
356 explicit dense_set(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{})
357 : sparse{allocator, hash},
358 packed{allocator, equal} {
359 rehash(cnt);
360 }
361
363 dense_set(const dense_set &) = default;
364
370 dense_set(const dense_set &other, const allocator_type &allocator)
371 : sparse{std::piecewise_construct, std::forward_as_tuple(other.sparse.first(), allocator), std::forward_as_tuple(other.sparse.second())},
372 packed{std::piecewise_construct, std::forward_as_tuple(other.packed.first(), allocator), std::forward_as_tuple(other.packed.second())},
373 threshold{other.threshold} {}
374
376 dense_set(dense_set &&) noexcept = default;
377
383 dense_set(dense_set &&other, const allocator_type &allocator)
384 : sparse{std::piecewise_construct, std::forward_as_tuple(std::move(other.sparse.first()), allocator), std::forward_as_tuple(std::move(other.sparse.second()))},
385 packed{std::piecewise_construct, std::forward_as_tuple(std::move(other.packed.first()), allocator), std::forward_as_tuple(std::move(other.packed.second()))},
386 threshold{other.threshold} {}
387
389 ~dense_set() = default;
390
395 dense_set &operator=(const dense_set &) = default;
396
401 dense_set &operator=(dense_set &&) noexcept = default;
402
407 void swap(dense_set &other) noexcept {
408 using std::swap;
409 swap(sparse, other.sparse);
410 swap(packed, other.packed);
411 swap(threshold, other.threshold);
412 }
413
418 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
419 return sparse.first().get_allocator();
420 }
421
429 [[nodiscard]] const_iterator cbegin() const noexcept {
430 return packed.first().begin();
431 }
432
434 [[nodiscard]] const_iterator begin() const noexcept {
435 return cbegin();
436 }
437
439 [[nodiscard]] iterator begin() noexcept {
440 return packed.first().begin();
441 }
442
448 [[nodiscard]] const_iterator cend() const noexcept {
449 return packed.first().end();
450 }
451
453 [[nodiscard]] const_iterator end() const noexcept {
454 return cend();
455 }
456
458 [[nodiscard]] iterator end() noexcept {
459 return packed.first().end();
460 }
461
469 [[nodiscard]] const_reverse_iterator crbegin() const noexcept {
470 return std::make_reverse_iterator(cend());
471 }
472
474 [[nodiscard]] const_reverse_iterator rbegin() const noexcept {
475 return crbegin();
476 }
477
479 [[nodiscard]] reverse_iterator rbegin() noexcept {
480 return std::make_reverse_iterator(end());
481 }
482
488 [[nodiscard]] const_reverse_iterator crend() const noexcept {
489 return std::make_reverse_iterator(cbegin());
490 }
491
493 [[nodiscard]] const_reverse_iterator rend() const noexcept {
494 return crend();
495 }
496
498 [[nodiscard]] reverse_iterator rend() noexcept {
499 return std::make_reverse_iterator(begin());
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);
542 }
543
545 std::pair<iterator, bool> insert(value_type &&value) {
546 return insert_or_do_nothing(std::move(value));
547 }
548
555 template<typename It>
556 void insert(It first, It last) {
557 for(; first != last; ++first) {
558 insert(*first);
559 }
560 }
561
575 template<typename... Args>
576 std::pair<iterator, bool> emplace(Args &&...args) {
577 if constexpr(((sizeof...(Args) == 1u) && ... && std::is_same_v<std::decay_t<Args>, value_type>)) {
578 return insert_or_do_nothing(std::forward<Args>(args)...);
579 } else {
580 auto &node = packed.first().emplace_back(std::piecewise_construct, std::make_tuple(packed.first().size()), std::forward_as_tuple(std::forward<Args>(args)...));
581 const auto index = value_to_bucket(node.second);
582
583 if(auto it = constrained_find(node.second, index); it != end()) {
584 packed.first().pop_back();
585 return std::make_pair(it, false);
586 }
587
588 std::swap(node.first, sparse.first()[index]);
589 rehash_if_required();
590
591 return std::make_pair(--end(), true);
592 }
593 }
594
601 const auto diff = pos - cbegin();
602 erase(*pos);
603 return begin() + diff;
604 }
605
613 const auto dist = first - cbegin();
614
615 for(auto from = last - cbegin(); from != dist; --from) {
616 erase(packed.first()[static_cast<size_type>(from) - 1u].second);
617 }
618
619 return (begin() + dist);
620 }
621
627 size_type erase(const value_type &value) {
628 for(size_type *curr = &sparse.first()[value_to_bucket(value)]; *curr != placeholder_position; curr = &packed.first()[*curr].first) {
629 if(packed.second()(packed.first()[*curr].second, value)) {
630 const auto index = *curr;
631 *curr = packed.first()[*curr].first;
632 move_and_pop(index);
633 return 1u;
634 }
635 }
636
637 return 0u;
638 }
639
645 [[nodiscard]] size_type count(const value_type &key) const {
646 return find(key) != end();
647 }
648
655 template<typename Other>
656 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, size_type>>
657 count(const Other &key) const {
658 return find(key) != end();
659 }
660
667 [[nodiscard]] iterator find(const value_type &value) {
668 return constrained_find(value, value_to_bucket(value));
669 }
670
672 [[nodiscard]] const_iterator find(const value_type &value) const {
673 return constrained_find(value, value_to_bucket(value));
674 }
675
683 template<typename Other>
684 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, iterator>>
685 find(const Other &value) {
686 return constrained_find(value, value_to_bucket(value));
687 }
688
690 template<typename Other>
691 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, const_iterator>>
692 find(const Other &value) const {
693 return constrained_find(value, value_to_bucket(value));
694 }
695
702 [[nodiscard]] std::pair<iterator, iterator> equal_range(const value_type &value) {
703 const auto it = find(value);
704 return {it, it + !(it == end())};
705 }
706
708 [[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(const value_type &value) const {
709 const auto it = find(value);
710 return {it, it + !(it == cend())};
711 }
712
721 template<typename Other>
722 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<iterator, iterator>>>
723 equal_range(const Other &value) {
724 const auto it = find(value);
725 return {it, it + !(it == end())};
726 }
727
729 template<typename Other>
730 [[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>>>
731 equal_range(const Other &value) const {
732 const auto it = find(value);
733 return {it, it + !(it == cend())};
734 }
735
741 [[nodiscard]] bool contains(const value_type &value) const {
742 return (find(value) != cend());
743 }
744
752 template<typename Other>
753 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, bool>>
754 contains(const Other &value) const {
755 return (find(value) != cend());
756 }
757
763 [[nodiscard]] const_local_iterator cbegin(const size_type index) const {
764 return {packed.first().begin(), sparse.first()[index]};
765 }
766
772 [[nodiscard]] const_local_iterator begin(const size_type index) const {
773 return cbegin(index);
774 }
775
781 [[nodiscard]] local_iterator begin(const size_type index) {
782 return {packed.first().begin(), sparse.first()[index]};
783 }
784
790 [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const {
791 return {};
792 }
793
799 [[nodiscard]] const_local_iterator end(const size_type index) const {
800 return cend(index);
801 }
802
808 [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) {
809 return {};
810 }
811
816 [[nodiscard]] size_type bucket_count() const {
817 return sparse.first().size();
818 }
819
824 [[nodiscard]] size_type max_bucket_count() const {
825 return sparse.first().max_size();
826 }
827
833 [[nodiscard]] size_type bucket_size(const size_type index) const {
834 return static_cast<size_type>(std::distance(begin(index), end(index)));
835 }
836
842 [[nodiscard]] size_type bucket(const value_type &value) const {
843 return value_to_bucket(value);
844 }
845
850 [[nodiscard]] float load_factor() const {
851 return static_cast<float>(size()) / static_cast<float>(bucket_count());
852 }
853
858 [[nodiscard]] float max_load_factor() const {
859 return threshold;
860 }
861
866 void max_load_factor(const float value) {
867 ENTT_ASSERT(value > 0.f, "Invalid load factor");
868 threshold = value;
869 rehash(0u);
870 }
871
877 void rehash(const size_type cnt) {
878 auto value = cnt > minimum_capacity ? cnt : minimum_capacity;
879 const auto cap = static_cast<size_type>(static_cast<float>(size()) / max_load_factor());
880 value = value > cap ? value : cap;
881
882 if(const auto sz = next_power_of_two(value); sz != bucket_count()) {
883 sparse.first().resize(sz);
884
885 for(auto &&elem: sparse.first()) {
886 elem = placeholder_position;
887 }
888
889 for(size_type pos{}, last = size(); pos < last; ++pos) {
890 const auto index = value_to_bucket(packed.first()[pos].second);
891 packed.first()[pos].first = std::exchange(sparse.first()[index], pos);
892 }
893 }
894 }
895
901 void reserve(const size_type cnt) {
902 packed.first().reserve(cnt);
903 rehash(static_cast<size_type>(std::ceil(static_cast<float>(cnt) / max_load_factor())));
904 }
905
910 [[nodiscard]] hasher hash_function() const {
911 return sparse.second();
912 }
913
918 [[nodiscard]] key_equal key_eq() const {
919 return packed.second();
920 }
921
922private:
925 float threshold{default_threshold};
926};
927
928} // namespace entt
929
930#endif
A compressed pair.
size_type bucket_size(const size_type index) const
Returns the number of elements in a given bucket.
void clear() noexcept
Clears the container.
internal::dense_set_local_iterator< typename packed_container_type::const_iterator > const_local_iterator
Constant forward iterator type.
const_reverse_iterator crbegin() const noexcept
Returns a reverse iterator to the beginning.
std::ptrdiff_t difference_type
Signed integer type.
const_iterator begin() const noexcept
Returns an iterator to the beginning.
key_equal key_eq() const
Returns the function used to compare elements for equality.
KeyEqual key_equal
Type of function to use to compare the elements for equality.
internal::dense_set_iterator< typename packed_container_type::const_iterator > const_iterator
Constant random access iterator type.
const_iterator cend() const noexcept
Returns an iterator to the end.
iterator erase(const_iterator first, const_iterator last)
Removes the given elements from a container.
std::enable_if_t< is_transparent_v< hasher > &&is_transparent_v< key_equal >, std::conditional_t< false, Other, bool > > contains(const Other &value) const
Checks if the container contains an element that compares equivalent to a given value.
Hash hasher
Type of function to use to hash the elements.
std::size_t size_type
Unsigned integer type.
size_type bucket(const value_type &value) const
Returns the bucket for a given element.
reverse_iterator rbegin() noexcept
Returns a reverse iterator to the beginning.
iterator find(const value_type &value)
Finds an element with a given value.
Type key_type
Key type of the container.
Type value_type
Value type of the container.
internal::dense_set_iterator< typename packed_container_type::iterator > iterator
Random access iterator type.
std::pair< iterator, bool > emplace(Args &&...args)
Constructs an element in-place, if it does not exist.
dense_set & operator=(dense_set &&) noexcept=default
Default move assignment operator.
size_type bucket_count() const
Returns the number of buckets.
size_type max_size() const noexcept
Returns the maximum possible number of elements.
size_type size() const noexcept
Returns the number of elements in a container.
std::pair< iterator, iterator > equal_range(const value_type &value)
Returns a range containing all elements with a given value.
std::reverse_iterator< const_iterator > const_reverse_iterator
Constant reverse iterator type.
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 &value)
Returns a range containing all elements that compare equivalent to a given value.
local_iterator end(const size_type index)
Returns an iterator to the end of a given bucket.
dense_set(const dense_set &other, const allocator_type &allocator)
Allocator-extended copy constructor.
bool empty() const noexcept
Checks whether a container is empty.
dense_set(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 ...
const_iterator find(const value_type &value) const
Finds an element with a given value.
const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
const_reverse_iterator rend() const noexcept
Returns a reverse iterator to the end.
dense_set(const size_type cnt, const allocator_type &allocator)
Constructs an empty container with a given allocator and user supplied minimal number of buckets.
hasher hash_function() const
Returns the function used to hash the elements.
std::pair< iterator, bool > insert(const value_type &value)
Inserts an element into the container, if it does not exist.
internal::dense_set_local_iterator< typename packed_container_type::iterator > local_iterator
Forward iterator type.
~dense_set()=default
Default destructor.
void reserve(const size_type cnt)
Reserves space for at least the specified number of elements and regenerates the hash table.
const_local_iterator cend(const size_type index) const
Returns an iterator to the end of a given bucket.
std::reverse_iterator< iterator > reverse_iterator
Reverse iterator type.
Allocator allocator_type
Allocator type.
size_type count(const value_type &key) const
Returns the number of elements matching a value (either 1 or 0).
iterator end() noexcept
Returns an iterator to the end.
std::enable_if_t< is_transparent_v< hasher > &&is_transparent_v< key_equal >, std::conditional_t< false, Other, const_iterator > > find(const Other &value) const
Finds an element with a given value.
dense_set(const dense_set &)=default
Default copy constructor.
dense_set(dense_set &&) noexcept=default
Default move constructor.
const_local_iterator end(const size_type index) const
Returns an iterator to the end of a given bucket.
void max_load_factor(const float value)
Sets the desired maximum average number of elements per bucket.
float load_factor() const
Returns the average number of elements per bucket.
size_type erase(const value_type &value)
Removes the element associated with a given value.
std::pair< iterator, bool > insert(value_type &&value)
Inserts an element into the container, if it does not exist.
size_type max_bucket_count() const
Returns the maximum number of buckets.
dense_set(const allocator_type &allocator)
Constructs an empty container with a given allocator.
const_reverse_iterator rbegin() const noexcept
Returns a reverse iterator to the beginning.
dense_set()
Default constructor.
const_iterator end() const noexcept
Returns an iterator to the end.
dense_set & operator=(const dense_set &)=default
Default copy assignment operator.
dense_set(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 pos)
Removes an element from a given position.
std::enable_if_t< is_transparent_v< hasher > &&is_transparent_v< key_equal >, std::conditional_t< false, Other, iterator > > find(const Other &value)
Finds an element that compares equivalent to a given value.
void rehash(const size_type cnt)
Reserves at least the specified number of buckets and regenerates the hash table.
const_reverse_iterator crend() const noexcept
Returns a reverse iterator to the end.
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).
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
void insert(It first, It last)
Inserts elements into the container, if they do not exist.
reverse_iterator rend() noexcept
Returns a reverse iterator to the end.
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, std::pair< const_iterator, const_iterator > > > equal_range(const Other &value) const
Returns a range containing all elements with a given value.
std::pair< const_iterator, const_iterator > equal_range(const value_type &value) const
Returns a range containing all elements with a given value.
const_local_iterator begin(const size_type index) const
Returns an iterator to the beginning of a given bucket.
local_iterator begin(const size_type index)
Returns an iterator to the beginning of a given bucket.
const_local_iterator cbegin(const size_type index) const
Returns an iterator to the beginning of a given bucket.
bool contains(const value_type &value) const
Checks if the container contains an element with a given value.
iterator begin() noexcept
Returns an iterator to the beginning.
EnTT default namespace.
Definition dense_map.hpp:22
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:63
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.