2#ifndef LIBSBX_CONTAINERS_DENSE_MAP_HPP_
3#define LIBSBX_CONTAINERS_DENSE_MAP_HPP_
10#include <libsbx/utility/fast_mod.hpp>
11#include <libsbx/utility/assert.hpp>
13#include <libsbx/memory/iterable_adaptor.hpp>
14#include <libsbx/memory/concepts.hpp>
16#include <libsbx/containers/compressed_pair.hpp>
18namespace sbx::containers {
22template<
typename Key,
typename Type>
25 using value_type = std::pair<Key, Type>;
26 using size_type = std::size_t;
28 template<
typename... Args>
30 : element{std::forward<Args>(args)...},
33 template<
typename Allocator,
typename... Args>
34 dense_map_node(std::allocator_arg_t,
const Allocator& allocator,
const size_type position, Args&&... args)
35 : element{std::make_obj_using_allocator<value_type>(allocator, std::forward<Args>(args)...)},
38 template<
typename Allocator>
40 : element{std::make_obj_using_allocator<value_type>(allocator, other.element)},
43 template<
typename Allocator>
45 : element{std::make_obj_using_allocator<value_type>(allocator, std::move(other.element))},
53template<
typename Iterator>
59 template<
typename Lhs,
typename Rhs>
62 template<
typename Lhs,
typename Rhs>
65 template<
typename Lhs,
typename Rhs>
68 using first_type =
decltype(std::as_const(std::declval<Iterator>()->element.first));
69 using second_type =
decltype((std::declval<Iterator>()->element.second));
73 using value_type = std::pair<first_type, second_type>;
75 using reference = value_type;
76 using difference_type = std::ptrdiff_t;
77 using iterator_category = std::input_iterator_tag;
78 using iterator_concept = std::random_access_iterator_tag;
84 : _iterator{iterator} {}
86 template<
typename Other,
typename = std::enable_if_t<!std::is_same_v<Iterator, Other> && std::is_constructible_v<Iterator, Other>>>
88 : _iterator{other._iterator} {}
96 const auto original = *
this;
107 const auto original = *
this;
112 constexpr auto operator+=(
const difference_type value)
noexcept ->
dense_map_iterator& {
117 constexpr auto operator+(
const difference_type value)
const noexcept ->
dense_map_iterator {
119 return (copy += value);
122 constexpr auto operator-=(
const difference_type value)
noexcept ->
dense_map_iterator& {
123 return (*
this += -value);
126 constexpr auto operator-(
const difference_type value)
const noexcept ->
dense_map_iterator {
127 return (*
this + -value);
130 [[nodiscard]]
constexpr auto operator[](
const difference_type value)
const noexcept -> reference {
131 return {_iterator[value].element.first, _iterator[value].element.second};
134 [[nodiscard]]
constexpr auto operator->()
const noexcept ->
pointer {
138 [[nodiscard]]
constexpr auto operator*()
const noexcept -> reference {
139 return operator[](0);
148template<
typename Lhs,
typename Rhs>
150 return lhs._iterator - rhs._iterator;
153template<
typename Lhs,
typename Rhs>
154[[nodiscard]]
constexpr auto operator==(
const dense_map_iterator<Lhs>& lhs,
const dense_map_iterator<Rhs>& rhs)
noexcept ->
bool {
155 return lhs._iterator == rhs._iterator;
158template<
typename Lhs,
typename Rhs>
159[[nodiscard]]
constexpr auto operator<=>(
const dense_map_iterator<Lhs>& lhs,
const dense_map_iterator<Rhs>& rhs)
noexcept -> std::strong_ordering {
160 return lhs._iterator <=> rhs._iterator;
163template<
typename Iterator>
169 using first_type =
decltype(std::as_const(std::declval<Iterator>()->element.first));
170 using second_type =
decltype((std::declval<Iterator>()->element.second));
174 using value_type = std::pair<first_type, second_type>;
175 using size_type = std::size_t;
177 using reference = value_type;
178 using difference_type = std::ptrdiff_t;
179 using iterator_category = std::input_iterator_tag;
180 using iterator_concept = std::forward_iterator_tag;
187 : _iterator{iterator},
190 template<
typename Other,
typename = std::enable_if_t<!std::is_same_v<Iterator, Other> && std::is_constructible_v<Iterator, Other>>>
192 : _iterator{other._iterator},
193 _offset{other._offset} {}
196 return (_offset = _iterator[
static_cast<typename Iterator::difference_type
>(_offset)].next), *
this;
200 const auto original = *
this;
205 [[nodiscard]]
constexpr auto operator->()
const noexcept ->
pointer {
209 [[nodiscard]]
constexpr auto operator*()
const noexcept -> reference {
210 const auto index =
static_cast<typename Iterator::difference_type
>(_offset);
211 return {_iterator[index].element.first, _iterator[index].element.second};
214 [[nodiscard]]
constexpr auto index()
const noexcept -> size_type {
225template<
typename Lhs,
typename Rhs>
227 return lhs.index() == rhs.index();
232template<
typename Key,
typename Type,
typename Hash = std::hash<Key>,
typename KeyEqual = std::equal_to<Key>,
typename Allocator = std::allocator<std::pair<Key, Type>>>
235 static constexpr auto default_threshold = std::float_t{0.875f};
236 static constexpr auto minimum_capacity = std::size_t{8};
239 using allocator_traits = std::allocator_traits<Allocator>;
241 using sparse_container_type = std::vector<std::size_t, memory::rebound_allocator_t<Allocator, std::size_t>>;
242 using dense_container_type = std::vector<node_type, memory::rebound_allocator_t<Allocator, node_type>>;
246 using allocator_type = Allocator;
247 using value_type = std::pair<Key, Type>;
248 using key_type = Key;
249 using mapped_type = Type;
250 using size_type = std::size_t;
251 using difference_type = std::ptrdiff_t;
253 using key_equal = KeyEqual;
262 explicit dense_map(
const allocator_type& allocator)
263 :
dense_map{minimum_capacity, hasher{}, key_equal{}, allocator} { }
265 dense_map(
const size_type count,
const allocator_type& allocator)
266 :
dense_map{count, hasher{}, key_equal{}, allocator} { }
268 dense_map(
const size_type count,
const hasher& hash,
const allocator_type& allocator)
269 :
dense_map{count, hash, key_equal{}, allocator} { }
271 explicit dense_map(
const size_type count,
const hasher& hash = hasher{},
const key_equal& equal = key_equal{},
const allocator_type& allocator = allocator_type{})
272 : _sparse{allocator, hash},
273 _dense{allocator, equal},
274 _threshold{default_threshold} {
281 : _sparse{std::piecewise_construct, std::forward_as_tuple(other._sparse.first(), allocator), std::forward_as_tuple(other._sparse.second())},
282 _dense{std::piecewise_construct, std::forward_as_tuple(other._dense.first(), allocator), std::forward_as_tuple(other._dense.second())},
283 _threshold{other._threshold} { }
288 : _sparse{std::piecewise_construct, std::forward_as_tuple(std::move(other._sparse.first()), allocator), std::forward_as_tuple(std::move(other._sparse.second()))},
289 _dense{std::piecewise_construct, std::forward_as_tuple(std::move(other._dense.first()), allocator), std::forward_as_tuple(std::move(other._dense.second()))},
290 _threshold{other._threshold} { }
298 auto swap(
dense_map& other)
noexcept ->
void {
300 swap(_sparse, other._sparse);
301 swap(_dense, other._dense);
302 swap(_threshold, other._threshold);
305 [[nodiscard]]
constexpr auto get_allocator()
const noexcept -> allocator_type {
306 return _sparse.first().get_allocator();
310 return _dense.first().begin();
317 [[nodiscard]]
auto begin()
noexcept ->
iterator {
318 return _dense.first().begin();
322 auto& first = _dense.first();
330 [[nodiscard]]
auto end()
noexcept ->
iterator {
331 return _dense.first().end();
334 [[nodiscard]]
bool empty()
const noexcept {
335 return _dense.first().empty();
338 [[nodiscard]]
auto size()
const noexcept -> size_type {
339 return _dense.first().size();
342 [[nodiscard]]
auto max_size()
const noexcept -> size_type {
343 return _dense.first().max_size();
346 auto clear()
noexcept ->
void {
347 _sparse.first().clear();
348 _dense.first().clear();
352 auto insert(
const value_type& value) -> std::pair<iterator, bool> {
353 return _insert_or_do_nothing(value.first, value.second);
356 auto insert(value_type&& value) -> std::pair<iterator, bool> {
357 return _insert_or_do_nothing(std::move(value.first), std::move(value.second));
360 template<
typename Arg>
361 requires(std::is_constructible_v<value_type, Arg&&>)
362 auto insert(Arg&& value) -> std::pair<iterator, bool> {
363 return _insert_or_do_nothing(std::forward<Arg>(value).first, std::forward<Arg>(value).second);
366 template<
typename... Args>
367 auto emplace([[maybe_unused]] Args&&... args) -> std::pair<iterator, bool> {
368 if constexpr (
sizeof...(Args) == 0u) {
369 return _insert_or_do_nothing(key_type{});
370 }
else if constexpr (
sizeof...(Args) == 1u) {
371 return _insert_or_do_nothing(std::forward<Args>(args).first..., std::forward<Args>(args).second...);
372 }
else if constexpr (
sizeof...(Args) == 2u) {
373 return _insert_or_do_nothing(std::forward<Args>(args)...);
375 auto&
node = _dense.first().emplace_back(_dense.first().size(), std::forward<Args>(args)...);
376 const auto index = _key_to_bucket(
node.element.first);
378 if (
auto it = _constrained_find(
node.element.first, index); it != end()) {
379 _dense.first().pop_back();
380 return std::make_pair(it,
false);
383 std::swap(
node.next, _sparse.first()[index]);
384 _rehash_if_required();
386 return std::make_pair(--end(),
true);
391 const auto offset = position - cbegin();
392 erase(position->first);
393 return begin() + offset;
396 auto erase(
const key_type& key) ->
bool {
397 for (
auto* current = &_sparse.first()[key_to_bucket(key)]; *current != (std::numeric_limits<size_type>::max)(); current = &_dense.first()[*current].next) {
398 if (_dense.second()(_dense.first()[*current].element.first, key)) {
399 const auto index = *current;
400 *current = _dense.first()[*current].next;
401 _move_and_pop(index);
410 [[nodiscard]]
auto at(
const key_type& key) -> mapped_type& {
412 utility::assert_that(it != end(),
"Invalid key");
418 [[nodiscard]]
auto at(
const key_type &key)
const ->
const mapped_type& {
420 utility::assert_that(it != cend(),
"Invalid key");
424 [[nodiscard]]
auto operator[](
const key_type& key) -> mapped_type& {
425 return _insert_or_do_nothing(key).first->second;
428 [[nodiscard]]
auto operator[](key_type&& key) -> mapped_type& {
429 return _insert_or_do_nothing(std::move(key)).first->second;
432 [[nodiscard]]
auto find(
const key_type& key) -> iterator {
433 return _constrained_find(key, _key_to_bucket(key));
436 [[nodiscard]]
auto find(
const key_type& key)
const -> const_iterator {
437 return _constrained_find(key, _key_to_bucket(key));
440 [[nodiscard]]
auto contains(
const key_type& key)
const ->
bool {
441 return find(key) != cend();
444 [[nodiscard]]
auto cbegin(
const size_type index)
const -> const_local_iterator {
445 return {_dense.first().begin(), _sparse.first()[index]};
448 [[nodiscard]]
auto begin(
const size_type index)
const -> const_local_iterator {
449 return cbegin(index);
452 [[nodiscard]]
auto begin(
const size_type index) -> local_iterator {
453 return {_dense.first().begin(), _sparse.first()[index]};
456 [[nodiscard]]
auto cend([[maybe_unused]]
const size_type index)
const -> const_local_iterator {
457 return {_dense.first().begin(), (std::numeric_limits<size_type>::max)()};
460 [[nodiscard]]
auto end(
const size_type index)
const -> const_local_iterator {
464 [[nodiscard]]
auto end([[maybe_unused]]
const size_type index) -> local_iterator {
465 return {_dense.first().begin(), (std::numeric_limits<size_type>::max)()};
468 [[nodiscard]]
auto max_load_factor() const -> std::float_t {
472 auto set_max_load_factor(
const std::float_t value) ->
void {
473 utility::assert_that(value > 0.f,
"Invalid load factor");
478 [[nodiscard]]
auto bucket_count() const -> size_type {
479 return _sparse.first().size();
482 void rehash(
const size_type count) {
483 auto value = count > minimum_capacity ? count : minimum_capacity;
484 const auto capacity =
static_cast<size_type
>(
static_cast<std::float_t
>(size()) / max_load_factor());
485 value = value > capacity ? value : capacity;
487 if (
const auto length = std::bit_ceil(value); length != bucket_count()) {
488 _sparse.first().resize(length);
490 for (
auto&& elem: _sparse.first()) {
491 elem = (std::numeric_limits<size_type>::max)();
494 for (
auto position = 0u, last = size(); position < last; ++position) {
495 const auto index = _key_to_bucket(_dense.first()[position].element.first);
496 _dense.first()[position].next = std::exchange(_sparse.first()[index], position);
501 void reserve(
const size_type count) {
502 _dense.first().reserve(count);
503 rehash(
static_cast<size_type
>(std::ceil(
static_cast<std::float_t
>(count) / max_load_factor())));
506 [[nodiscard]]
auto hash_function() const -> hasher {
507 return _sparse.second();
510 [[nodiscard]]
auto key_eq() const -> key_equal {
511 return _dense.second();
516 template<
typename Other>
517 [[nodiscard]]
auto _key_to_bucket(
const Other& key)
const noexcept -> size_type {
518 return utility::fast_mod(
static_cast<size_type
>(_sparse.second()(key)), bucket_count());
521 template<
typename Other>
522 [[nodiscard]]
auto _constrained_find(
const Other& key,
const size_type bucket) -> iterator {
523 for (
auto it = begin(bucket), last = end(bucket); it != last; ++it) {
524 if (_dense.second()(it->first, key)) {
525 return begin() +
static_cast<difference_type
>(it.index());
532 template<
typename Other>
533 [[nodiscard]]
auto _constrained_find(
const Other& key,
const size_type bucket)
const -> const_iterator {
534 for (
auto it = cbegin(bucket), last = cend(bucket); it != last; ++it) {
535 if (_dense.second()(it->first, key)) {
536 return cbegin() +
static_cast<difference_type
>(it.index());
543 template<
typename Other,
typename... Args>
544 [[nodiscard]]
auto _insert_or_do_nothing(Other &&key, Args &&...args) -> std::pair<iterator, bool> {
545 const auto index = _key_to_bucket(key);
547 if (
auto it = _constrained_find(key, index); it != end()) {
548 return std::make_pair(it,
false);
551 _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)...));
552 _sparse.first()[index] = _dense.first().size() - 1u;
553 _rehash_if_required();
555 return std::make_pair(--end(),
true);
558 template<
typename Other,
typename Arg>
559 [[nodiscard]]
auto _insert_or_overwrite(Other&& key, Arg&& value) -> std::pair<iterator, bool> {
560 const auto index = key_to_bucket(key);
562 if (
auto it = _constrained_find(key, index); it != end()) {
563 it->second = std::forward<Arg>(value);
564 return std::make_pair(it,
false);
567 _dense.first().emplace_back(_sparse.first()[index], std::forward<Other>(key), std::forward<Arg>(value));
568 _sparse.first()[index] = _dense.first().size() - 1u;
569 _rehash_if_required();
571 return std::make_pair(--end(),
true);
574 auto _move_and_pop(
const size_type position) ->
void {
575 if (
const auto last = size() - 1u; position != last) {
576 auto* current = &_sparse.first()[_key_to_bucket(_dense.first().back().element.first)];
577 _dense.first()[position] = std::move(_dense.first().back());
578 for (; *current != last; current = &_dense.first()[*current].next) {}
582 _dense.first().pop_back();
585 auto _rehash_if_required() ->
void {
586 if (
const auto count = bucket_count(); size() >
static_cast<size_type
>(
static_cast<std::float_t
>(count) * max_load_factor())) {
591 compressed_pair<sparse_container_type, hasher> _sparse;
592 compressed_pair<dense_container_type, key_equal> _dense;
593 std::float_t _threshold;
599template<
typename Key,
typename Value,
typename Allocator>
600struct std::uses_allocator<sbx::containers::detail::dense_map_node<Key, Value>, Allocator> : std::true_type { };
Definition: dense_map.hpp:233
auto at(const key_type &key) const -> const mapped_type &
Definition: dense_map.hpp:418
Definition: dense_map.hpp:54
Definition: dense_map.hpp:164
Definition: dense_map.hpp:23