24 #ifndef TSL_ORDERED_HASH_H 25 #define TSL_ORDERED_HASH_H 41 #include <type_traits> 49 #if (defined(__GNUC__
) && (__GNUC__
== 4
) && (__GNUC_MINOR__
< 9
)) 50 # define TSL_OH_NO_CONTAINER_ERASE_CONST_ITERATOR 51 # define TSL_OH_NO_CONTAINER_EMPLACE_CONST_ITERATOR 60 # define tsl_oh_assert(expr) assert(expr) 62 # define tsl_oh_assert(expr) (static_cast<void>(0
)) 68 #if (defined(__cpp_exceptions
) || defined(__EXCEPTIONS
) || (defined (_MSC_VER) && defined (_CPPUNWIND))) && !defined(TSL_NO_EXCEPTIONS) 69 # define TSL_OH_THROW_OR_TERMINATE(ex, msg) throw ex(msg) 72 # define TSL_OH_THROW_OR_TERMINATE(ex, msg) std::terminate() 75 # define TSL_OH_THROW_OR_TERMINATE(ex, msg) do { std::fprintf(stderr, msg); std::terminate(); } while(0
) 89 template<
typename T,
typename =
void>
90 struct has_is_transparent: std::false_type {
94 struct has_is_transparent<T,
typename make_void<
typename T::is_transparent>::type>: std::true_type {
98 template<
typename T,
typename =
void>
99 struct is_vector: std::false_type {
103 struct is_vector<T,
typename std::enable_if<
104 std::is_same<T, std::vector<
typename T::value_type,
typename T::allocator_type>>::value
105 >::type>: std::true_type {
108 template<
typename T,
typename U>
109 static T numeric_cast(U value,
const char* error_message =
"numeric_cast() failed.") {
110 T ret =
static_cast<T>(value);
111 if(
static_cast<U>(ret) != value) {
115 const bool is_same_signedness = (std::is_unsigned<T>::value && std::is_unsigned<U>::value) ||
116 (std::is_signed<T>::value && std::is_signed<U>::value);
117 if(!is_same_signedness && (ret < T{}) != (value < U{})) {
129 using slz_size_type = std::uint64_t;
130 static_assert(std::numeric_limits<slz_size_type>::max() >= std::numeric_limits<std::size_t>::max(),
131 "slz_size_type must be >= std::size_t");
133 template<
class T,
class Deserializer>
134 static T deserialize_value(Deserializer& deserializer) {
136 #if defined (_MSC_VER) && _MSC_VER < 1910
137 return deserializer.Deserializer::operator()<T>();
139 return deserializer.Deserializer::
template operator()<T>();
151 template<
class IndexType>
153 static_assert(std::is_unsigned<IndexType>::value,
"IndexType must be an unsigned value.");
154 static_assert(std::numeric_limits<IndexType>::max() <= std::numeric_limits<std::size_t>::max(),
155 "std::numeric_limits<IndexType>::max() must be <= std::numeric_limits<std::size_t>::max().");
158 using index_type = IndexType;
159 using truncated_hash_type =
typename std::conditional<std::numeric_limits<IndexType>::max() <=
160 std::numeric_limits<std::uint_least32_t>::max(),
164 bucket_entry()
noexcept: m_index(EMPTY_MARKER_INDEX), m_hash(0) {
167 bool empty()
const noexcept {
168 return m_index == EMPTY_MARKER_INDEX;
171 void clear()
noexcept {
172 m_index = EMPTY_MARKER_INDEX;
175 index_type index()
const noexcept {
180 index_type& index_ref()
noexcept {
185 void set_index(index_type index)
noexcept {
191 truncated_hash_type truncated_hash()
const noexcept {
196 truncated_hash_type& truncated_hash_ref()
noexcept {
201 void set_hash(std::size_t hash)
noexcept {
202 m_hash = truncate_hash(hash);
205 template<
class Serializer>
206 void serialize(Serializer& serializer)
const {
207 const slz_size_type index = m_index;
210 const slz_size_type hash = m_hash;
214 template<
class Deserializer>
215 static bucket_entry deserialize(Deserializer& deserializer) {
216 const slz_size_type index = deserialize_value<slz_size_type>(deserializer);
217 const slz_size_type hash = deserialize_value<slz_size_type>(deserializer);
220 bentry.m_index = numeric_cast<index_type>(index,
"Deserialized index is too big.");
221 bentry.m_hash = numeric_cast<truncated_hash_type>(hash,
"Deserialized hash is too big.");
228 static truncated_hash_type truncate_hash(std::size_t hash)
noexcept {
229 return truncated_hash_type(hash);
232 static std::size_t max_size()
noexcept {
233 return static_cast<std::size_t>(std::numeric_limits<index_type>::max()) - NB_RESERVED_INDEXES;
237 static const index_type EMPTY_MARKER_INDEX = std::numeric_limits<index_type>::max();
238 static const std::size_t NB_RESERVED_INDEXES = 1;
241 truncated_hash_type m_hash;
271 template<
class ValueType,
277 class ValueTypeContainer,
282 using has_mapped_type =
typename std::integral_constant<
bool, !std::is_same<U,
void>::value>;
284 static_assert(std::is_same<
typename ValueTypeContainer::value_type, ValueType>::value,
285 "ValueTypeContainer::value_type != ValueType. " 286 "Check that the ValueTypeContainer has 'Key' as type for a set or 'std::pair<Key, T>' as type for a map.");
288 static_assert(std::is_same<
typename ValueTypeContainer::allocator_type, Allocator>::value,
289 "ValueTypeContainer::allocator_type != Allocator. " 290 "Check that the allocator for ValueTypeContainer is the same as Allocator.");
292 static_assert(std::is_same<
typename Allocator::value_type, ValueType>::value,
293 "Allocator::value_type != ValueType. " 294 "Check that the allocator has 'Key' as type for a set or 'std::pair<Key, T>' as type for a map.");
298 template<
bool IsConst>
301 using key_type =
typename KeySelect::key_type;
302 using value_type = ValueType;
303 using size_type = std::size_t;
304 using difference_type = std::ptrdiff_t;
306 using key_equal = KeyEqual;
307 using allocator_type = Allocator;
308 using reference = value_type&;
309 using const_reference =
const value_type&;
310 using pointer = value_type*;
311 using const_pointer =
const value_type*;
314 using reverse_iterator = std::reverse_iterator<iterator>;
315 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
317 using values_container_type = ValueTypeContainer;
320 template<
bool IsConst>
325 using iterator =
typename std::conditional<IsConst,
326 typename values_container_type::const_iterator,
327 typename values_container_type::iterator>::type;
330 ordered_iterator(iterator it)
noexcept: m_iterator(it) {
334 using iterator_category = std::random_access_iterator_tag;
336 using difference_type =
typename iterator::difference_type;
337 using reference = value_type&;
338 using pointer = value_type*;
345 template<
bool TIsConst = IsConst,
typename std::enable_if<TIsConst>::type* =
nullptr>
355 return KeySelect()(*m_iterator);
358 template<
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value && IsConst>::type* =
nullptr>
360 return U()(*m_iterator);
363 template<
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value && !IsConst>::type* =
nullptr>
365 return U()(*m_iterator);
368 reference
operator*()
const {
return *m_iterator; }
369 pointer
operator->()
const {
return m_iterator.operator->(); }
377 reference
operator[](difference_type n)
const {
return m_iterator[n]; }
386 return lhs.m_iterator == rhs.m_iterator;
390 return lhs.m_iterator != rhs.m_iterator;
394 return lhs.m_iterator < rhs.m_iterator;
398 return lhs.m_iterator > rhs.m_iterator;
402 return lhs.m_iterator <= rhs.m_iterator;
406 return lhs.m_iterator >= rhs.m_iterator;
410 return n + it.m_iterator;
414 return lhs.m_iterator - rhs.m_iterator;
425 using buckets_container_allocator =
typename 426 std::allocator_traits<allocator_type>::
template rebind_alloc<bucket_entry>;
428 using buckets_container_type = std::vector<bucket_entry, buckets_container_allocator>;
431 using truncated_hash_type =
typename bucket_entry::truncated_hash_type;
432 using index_type =
typename bucket_entry::index_type;
437 const KeyEqual& equal,
438 const Allocator& alloc,
439 float max_load_factor): Hash(hash),
441 m_buckets_data(alloc),
442 m_buckets(static_empty_bucket_ptr()),
445 m_grow_on_next_insert(
false)
451 if(bucket_count > 0) {
452 bucket_count = round_up_to_power_of_two(bucket_count);
454 m_buckets_data.resize(bucket_count);
455 m_buckets = m_buckets_data.data(),
456 m_mask = bucket_count - 1;
459 this->max_load_factor(max_load_factor);
464 m_buckets_data(other.m_buckets_data),
465 m_buckets(m_buckets_data.empty()?static_empty_bucket_ptr():
466 m_buckets_data.data()),
467 m_mask(other.m_mask),
468 m_values(other.m_values),
469 m_grow_on_next_insert(other.m_grow_on_next_insert),
470 m_max_load_factor(other.m_max_load_factor),
471 m_load_threshold(other.m_load_threshold)
479 : Hash(std::move(
static_cast<Hash&>(other))),
480 KeyEqual(std::move(
static_cast<KeyEqual&>(other))),
481 m_buckets_data(std::move(other.m_buckets_data)),
482 m_buckets(m_buckets_data.empty()?static_empty_bucket_ptr():
483 m_buckets_data.data()),
484 m_mask(other.m_mask),
485 m_values(std::move(other.m_values)),
486 m_grow_on_next_insert(other.m_grow_on_next_insert),
487 m_max_load_factor(other.m_max_load_factor),
488 m_load_threshold(other.m_load_threshold)
490 other.m_buckets_data.clear();
491 other.m_buckets = static_empty_bucket_ptr();
493 other.m_values.clear();
494 other.m_grow_on_next_insert =
false;
495 other.m_load_threshold = 0;
500 Hash::operator=(other);
501 KeyEqual::operator=(other);
503 m_buckets_data = other.m_buckets_data;
504 m_buckets = m_buckets_data.empty()?static_empty_bucket_ptr():
505 m_buckets_data.data();
507 m_mask = other.m_mask;
508 m_values = other.m_values;
509 m_grow_on_next_insert = other.m_grow_on_next_insert;
510 m_max_load_factor = other.m_max_load_factor;
511 m_load_threshold = other.m_load_threshold;
525 return m_values.get_allocator();
533 return iterator(m_values.begin());
536 const_iterator
begin()
const noexcept {
541 return const_iterator(m_values.cbegin());
545 return iterator(m_values.end());
548 const_iterator
end()
const noexcept {
552 const_iterator
cend()
const noexcept {
553 return const_iterator(m_values.cend());
558 return reverse_iterator(m_values.end());
561 const_reverse_iterator
rbegin()
const noexcept {
565 const_reverse_iterator
rcbegin()
const noexcept {
566 return const_reverse_iterator(m_values.cend());
569 reverse_iterator
rend()
noexcept {
570 return reverse_iterator(m_values.begin());
573 const_reverse_iterator
rend()
const noexcept {
577 const_reverse_iterator
rcend()
const noexcept {
578 return const_reverse_iterator(m_values.cbegin());
586 return m_values.empty();
589 size_type
size()
const noexcept {
590 return m_values.size();
594 return std::min(bucket_entry::max_size(), m_values.max_size());
602 for(
auto& bucket: m_buckets_data) {
607 m_grow_on_next_insert =
false;
611 std::pair<iterator,
bool>
insert(P&& value) {
612 return insert_impl(KeySelect()(value), std::forward<P>(value));
617 if(hint !=
cend() && compare_keys(KeySelect()(*hint), KeySelect()(value))) {
621 return insert(std::forward<P>(value)).first;
624 template<
class InputIt>
625 void insert(InputIt first, InputIt last) {
626 if(std::is_base_of<std::forward_iterator_tag,
627 typename std::iterator_traits<InputIt>::iterator_category>::value)
629 const auto nb_elements_insert = std::distance(first, last);
630 const size_type nb_free_buckets = m_load_threshold -
size();
633 if(nb_elements_insert > 0 && nb_free_buckets < size_type(nb_elements_insert)) {
638 for(; first != last; ++first) {
645 template<
class K,
class M>
647 auto it = try_emplace(std::forward<K>(key), std::forward<M>(value));
649 it.first.value() = std::forward<M>(value);
655 template<
class K,
class M>
657 if(hint !=
cend() && compare_keys(KeySelect()(*hint), key)) {
659 it.value() = std::forward<M>(obj);
664 return insert_or_assign(std::forward<K>(key), std::forward<M>(obj)).first;
669 template<
class... Args>
670 std::pair<iterator,
bool>
emplace(Args&&... args) {
671 return insert(value_type(std::forward<Args>(args)...));
674 template<
class... Args>
676 return insert_hint(hint, value_type(std::forward<Args>(args)...));
681 template<
class K,
class... Args>
682 std::pair<iterator,
bool>
try_emplace(K&& key, Args&&... value_args) {
683 return insert_impl(key, std::piecewise_construct,
684 std::forward_as_tuple(std::forward<K>(key)),
685 std::forward_as_tuple(std::forward<Args>(value_args)...));
688 template<
class K,
class... Args>
690 if(hint !=
cend() && compare_keys(KeySelect()(*hint), key)) {
694 return try_emplace(std::forward<K>(key), std::forward<Args>(args)...).first;
704 return erase(const_iterator(pos));
707 iterator
erase(const_iterator pos) {
710 const std::size_t index_erase = iterator_to_index(pos);
712 auto it_bucket = find_key(pos.key(), hash_key(pos.key()));
715 erase_value_from_bucket(it_bucket);
721 return begin() + index_erase;
724 iterator
erase(const_iterator first, const_iterator last) {
730 const std::size_t start_index = iterator_to_index(first);
731 const std::size_t nb_values = std::size_t(std::distance(first, last));
732 const std::size_t end_index = start_index + nb_values;
735 #ifdef TSL_OH_NO_CONTAINER_ERASE_CONST_ITERATOR
738 auto next_it = m_values.erase(first.m_iterator, last.m_iterator);
747 std::size_t ibucket = 0;
748 while(ibucket < m_buckets_data.size()) {
749 if(m_buckets[ibucket].empty()) {
752 else if(m_buckets[ibucket].index() >= start_index && m_buckets[ibucket].index() < end_index) {
753 m_buckets[ibucket].clear();
754 backward_shift(ibucket);
757 else if(m_buckets[ibucket].index() >= end_index) {
758 m_buckets[ibucket].set_index(index_type(m_buckets[ibucket].index() - nb_values));
766 return iterator(next_it);
772 return erase(key, hash_key(key));
776 size_type
erase(
const K& key, std::size_t hash) {
777 return erase_impl(key, hash);
783 swap(
static_cast<Hash&>(*
this),
static_cast<Hash&>(other));
784 swap(
static_cast<KeyEqual&>(*
this),
static_cast<KeyEqual&>(other));
785 swap(m_buckets_data, other.m_buckets_data);
786 swap(m_buckets, other.m_buckets);
787 swap(m_mask, other.m_mask);
788 swap(m_values, other.m_values);
789 swap(m_grow_on_next_insert, other.m_grow_on_next_insert);
790 swap(m_max_load_factor, other.m_max_load_factor);
791 swap(m_load_threshold, other.m_load_threshold);
800 template<
class K,
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value>::type* =
nullptr>
802 return at(key, hash_key(key));
805 template<
class K,
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value>::type* =
nullptr>
807 return const_cast<
typename U::value_type&>(
static_cast<
const ordered_hash*>(
this)->at(key, hash));
810 template<
class K,
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value>::type* =
nullptr>
812 return at(key, hash_key(key));
815 template<
class K,
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value>::type* =
nullptr>
816 const typename U::
value_type&
at(
const K& key, std::size_t hash)
const {
817 auto it = find(key, hash);
827 template<
class K,
class U = ValueSelect,
typename std::enable_if<has_mapped_type<U>::value>::type* =
nullptr>
829 return try_emplace(std::forward<K>(key)).first.value();
834 size_type
count(
const K& key)
const {
835 return count(key, hash_key(key));
839 size_type
count(
const K& key, std::size_t hash)
const {
840 if(find(key, hash) ==
cend()) {
850 return find(key, hash_key(key));
854 iterator
find(
const K& key, std::size_t hash) {
855 auto it_bucket = find_key(key, hash);
856 return (it_bucket != m_buckets_data.end())?iterator(m_values.begin() + it_bucket->index()):end();
860 const_iterator
find(
const K& key)
const {
861 return find(key, hash_key(key));
865 const_iterator
find(
const K& key, std::size_t hash)
const {
866 auto it_bucket = find_key(key, hash);
867 return (it_bucket != m_buckets_data.cend())?const_iterator(m_values.begin() + it_bucket->index()):end();
873 return equal_range(key, hash_key(key));
877 std::pair<iterator, iterator>
equal_range(
const K& key, std::size_t hash) {
878 iterator it = find(key, hash);
879 return std::make_pair(it, (it == end())?it:std::next(it));
883 std::pair<const_iterator, const_iterator>
equal_range(
const K& key)
const {
884 return equal_range(key, hash_key(key));
888 std::pair<const_iterator, const_iterator>
equal_range(
const K& key, std::size_t hash)
const {
889 const_iterator it = find(key, hash);
890 return std::make_pair(it, (it ==
cend())?it:std::next(it));
898 return m_buckets_data.size();
902 return m_buckets_data.max_size();
917 return m_max_load_factor;
921 m_max_load_factor = std::max(0.1f, std::min(ml, 0.95f));
922 m_load_threshold = size_type(
float(
bucket_count())*m_max_load_factor);
926 count = std::max(count, size_type(std::ceil(
float(
size())/max_load_factor())));
931 reserve_space_for_values(count);
933 count = size_type(std::ceil(
float(count)/max_load_factor()));
942 return static_cast<
const Hash&>(*
this);
946 return static_cast<
const KeyEqual&>(*
this);
954 return iterator(m_values.begin() + iterator_to_index(pos));
957 iterator
nth(size_type index) {
959 return iterator(m_values.begin() + index);
962 const_iterator
nth(size_type index)
const {
964 return const_iterator(m_values.cbegin() + index);
969 return m_values.front();
974 return m_values.back();
981 template<
class U = values_container_type,
typename std::enable_if<is_vector<U>::value>::type* =
nullptr>
983 return m_values.data();
986 template<
class U = values_container_type,
typename std::enable_if<is_vector<U>::value>::type* =
nullptr>
988 return m_values.capacity();
992 m_values.shrink_to_fit();
998 return insert_at_position_impl(pos.m_iterator, KeySelect()(value), std::forward<P>(value));
1001 template<
class... Args>
1003 return insert_at_position(pos, value_type(std::forward<Args>(args)...));
1006 template<
class K,
class... Args>
1008 return insert_at_position_impl(pos.m_iterator, key,
1009 std::piecewise_construct,
1010 std::forward_as_tuple(std::forward<K>(key)),
1011 std::forward_as_tuple(std::forward<Args>(value_args)...));
1017 erase(std::prev(end()));
1026 return unordered_erase(const_iterator(pos));
1030 const std::size_t index_erase = iterator_to_index(pos);
1031 unordered_erase(pos.key());
1037 return begin() + index_erase;
1042 return unordered_erase(key, hash_key(key));
1047 auto it_bucket_key = find_key(key, hash);
1048 if(it_bucket_key == m_buckets_data.end()) {
1057 if(!compare_keys(key, KeySelect()(
back()))) {
1058 auto it_bucket_last_elem = find_key(KeySelect()(
back()), hash_key(KeySelect()(
back())));
1060 tsl_oh_assert(it_bucket_last_elem->index() == m_values.size() - 1);
1063 swap(m_values[it_bucket_key->index()], m_values[it_bucket_last_elem->index()]);
1064 swap(it_bucket_key->index_ref(), it_bucket_last_elem->index_ref());
1067 erase_value_from_bucket(it_bucket_key);
1072 template<
class Serializer>
1074 serialize_impl(serializer);
1077 template<
class Deserializer>
1079 deserialize_impl(deserializer, hash_compatible);
1083 return lhs.m_values == rhs.m_values;
1087 return lhs.m_values != rhs.m_values;
1091 return lhs.m_values < rhs.m_values;
1095 return lhs.m_values <= rhs.m_values;
1099 return lhs.m_values > rhs.m_values;
1103 return lhs.m_values >= rhs.m_values;
1109 std::size_t hash_key(
const K& key)
const {
1110 return Hash::operator()(key);
1113 template<
class K1,
class K2>
1114 bool compare_keys(
const K1& key1,
const K2& key2)
const {
1115 return KeyEqual::operator()(key1, key2);
1119 typename buckets_container_type::iterator find_key(
const K& key, std::size_t hash) {
1120 auto it =
static_cast<
const ordered_hash*>(
this)->find_key(key, hash);
1121 return m_buckets_data.begin() + std::distance(m_buckets_data.cbegin(), it);
1132 typename buckets_container_type::const_iterator find_key(
const K& key, std::size_t hash)
const {
1133 for(std::size_t ibucket = bucket_for_hash(hash), dist_from_ideal_bucket = 0; ;
1134 ibucket = next_bucket(ibucket), dist_from_ideal_bucket++)
1136 if(m_buckets[ibucket].empty()) {
1137 return m_buckets_data.end();
1139 else if(m_buckets[ibucket].truncated_hash() == bucket_entry::truncate_hash(hash) &&
1140 compare_keys(key, KeySelect()(m_values[m_buckets[ibucket].index()])))
1142 return m_buckets_data.begin() + ibucket;
1144 else if(dist_from_ideal_bucket > distance_from_ideal_bucket(ibucket)) {
1145 return m_buckets_data.end();
1150 void rehash_impl(size_type bucket_count) {
1151 tsl_oh_assert(bucket_count >= size_type(std::ceil(
float(size())/max_load_factor())));
1157 if(bucket_count > 0) {
1158 bucket_count = round_up_to_power_of_two(bucket_count);
1161 if(bucket_count ==
this->bucket_count()) {
1166 buckets_container_type old_buckets(bucket_count);
1167 m_buckets_data.swap(old_buckets);
1168 m_buckets = m_buckets_data.empty()?static_empty_bucket_ptr():
1169 m_buckets_data.data();
1172 m_mask = (bucket_count > 0)?(bucket_count - 1):0;
1173 this->max_load_factor(m_max_load_factor);
1174 m_grow_on_next_insert =
false;
1178 for(
const bucket_entry& old_bucket: old_buckets) {
1179 if(old_bucket.empty()) {
1183 truncated_hash_type insert_hash = old_bucket.truncated_hash();
1184 index_type insert_index = old_bucket.index();
1186 for(std::size_t ibucket = bucket_for_hash(insert_hash), dist_from_ideal_bucket = 0; ;
1187 ibucket = next_bucket(ibucket), dist_from_ideal_bucket++)
1189 if(m_buckets[ibucket].empty()) {
1190 m_buckets[ibucket].set_index(insert_index);
1191 m_buckets[ibucket].set_hash(insert_hash);
1195 const std::size_t distance = distance_from_ideal_bucket(ibucket);
1196 if(dist_from_ideal_bucket > distance) {
1197 std::swap(insert_index, m_buckets[ibucket].index_ref());
1198 std::swap(insert_hash, m_buckets[ibucket].truncated_hash_ref());
1199 dist_from_ideal_bucket = distance;
1205 template<
class T = values_container_type,
typename std::enable_if<is_vector<T>::value>::type* =
nullptr>
1206 void reserve_space_for_values(size_type count) {
1207 m_values.reserve(count);
1210 template<
class T = values_container_type,
typename std::enable_if<!is_vector<T>::value>::type* =
nullptr>
1211 void reserve_space_for_values(size_type ) {
1218 void backward_shift(std::size_t empty_ibucket)
noexcept {
1221 std::size_t previous_ibucket = empty_ibucket;
1222 for(std::size_t current_ibucket = next_bucket(previous_ibucket);
1223 !m_buckets[current_ibucket].empty() && distance_from_ideal_bucket(current_ibucket) > 0;
1224 previous_ibucket = current_ibucket, current_ibucket = next_bucket(current_ibucket))
1226 std::swap(m_buckets[current_ibucket], m_buckets[previous_ibucket]);
1230 void erase_value_from_bucket(
typename buckets_container_type::iterator it_bucket) {
1231 tsl_oh_assert(it_bucket != m_buckets_data.end() && !it_bucket->empty());
1233 m_values.erase(m_values.begin() + it_bucket->index());
1239 if(it_bucket->index() != m_values.size()) {
1240 shift_indexes_in_buckets(it_bucket->index(), -1);
1245 backward_shift(std::size_t(std::distance(m_buckets_data.begin(), it_bucket)));
1254 void shift_indexes_in_buckets(index_type from_ivalue,
int delta)
noexcept {
1257 for(std::size_t ivalue = from_ivalue; ivalue < m_values.size(); ivalue++) {
1260 const index_type old_index =
static_cast<index_type>(ivalue - delta);
1262 std::size_t ibucket = bucket_for_hash(hash_key(KeySelect()(m_values[ivalue])));
1263 while(m_buckets[ibucket].index() != old_index) {
1264 ibucket = next_bucket(ibucket);
1267 m_buckets[ibucket].set_index(index_type(ivalue));
1272 size_type erase_impl(
const K& key, std::size_t hash) {
1273 auto it_bucket = find_key(key, hash);
1274 if(it_bucket != m_buckets_data.end()) {
1275 erase_value_from_bucket(it_bucket);
1287 template<
class K,
class... Args>
1288 std::pair<iterator,
bool> insert_impl(
const K& key, Args&&... value_type_args) {
1289 const std::size_t hash = hash_key(key);
1291 std::size_t ibucket = bucket_for_hash(hash);
1292 std::size_t dist_from_ideal_bucket = 0;
1294 while(!m_buckets[ibucket].empty() && dist_from_ideal_bucket <= distance_from_ideal_bucket(ibucket)) {
1295 if(m_buckets[ibucket].truncated_hash() == bucket_entry::truncate_hash(hash) &&
1296 compare_keys(key, KeySelect()(m_values[m_buckets[ibucket].index()])))
1298 return std::make_pair(begin() + m_buckets[ibucket].index(),
false);
1301 ibucket = next_bucket(ibucket);
1302 dist_from_ideal_bucket++;
1310 if(grow_on_high_load()) {
1311 ibucket = bucket_for_hash(hash);
1312 dist_from_ideal_bucket = 0;
1316 m_values.emplace_back(std::forward<Args>(value_type_args)...);
1317 insert_index(ibucket, dist_from_ideal_bucket,
1318 index_type(m_values.size() - 1), bucket_entry::truncate_hash(hash));
1321 return std::make_pair(std::prev(end()),
true);
1327 template<
class K,
class... Args>
1328 std::pair<iterator,
bool> insert_at_position_impl(
typename values_container_type::const_iterator insert_position,
1329 const K& key, Args&&... value_type_args)
1331 const std::size_t hash = hash_key(key);
1333 std::size_t ibucket = bucket_for_hash(hash);
1334 std::size_t dist_from_ideal_bucket = 0;
1336 while(!m_buckets[ibucket].empty() && dist_from_ideal_bucket <= distance_from_ideal_bucket(ibucket)) {
1337 if(m_buckets[ibucket].truncated_hash() == bucket_entry::truncate_hash(hash) &&
1338 compare_keys(key, KeySelect()(m_values[m_buckets[ibucket].index()])))
1340 return std::make_pair(begin() + m_buckets[ibucket].index(),
false);
1343 ibucket = next_bucket(ibucket);
1344 dist_from_ideal_bucket++;
1352 if(grow_on_high_load()) {
1353 ibucket = bucket_for_hash(hash);
1354 dist_from_ideal_bucket = 0;
1358 const index_type index_insert_position = index_type(std::distance(m_values.cbegin(), insert_position));
1360 #ifdef TSL_OH_NO_CONTAINER_EMPLACE_CONST_ITERATOR
1361 m_values.emplace(m_values.begin() + std::distance(m_values.cbegin(), insert_position), std::forward<Args>(value_type_args)...);
1363 m_values.emplace(insert_position, std::forward<Args>(value_type_args)...);
1366 insert_index(ibucket, dist_from_ideal_bucket,
1367 index_insert_position, bucket_entry::truncate_hash(hash));
1373 if(index_insert_position != m_values.size() - 1) {
1374 shift_indexes_in_buckets(index_insert_position + 1, 1);
1377 return std::make_pair(iterator(m_values.begin() + index_insert_position),
true);
1380 void insert_index(std::size_t ibucket, std::size_t dist_from_ideal_bucket,
1381 index_type index_insert, truncated_hash_type hash_insert)
noexcept 1383 while(!m_buckets[ibucket].empty()) {
1384 const std::size_t distance = distance_from_ideal_bucket(ibucket);
1385 if(dist_from_ideal_bucket > distance) {
1386 std::swap(index_insert, m_buckets[ibucket].index_ref());
1387 std::swap(hash_insert, m_buckets[ibucket].truncated_hash_ref());
1389 dist_from_ideal_bucket = distance;
1393 ibucket = next_bucket(ibucket);
1394 dist_from_ideal_bucket++;
1397 if(dist_from_ideal_bucket > REHASH_ON_HIGH_NB_PROBES__NPROBES && !m_grow_on_next_insert &&
1402 m_grow_on_next_insert =
true;
1407 m_buckets[ibucket].set_index(index_insert);
1408 m_buckets[ibucket].set_hash(hash_insert);
1411 std::size_t distance_from_ideal_bucket(std::size_t ibucket)
const noexcept {
1412 const std::size_t ideal_bucket = bucket_for_hash(m_buckets[ibucket].truncated_hash());
1414 if(ibucket >= ideal_bucket) {
1415 return ibucket - ideal_bucket;
1424 std::size_t next_bucket(std::size_t index)
const noexcept {
1428 return (index < m_buckets_data.size())?index:0;
1431 std::size_t bucket_for_hash(std::size_t hash)
const noexcept {
1432 return hash & m_mask;
1435 std::size_t iterator_to_index(const_iterator it)
const noexcept {
1436 const auto dist = std::distance(
cbegin(), it);
1439 return std::size_t(dist);
1445 bool grow_on_high_load() {
1446 if(m_grow_on_next_insert ||
size() >= m_load_threshold) {
1448 m_grow_on_next_insert =
false;
1457 template<
class Serializer>
1458 void serialize_impl(Serializer& serializer)
const {
1459 const slz_size_type version = SERIALIZATION_PROTOCOL_VERSION;
1460 serializer(version);
1462 const slz_size_type nb_elements = m_values.size();
1463 serializer(nb_elements);
1465 const slz_size_type bucket_count = m_buckets_data.size();
1466 serializer(bucket_count);
1468 const float max_load_factor = m_max_load_factor;
1469 serializer(max_load_factor);
1472 for(
const value_type& value: m_values) {
1476 for(
const bucket_entry& bucket: m_buckets_data) {
1477 bucket.serialize(serializer);
1481 template<
class Deserializer>
1482 void deserialize_impl(Deserializer& deserializer,
bool hash_compatible) {
1485 const slz_size_type version = deserialize_value<slz_size_type>(deserializer);
1488 if(version != SERIALIZATION_PROTOCOL_VERSION) {
1490 "The protocol version header is invalid.");
1493 const slz_size_type nb_elements = deserialize_value<slz_size_type>(deserializer);
1494 const slz_size_type bucket_count_ds = deserialize_value<slz_size_type>(deserializer);
1495 const float max_load_factor = deserialize_value<
float>(deserializer);
1498 this->max_load_factor(max_load_factor);
1500 if(bucket_count_ds == 0) {
1506 if(!hash_compatible) {
1507 reserve(numeric_cast<size_type>(nb_elements,
"Deserialized nb_elements is too big.")
);
1508 for(slz_size_type el = 0; el < nb_elements; el++) {
1509 insert(deserialize_value<value_type>(deserializer));
1513 m_buckets_data.reserve(numeric_cast<size_type>(bucket_count_ds,
"Deserialized bucket_count is too big."));
1514 m_buckets = m_buckets_data.data(),
1515 m_mask = m_buckets_data.capacity() - 1;
1517 reserve_space_for_values(numeric_cast<size_type>(nb_elements,
"Deserialized nb_elements is too big."));
1518 for(slz_size_type el = 0; el < nb_elements; el++) {
1519 m_values.push_back(deserialize_value<value_type>(deserializer));
1522 for(slz_size_type b = 0; b < bucket_count_ds; b++) {
1523 m_buckets_data.push_back(bucket_entry::deserialize(deserializer));
1528 "and deserializer supports floats correctly as they " 1529 "can be converted implicitely to ints.");
1534 static std::size_t round_up_to_power_of_two(std::size_t value) {
1535 if(is_power_of_two(value)) {
1544 for(std::size_t i = 1; i <
sizeof(std::size_t) * CHAR_BIT; i *= 2) {
1545 value |= value >> i;
1551 static constexpr bool is_power_of_two(std::size_t value) {
1552 return value != 0 && (value & (value - 1)) == 0;
1561 static const size_type REHASH_ON_HIGH_NB_PROBES__NPROBES = 128;
1562 static constexpr float REHASH_ON_HIGH_NB_PROBES__MIN_LOAD_FACTOR = 0.15f;
1567 static const slz_size_type SERIALIZATION_PROTOCOL_VERSION = 1;
1572 bucket_entry* static_empty_bucket_ptr() {
1573 static bucket_entry empty_bucket;
1574 return &empty_bucket;
1578 buckets_container_type m_buckets_data;
1587 bucket_entry* m_buckets;
1591 values_container_type m_values;
1593 bool m_grow_on_next_insert;
1594 float m_max_load_factor;
1595 size_type m_load_threshold;
size_type unordered_erase(const K &key, std::size_t hash)
Definition: ordered_hash.h:1046
U::value_type & at(const K &key, std::size_t hash)
Definition: ordered_hash.h:806
std::pair< iterator, bool > insert(P &&value)
Definition: ordered_hash.h:611
iterator emplace_hint(const_iterator hint, Args &&... args)
Definition: ordered_hash.h:675
iterator try_emplace_hint(const_iterator hint, K &&key, Args &&... args)
Definition: ordered_hash.h:689
static constexpr float DEFAULT_MAX_LOAD_FACTOR
Definition: ordered_hash.h:1558
Definition: ordered_hash.h:279
const_reverse_iterator rcbegin() const noexcept
Definition: ordered_hash.h:565
size_type bucket_count() const
Definition: ordered_hash.h:897
static const size_type DEFAULT_INIT_BUCKETS_SIZE
Definition: ordered_hash.h:1557
void pop_back()
Definition: ordered_hash.h:1015
ordered_iterator(const ordered_iterator<!TIsConst > &other) noexcept
Definition: ordered_hash.h:346
friend bool operator>(const ordered_hash &lhs, const ordered_hash &rhs)
Definition: ordered_hash.h:1098
size_type count(const K &key, std::size_t hash) const
Definition: ordered_hash.h:839
ordered_iterator() noexcept
Definition: ordered_hash.h:341
Definition: ordered_hash.h:82
iterator mutable_iterator(const_iterator pos)
Definition: ordered_hash.h:953
Definition: ordered_hash.h:80
const ordered_hash::key_type & key() const
Definition: ordered_hash.h:354
const_reverse_iterator rend() const noexcept
Definition: ordered_hash.h:573
std::pair< iterator, iterator > equal_range(const K &key)
Definition: ordered_hash.h:872
ordered_iterator operator-(difference_type n)
Definition: ordered_hash.h:383
friend bool operator!=(const ordered_iterator &lhs, const ordered_iterator &rhs)
Definition: ordered_hash.h:389
key_equal key_eq() const
Definition: ordered_hash.h:945
void deserialize(Deserializer &deserializer, bool hash_compatible)
Definition: ordered_hash.h:1078
friend bool operator<=(const ordered_hash &lhs, const ordered_hash &rhs)
Definition: ordered_hash.h:1094
std::pair< iterator, bool > try_emplace_at_position(const_iterator pos, K &&key, Args &&... value_args)
Definition: ordered_hash.h:1007
const_iterator end() const noexcept
Definition: ordered_hash.h:548
iterator erase(const_iterator pos)
Definition: ordered_hash.h:707
reference operator[](difference_type n) const
Definition: ordered_hash.h:377
const_iterator find(const K &key) const
Definition: ordered_hash.h:860
iterator unordered_erase(const_iterator pos)
Definition: ordered_hash.h:1029
const_iterator cend() const noexcept
Definition: ordered_hash.h:552
const_iterator begin() const noexcept
Definition: ordered_hash.h:536
friend bool operator>(const ordered_iterator &lhs, const ordered_iterator &rhs)
Definition: ordered_hash.h:397
void insert(InputIt first, InputIt last)
Definition: ordered_hash.h:625
iterator end() noexcept
Definition: ordered_hash.h:544
size_type capacity() const noexcept
Definition: ordered_hash.h:987
const U::value_type & at(const K &key, std::size_t hash) const
Definition: ordered_hash.h:816
reference operator*() const
Definition: ordered_hash.h:368
friend bool operator<(const ordered_iterator &lhs, const ordered_iterator &rhs)
Definition: ordered_hash.h:393
friend bool operator>=(const ordered_iterator &lhs, const ordered_iterator &rhs)
Definition: ordered_hash.h:405
size_type unordered_erase(const K &key)
Definition: ordered_hash.h:1041
iterator find(const K &key, std::size_t hash)
Definition: ordered_hash.h:854
friend bool operator==(const ordered_iterator &lhs, const ordered_iterator &rhs)
Definition: ordered_hash.h:385
std::pair< iterator, bool > try_emplace(K &&key, Args &&... value_args)
Definition: ordered_hash.h:682
ordered_iterator operator--(int)
Definition: ordered_hash.h:375
friend bool operator>=(const ordered_hash &lhs, const ordered_hash &rhs)
Definition: ordered_hash.h:1102
iterator insert_or_assign(const_iterator hint, K &&key, M &&obj)
Definition: ordered_hash.h:656
void reserve(size_type count)
Definition: ordered_hash.h:930
std::pair< iterator, bool > emplace_at_position(const_iterator pos, Args &&... args)
Definition: ordered_hash.h:1002
const values_container_type::value_type * data() const noexcept
Definition: ordered_hash.h:982
iterator begin() noexcept
Definition: ordered_hash.h:532
friend class ordered_hash
Definition: ordered_hash.h:322
void clear() noexcept
Definition: ordered_hash.h:601
iterator erase(iterator pos)
Definition: ordered_hash.h:703
size_type count(const K &key) const
Definition: ordered_hash.h:834
friend bool operator<=(const ordered_iterator &lhs, const ordered_iterator &rhs)
Definition: ordered_hash.h:401
allocator_type get_allocator() const
Definition: ordered_hash.h:524
size_type erase(const K &key, std::size_t hash)
Definition: ordered_hash.h:776
ordered_iterator(ordered_iterator &&other)=default
std::pair< iterator, bool > insert_or_assign(K &&key, M &&value)
Definition: ordered_hash.h:646
float max_load_factor() const
Definition: ordered_hash.h:916
ordered_iterator & operator-=(difference_type n)
Definition: ordered_hash.h:380
friend bool operator!=(const ordered_hash &lhs, const ordered_hash &rhs)
Definition: ordered_hash.h:1086
U::value_type & operator[](K &&key)
Definition: ordered_hash.h:828
const_iterator cbegin() const noexcept
Definition: ordered_hash.h:540
const_iterator nth(size_type index) const
Definition: ordered_hash.h:962
std::pair< const_iterator, const_iterator > equal_range(const K &key) const
Definition: ordered_hash.h:883
bool empty() const noexcept
Definition: ordered_hash.h:585
const_reverse_iterator rcend() const noexcept
Definition: ordered_hash.h:577
ordered_iterator & operator=(const ordered_iterator &other)=default
std::pair< iterator, bool > emplace(Args &&... args)
Definition: ordered_hash.h:670
const_iterator find(const K &key, std::size_t hash) const
Definition: ordered_hash.h:865
hasher hash_function() const
Definition: ordered_hash.h:941
void shrink_to_fit()
Definition: ordered_hash.h:991
pointer operator->() const
Definition: ordered_hash.h:369
ordered_hash(size_type bucket_count, const Hash &hash, const KeyEqual &equal, const Allocator &alloc, float max_load_factor)
Definition: ordered_hash.h:435
iterator find(const K &key)
Definition: ordered_hash.h:849
const U::value_type & value() const
Definition: ordered_hash.h:359
size_type max_bucket_count() const
Definition: ordered_hash.h:901
size_type size() const noexcept
Definition: ordered_hash.h:589
friend ordered_iterator operator+(difference_type n, const ordered_iterator &it)
Definition: ordered_hash.h:409
size_type max_size() const noexcept
Definition: ordered_hash.h:593
ordered_hash & operator=(const ordered_hash &other)
Definition: ordered_hash.h:498
iterator insert_hint(const_iterator hint, P &&value)
Definition: ordered_hash.h:616
iterator unordered_erase(iterator pos)
Definition: ordered_hash.h:1025
ordered_iterator operator++(int)
Definition: ordered_hash.h:374
ordered_iterator & operator=(ordered_iterator &&other)=default
iterator nth(size_type index)
Definition: ordered_hash.h:957
#define tsl_oh_assert(expr)
Definition: ordered_hash.h:62
ordered_iterator & operator++()
Definition: ordered_hash.h:371
const_reverse_iterator rbegin() const noexcept
Definition: ordered_hash.h:561
iterator erase(const_iterator first, const_iterator last)
Definition: ordered_hash.h:724
ordered_iterator & operator--()
Definition: ordered_hash.h:372
const_reference front() const
Definition: ordered_hash.h:967
ordered_iterator operator+(difference_type n)
Definition: ordered_hash.h:382
std::pair< iterator, iterator > equal_range(const K &key, std::size_t hash)
Definition: ordered_hash.h:877
float load_factor() const
Definition: ordered_hash.h:908
reverse_iterator rbegin() noexcept
Definition: ordered_hash.h:557
const U::value_type & at(const K &key) const
Definition: ordered_hash.h:811
void swap(ordered_hash &other)
Definition: ordered_hash.h:780
ordered_iterator & operator+=(difference_type n)
Definition: ordered_hash.h:379
friend bool operator==(const ordered_hash &lhs, const ordered_hash &rhs)
Definition: ordered_hash.h:1082
std::pair< const_iterator, const_iterator > equal_range(const K &key, std::size_t hash) const
Definition: ordered_hash.h:888
U::value_type & value()
Definition: ordered_hash.h:364
ordered_hash(ordered_hash &&other) noexcept(std::is_nothrow_move_constructible< Hash >::value &&std::is_nothrow_move_constructible< KeyEqual >::value &&std::is_nothrow_move_constructible< buckets_container_type >::value &&std::is_nothrow_move_constructible< values_container_type >::value)
Definition: ordered_hash.h:475
friend bool operator<(const ordered_hash &lhs, const ordered_hash &rhs)
Definition: ordered_hash.h:1090
#define TSL_OH_THROW_OR_TERMINATE(ex, msg)
Definition: ordered_hash.h:75
reverse_iterator rend() noexcept
Definition: ordered_hash.h:569
friend difference_type operator-(const ordered_iterator &lhs, const ordered_iterator &rhs)
Definition: ordered_hash.h:413
size_type erase(const K &key)
Definition: ordered_hash.h:771
const values_container_type & values_container() const noexcept
Definition: ordered_hash.h:977
const_reference back() const
Definition: ordered_hash.h:972
ordered_iterator(const ordered_iterator &other)=default
ordered_hash(const ordered_hash &other)
Definition: ordered_hash.h:462
U::value_type & at(const K &key)
Definition: ordered_hash.h:801
void max_load_factor(float ml)
Definition: ordered_hash.h:920
std::pair< iterator, bool > insert_at_position(const_iterator pos, P &&value)
Definition: ordered_hash.h:997
void serialize(Serializer &serializer) const
Definition: ordered_hash.h:1073
ordered_hash & operator=(ordered_hash &&other)
Definition: ordered_hash.h:517
void rehash(size_type count)
Definition: ordered_hash.h:925