1#ifndef LIBSBX_CONTAINERS_DENSE_MAP_HPP_
2#define LIBSBX_CONTAINERS_DENSE_MAP_HPP_
9#include <libsbx/utility/fast_mod.hpp>
10#include <libsbx/utility/assert.hpp>
12#include <libsbx/memory/iterable_adaptor.hpp>
13#include <libsbx/memory/concepts.hpp>
15#include <libsbx/containers/compressed_pair.hpp>
17namespace sbx::containers {
21template<
typename Key,
typename Type>
24 using value_type = std::pair<Key, Type>;
25 using size_type = std::size_t;
27 template<
typename... Args>
29 : element{std::forward<Args>(args)...},
32 template<
typename Allocator,
typename... Args>
33 dense_map_node(std::allocator_arg_t,
const Allocator& allocator,
const size_type position, Args&&... args)
34 : element{std::make_obj_using_allocator<value_type>(allocator, std::forward<Args>(args)...)},
37 template<
typename Allocator>
39 : element{std::make_obj_using_allocator<value_type>(allocator, other.element)},
42 template<
typename Allocator>
44 : element{std::make_obj_using_allocator<value_type>(allocator, std::move(other.element))},
52template<
typename Iterator>
58 template<
typename Lhs,
typename Rhs>
61 template<
typename Lhs,
typename Rhs>
64 template<
typename Lhs,
typename Rhs>
67 using first_type =
decltype(std::as_const(std::declval<Iterator>()->element.first));
68 using second_type =
decltype((std::declval<Iterator>()->element.second));
72 using value_type = std::pair<first_type, second_type>;
74 using reference = value_type;
75 using difference_type = std::ptrdiff_t;
76 using iterator_category = std::input_iterator_tag;
77 using iterator_concept = std::random_access_iterator_tag;
83 : _iterator{iterator} {}
85 template<
typename Other,
typename = std::enable_if_t<!std::is_same_v<Iterator, Other> && std::is_constructible_v<Iterator, Other>>>
87 : _iterator{other._iterator} {}
95 const auto original = *
this;
106 const auto original = *
this;
111 constexpr auto operator+=(
const difference_type value)
noexcept ->
dense_map_iterator& {
116 constexpr auto operator+(
const difference_type value)
const noexcept ->
dense_map_iterator {
118 return (copy += value);
121 constexpr auto operator-=(
const difference_type value)
noexcept ->
dense_map_iterator& {
122 return (*
this += -value);
125 constexpr auto operator-(
const difference_type value)
const noexcept ->
dense_map_iterator {
126 return (*
this + -value);
129 [[nodiscard]]
constexpr auto operator[](
const difference_type value)
const noexcept -> reference {
130 return {_iterator[value].element.first, _iterator[value].element.second};
133 [[nodiscard]]
constexpr auto operator->()
const noexcept ->
pointer {
137 [[nodiscard]]
constexpr auto operator*()
const noexcept -> reference {
138 return operator[](0);
147template<
typename Lhs,
typename Rhs>
149 return lhs._iterator - rhs._iterator;
152template<
typename Lhs,
typename Rhs>
153[[nodiscard]]
constexpr auto operator==(
const dense_map_iterator<Lhs>& lhs,
const dense_map_iterator<Rhs>& rhs)
noexcept ->
bool {
154 return lhs._iterator == rhs._iterator;
157template<
typename Lhs,
typename Rhs>
158[[nodiscard]]
constexpr auto operator<=>(
const dense_map_iterator<Lhs>& lhs,
const dense_map_iterator<Rhs>& rhs)
noexcept -> std::strong_ordering {
159 return lhs._iterator <=> rhs._iterator;
162template<
typename Iterator>
168 using first_type =
decltype(std::as_const(std::declval<Iterator>()->element.first));
169 using second_type =
decltype((std::declval<Iterator>()->element.second));
173 using value_type = std::pair<first_type, second_type>;
174 using size_type = std::size_t;
176 using reference = value_type;
177 using difference_type = std::ptrdiff_t;
178 using iterator_category = std::input_iterator_tag;
179 using iterator_concept = std::forward_iterator_tag;
186 : _iterator{iterator},
189 template<
typename Other,
typename = std::enable_if_t<!std::is_same_v<Iterator, Other> && std::is_constructible_v<Iterator, Other>>>
191 : _iterator{other._iterator},
192 _offset{other._offset} {}
195 return (_offset = _iterator[
static_cast<typename Iterator::difference_type
>(_offset)].next), *
this;
199 const auto original = *
this;
204 [[nodiscard]]
constexpr auto operator->()
const noexcept ->
pointer {
208 [[nodiscard]]
constexpr auto operator*()
const noexcept -> reference {
209 const auto index =
static_cast<typename Iterator::difference_type
>(_offset);
210 return {_iterator[index].element.first, _iterator[index].element.second};
213 [[nodiscard]]
constexpr auto index()
const noexcept -> size_type {
224template<
typename Lhs,
typename Rhs>
226 return lhs.index() == rhs.index();
231template<
typename Key,
typename Type,
typename Hash = std::hash<Key>,
typename KeyEqual = std::equal_to<Key>,
typename Allocator = std::allocator<std::pair<Key, Type>>>
234 static constexpr auto default_threshold = std::float_t{0.875f};
235 static constexpr auto minimum_capacity = std::size_t{8};
238 using allocator_traits = std::allocator_traits<Allocator>;
240 using sparse_container_type = std::vector<std::size_t, memory::rebound_allocator_t<Allocator, std::size_t>>;
241 using dense_container_type = std::vector<node_type, memory::rebound_allocator_t<Allocator, node_type>>;
245 using allocator_type = Allocator;
246 using value_type = std::pair<Key, Type>;
247 using key_type = Key;
248 using mapped_type = Type;
249 using size_type = std::size_t;
250 using difference_type = std::ptrdiff_t;
252 using key_equal = KeyEqual;
261 explicit dense_map(
const allocator_type& allocator)
262 :
dense_map{minimum_capacity, hasher{}, key_equal{}, allocator} { }
264 dense_map(
const size_type count,
const allocator_type& allocator)
265 :
dense_map{count, hasher{}, key_equal{}, allocator} { }
267 dense_map(
const size_type count,
const hasher& hash,
const allocator_type& allocator)
268 :
dense_map{count, hash, key_equal{}, allocator} { }
270 explicit dense_map(
const size_type count,
const hasher& hash = hasher{},
const key_equal& equal = key_equal{},
const allocator_type& allocator = allocator_type{})
271 : _sparse{allocator, hash},
272 _dense{allocator, equal},
273 _threshold{default_threshold} {
280 : _sparse{std::piecewise_construct, std::forward_as_tuple(other._sparse.first(), allocator), std::forward_as_tuple(other._sparse.second())},
281 _dense{std::piecewise_construct, std::forward_as_tuple(other._dense.first(), allocator), std::forward_as_tuple(other._dense.second())},
282 _threshold{other._threshold} { }
287 : _sparse{std::piecewise_construct, std::forward_as_tuple(std::move(other._sparse.first()), allocator), std::forward_as_tuple(std::move(other._sparse.second()))},
288 _dense{std::piecewise_construct, std::forward_as_tuple(std::move(other._dense.first()), allocator), std::forward_as_tuple(std::move(other._dense.second()))},
289 _threshold{other._threshold} { }
297 auto swap(
dense_map& other)
noexcept ->
void {
299 swap(_sparse, other._sparse);
300 swap(_dense, other._dense);
301 swap(_threshold, other._threshold);
304 [[nodiscard]]
constexpr auto get_allocator()
const noexcept -> allocator_type {
305 return _sparse.first().get_allocator();
309 return _dense.first().begin();
316 [[nodiscard]]
auto begin()
noexcept ->
iterator {
317 return _dense.first().begin();
321 auto& first = _dense.first();
329 [[nodiscard]]
auto end()
noexcept ->
iterator {
330 return _dense.first().end();
333 [[nodiscard]]
bool empty()
const noexcept {
334 return _dense.first().empty();
337 [[nodiscard]]
auto size()
const noexcept -> size_type {
338 return _dense.first().size();
341 [[nodiscard]]
auto max_size()
const noexcept -> size_type {
342 return _dense.first().max_size();
345 auto clear()
noexcept ->
void {
346 _sparse.first().clear();
347 _dense.first().clear();
351 auto insert(
const value_type& value) -> std::pair<iterator, bool> {
352 return _insert_or_do_nothing(value.first, value.second);
355 auto insert(value_type&& value) -> std::pair<iterator, bool> {
356 return _insert_or_do_nothing(std::move(value.first), std::move(value.second));
359 template<
typename Arg>
360 requires(std::is_constructible_v<value_type, Arg&&>)
361 auto insert(Arg&& value) -> std::pair<iterator, bool> {
362 return _insert_or_do_nothing(std::forward<Arg>(value).first, std::forward<Arg>(value).second);
365 template<
typename... Args>
366 auto emplace([[maybe_unused]] Args&&... args) -> std::pair<iterator, bool> {
367 if constexpr (
sizeof...(Args) == 0u) {
368 return _insert_or_do_nothing(key_type{});
369 }
else if constexpr (
sizeof...(Args) == 1u) {
370 return _insert_or_do_nothing(std::forward<Args>(args).first..., std::forward<Args>(args).second...);
371 }
else if constexpr (
sizeof...(Args) == 2u) {
372 return _insert_or_do_nothing(std::forward<Args>(args)...);
374 auto&
node = _dense.first().emplace_back(_dense.first().size(), std::forward<Args>(args)...);
375 const auto index = _key_to_bucket(
node.element.first);
377 if (
auto it = _constrained_find(
node.element.first, index); it != end()) {
378 _dense.first().pop_back();
379 return std::make_pair(it,
false);
382 std::swap(
node.next, _sparse.first()[index]);
383 _rehash_if_required();
385 return std::make_pair(--end(),
true);
390 const auto offset = position - cbegin();
391 erase(position->first);
392 return begin() + offset;
395 auto erase(
const key_type& key) ->
bool {
396 for (
auto* current = &_sparse.first()[key_to_bucket(key)]; *current != (std::numeric_limits<size_type>::max)(); current = &_dense.first()[*current].next) {
397 if (_dense.second()(_dense.first()[*current].element.first, key)) {
398 const auto index = *current;
399 *current = _dense.first()[*current].next;
400 _move_and_pop(index);
409 [[nodiscard]]
auto at(
const key_type& key) -> mapped_type& {
411 utility::assert_that(it != end(),
"Invalid key");
417 [[nodiscard]]
auto at(
const key_type &key)
const ->
const mapped_type& {
419 utility::assert_that(it != cend(),
"Invalid key");
423 [[nodiscard]]
auto operator[](
const key_type& key) -> mapped_type& {
424 return _insert_or_do_nothing(key).first->second;
427 [[nodiscard]]
auto operator[](key_type&& key) -> mapped_type& {
428 return _insert_or_do_nothing(std::move(key)).first->second;
431 [[nodiscard]]
auto find(
const key_type& key) -> iterator {
432 return _constrained_find(key, _key_to_bucket(key));
435 [[nodiscard]]
auto find(
const key_type& key)
const -> const_iterator {
436 return _constrained_find(key, _key_to_bucket(key));
439 [[nodiscard]]
auto contains(
const key_type& key)
const ->
bool {
440 return find(key) != cend();
443 [[nodiscard]]
auto cbegin(
const size_type index)
const -> const_local_iterator {
444 return {_dense.first().begin(), _sparse.first()[index]};
447 [[nodiscard]]
auto begin(
const size_type index)
const -> const_local_iterator {
448 return cbegin(index);
451 [[nodiscard]]
auto begin(
const size_type index) -> local_iterator {
452 return {_dense.first().begin(), _sparse.first()[index]};
455 [[nodiscard]]
auto cend([[maybe_unused]]
const size_type index)
const -> const_local_iterator {
456 return {_dense.first().begin(), (std::numeric_limits<size_type>::max)()};
459 [[nodiscard]]
auto end(
const size_type index)
const -> const_local_iterator {
463 [[nodiscard]]
auto end([[maybe_unused]]
const size_type index) -> local_iterator {
464 return {_dense.first().begin(), (std::numeric_limits<size_type>::max)()};
467 [[nodiscard]]
auto max_load_factor() const -> std::float_t {
471 auto set_max_load_factor(
const std::float_t value) ->
void {
472 utility::assert_that(value > 0.f,
"Invalid load factor");
477 [[nodiscard]]
auto bucket_count() const -> size_type {
478 return _sparse.first().size();
481 void rehash(
const size_type count) {
482 auto value = count > minimum_capacity ? count : minimum_capacity;
483 const auto capacity =
static_cast<size_type
>(
static_cast<std::float_t
>(size()) / max_load_factor());
484 value = value > capacity ? value : capacity;
486 if (
const auto length = std::bit_ceil(value); length != bucket_count()) {
487 _sparse.first().resize(length);
489 for (
auto&& elem: _sparse.first()) {
490 elem = (std::numeric_limits<size_type>::max)();
493 for (
auto position = 0u, last = size(); position < last; ++position) {
494 const auto index = _key_to_bucket(_dense.first()[position].element.first);
495 _dense.first()[position].next = std::exchange(_sparse.first()[index], position);
500 void reserve(
const size_type count) {
501 _dense.first().reserve(count);
502 rehash(
static_cast<size_type
>(std::ceil(
static_cast<std::float_t
>(count) / max_load_factor())));
505 [[nodiscard]]
auto hash_function() const -> hasher {
506 return _sparse.second();
509 [[nodiscard]]
auto key_eq() const -> key_equal {
510 return _dense.second();
515 template<
typename Other>
516 [[nodiscard]]
auto _key_to_bucket(
const Other& key)
const noexcept -> size_type {
517 return utility::fast_mod(
static_cast<size_type
>(_sparse.second()(key)), bucket_count());
520 template<
typename Other>
521 [[nodiscard]]
auto _constrained_find(
const Other& key,
const size_type bucket) -> iterator {
522 for (
auto it = begin(bucket), last = end(bucket); it != last; ++it) {
523 if (_dense.second()(it->first, key)) {
524 return begin() +
static_cast<difference_type
>(it.index());
531 template<
typename Other>
532 [[nodiscard]]
auto _constrained_find(
const Other& key,
const size_type bucket)
const -> const_iterator {
533 for (
auto it = cbegin(bucket), last = cend(bucket); it != last; ++it) {
534 if (_dense.second()(it->first, key)) {
535 return cbegin() +
static_cast<difference_type
>(it.index());
542 template<
typename Other,
typename... Args>
543 [[nodiscard]]
auto _insert_or_do_nothing(Other &&key, Args &&...args) -> std::pair<iterator, bool> {
544 const auto index = _key_to_bucket(key);
546 if (
auto it = _constrained_find(key, index); it != end()) {
547 return std::make_pair(it,
false);
550 _dense.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)...));
551 _sparse.first()[index] = _dense.first().size() - 1u;
552 _rehash_if_required();
554 return std::make_pair(--end(),
true);
557 template<
typename Other,
typename Arg>
558 [[nodiscard]]
auto _insert_or_overwrite(Other&& key, Arg&& value) -> std::pair<iterator, bool> {
559 const auto index = key_to_bucket(key);
561 if (
auto it = _constrained_find(key, index); it != end()) {
562 it->second = std::forward<Arg>(value);
563 return std::make_pair(it,
false);
566 _dense.first().emplace_back(_sparse.first()[index], std::forward<Other>(key), std::forward<Arg>(value));
567 _sparse.first()[index] = _dense.first().size() - 1u;
568 _rehash_if_required();
570 return std::make_pair(--end(),
true);
573 auto _move_and_pop(
const size_type position) ->
void {
574 if (
const auto last = size() - 1u; position != last) {
575 auto* current = &_sparse.first()[_key_to_bucket(_dense.first().back().element.first)];
576 _dense.first()[position] = std::move(_dense.first().back());
577 for (; *current != last; current = &_dense.first()[*current].next) {}
581 _dense.first().pop_back();
584 auto _rehash_if_required() ->
void {
585 if (
const auto count = bucket_count(); size() >
static_cast<size_type
>(
static_cast<std::float_t
>(count) * max_load_factor())) {
590 compressed_pair<sparse_container_type, hasher> _sparse;
591 compressed_pair<dense_container_type, key_equal> _dense;
592 std::float_t _threshold;
598template<
typename Key,
typename Value,
typename Allocator>
599struct std::uses_allocator<sbx::containers::detail::dense_map_node<Key, Value>, Allocator> : std::true_type { };
Definition: dense_map.hpp:232
auto at(const key_type &key) const -> const mapped_type &
Definition: dense_map.hpp:417
Definition: dense_map.hpp:53
Definition: dense_map.hpp:163
Definition: dense_map.hpp:22