24 #ifndef TSL_HOPSCOTCH_HASH_H 25 #define TSL_HOPSCOTCH_HASH_H 35 #include <initializer_list> 41 #include <type_traits> 48 #if (defined(__GNUC__
) && (__GNUC__
== 4
) && (__GNUC_MINOR__
< 9
)) 49 #define TSL_NO_RANGE_ERASE_WITH_CONST_ITERATOR 61 #define tsl_assert(expr) assert(expr) 63 #define tsl_assert(expr) (static_cast<void>(0
)) 78 template<
typename T,
typename =
void>
79 struct has_is_transparent : std::false_type {
83 struct has_is_transparent<T,
typename make_void<
typename T::is_transparent>::type> : std::true_type {
87 template<
typename T,
typename =
void>
88 struct has_key_compare : std::false_type {
92 struct has_key_compare<T,
typename make_void<
typename T::key_compare>::type> : std::true_type {
97 struct is_power_of_two_policy: std::false_type {
100 template<std::size_t GrowthFactor>
111 static const std::size_t SMALLEST_TYPE_MAX_BITS_SUPPORTED = 64;
112 template<
unsigned int MinBits,
typename Enable =
void>
113 class smallest_type_for_min_bits {
116 template<
unsigned int MinBits>
117 class smallest_type_for_min_bits<MinBits,
typename std::enable_if<(MinBits > 0) && (MinBits <= 8)>::type> {
119 using type = std::uint_least8_t;
122 template<
unsigned int MinBits>
123 class smallest_type_for_min_bits<MinBits,
typename std::enable_if<(MinBits > 8) && (MinBits <= 16)>::type> {
125 using type = std::uint_least16_t;
128 template<
unsigned int MinBits>
129 class smallest_type_for_min_bits<MinBits,
typename std::enable_if<(MinBits > 16) && (MinBits <= 32)>::type> {
131 using type = std::uint_least32_t;
134 template<
unsigned int MinBits>
135 class smallest_type_for_min_bits<MinBits,
typename std::enable_if<(MinBits > 32) && (MinBits <= 64)>::type> {
137 using type = std::uint_least64_t;
160 static const std::size_t NB_RESERVED_BITS_IN_NEIGHBORHOOD = 2;
163 using truncated_hash_type = std::uint_least32_t;
168 template<
bool StoreHash>
169 class hopscotch_bucket_hash {
171 bool bucket_hash_equal(std::size_t )
const noexcept {
175 truncated_hash_type truncated_bucket_hash()
const noexcept {
180 void copy_hash(
const hopscotch_bucket_hash& )
noexcept {
183 void set_hash(truncated_hash_type )
noexcept {
188 class hopscotch_bucket_hash<
true> {
190 bool bucket_hash_equal(std::size_t hash)
const noexcept {
191 return m_hash == truncated_hash_type(hash);
194 truncated_hash_type truncated_bucket_hash()
const noexcept {
199 void copy_hash(
const hopscotch_bucket_hash& bucket)
noexcept {
200 m_hash = bucket.m_hash;
203 void set_hash(truncated_hash_type hash)
noexcept {
208 truncated_hash_type m_hash;
212 template<
typename ValueType,
unsigned int NeighborhoodSize,
bool StoreHash>
213 class hopscotch_bucket:
public hopscotch_bucket_hash<StoreHash> {
215 static const std::size_t MIN_NEIGHBORHOOD_SIZE = 4;
216 static const std::size_t MAX_NEIGHBORHOOD_SIZE = SMALLEST_TYPE_MAX_BITS_SUPPORTED - NB_RESERVED_BITS_IN_NEIGHBORHOOD;
219 static_assert(NeighborhoodSize >= 4,
"NeighborhoodSize should be >= 4.");
221 static_assert(MIN_NEIGHBORHOOD_SIZE == 4,
"");
223 static_assert(NeighborhoodSize <= 62,
"NeighborhoodSize should be <= 62.");
225 static_assert(MAX_NEIGHBORHOOD_SIZE == 62,
"");
228 static_assert(!StoreHash || NeighborhoodSize <= 30,
229 "NeighborhoodSize should be <= 30 if StoreHash is true.");
231 static_assert(MAX_NEIGHBORHOOD_SIZE - 32 == 30,
"");
233 using bucket_hash = hopscotch_bucket_hash<StoreHash>;
236 using value_type = ValueType;
237 using neighborhood_bitmap =
238 typename smallest_type_for_min_bits<NeighborhoodSize + NB_RESERVED_BITS_IN_NEIGHBORHOOD>::type;
241 hopscotch_bucket()
noexcept: bucket_hash(), m_neighborhood_infos(0) {
246 hopscotch_bucket(
const hopscotch_bucket& bucket)
247 noexcept(std::is_nothrow_copy_constructible<value_type>::value): bucket_hash(bucket),
248 m_neighborhood_infos(0)
250 if(!bucket.empty()) {
251 ::
new (
static_cast<
void*>(std::addressof(m_value))) value_type(bucket.value());
254 m_neighborhood_infos = bucket.m_neighborhood_infos;
257 hopscotch_bucket(hopscotch_bucket&& bucket)
258 noexcept(std::is_nothrow_move_constructible<value_type>::value) : bucket_hash(std::move(bucket)),
259 m_neighborhood_infos(0)
261 if(!bucket.empty()) {
262 ::
new (
static_cast<
void*>(std::addressof(m_value))) value_type(std::move(bucket.value()));
265 m_neighborhood_infos = bucket.m_neighborhood_infos;
268 hopscotch_bucket& operator=(
const hopscotch_bucket& bucket)
269 noexcept(std::is_nothrow_copy_constructible<value_type>::value)
271 if(
this != &bucket) {
274 bucket_hash::operator=(bucket);
275 if(!bucket.empty()) {
276 ::
new (
static_cast<
void*>(std::addressof(m_value))) value_type(bucket.value());
279 m_neighborhood_infos = bucket.m_neighborhood_infos;
285 hopscotch_bucket& operator=(hopscotch_bucket&& ) =
delete;
287 ~hopscotch_bucket()
noexcept {
293 neighborhood_bitmap neighborhood_infos()
const noexcept {
294 return neighborhood_bitmap(m_neighborhood_infos >> NB_RESERVED_BITS_IN_NEIGHBORHOOD);
297 void set_overflow(
bool has_overflow)
noexcept {
299 m_neighborhood_infos = neighborhood_bitmap(m_neighborhood_infos | 2);
302 m_neighborhood_infos = neighborhood_bitmap(m_neighborhood_infos & ~2);
306 bool has_overflow()
const noexcept {
307 return (m_neighborhood_infos & 2) != 0;
310 bool empty()
const noexcept {
311 return (m_neighborhood_infos & 1) == 0;
314 void toggle_neighbor_presence(std::size_t ineighbor)
noexcept {
316 m_neighborhood_infos = neighborhood_bitmap(
317 m_neighborhood_infos ^ (1ull << (ineighbor + NB_RESERVED_BITS_IN_NEIGHBORHOOD)));
320 bool check_neighbor_presence(std::size_t ineighbor)
const noexcept {
322 if(((m_neighborhood_infos >> (ineighbor + NB_RESERVED_BITS_IN_NEIGHBORHOOD)) & 1) == 1) {
329 value_type& value()
noexcept {
331 return *
reinterpret_cast<value_type*>(std::addressof(m_value));
334 const value_type& value()
const noexcept {
336 return *
reinterpret_cast<
const value_type*>(std::addressof(m_value));
339 template<
typename... Args>
340 void set_value_of_empty_bucket(truncated_hash_type hash, Args&&... value_type_args) {
343 ::
new (
static_cast<
void*>(std::addressof(m_value))) value_type(std::forward<Args>(value_type_args)...);
345 this->set_hash(hash);
348 void swap_value_into_empty_bucket(hopscotch_bucket& empty_bucket) {
351 ::
new (
static_cast<
void*>(std::addressof(empty_bucket.m_value))) value_type(std::move(value()));
352 empty_bucket.copy_hash(*
this);
353 empty_bucket.set_empty(
false);
360 void remove_value()
noexcept {
367 void clear()
noexcept {
372 m_neighborhood_infos = 0;
376 static std::size_t max_size()
noexcept {
378 return std::numeric_limits<
typename bucket_hash::hash_type>::max();
381 return std::numeric_limits<std::size_t>::max();
385 static truncated_hash_type truncate_hash(std::size_t hash)
noexcept {
386 return truncated_hash_type(hash);
390 void set_empty(
bool is_empty)
noexcept {
392 m_neighborhood_infos = neighborhood_bitmap(m_neighborhood_infos & ~1);
395 m_neighborhood_infos = neighborhood_bitmap(m_neighborhood_infos | 1);
399 void destroy_value()
noexcept {
401 value().~value_type();
405 using storage =
typename std::aligned_storage<
sizeof(value_type),
alignof(value_type)>::type;
407 neighborhood_bitmap m_neighborhood_infos;
425 template<
class ValueType,
431 unsigned int NeighborhoodSize,
434 class OverflowContainer>
435 class hopscotch_hash:
private Hash,
private KeyEqual,
private GrowthPolicy {
438 using has_mapped_type =
typename std::integral_constant<
bool, !std::is_same<U,
void>::value>;
440 static_assert(
noexcept(std::declval<GrowthPolicy>().bucket_for_hash(std::size_t(0))),
"GrowthPolicy::bucket_for_hash must be noexcept.");
441 static_assert(
noexcept(std::declval<GrowthPolicy>().clear()),
"GrowthPolicy::clear must be noexcept.");
444 template<
bool IsConst>
447 using key_type =
typename KeySelect::key_type;
448 using value_type = ValueType;
449 using size_type = std::size_t;
450 using difference_type = std::ptrdiff_t;
452 using key_equal = KeyEqual;
453 using allocator_type = Allocator;
454 using reference = value_type&;
455 using const_reference =
const value_type&;
456 using pointer = value_type*;
457 using const_pointer =
const value_type*;
463 using neighborhood_bitmap =
typename hopscotch_bucket::neighborhood_bitmap;
465 using buckets_allocator =
typename std::allocator_traits<allocator_type>::
template rebind_alloc<hopscotch_bucket>;
466 using buckets_container_type = std::vector<hopscotch_bucket, buckets_allocator>;
468 using overflow_container_type = OverflowContainer;
470 static_assert(std::is_same<
typename overflow_container_type::value_type, ValueType>::value,
471 "OverflowContainer should have ValueType as type.");
473 static_assert(std::is_same<
typename overflow_container_type::allocator_type, Allocator>::value,
474 "Invalid allocator, not the same type as the value_type.");
477 using iterator_buckets =
typename buckets_container_type::iterator;
478 using const_iterator_buckets =
typename buckets_container_type::const_iterator;
480 using iterator_overflow =
typename overflow_container_type::iterator;
481 using const_iterator_overflow =
typename overflow_container_type::const_iterator;
491 template<
bool IsConst>
495 using iterator_bucket =
typename std::conditional<IsConst,
496 typename hopscotch_hash::const_iterator_buckets,
497 typename hopscotch_hash::iterator_buckets>::type;
498 using iterator_overflow =
typename std::conditional<IsConst,
499 typename hopscotch_hash::const_iterator_overflow,
500 typename hopscotch_hash::iterator_overflow>::type;
503 hopscotch_iterator(iterator_bucket buckets_iterator, iterator_bucket buckets_end_iterator,
504 iterator_overflow overflow_iterator)
noexcept :
505 m_buckets_iterator(buckets_iterator), m_buckets_end_iterator(buckets_end_iterator),
506 m_overflow_iterator(overflow_iterator)
511 using iterator_category = std::forward_iterator_tag;
512 using value_type =
const typename hopscotch_hash::value_type;
513 using difference_type = std::ptrdiff_t;
514 using reference = value_type&;
515 using pointer = value_type*;
522 m_buckets_iterator(other.m_buckets_iterator), m_buckets_end_iterator(other.m_buckets_end_iterator),
523 m_overflow_iterator(other.m_overflow_iterator)
527 const typename hopscotch_hash::key_type&
key()
const {
528 if(m_buckets_iterator != m_buckets_end_iterator) {
529 return KeySelect()(m_buckets_iterator->value());
532 return KeySelect()(*m_overflow_iterator);
535 template<
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value>::type* =
nullptr>
536 typename std::conditional<
541 if(m_buckets_iterator != m_buckets_end_iterator) {
542 return U()(m_buckets_iterator->value());
545 return U()(*m_overflow_iterator);
549 if(m_buckets_iterator != m_buckets_end_iterator) {
550 return m_buckets_iterator->value();
553 return *m_overflow_iterator;
557 if(m_buckets_iterator != m_buckets_end_iterator) {
558 return std::addressof(m_buckets_iterator->value());
561 return std::addressof(*m_overflow_iterator);
565 if(m_buckets_iterator == m_buckets_end_iterator) {
566 ++m_overflow_iterator;
571 ++m_buckets_iterator;
572 }
while(m_buckets_iterator != m_buckets_end_iterator && m_buckets_iterator->empty());
585 return lhs.m_buckets_iterator == rhs.m_buckets_iterator &&
586 lhs.m_overflow_iterator == rhs.m_overflow_iterator;
590 return !(lhs == rhs);
594 iterator_bucket m_buckets_iterator;
595 iterator_bucket m_buckets_end_iterator;
596 iterator_overflow m_overflow_iterator;
600 template<
class OC = OverflowContainer,
typename std::enable_if<!has_key_compare<OC>::value>::type* =
nullptr>
603 const KeyEqual& equal,
604 const Allocator& alloc,
605 float max_load_factor) : Hash(hash),
607 GrowthPolicy(bucket_count),
609 m_overflow_elements(alloc),
610 m_first_or_empty_bucket(static_empty_bucket_ptr()),
614 throw std::length_error(
"The map exceeds its maxmimum size.");
617 if(bucket_count > 0) {
618 static_assert(NeighborhoodSize - 1 > 0,
"");
622 m_buckets.resize(bucket_count + NeighborhoodSize - 1);
623 m_first_or_empty_bucket = m_buckets.data();
627 this->max_load_factor(max_load_factor);
632 static_assert(std::is_nothrow_move_constructible<value_type>::value ||
633 std::is_copy_constructible<value_type>::value,
634 "value_type must be either copy constructible or nothrow move constructible.");
637 template<
class OC = OverflowContainer,
typename std::enable_if<has_key_compare<OC>::value>::type* =
nullptr>
640 const KeyEqual& equal,
641 const Allocator& alloc,
642 float max_load_factor,
643 const typename OC::key_compare& comp) : Hash(hash),
645 GrowthPolicy(bucket_count),
647 m_overflow_elements(comp, alloc),
648 m_first_or_empty_bucket(static_empty_bucket_ptr()),
653 throw std::length_error(
"The map exceeds its maxmimum size.");
656 if(bucket_count > 0) {
657 static_assert(NeighborhoodSize - 1 > 0,
"");
661 m_buckets.resize(bucket_count + NeighborhoodSize - 1);
662 m_first_or_empty_bucket = m_buckets.data();
666 this->max_load_factor(max_load_factor);
671 static_assert(std::is_nothrow_move_constructible<value_type>::value ||
672 std::is_copy_constructible<value_type>::value,
673 "value_type must be either copy constructible or nothrow move constructible.");
680 m_buckets(other.m_buckets),
681 m_overflow_elements(other.m_overflow_elements),
682 m_first_or_empty_bucket(m_buckets.empty()?static_empty_bucket_ptr():
684 m_nb_elements(other.m_nb_elements),
685 m_max_load_factor(other.m_max_load_factor),
686 m_max_load_threshold_rehash(other.m_max_load_threshold_rehash),
687 m_min_load_threshold_rehash(other.m_min_load_threshold_rehash)
699 Hash(std::move(
static_cast<Hash&>(other))),
700 KeyEqual(std::move(
static_cast<KeyEqual&>(other))),
701 GrowthPolicy(std::move(
static_cast<GrowthPolicy&>(other))),
702 m_buckets(std::move(other.m_buckets)),
703 m_overflow_elements(std::move(other.m_overflow_elements)),
704 m_first_or_empty_bucket(m_buckets.empty()?static_empty_bucket_ptr():
706 m_nb_elements(other.m_nb_elements),
707 m_max_load_factor(other.m_max_load_factor),
708 m_max_load_threshold_rehash(other.m_max_load_threshold_rehash),
709 m_min_load_threshold_rehash(other.m_min_load_threshold_rehash)
711 other.GrowthPolicy::clear();
712 other.m_buckets.clear();
713 other.m_overflow_elements.clear();
714 other.m_first_or_empty_bucket = static_empty_bucket_ptr();
715 other.m_nb_elements = 0;
716 other.m_max_load_threshold_rehash = 0;
717 other.m_min_load_threshold_rehash = 0;
720 hopscotch_hash&
operator=(
const hopscotch_hash& other) {
722 Hash::operator=(other);
723 KeyEqual::operator=(other);
724 GrowthPolicy::operator=(other);
726 m_buckets = other.m_buckets;
727 m_overflow_elements = other.m_overflow_elements;
728 m_first_or_empty_bucket = m_buckets.empty()?static_empty_bucket_ptr():
730 m_nb_elements = other.m_nb_elements;
731 m_max_load_factor = other.m_max_load_factor;
732 m_max_load_threshold_rehash = other.m_max_load_threshold_rehash;
733 m_min_load_threshold_rehash = other.m_min_load_threshold_rehash;
739 hopscotch_hash&
operator=(hopscotch_hash&& other) {
747 return m_buckets.get_allocator();
755 auto begin = m_buckets.begin();
756 while(begin != m_buckets.end() && begin->empty()) {
760 return iterator(begin, m_buckets.end(), m_overflow_elements.begin());
763 const_iterator
begin()
const noexcept {
768 auto begin = m_buckets.cbegin();
769 while(begin != m_buckets.cend() && begin->empty()) {
773 return const_iterator(begin, m_buckets.cend(), m_overflow_elements.cbegin());
777 return iterator(m_buckets.end(), m_buckets.end(), m_overflow_elements.end());
780 const_iterator
end()
const noexcept {
784 const_iterator
cend()
const noexcept {
785 return const_iterator(m_buckets.cend(), m_buckets.cend(), m_overflow_elements.cend());
793 return m_nb_elements == 0;
796 size_type
size()
const noexcept {
797 return m_nb_elements;
801 return hopscotch_bucket::max_size();
808 for(
auto& bucket: m_buckets) {
812 m_overflow_elements.clear();
817 std::pair<iterator,
bool>
insert(
const value_type& value) {
818 return insert_impl(value);
821 template<
class P,
typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* =
nullptr>
822 std::pair<iterator,
bool>
insert(P&& value) {
823 return insert_impl(value_type(std::forward<P>(value)));
826 std::pair<iterator,
bool>
insert(value_type&& value) {
827 return insert_impl(std::move(value));
831 iterator
insert(const_iterator hint,
const value_type& value) {
832 if(hint !=
cend() && compare_keys(KeySelect()(*hint), KeySelect()(value))) {
836 return insert(value).first;
839 template<
class P,
typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* =
nullptr>
840 iterator
insert(const_iterator hint, P&& value) {
841 return emplace_hint(hint, std::forward<P>(value));
844 iterator
insert(const_iterator hint, value_type&& value) {
845 if(hint !=
cend() && compare_keys(KeySelect()(*hint), KeySelect()(value))) {
849 return insert(std::move(value)).first;
853 template<
class InputIt>
854 void insert(InputIt first, InputIt last) {
855 if(std::is_base_of<std::forward_iterator_tag,
856 typename std::iterator_traits<InputIt>::iterator_category>::value)
858 const auto nb_elements_insert = std::distance(first, last);
859 const std::size_t nb_elements_in_buckets = m_nb_elements - m_overflow_elements.size();
860 const std::size_t nb_free_buckets = m_max_load_threshold_rehash - nb_elements_in_buckets;
861 tsl_assert(m_nb_elements >= m_overflow_elements.size());
862 tsl_assert(m_max_load_threshold_rehash >= nb_elements_in_buckets);
864 if(nb_elements_insert > 0 && nb_free_buckets < std::size_t(nb_elements_insert)) {
865 reserve(nb_elements_in_buckets + std::size_t(nb_elements_insert)
);
869 for(; first != last; ++first) {
877 return insert_or_assign_impl(k, std::forward<M>(obj));
882 return insert_or_assign_impl(std::move(k), std::forward<M>(obj));
888 if(hint !=
cend() && compare_keys(KeySelect()(*hint), k)) {
890 it.value() = std::forward<M>(obj);
895 return insert_or_assign(k, std::forward<M>(obj)).first;
900 if(hint !=
cend() && compare_keys(KeySelect()(*hint), k)) {
902 it.value() = std::forward<M>(obj);
907 return insert_or_assign(std::move(k), std::forward<M>(obj)).first;
911 template<
class... Args>
912 std::pair<iterator,
bool>
emplace(Args&&... args) {
913 return insert(value_type(std::forward<Args>(args)...));
916 template<
class... Args>
918 return insert(hint, value_type(std::forward<Args>(args)...));
921 template<
class... Args>
922 std::pair<iterator,
bool>
try_emplace(
const key_type& k, Args&&... args) {
923 return try_emplace_impl(k, std::forward<Args>(args)...);
926 template<
class... Args>
927 std::pair<iterator,
bool>
try_emplace(key_type&& k, Args&&... args) {
928 return try_emplace_impl(std::move(k), std::forward<Args>(args)...);
931 template<
class... Args>
932 iterator
try_emplace(const_iterator hint,
const key_type& k, Args&&... args) {
933 if(hint !=
cend() && compare_keys(KeySelect()(*hint), k)) {
937 return try_emplace(k, std::forward<Args>(args)...).first;
940 template<
class... Args>
941 iterator
try_emplace(const_iterator hint, key_type&& k, Args&&... args) {
942 if(hint !=
cend() && compare_keys(KeySelect()(*hint), k)) {
946 return try_emplace(std::move(k), std::forward<Args>(args)...).first;
955 return erase(const_iterator(pos));
958 iterator
erase(const_iterator pos) {
959 const std::size_t ibucket_for_hash = bucket_for_hash(hash_key(pos.key()));
961 if(pos.m_buckets_iterator != pos.m_buckets_end_iterator) {
962 auto it_bucket = m_buckets.begin() + std::distance(m_buckets.cbegin(), pos.m_buckets_iterator);
963 erase_from_bucket(*it_bucket, ibucket_for_hash);
965 return ++iterator(it_bucket, m_buckets.end(), m_overflow_elements.begin());
968 auto it_next_overflow = erase_from_overflow(pos.m_overflow_iterator, ibucket_for_hash);
969 return iterator(m_buckets.end(), m_buckets.end(), it_next_overflow);
973 iterator
erase(const_iterator first, const_iterator last) {
978 auto to_delete = erase(first);
979 while(to_delete != last) {
980 to_delete = erase(to_delete);
988 return erase(key, hash_key(key));
992 size_type
erase(
const K& key, std::size_t hash) {
993 const std::size_t ibucket_for_hash = bucket_for_hash(hash);
995 hopscotch_bucket* bucket_found = find_in_buckets(key, hash, m_first_or_empty_bucket + ibucket_for_hash);
996 if(bucket_found !=
nullptr) {
997 erase_from_bucket(*bucket_found, ibucket_for_hash);
1002 if((m_first_or_empty_bucket + ibucket_for_hash)->has_overflow()) {
1003 auto it_overflow = find_in_overflow(key);
1004 if(it_overflow != m_overflow_elements.end()) {
1005 erase_from_overflow(it_overflow, ibucket_for_hash);
1017 swap(
static_cast<Hash&>(*
this),
static_cast<Hash&>(other));
1018 swap(
static_cast<KeyEqual&>(*
this),
static_cast<KeyEqual&>(other));
1019 swap(
static_cast<GrowthPolicy&>(*
this),
static_cast<GrowthPolicy&>(other));
1020 swap(m_buckets, other.m_buckets);
1021 swap(m_overflow_elements, other.m_overflow_elements);
1022 swap(m_first_or_empty_bucket, other.m_first_or_empty_bucket);
1023 swap(m_nb_elements, other.m_nb_elements);
1024 swap(m_max_load_factor, other.m_max_load_factor);
1025 swap(m_max_load_threshold_rehash, other.m_max_load_threshold_rehash);
1026 swap(m_min_load_threshold_rehash, other.m_min_load_threshold_rehash);
1033 template<
class K,
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value>::type* =
nullptr>
1035 return at(key, hash_key(key));
1038 template<
class K,
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value>::type* =
nullptr>
1040 return const_cast<
typename U::value_type&>(
static_cast<
const hopscotch_hash*>(
this)->at(key, hash));
1044 template<
class K,
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value>::type* =
nullptr>
1046 return at(key, hash_key(key));
1049 template<
class K,
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value>::type* =
nullptr>
1051 using T =
typename U::value_type;
1053 const T* value = find_value_impl(key, hash, m_first_or_empty_bucket + bucket_for_hash(hash));
1054 if(value ==
nullptr) {
1055 throw std::out_of_range(
"Couldn't find key.");
1063 template<
class K,
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value>::type* =
nullptr>
1065 using T =
typename U::value_type;
1067 const std::size_t hash = hash_key(key);
1068 const std::size_t ibucket_for_hash = bucket_for_hash(hash);
1070 T* value = find_value_impl(key, hash, m_first_or_empty_bucket + ibucket_for_hash);
1071 if(value !=
nullptr) {
1075 return insert_impl(ibucket_for_hash, hash, std::piecewise_construct,
1076 std::forward_as_tuple(std::forward<K>(key)),
1077 std::forward_as_tuple()).first.value();
1084 return count(key, hash_key(key));
1088 size_type
count(
const K& key, std::size_t hash)
const {
1089 return count_impl(key, hash, m_first_or_empty_bucket + bucket_for_hash(hash));
1095 return find(key, hash_key(key));
1099 iterator
find(
const K& key, std::size_t hash) {
1100 return find_impl(key, hash, m_first_or_empty_bucket + bucket_for_hash(hash));
1105 const_iterator
find(
const K& key)
const {
1106 return find(key, hash_key(key));
1110 const_iterator
find(
const K& key, std::size_t hash)
const {
1111 return find_impl(key, hash, m_first_or_empty_bucket + bucket_for_hash(hash));
1117 return equal_range(key, hash_key(key));
1121 std::pair<iterator, iterator>
equal_range(
const K& key, std::size_t hash) {
1122 iterator it = find(key, hash);
1123 return std::make_pair(it, (it == end())?it:std::next(it));
1128 std::pair<const_iterator, const_iterator>
equal_range(
const K& key)
const {
1129 return equal_range(key, hash_key(key));
1133 std::pair<const_iterator, const_iterator>
equal_range(
const K& key, std::size_t hash)
const {
1134 const_iterator it = find(key, hash);
1135 return std::make_pair(it, (it ==
cend())?it:std::next(it));
1147 if(m_buckets.empty()) {
1151 return m_buckets.size() - NeighborhoodSize + 1;
1155 const std::size_t max_bucket_count = std::min(GrowthPolicy::max_bucket_count(), m_buckets.max_size());
1156 return max_bucket_count - NeighborhoodSize + 1;
1172 return m_max_load_factor;
1176 m_max_load_factor = std::max(0.1f, std::min(ml, 0.95f));
1177 m_max_load_threshold_rehash = size_type(
float(
bucket_count())*m_max_load_factor);
1178 m_min_load_threshold_rehash = size_type(
float(
bucket_count())*MIN_LOAD_FACTOR_FOR_REHASH);
1182 count_ = std::max(count_, size_type(std::ceil(
float(
size())/max_load_factor())));
1183 rehash_impl(count_);
1187 rehash(size_type(std::ceil(
float(count_)/max_load_factor()))
);
1195 return static_cast<
const Hash&>(*
this);
1199 return static_cast<
const KeyEqual&>(*
this);
1206 if(pos.m_buckets_iterator != pos.m_buckets_end_iterator) {
1208 auto it = m_buckets.begin() + std::distance(m_buckets.cbegin(), pos.m_buckets_iterator);
1209 return iterator(it, m_buckets.end(), m_overflow_elements.begin());
1213 auto it = mutable_overflow_iterator(pos.m_overflow_iterator);
1214 return iterator(m_buckets.end(), m_buckets.end(), it);
1219 return m_overflow_elements.size();
1222 template<
class U = OverflowContainer,
typename std::enable_if<has_key_compare<U>::value>::type* =
nullptr>
1224 return m_overflow_elements.key_comp();
1230 std::size_t hash_key(
const K& key)
const {
1231 return Hash::operator()(key);
1234 template<
class K1,
class K2>
1235 bool compare_keys(
const K1& key1,
const K2& key2)
const {
1236 return KeyEqual::operator()(key1, key2);
1239 std::size_t bucket_for_hash(std::size_t hash)
const {
1240 const std::size_t bucket = GrowthPolicy::bucket_for_hash(hash);
1241 tsl_assert(bucket < m_buckets.size() || (bucket == 0 && m_buckets.empty()));
1246 template<
typename U = value_type,
1247 typename std::enable_if<std::is_nothrow_move_constructible<U>::value>::type* =
nullptr>
1248 void rehash_impl(size_type count_) {
1249 hopscotch_hash new_map = new_hopscotch_hash(count_);
1251 if(!m_overflow_elements.empty()) {
1252 new_map.m_overflow_elements.swap(m_overflow_elements);
1253 new_map.m_nb_elements += new_map.m_overflow_elements.size();
1255 for(
const value_type& value : new_map.m_overflow_elements) {
1256 const std::size_t ibucket_for_hash = new_map.bucket_for_hash(new_map.hash_key(KeySelect()(value)));
1257 new_map.m_buckets[ibucket_for_hash].set_overflow(
true);
1262 const bool use_stored_hash = USE_STORED_HASH_ON_REHASH(new_map.bucket_count());
1263 for(
auto it_bucket = m_buckets.begin(); it_bucket != m_buckets.end(); ++it_bucket) {
1264 if(it_bucket->empty()) {
1268 const std::size_t hash = use_stored_hash?
1269 it_bucket->truncated_bucket_hash():
1270 new_map.hash_key(KeySelect()(it_bucket->value()));
1271 const std::size_t ibucket_for_hash = new_map.bucket_for_hash(hash);
1273 new_map.insert_impl(ibucket_for_hash, hash, std::move(it_bucket->value()));
1276 erase_from_bucket(*it_bucket, bucket_for_hash(hash));
1284 m_overflow_elements.swap(new_map.m_overflow_elements);
1286 const bool use_stored_hash = USE_STORED_HASH_ON_REHASH(new_map.bucket_count());
1287 for(
auto it_bucket = new_map.m_buckets.begin(); it_bucket != new_map.m_buckets.end(); ++it_bucket) {
1288 if(it_bucket->empty()) {
1292 const std::size_t hash = use_stored_hash?
1293 it_bucket->truncated_bucket_hash():
1294 hash_key(KeySelect()(it_bucket->value()));
1295 const std::size_t ibucket_for_hash = bucket_for_hash(hash);
1299 insert_impl(ibucket_for_hash, hash, std::move(it_bucket->value()));
1305 new_map.swap(*
this);
1308 template<
typename U = value_type,
1309 typename std::enable_if<std::is_copy_constructible<U>::value &&
1310 !std::is_nothrow_move_constructible<U>::value>::type* =
nullptr>
1311 void rehash_impl(size_type count_) {
1312 hopscotch_hash new_map = new_hopscotch_hash(count_);
1314 const bool use_stored_hash = USE_STORED_HASH_ON_REHASH(new_map.bucket_count());
1315 for(
const hopscotch_bucket& bucket: m_buckets) {
1316 if(bucket.empty()) {
1320 const std::size_t hash = use_stored_hash?
1321 bucket.truncated_bucket_hash():
1322 new_map.hash_key(KeySelect()(bucket.value()));
1323 const std::size_t ibucket_for_hash = new_map.bucket_for_hash(hash);
1325 new_map.insert_impl(ibucket_for_hash, hash, bucket.value());
1328 for(
const value_type& value: m_overflow_elements) {
1329 const std::size_t hash = new_map.hash_key(KeySelect()(value));
1330 const std::size_t ibucket_for_hash = new_map.bucket_for_hash(hash);
1332 new_map.insert_impl(ibucket_for_hash, hash, value);
1335 new_map.swap(*
this);
1338 #ifdef TSL_NO_RANGE_ERASE_WITH_CONST_ITERATOR
1339 iterator_overflow mutable_overflow_iterator(const_iterator_overflow it) {
1340 return std::next(m_overflow_elements.begin(), std::distance(m_overflow_elements.cbegin(), it));
1343 iterator_overflow mutable_overflow_iterator(const_iterator_overflow it) {
1344 return m_overflow_elements.erase(it, it);
1349 iterator_overflow erase_from_overflow(const_iterator_overflow pos, std::size_t ibucket_for_hash) {
1350 #ifdef TSL_NO_RANGE_ERASE_WITH_CONST_ITERATOR
1351 auto it_next = m_overflow_elements.erase(mutable_overflow_iterator(pos));
1353 auto it_next = m_overflow_elements.erase(pos);
1359 tsl_assert(m_buckets[ibucket_for_hash].has_overflow());
1360 for(
const value_type& value: m_overflow_elements) {
1361 const std::size_t bucket_for_value = bucket_for_hash(hash_key(KeySelect()(value)));
1362 if(bucket_for_value == ibucket_for_hash) {
1367 m_buckets[ibucket_for_hash].set_overflow(
false);
1376 void erase_from_bucket(hopscotch_bucket& bucket_for_value, std::size_t ibucket_for_hash)
noexcept {
1377 const std::size_t ibucket_for_value = std::distance(m_buckets.data(), &bucket_for_value);
1378 tsl_assert(ibucket_for_value >= ibucket_for_hash);
1380 bucket_for_value.remove_value();
1381 m_buckets[ibucket_for_hash].toggle_neighbor_presence(ibucket_for_value - ibucket_for_hash);
1387 template<
class K,
class M>
1388 std::pair<iterator,
bool> insert_or_assign_impl(K&& key, M&& obj) {
1389 auto it = try_emplace_impl(std::forward<K>(key), std::forward<M>(obj));
1391 it.first.value() = std::forward<M>(obj);
1397 template<
typename P,
class... Args>
1398 std::pair<iterator,
bool> try_emplace_impl(P&& key, Args&&... args_value) {
1399 const std::size_t hash = hash_key(key);
1400 const std::size_t ibucket_for_hash = bucket_for_hash(hash);
1403 auto it_find = find_impl(key, hash, m_first_or_empty_bucket + ibucket_for_hash);
1404 if(it_find != end()) {
1405 return std::make_pair(it_find,
false);
1408 return insert_impl(ibucket_for_hash, hash, std::piecewise_construct,
1409 std::forward_as_tuple(std::forward<P>(key)),
1410 std::forward_as_tuple(std::forward<Args>(args_value)...));
1413 template<
typename P>
1414 std::pair<iterator,
bool> insert_impl(P&& value) {
1415 const std::size_t hash = hash_key(KeySelect()(value));
1416 const std::size_t ibucket_for_hash = bucket_for_hash(hash);
1419 auto it_find = find_impl(KeySelect()(value), hash, m_first_or_empty_bucket + ibucket_for_hash);
1420 if(it_find != end()) {
1421 return std::make_pair(it_find,
false);
1425 return insert_impl(ibucket_for_hash, hash, std::forward<P>(value));
1428 template<
typename... Args>
1429 std::pair<iterator,
bool> insert_impl(std::size_t ibucket_for_hash, std::size_t hash, Args&&... value_type_args) {
1430 if((m_nb_elements - m_overflow_elements.size()) >= m_max_load_threshold_rehash) {
1431 rehash(GrowthPolicy::next_bucket_count()
);
1432 ibucket_for_hash = bucket_for_hash(hash);
1435 std::size_t ibucket_empty = find_empty_bucket(ibucket_for_hash);
1436 if(ibucket_empty < m_buckets.size()) {
1438 tsl_assert(ibucket_empty >= ibucket_for_hash);
1441 if(ibucket_empty - ibucket_for_hash < NeighborhoodSize) {
1442 auto it = insert_in_bucket(ibucket_empty, ibucket_for_hash,
1443 hash, std::forward<Args>(value_type_args)...);
1444 return std::make_pair(iterator(it, m_buckets.end(), m_overflow_elements.begin()),
true);
1448 while(swap_empty_bucket_closer(ibucket_empty));
1452 if(
size() < m_min_load_threshold_rehash || !will_neighborhood_change_on_rehash(ibucket_for_hash)) {
1453 auto it = insert_in_overflow(ibucket_for_hash, std::forward<Args>(value_type_args)...);
1454 return std::make_pair(iterator(m_buckets.end(), m_buckets.end(), it),
true);
1457 rehash(GrowthPolicy::next_bucket_count()
);
1458 ibucket_for_hash = bucket_for_hash(hash);
1460 return insert_impl(ibucket_for_hash, hash, std::forward<Args>(value_type_args)...);
1467 bool will_neighborhood_change_on_rehash(size_t ibucket_neighborhood_check)
const {
1468 std::size_t expand_bucket_count = GrowthPolicy::next_bucket_count();
1469 GrowthPolicy expand_growth_policy(expand_bucket_count);
1471 const bool use_stored_hash = USE_STORED_HASH_ON_REHASH(expand_bucket_count);
1472 for(size_t ibucket = ibucket_neighborhood_check;
1473 ibucket < m_buckets.size() && (ibucket - ibucket_neighborhood_check) < NeighborhoodSize;
1478 const size_t hash = use_stored_hash?
1479 m_buckets[ibucket].truncated_bucket_hash():
1480 hash_key(KeySelect()(m_buckets[ibucket].value()));
1481 if(bucket_for_hash(hash) != expand_growth_policy.bucket_for_hash(hash)) {
1493 std::size_t find_empty_bucket(std::size_t ibucket_start)
const {
1494 const std::size_t limit = std::min(ibucket_start + MAX_PROBES_FOR_EMPTY_BUCKET, m_buckets.size());
1495 for(; ibucket_start < limit; ibucket_start++) {
1496 if(m_buckets[ibucket_start].empty()) {
1497 return ibucket_start;
1501 return m_buckets.size();
1509 template<
typename... Args>
1510 iterator_buckets insert_in_bucket(std::size_t ibucket_empty, std::size_t ibucket_for_hash,
1511 std::size_t hash, Args&&... value_type_args)
1513 tsl_assert(ibucket_empty >= ibucket_for_hash );
1514 tsl_assert(m_buckets[ibucket_empty].empty());
1515 m_buckets[ibucket_empty].set_value_of_empty_bucket(hopscotch_bucket::truncate_hash(hash), std::forward<Args>(value_type_args)...);
1517 tsl_assert(!m_buckets[ibucket_for_hash].empty());
1518 m_buckets[ibucket_for_hash].toggle_neighbor_presence(ibucket_empty - ibucket_for_hash);
1521 return m_buckets.begin() + ibucket_empty;
1524 template<
class... Args,
class U = OverflowContainer,
typename std::enable_if<!has_key_compare<U>::value>::type* =
nullptr>
1525 iterator_overflow insert_in_overflow(std::size_t ibucket_for_hash, Args&&... value_type_args) {
1526 auto it = m_overflow_elements.emplace(m_overflow_elements.end(), std::forward<Args>(value_type_args)...);
1528 m_buckets[ibucket_for_hash].set_overflow(
true);
1534 template<
class... Args,
class U = OverflowContainer,
typename std::enable_if<has_key_compare<U>::value>::type* =
nullptr>
1535 iterator_overflow insert_in_overflow(std::size_t ibucket_for_hash, Args&&... value_type_args) {
1536 auto it = m_overflow_elements.emplace(std::forward<Args>(value_type_args)...).first;
1538 m_buckets[ibucket_for_hash].set_overflow(
true);
1550 bool swap_empty_bucket_closer(std::size_t& ibucket_empty_in_out) {
1551 tsl_assert(ibucket_empty_in_out >= NeighborhoodSize);
1552 const std::size_t neighborhood_start = ibucket_empty_in_out - NeighborhoodSize + 1;
1554 for(std::size_t to_check = neighborhood_start; to_check < ibucket_empty_in_out; to_check++) {
1555 neighborhood_bitmap neighborhood_infos = m_buckets[to_check].neighborhood_infos();
1556 std::size_t to_swap = to_check;
1558 while(neighborhood_infos != 0 && to_swap < ibucket_empty_in_out) {
1559 if((neighborhood_infos & 1) == 1) {
1560 tsl_assert(m_buckets[ibucket_empty_in_out].empty());
1563 m_buckets[to_swap].swap_value_into_empty_bucket(m_buckets[ibucket_empty_in_out]);
1565 tsl_assert(!m_buckets[to_check].check_neighbor_presence(ibucket_empty_in_out - to_check));
1566 tsl_assert(m_buckets[to_check].check_neighbor_presence(to_swap - to_check));
1568 m_buckets[to_check].toggle_neighbor_presence(ibucket_empty_in_out - to_check);
1569 m_buckets[to_check].toggle_neighbor_presence(to_swap - to_check);
1572 ibucket_empty_in_out = to_swap;
1578 neighborhood_infos = neighborhood_bitmap(neighborhood_infos >> 1);
1587 template<
class K,
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value>::type* =
nullptr>
1588 typename U::value_type* find_value_impl(
const K& key, std::size_t hash, hopscotch_bucket* bucket_for_hash) {
1589 return const_cast<
typename U::value_type*>(
1590 static_cast<
const hopscotch_hash*>(
this)->find_value_impl(key, hash, bucket_for_hash));
1598 template<
class K,
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value>::type* =
nullptr>
1599 const typename U::value_type* find_value_impl(
const K& key, std::size_t hash,
1600 const hopscotch_bucket* bucket_for_hash)
const 1602 const hopscotch_bucket* bucket_found = find_in_buckets(key, hash, bucket_for_hash);
1603 if(bucket_found !=
nullptr) {
1604 return std::addressof(ValueSelect()(bucket_found->value()));
1607 if(bucket_for_hash->has_overflow()) {
1608 auto it_overflow = find_in_overflow(key);
1609 if(it_overflow != m_overflow_elements.end()) {
1610 return std::addressof(ValueSelect()(*it_overflow));
1618 size_type count_impl(
const K& key, std::size_t hash,
const hopscotch_bucket* bucket_for_hash)
const {
1619 if(find_in_buckets(key, hash, bucket_for_hash) !=
nullptr) {
1622 else if(bucket_for_hash->has_overflow() && find_in_overflow(key) != m_overflow_elements.cend()) {
1631 iterator find_impl(
const K& key, std::size_t hash, hopscotch_bucket* bucket_for_hash) {
1632 hopscotch_bucket* bucket_found = find_in_buckets(key, hash, bucket_for_hash);
1633 if(bucket_found !=
nullptr) {
1634 return iterator(m_buckets.begin() + std::distance(m_buckets.data(), bucket_found),
1635 m_buckets.end(), m_overflow_elements.begin());
1638 if(!bucket_for_hash->has_overflow()) {
1642 return iterator(m_buckets.end(), m_buckets.end(), find_in_overflow(key));
1646 const_iterator find_impl(
const K& key, std::size_t hash,
const hopscotch_bucket* bucket_for_hash)
const {
1647 const hopscotch_bucket* bucket_found = find_in_buckets(key, hash, bucket_for_hash);
1648 if(bucket_found !=
nullptr) {
1649 return const_iterator(m_buckets.cbegin() + std::distance(m_buckets.data(), bucket_found),
1650 m_buckets.cend(), m_overflow_elements.cbegin());
1653 if(!bucket_for_hash->has_overflow()) {
1658 return const_iterator(m_buckets.cend(), m_buckets.cend(), find_in_overflow(key));
1662 hopscotch_bucket* find_in_buckets(
const K& key, std::size_t hash, hopscotch_bucket* bucket_for_hash) {
1663 const hopscotch_bucket* bucket_found =
1664 static_cast<
const hopscotch_hash*>(
this)->find_in_buckets(key, hash, bucket_for_hash);
1665 return const_cast<hopscotch_bucket*>(bucket_found);
1673 const hopscotch_bucket* find_in_buckets(
const K& key, std::size_t hash,
const hopscotch_bucket* bucket_for_hash)
const {
1680 neighborhood_bitmap neighborhood_infos = bucket_for_hash->neighborhood_infos();
1681 while(neighborhood_infos != 0) {
1682 if((neighborhood_infos & 1) == 1) {
1686 if((!StoreHash || bucket_for_hash->bucket_hash_equal(hash)) &&
1687 compare_keys(KeySelect()(bucket_for_hash->value()), key))
1689 return bucket_for_hash;
1694 neighborhood_infos = neighborhood_bitmap(neighborhood_infos >> 1);
1702 template<
class K,
class U = OverflowContainer,
typename std::enable_if<!has_key_compare<U>::value>::type* =
nullptr>
1703 iterator_overflow find_in_overflow(
const K& key) {
1704 return std::find_if(m_overflow_elements.begin(), m_overflow_elements.end(),
1705 [&](
const value_type& value) {
1706 return compare_keys(key, KeySelect()(value));
1710 template<
class K,
class U = OverflowContainer,
typename std::enable_if<!has_key_compare<U>::value>::type* =
nullptr>
1711 const_iterator_overflow find_in_overflow(
const K& key)
const {
1712 return std::find_if(m_overflow_elements.cbegin(), m_overflow_elements.cend(),
1713 [&](
const value_type& value) {
1714 return compare_keys(key, KeySelect()(value));
1718 template<
class K,
class U = OverflowContainer,
typename std::enable_if<has_key_compare<U>::value>::type* =
nullptr>
1719 iterator_overflow find_in_overflow(
const K& key) {
1720 return m_overflow_elements.find(key);
1723 template<
class K,
class U = OverflowContainer,
typename std::enable_if<has_key_compare<U>::value>::type* =
nullptr>
1724 const_iterator_overflow find_in_overflow(
const K& key)
const {
1725 return m_overflow_elements.find(key);
1730 template<
class U = OverflowContainer,
typename std::enable_if<!has_key_compare<U>::value>::type* =
nullptr>
1731 hopscotch_hash new_hopscotch_hash(size_type bucket_count) {
1732 return hopscotch_hash(bucket_count,
static_cast<Hash&>(*
this),
static_cast<KeyEqual&>(*
this),
1736 template<
class U = OverflowContainer,
typename std::enable_if<has_key_compare<U>::value>::type* =
nullptr>
1737 hopscotch_hash new_hopscotch_hash(size_type bucket_count) {
1738 return hopscotch_hash(bucket_count,
static_cast<Hash&>(*
this),
static_cast<KeyEqual&>(*
this),
1747 static const std::size_t MAX_PROBES_FOR_EMPTY_BUCKET = 12*NeighborhoodSize;
1748 static constexpr float MIN_LOAD_FACTOR_FOR_REHASH = 0.1f;
1750 static bool USE_STORED_HASH_ON_REHASH(size_type bucket_count) {
1751 (
void) bucket_count;
1752 if(StoreHash && is_power_of_two_policy<GrowthPolicy>::value) {
1754 return (bucket_count - 1) <= std::numeric_limits<truncated_hash_type>::max();
1764 hopscotch_bucket* static_empty_bucket_ptr() {
1765 static hopscotch_bucket empty_bucket;
1766 return &empty_bucket;
1770 buckets_container_type m_buckets;
1771 overflow_container_type m_overflow_elements;
1778 hopscotch_bucket* m_first_or_empty_bucket;
1780 size_type m_nb_elements;
1782 float m_max_load_factor;
1787 size_type m_max_load_threshold_rehash;
1793 size_type m_min_load_threshold_rehash;
iterator erase(const_iterator pos)
Definition: hopscotch_hash.h:958
hopscotch_hash(const hopscotch_hash &other)
Definition: hopscotch_hash.h:676
void reserve(size_type count_)
Definition: hopscotch_hash.h:1186
iterator find(const K &key)
Definition: hopscotch_hash.h:1094
friend bool operator==(const hopscotch_iterator &lhs, const hopscotch_iterator &rhs)
Definition: hopscotch_hash.h:584
size_type bucket_count() const
Definition: hopscotch_hash.h:1141
std::pair< iterator, bool > insert_or_assign(key_type &&k, M &&obj)
Definition: hopscotch_hash.h:881
const_iterator end() const noexcept
Definition: hopscotch_hash.h:780
const_iterator cbegin() const noexcept
Definition: hopscotch_hash.h:767
pointer operator->() const
Definition: hopscotch_hash.h:556
std::pair< iterator, bool > insert(const value_type &value)
Definition: hopscotch_hash.h:817
static const size_type DEFAULT_INIT_BUCKETS_SIZE
Definition: hopscotch_hash.h:1743
iterator insert(const_iterator hint, const value_type &value)
Definition: hopscotch_hash.h:831
iterator end() noexcept
Definition: hopscotch_hash.h:776
Definition: hopscotch_hash.h:69
Definition: bhopscotch_map.h:39
iterator insert(const_iterator hint, value_type &&value)
Definition: hopscotch_hash.h:844
iterator insert_or_assign(const_iterator hint, key_type &&k, M &&obj)
Definition: hopscotch_hash.h:899
std::pair< iterator, bool > insert_or_assign(const key_type &k, M &&obj)
Definition: hopscotch_hash.h:876
iterator begin() noexcept
Definition: hopscotch_hash.h:754
hasher hash_function() const
Definition: hopscotch_hash.h:1194
iterator try_emplace(const_iterator hint, key_type &&k, Args &&... args)
Definition: hopscotch_hash.h:941
float max_load_factor() const
Definition: hopscotch_hash.h:1171
U::value_type & at(const K &key, std::size_t hash)
Definition: hopscotch_hash.h:1039
std::pair< iterator, bool > try_emplace(const key_type &k, Args &&... args)
Definition: hopscotch_hash.h:922
#define tsl_assert(expr)
Definition: hopscotch_hash.h:63
const_iterator find(const K &key) const
Definition: hopscotch_hash.h:1105
reference operator*() const
Definition: hopscotch_hash.h:548
iterator mutable_iterator(const_iterator pos)
Definition: hopscotch_hash.h:1205
bool empty() const noexcept
Definition: hopscotch_hash.h:792
iterator emplace_hint(const_iterator hint, Args &&... args)
Definition: hopscotch_hash.h:917
std::pair< iterator, bool > insert(P &&value)
Definition: hopscotch_hash.h:822
std::pair< iterator, bool > insert(value_type &&value)
Definition: hopscotch_hash.h:826
size_type size() const noexcept
Definition: hopscotch_hash.h:796
std::pair< iterator, iterator > equal_range(const K &key)
Definition: hopscotch_hash.h:1116
iterator erase(const_iterator first, const_iterator last)
Definition: hopscotch_hash.h:973
hopscotch_hash(hopscotch_hash &&other) noexcept(std::is_nothrow_move_constructible< Hash >::value &&std::is_nothrow_move_constructible< KeyEqual >::value &&std::is_nothrow_move_constructible< GrowthPolicy >::value &&std::is_nothrow_move_constructible< buckets_container_type >::value &&std::is_nothrow_move_constructible< overflow_container_type >::value)
Definition: hopscotch_hash.h:691
hopscotch_iterator() noexcept
Definition: hopscotch_hash.h:518
std::pair< iterator, bool > try_emplace(key_type &&k, Args &&... args)
Definition: hopscotch_hash.h:927
void max_load_factor(float ml)
Definition: hopscotch_hash.h:1175
const U::value_type & at(const K &key, std::size_t hash) const
Definition: hopscotch_hash.h:1050
U::value_type & at(const K &key)
Definition: hopscotch_hash.h:1034
size_type erase(const K &key, std::size_t hash)
Definition: hopscotch_hash.h:992
static constexpr float DEFAULT_MAX_LOAD_FACTOR
Definition: hopscotch_hash.h:1744
std::pair< iterator, bool > emplace(Args &&... args)
Definition: hopscotch_hash.h:912
void swap(hopscotch_hash &other)
Definition: hopscotch_hash.h:1014
iterator try_emplace(const_iterator hint, const key_type &k, Args &&... args)
Definition: hopscotch_hash.h:932
std::pair< const_iterator, const_iterator > equal_range(const K &key, std::size_t hash) const
Definition: hopscotch_hash.h:1133
void insert(InputIt first, InputIt last)
Definition: hopscotch_hash.h:854
U::key_compare key_comp() const
Definition: hopscotch_hash.h:1223
key_equal key_eq() const
Definition: hopscotch_hash.h:1198
Definition: hopscotch_growth_policy.h:49
hopscotch_hash(size_type bucket_count, const Hash &hash, const KeyEqual &equal, const Allocator &alloc, float max_load_factor, const typename OC::key_compare &comp)
Definition: hopscotch_hash.h:638
size_type max_bucket_count() const
Definition: hopscotch_hash.h:1154
size_type count(const K &key, std::size_t hash) const
Definition: hopscotch_hash.h:1088
size_type count(const K &key) const
Definition: hopscotch_hash.h:1083
iterator find(const K &key, std::size_t hash)
Definition: hopscotch_hash.h:1099
friend bool operator!=(const hopscotch_iterator &lhs, const hopscotch_iterator &rhs)
Definition: hopscotch_hash.h:589
hopscotch_iterator operator++(int)
Definition: hopscotch_hash.h:577
std::pair< iterator, iterator > equal_range(const K &key, std::size_t hash)
Definition: hopscotch_hash.h:1121
hopscotch_iterator & operator++()
Definition: hopscotch_hash.h:564
friend class hopscotch_hash
Definition: hopscotch_hash.h:493
float load_factor() const
Definition: hopscotch_hash.h:1163
size_type overflow_size() const noexcept
Definition: hopscotch_hash.h:1218
const U::value_type & at(const K &key) const
Definition: hopscotch_hash.h:1045
const hopscotch_hash::key_type & key() const
Definition: hopscotch_hash.h:527
iterator insert_or_assign(const_iterator hint, const key_type &k, M &&obj)
Definition: hopscotch_hash.h:887
void rehash(size_type count_)
Definition: hopscotch_hash.h:1181
hopscotch_hash & operator=(hopscotch_hash &&other)
Definition: hopscotch_hash.h:739
size_type max_size() const noexcept
Definition: hopscotch_hash.h:800
U::value_type & operator[](K &&key)
Definition: hopscotch_hash.h:1064
void clear() noexcept
Definition: hopscotch_hash.h:807
const_iterator cend() const noexcept
Definition: hopscotch_hash.h:784
const_iterator find(const K &key, std::size_t hash) const
Definition: hopscotch_hash.h:1110
size_type erase(const K &key)
Definition: hopscotch_hash.h:987
hopscotch_hash(size_type bucket_count, const Hash &hash, const KeyEqual &equal, const Allocator &alloc, float max_load_factor)
Definition: hopscotch_hash.h:601
std::pair< const_iterator, const_iterator > equal_range(const K &key) const
Definition: hopscotch_hash.h:1128
allocator_type get_allocator() const
Definition: hopscotch_hash.h:746
Definition: hopscotch_growth_policy.h:40
iterator erase(iterator pos)
Definition: hopscotch_hash.h:954
hopscotch_iterator(const hopscotch_iterator< false > &other) noexcept
Definition: hopscotch_hash.h:521
hopscotch_hash & operator=(const hopscotch_hash &other)
Definition: hopscotch_hash.h:720
iterator insert(const_iterator hint, P &&value)
Definition: hopscotch_hash.h:840
std::conditional< IsConst, const typename U::value_type &, typename U::value_type & >::type value() const
Definition: hopscotch_hash.h:539
const_iterator begin() const noexcept
Definition: hopscotch_hash.h:763