1#ifndef ENTT_CONTAINER_DENSE_MAP_HPP
2#define ENTT_CONTAINER_DENSE_MAP_HPP
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"
27static constexpr std::size_t dense_map_placeholder_position = (std::numeric_limits<std::size_t>::max)();
29template<
typename Key,
typename Type>
30struct dense_map_node final {
31 using value_type = std::pair<Key, Type>;
33 template<
typename... Args>
34 dense_map_node(
const std::size_t pos, Args &&...args)
36 element{std::forward<Args>(args)...} {}
38 template<
typename Allocator,
typename... Args>
39 dense_map_node(std::allocator_arg_t,
const Allocator &allocator,
const std::size_t pos, Args &&...args)
43 template<
typename Allocator>
44 dense_map_node(std::allocator_arg_t,
const Allocator &allocator,
const dense_map_node &other)
48 template<
typename Allocator>
49 dense_map_node(std::allocator_arg_t,
const Allocator &allocator, dense_map_node &&other)
58class dense_map_iterator final {
60 friend class dense_map_iterator;
62 using first_type =
decltype(std::as_const(std::declval<It>()->element.first));
63 using second_type =
decltype((std::declval<It>()->element.second));
66 using value_type = std::pair<first_type, second_type>;
68 using reference = value_type;
69 using difference_type = std::ptrdiff_t;
70 using iterator_category = std::input_iterator_tag;
71 using iterator_concept = std::random_access_iterator_tag;
73 constexpr dense_map_iterator() noexcept
76 constexpr dense_map_iterator(
const It iter) noexcept
79 template<
typename Other,
typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
80 constexpr dense_map_iterator(
const dense_map_iterator<Other> &other) noexcept
83 constexpr dense_map_iterator &operator++()
noexcept {
87 constexpr dense_map_iterator operator++(
int)
noexcept {
88 const dense_map_iterator orig = *
this;
89 return ++(*this), orig;
92 constexpr dense_map_iterator &operator--()
noexcept {
96 constexpr dense_map_iterator operator--(
int)
noexcept {
97 const dense_map_iterator orig = *
this;
98 return operator--(), orig;
101 constexpr dense_map_iterator &operator+=(
const difference_type value)
noexcept {
106 constexpr dense_map_iterator
operator+(
const difference_type value)
const noexcept {
107 dense_map_iterator copy = *
this;
108 return (copy += value);
111 constexpr dense_map_iterator &operator-=(
const difference_type value)
noexcept {
112 return (*
this += -value);
115 constexpr dense_map_iterator operator-(
const difference_type value)
const noexcept {
116 return (*
this + -value);
119 [[nodiscard]]
constexpr reference operator[](
const difference_type value)
const noexcept {
120 return {it[value].element.first, it[value].element.second};
123 [[nodiscard]]
constexpr pointer operator->()
const noexcept {
127 [[nodiscard]]
constexpr reference operator*()
const noexcept {
128 return operator[](0);
131 template<
typename Lhs,
typename Rhs>
132 friend constexpr std::ptrdiff_t operator-(
const dense_map_iterator<Lhs> &,
const dense_map_iterator<Rhs> &)
noexcept;
134 template<
typename Lhs,
typename Rhs>
135 friend constexpr bool operator==(
const dense_map_iterator<Lhs> &,
const dense_map_iterator<Rhs> &)
noexcept;
137 template<
typename Lhs,
typename Rhs>
138 friend constexpr bool operator<(
const dense_map_iterator<Lhs> &,
const dense_map_iterator<Rhs> &)
noexcept;
144template<
typename Lhs,
typename Rhs>
145[[nodiscard]]
constexpr std::ptrdiff_t operator-(
const dense_map_iterator<Lhs> &lhs,
const dense_map_iterator<Rhs> &rhs)
noexcept {
146 return lhs.it - rhs.it;
149template<
typename Lhs,
typename Rhs>
150[[nodiscard]]
constexpr bool operator==(
const dense_map_iterator<Lhs> &lhs,
const dense_map_iterator<Rhs> &rhs)
noexcept {
151 return lhs.it == rhs.it;
154template<
typename Lhs,
typename Rhs>
155[[nodiscard]]
constexpr bool operator!=(
const dense_map_iterator<Lhs> &lhs,
const dense_map_iterator<Rhs> &rhs)
noexcept {
156 return !(lhs == rhs);
159template<
typename Lhs,
typename Rhs>
160[[nodiscard]]
constexpr bool operator<(
const dense_map_iterator<Lhs> &lhs,
const dense_map_iterator<Rhs> &rhs)
noexcept {
161 return lhs.it < rhs.it;
164template<
typename Lhs,
typename Rhs>
165[[nodiscard]]
constexpr bool operator>(
const dense_map_iterator<Lhs> &lhs,
const dense_map_iterator<Rhs> &rhs)
noexcept {
169template<
typename Lhs,
typename Rhs>
170[[nodiscard]]
constexpr bool operator<=(
const dense_map_iterator<Lhs> &lhs,
const dense_map_iterator<Rhs> &rhs)
noexcept {
174template<
typename Lhs,
typename Rhs>
175[[nodiscard]]
constexpr bool operator>=(
const dense_map_iterator<Lhs> &lhs,
const dense_map_iterator<Rhs> &rhs)
noexcept {
180class dense_map_local_iterator final {
182 friend class dense_map_local_iterator;
184 using first_type =
decltype(std::as_const(std::declval<It>()->element.first));
185 using second_type =
decltype((std::declval<It>()->element.second));
188 using value_type = std::pair<first_type, second_type>;
190 using reference = value_type;
191 using difference_type = std::ptrdiff_t;
192 using iterator_category = std::input_iterator_tag;
193 using iterator_concept = std::forward_iterator_tag;
195 constexpr dense_map_local_iterator()
noexcept =
default;
197 constexpr dense_map_local_iterator(It iter,
const std::size_t pos) noexcept
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
204 offset{other.offset} {}
206 constexpr dense_map_local_iterator &operator++()
noexcept {
207 return (offset = it[
static_cast<typename It::difference_type
>(offset)].next), *
this;
210 constexpr dense_map_local_iterator operator++(
int)
noexcept {
211 const dense_map_local_iterator orig = *
this;
212 return ++(*this), orig;
215 [[nodiscard]]
constexpr pointer operator->()
const noexcept {
219 [[nodiscard]]
constexpr reference operator*()
const noexcept {
220 const auto idx =
static_cast<typename It::difference_type
>(offset);
221 return {it[idx].element.first, it[idx].element.second};
224 [[nodiscard]]
constexpr std::size_t index()
const noexcept {
230 std::size_t offset{dense_map_placeholder_position};
233template<
typename Lhs,
typename Rhs>
234[[nodiscard]]
constexpr bool operator==(
const dense_map_local_iterator<Lhs> &lhs,
const dense_map_local_iterator<Rhs> &rhs)
noexcept {
235 return lhs.index() == rhs.index();
238template<
typename Lhs,
typename Rhs>
239[[nodiscard]]
constexpr bool operator!=(
const dense_map_local_iterator<Lhs> &lhs,
const dense_map_local_iterator<Rhs> &rhs)
noexcept {
240 return !(lhs == rhs);
259template<
typename Key,
typename Type,
typename Hash,
typename KeyEqual,
typename Allocator>
261 static constexpr float default_threshold = 0.875f;
262 static constexpr std::size_t minimum_capacity = 8u;
263 static constexpr std::size_t placeholder_position = internal::dense_map_placeholder_position;
265 using node_type = internal::dense_map_node<Key, Type>;
266 using alloc_traits = std::allocator_traits<Allocator>;
267 static_assert(std::is_same_v<typename alloc_traits::value_type, std::pair<const Key, Type>>,
"Invalid value type");
268 using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
269 using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
271 template<
typename Other>
272 [[nodiscard]] std::size_t key_to_bucket(
const Other &key)
const noexcept {
277 template<
typename Other>
278 [[nodiscard]]
auto constrained_find(
const Other &key,
const std::size_t
bucket) {
279 for(
auto offset = sparse.first()[
bucket]; offset != placeholder_position; offset = packed.first()[offset].next) {
280 if(packed.second()(packed.first()[offset].element.first, key)) {
281 return begin() +
static_cast<typename iterator::difference_type
>(offset);
288 template<
typename Other>
289 [[nodiscard]]
auto constrained_find(
const Other &key,
const std::size_t
bucket)
const {
290 for(
auto offset = sparse.first()[
bucket]; offset != placeholder_position; offset = packed.first()[offset].next) {
291 if(packed.second()(packed.first()[offset].element.first, key)) {
292 return cbegin() +
static_cast<typename const_iterator::difference_type
>(offset);
299 template<
typename Other,
typename... Args>
300 [[nodiscard]]
auto insert_or_do_nothing(Other &&key, Args &&...args) {
301 const auto index = key_to_bucket(key);
303 if(
auto it = constrained_find(key, index); it !=
end()) {
304 return std::make_pair(it,
false);
307 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)...));
308 sparse.first()[index] = packed.first().size() - 1u;
309 rehash_if_required();
311 return std::make_pair(--
end(),
true);
314 template<
typename Other,
typename Arg>
315 [[nodiscard]]
auto insert_or_overwrite(Other &&key, Arg &&value) {
316 const auto index = key_to_bucket(key);
318 if(
auto it = constrained_find(key, index); it !=
end()) {
319 it->second = std::forward<Arg>(value);
320 return std::make_pair(it,
false);
323 packed.first().emplace_back(sparse.first()[index], std::forward<Other>(key), std::forward<Arg>(value));
324 sparse.first()[index] = packed.first().size() - 1u;
325 rehash_if_required();
327 return std::make_pair(--
end(),
true);
330 void move_and_pop(
const std::size_t pos) {
331 if(
const auto last =
size() - 1u; pos != last) {
332 size_type *curr = &sparse.first()[key_to_bucket(packed.first().back().element.first)];
333 packed.first()[pos] = std::move(packed.first().back());
334 for(; *curr != last; curr = &packed.first()[*curr].next) {}
338 packed.first().pop_back();
341 void rehash_if_required() {
365 using iterator = internal::dense_map_iterator<typename packed_container_type::iterator>;
367 using const_iterator = internal::dense_map_iterator<typename packed_container_type::const_iterator>;
369 using local_iterator = internal::dense_map_local_iterator<typename packed_container_type::iterator>;
371 using const_local_iterator = internal::dense_map_local_iterator<typename packed_container_type::const_iterator>;
412 : sparse{allocator, hash},
413 packed{allocator, equal} {
426 : sparse{std::piecewise_construct, std::forward_as_tuple(other.sparse.first(), allocator), std::forward_as_tuple(other.sparse.second())},
427 packed{std::piecewise_construct, std::forward_as_tuple(other.packed.first(), allocator), std::forward_as_tuple(other.packed.second())},
428 threshold{other.threshold} {}
439 : sparse{std::piecewise_construct, std::forward_as_tuple(std::move(other.sparse.first()), allocator), std::forward_as_tuple(std::move(other.sparse.second()))},
440 packed{std::piecewise_construct, std::forward_as_tuple(std::move(other.packed.first()), allocator), std::forward_as_tuple(std::move(other.packed.second()))},
441 threshold{other.threshold} {}
464 swap(sparse, other.sparse);
465 swap(packed, other.packed);
466 swap(threshold, other.threshold);
474 return sparse.first().get_allocator();
485 return packed.first().begin();
495 return packed.first().begin();
504 return packed.first().end();
514 return packed.first().end();
521 [[nodiscard]]
bool empty() const noexcept {
522 return packed.first().empty();
530 return packed.first().size();
538 return packed.first().max_size();
543 sparse.first().clear();
544 packed.first().clear();
556 return insert_or_do_nothing(value.first, value.second);
561 return insert_or_do_nothing(std::move(value.first), std::move(value.second));
568 template<
typename Arg>
569 std::enable_if_t<std::is_constructible_v<value_type, Arg &&>, std::pair<iterator, bool>>
571 return insert_or_do_nothing(std::forward<Arg>(value).first, std::forward<Arg>(value).second);
580 template<
typename It>
582 for(; first != last; ++first) {
596 template<
typename Arg>
598 return insert_or_overwrite(key, std::forward<Arg>(value));
602 template<
typename Arg>
604 return insert_or_overwrite(std::move(key), std::forward<Arg>(value));
620 template<
typename... Args>
621 std::pair<iterator, bool>
emplace([[maybe_unused]] Args &&...args) {
622 if constexpr(
sizeof...(Args) == 0u) {
623 return insert_or_do_nothing(
key_type{});
624 }
else if constexpr(
sizeof...(Args) == 1u) {
625 return insert_or_do_nothing(std::forward<Args>(args).first..., std::forward<Args>(args).second...);
626 }
else if constexpr(
sizeof...(Args) == 2u) {
627 return insert_or_do_nothing(std::forward<Args>(args)...);
629 auto &node = packed.first().emplace_back(packed.first().size(), std::forward<Args>(args)...);
630 const auto index = key_to_bucket(node.element.first);
632 if(
auto it = constrained_find(node.element.first, index); it !=
end()) {
633 packed.first().pop_back();
634 return std::make_pair(it,
false);
637 std::swap(node.next, sparse.first()[index]);
638 rehash_if_required();
640 return std::make_pair(--
end(),
true);
655 template<
typename... Args>
657 return insert_or_do_nothing(key, std::forward<Args>(args)...);
661 template<
typename... Args>
663 return insert_or_do_nothing(std::move(key), std::forward<Args>(args)...);
672 const auto diff = pos -
cbegin();
674 return begin() + diff;
684 const auto dist = first -
cbegin();
686 for(
auto from = last -
cbegin(); from != dist; --from) {
687 erase(packed.first()[
static_cast<size_type>(from) - 1u].element.first);
690 return (
begin() + dist);
699 for(
size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != placeholder_position; curr = &packed.first()[*curr].next) {
700 if(packed.second()(packed.first()[*curr].element.first, key)) {
701 const auto index = *curr;
702 *curr = packed.first()[*curr].next;
718 ENTT_ASSERT(it !=
end(),
"Invalid key");
725 ENTT_ASSERT(it !=
cend(),
"Invalid key");
735 template<
typename Other>
736 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> &&
is_transparent_v<key_equal>, std::conditional_t<false, Other, mapped_type const &>>
737 at(
const Other &key)
const {
739 ENTT_ASSERT(it !=
cend(),
"Invalid key");
744 template<
typename Other>
745 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> &&
is_transparent_v<key_equal>, std::conditional_t<false, Other, mapped_type &>>
746 at(
const Other &key) {
748 ENTT_ASSERT(it !=
end(),
"Invalid key");
758 return insert_or_do_nothing(key).first->second;
767 return insert_or_do_nothing(std::move(key)).first->second;
785 template<
typename Other>
786 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> &&
is_transparent_v<key_equal>, std::conditional_t<false, Other, size_type>>
798 return constrained_find(key, key_to_bucket(key));
803 return constrained_find(key, key_to_bucket(key));
814 template<
typename Other>
815 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> &&
is_transparent_v<key_equal>, std::conditional_t<false, Other, iterator>>
817 return constrained_find(key, key_to_bucket(key));
821 template<
typename Other>
822 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> &&
is_transparent_v<key_equal>, std::conditional_t<false, Other, const_iterator>>
824 return constrained_find(key, key_to_bucket(key));
834 const auto it =
find(key);
835 return {it, it + !(it ==
end())};
840 const auto it =
find(key);
841 return {it, it + !(it ==
cend())};
852 template<
typename Other>
853 [[nodiscard]] std::enable_if_t<is_transparent_v<hasher> &&
is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<iterator, iterator>>>
855 const auto it =
find(key);
856 return {it, it + !(it ==
end())};
860 template<
typename Other>
861 [[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>>>
863 const auto it =
find(key);
864 return {it, it + !(it ==
cend())};
883 template<
typename Other>
895 return {packed.first().begin(), sparse.first()[index]};
913 return {packed.first().begin(), sparse.first()[index]};
948 return sparse.first().size();
956 return sparse.first().max_size();
974 return key_to_bucket(key);
998 ENTT_ASSERT(value > 0.f,
"Invalid load factor");
1009 auto value = cnt > minimum_capacity ? cnt : minimum_capacity;
1011 value = value > cap ? value : cap;
1014 sparse.first().resize(sz);
1016 for(
auto &&elem: sparse.first()) {
1017 elem = placeholder_position;
1021 const auto index = key_to_bucket(packed.first()[pos].element.first);
1022 packed.first()[pos].next = std::exchange(sparse.first()[index], pos);
1033 packed.first().reserve(cnt);
1042 return sparse.second();
1050 return packed.second();
1056 float threshold{default_threshold};
1064template<
typename Key,
typename Value,
typename Allocator>
1065struct uses_allocator<entt::internal::dense_map_node<Key, Value>, Allocator>
1066 : std::true_type {};
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.
std::enable_if_t< is_transparent_v< hasher > &&is_transparent_v< key_equal >, std::conditional_t< false, Other, mapped_type & > > at(const Other &key)
Accesses a given element with bounds checking.
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
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.
std::enable_if_t< is_transparent_v< hasher > &&is_transparent_v< key_equal >, std::conditional_t< false, Other, mapped_type const & > > at(const Other &key) const
Accesses a given element with bounds checking.
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.
std::ptrdiff_t difference_type
Signed integer type.
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
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).
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...
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.