insert(P&& value) {
- return insert_impl(KeySelect()(value), std::forward(value));
- }
-
- template
- iterator insert_hint(const_iterator hint, P&& value) {
- if (hint != cend() &&
- compare_keys(KeySelect()(*hint), KeySelect()(value))) {
- return mutable_iterator(hint);
- }
-
- return insert(std::forward(value)).first;
- }
-
- template
- void insert(InputIt first, InputIt last) {
- if (std::is_base_of<
- std::forward_iterator_tag,
- typename std::iterator_traits::iterator_category>::value) {
- const auto nb_elements_insert = std::distance(first, last);
- const size_type nb_free_buckets = m_load_threshold - size();
- tsl_oh_assert(m_load_threshold >= size());
-
- if (nb_elements_insert > 0 &&
- nb_free_buckets < size_type(nb_elements_insert)) {
- reserve(size() + size_type(nb_elements_insert));
- }
- }
-
- for (; first != last; ++first) {
- insert(*first);
- }
- }
-
- template
- std::pair insert_or_assign(K&& key, M&& value) {
- auto it = try_emplace(std::forward(key), std::forward(value));
- if (!it.second) {
- it.first.value() = std::forward(value);
- }
-
- return it;
- }
-
- template
- iterator insert_or_assign(const_iterator hint, K&& key, M&& obj) {
- if (hint != cend() && compare_keys(KeySelect()(*hint), key)) {
- auto it = mutable_iterator(hint);
- it.value() = std::forward(obj);
-
- return it;
- }
-
- return insert_or_assign(std::forward(key), std::forward(obj)).first;
- }
-
- template
- std::pair emplace(Args&&... args) {
- return insert(value_type(std::forward(args)...));
- }
-
- template
- iterator emplace_hint(const_iterator hint, Args&&... args) {
- return insert_hint(hint, value_type(std::forward(args)...));
- }
-
- template
- std::pair try_emplace(K&& key, Args&&... value_args) {
- return insert_impl(
- key, std::piecewise_construct,
- std::forward_as_tuple(std::forward(key)),
- std::forward_as_tuple(std::forward(value_args)...));
- }
-
- template
- iterator try_emplace_hint(const_iterator hint, K&& key, Args&&... args) {
- if (hint != cend() && compare_keys(KeySelect()(*hint), key)) {
- return mutable_iterator(hint);
- }
-
- return try_emplace(std::forward(key), std::forward(args)...).first;
- }
-
- /**
- * Here to avoid `template size_type erase(const K& key)` being used
- * when we use an `iterator` instead of a `const_iterator`.
- */
- iterator erase(iterator pos) { return erase(const_iterator(pos)); }
-
- iterator erase(const_iterator pos) {
- tsl_oh_assert(pos != cend());
-
- const std::size_t index_erase = iterator_to_index(pos);
-
- auto it_bucket = find_key(pos.key(), hash_key(pos.key()));
- tsl_oh_assert(it_bucket != m_buckets_data.end());
-
- erase_value_from_bucket(it_bucket);
-
- /*
- * One element was removed from m_values, due to the left shift the next
- * element is now at the position of the previous element (or end if none).
- */
- return begin() + index_erase;
- }
-
- iterator erase(const_iterator first, const_iterator last) {
- if (first == last) {
- return mutable_iterator(first);
- }
-
- tsl_oh_assert(std::distance(first, last) > 0);
- const std::size_t start_index = iterator_to_index(first);
- const std::size_t nb_values = std::size_t(std::distance(first, last));
- const std::size_t end_index = start_index + nb_values;
-
- // Delete all values
-#ifdef TSL_OH_NO_CONTAINER_ERASE_CONST_ITERATOR
- auto next_it = m_values.erase(mutable_iterator(first).m_iterator,
- mutable_iterator(last).m_iterator);
-#else
- auto next_it = m_values.erase(first.m_iterator, last.m_iterator);
-#endif
-
- /*
- * Mark the buckets corresponding to the values as empty and do a backward
- * shift.
- *
- * Also, the erase operation on m_values has shifted all the values on the
- * right of last.m_iterator. Adapt the indexes for these values.
- */
- std::size_t ibucket = 0;
- while (ibucket < m_buckets_data.size()) {
- if (m_buckets[ibucket].empty()) {
- ibucket++;
- } else if (m_buckets[ibucket].index() >= start_index &&
- m_buckets[ibucket].index() < end_index) {
- m_buckets[ibucket].clear();
- backward_shift(ibucket);
- // Don't increment ibucket, backward_shift may have replaced current
- // bucket.
- } else if (m_buckets[ibucket].index() >= end_index) {
- m_buckets[ibucket].set_index(
- index_type(m_buckets[ibucket].index() - nb_values));
- ibucket++;
- } else {
- ibucket++;
- }
- }
-
- return iterator(next_it);
- }
-
- template
- size_type erase(const K& key) {
- return erase(key, hash_key(key));
- }
-
- template
- size_type erase(const K& key, std::size_t hash) {
- return erase_impl(key, hash);
- }
-
- void swap(ordered_hash& other) {
- using std::swap;
-
- swap(static_cast(*this), static_cast(other));
- swap(static_cast(*this), static_cast(other));
- swap(m_buckets_data, other.m_buckets_data);
- swap(m_buckets, other.m_buckets);
- swap(m_hash_mask, other.m_hash_mask);
- swap(m_values, other.m_values);
- swap(m_load_threshold, other.m_load_threshold);
- swap(m_max_load_factor, other.m_max_load_factor);
- swap(m_grow_on_next_insert, other.m_grow_on_next_insert);
- }
-
- /*
- * Lookup
- */
- template ::value>::type* = nullptr>
- typename U::value_type& at(const K& key) {
- return at(key, hash_key(key));
- }
-
- template ::value>::type* = nullptr>
- typename U::value_type& at(const K& key, std::size_t hash) {
- return const_cast(
- static_cast(this)->at(key, hash));
- }
-
- template ::value>::type* = nullptr>
- const typename U::value_type& at(const K& key) const {
- return at(key, hash_key(key));
- }
-
- template ::value>::type* = nullptr>
- const typename U::value_type& at(const K& key, std::size_t hash) const {
- auto it = find(key, hash);
- if (it != end()) {
- return it.value();
- } else {
- TSL_OH_THROW_OR_TERMINATE(std::out_of_range, "Couldn't find the key.");
- }
- }
-
- template ::value>::type* = nullptr>
- typename U::value_type& operator[](K&& key) {
- return try_emplace(std::forward(key)).first.value();
- }
-
- template
- size_type count(const K& key) const {
- return count(key, hash_key(key));
- }
-
- template
- size_type count(const K& key, std::size_t hash) const {
- if (find(key, hash) == cend()) {
- return 0;
- } else {
- return 1;
- }
- }
-
- template
- iterator find(const K& key) {
- return find(key, hash_key(key));
- }
-
- template
- iterator find(const K& key, std::size_t hash) {
- auto it_bucket = find_key(key, hash);
- return (it_bucket != m_buckets_data.end())
- ? iterator(m_values.begin() + it_bucket->index())
- : end();
- }
-
- template
- const_iterator find(const K& key) const {
- return find(key, hash_key(key));
- }
-
- template
- const_iterator find(const K& key, std::size_t hash) const {
- auto it_bucket = find_key(key, hash);
- return (it_bucket != m_buckets_data.cend())
- ? const_iterator(m_values.begin() + it_bucket->index())
- : end();
- }
-
- template
- bool contains(const K& key) const {
- return contains(key, hash_key(key));
- }
-
- template
- bool contains(const K& key, std::size_t hash) const {
- return find(key, hash) != cend();
- }
-
- template
- std::pair equal_range(const K& key) {
- return equal_range(key, hash_key(key));
- }
-
- template
- std::pair equal_range(const K& key, std::size_t hash) {
- iterator it = find(key, hash);
- return std::make_pair(it, (it == end()) ? it : std::next(it));
- }
-
- template
- std::pair equal_range(const K& key) const {
- return equal_range(key, hash_key(key));
- }
-
- template
- std::pair equal_range(
- const K& key, std::size_t hash) const {
- const_iterator it = find(key, hash);
- return std::make_pair(it, (it == cend()) ? it : std::next(it));
- }
-
- /*
- * Bucket interface
- */
- size_type bucket_count() const { return m_buckets_data.size(); }
-
- size_type max_bucket_count() const { return m_buckets_data.max_size(); }
-
- /*
- * Hash policy
- */
- float load_factor() const {
- if (bucket_count() == 0) {
- return 0;
- }
-
- return float(size()) / float(bucket_count());
- }
-
- float max_load_factor() const { return m_max_load_factor; }
-
- void max_load_factor(float ml) {
- m_max_load_factor = clamp(ml, float(MAX_LOAD_FACTOR__MINIMUM),
- float(MAX_LOAD_FACTOR__MAXIMUM));
-
- m_max_load_factor = ml;
- m_load_threshold = size_type(float(bucket_count()) * m_max_load_factor);
- }
-
- void rehash(size_type count) {
- count = std::max(count,
- size_type(std::ceil(float(size()) / max_load_factor())));
- rehash_impl(count);
- }
-
- void reserve(size_type count) {
- reserve_space_for_values(count);
-
- count = size_type(std::ceil(float(count) / max_load_factor()));
- rehash(count);
- }
-
- /*
- * Observers
- */
- hasher hash_function() const { return static_cast(*this); }
-
- key_equal key_eq() const { return static_cast(*this); }
-
- /*
- * Other
- */
- iterator mutable_iterator(const_iterator pos) {
- return iterator(m_values.begin() + iterator_to_index(pos));
- }
-
- iterator nth(size_type index) {
- tsl_oh_assert(index <= size());
- return iterator(m_values.begin() + index);
- }
-
- const_iterator nth(size_type index) const {
- tsl_oh_assert(index <= size());
- return const_iterator(m_values.cbegin() + index);
- }
-
- const_reference front() const {
- tsl_oh_assert(!empty());
- return m_values.front();
- }
-
- const_reference back() const {
- tsl_oh_assert(!empty());
- return m_values.back();
- }
-
- const values_container_type& values_container() const noexcept {
- return m_values;
- }
-
- values_container_type release() {
- values_container_type ret;
- for (auto& bucket : m_buckets_data) {
- bucket.clear();
- }
- m_grow_on_next_insert = false;
- std::swap(ret, m_values);
- return ret;
- }
-
- template ::value>::type* = nullptr>
- const typename values_container_type::value_type* data() const noexcept {
- return m_values.data();
- }
-
- template ::value>::type* = nullptr>
- size_type capacity() const noexcept {
- return m_values.capacity();
- }
-
- void shrink_to_fit() { m_values.shrink_to_fit(); }
-
- template
- std::pair insert_at_position(const_iterator pos, P&& value) {
- return insert_at_position_impl(pos.m_iterator, KeySelect()(value),
- std::forward(value));
- }
-
- template
- std::pair emplace_at_position(const_iterator pos,
- Args&&... args) {
- return insert_at_position(pos, value_type(std::forward(args)...));
- }
-
- template
- std::pair try_emplace_at_position(const_iterator pos, K&& key,
- Args&&... value_args) {
- return insert_at_position_impl(
- pos.m_iterator, key, std::piecewise_construct,
- std::forward_as_tuple(std::forward(key)),
- std::forward_as_tuple(std::forward(value_args)...));
- }
-
- void pop_back() {
- tsl_oh_assert(!empty());
- erase(std::prev(end()));
- }
-
- /**
- * Here to avoid `template size_type unordered_erase(const K& key)`
- * being used when we use a iterator instead of a const_iterator.
- */
- iterator unordered_erase(iterator pos) {
- return unordered_erase(const_iterator(pos));
- }
-
- iterator unordered_erase(const_iterator pos) {
- const std::size_t index_erase = iterator_to_index(pos);
- unordered_erase(pos.key());
-
- /*
- * One element was deleted, index_erase now points to the next element as
- * the elements after the deleted value were shifted to the left in m_values
- * (will be end() if we deleted the last element).
- */
- return begin() + index_erase;
- }
-
- template
- size_type unordered_erase(const K& key) {
- return unordered_erase(key, hash_key(key));
- }
-
- template
- size_type unordered_erase(const K& key, std::size_t hash) {
- auto it_bucket_key = find_key(key, hash);
- if (it_bucket_key == m_buckets_data.end()) {
- return 0;
- }
-
- /**
- * If we are not erasing the last element in m_values, we swap
- * the element we are erasing with the last element. We then would
- * just have to do a pop_back() in m_values.
- */
- if (!compare_keys(key, KeySelect()(back()))) {
- auto it_bucket_last_elem =
- find_key(KeySelect()(back()), hash_key(KeySelect()(back())));
- tsl_oh_assert(it_bucket_last_elem != m_buckets_data.end());
- tsl_oh_assert(it_bucket_last_elem->index() == m_values.size() - 1);
-
- using std::swap;
- swap(m_values[it_bucket_key->index()],
- m_values[it_bucket_last_elem->index()]);
- swap(it_bucket_key->index_ref(), it_bucket_last_elem->index_ref());
- }
-
- erase_value_from_bucket(it_bucket_key);
-
- return 1;
- }
-
- /**
- * Remove all entries for which the given predicate matches.
- */
- template
- size_type erase_if(Predicate& pred) {
- // Get the bucket associated with the given element.
- auto get_bucket = [this](typename values_container_type::iterator it) {
- return find_key(KeySelect()(*it), hash_key(KeySelect()(*it)));
- };
- // Clear a bucket without touching the container holding the values.
- auto clear_bucket = [this](typename buckets_container_type::iterator it) {
- tsl_oh_assert(it != m_buckets_data.end());
- it->clear();
- backward_shift(std::size_t(std::distance(m_buckets_data.begin(), it)));
- };
- // Ensure that only const references are passed to the predicate.
- auto cpred = [&pred](typename values_container_type::const_reference x) {
- return pred(x);
- };
-
- // Find first element that matches the predicate.
- const auto last = m_values.end();
- auto first = std::find_if(m_values.begin(), last, cpred);
- if (first == last) {
- return 0;
- }
- // Remove all elements that match the predicate.
- clear_bucket(get_bucket(first));
- for (auto it = std::next(first); it != last; ++it) {
- auto it_bucket = get_bucket(it);
- if (cpred(*it)) {
- clear_bucket(it_bucket);
- } else {
- it_bucket->set_index(
- static_cast(std::distance(m_values.begin(), first)));
- *first++ = std::move(*it);
- }
- }
- // Resize the vector and return the number of deleted elements.
- auto deleted = static_cast(std::distance(first, last));
- m_values.erase(first, last);
- return deleted;
- }
-
- template
- void serialize(Serializer& serializer) const {
- serialize_impl(serializer);
- }
-
- template
- void deserialize(Deserializer& deserializer, bool hash_compatible) {
- deserialize_impl(deserializer, hash_compatible);
- }
-
- friend bool operator==(const ordered_hash& lhs, const ordered_hash& rhs) {
- return lhs.m_values == rhs.m_values;
- }
-
- friend bool operator!=(const ordered_hash& lhs, const ordered_hash& rhs) {
- return lhs.m_values != rhs.m_values;
- }
-
- friend bool operator<(const ordered_hash& lhs, const ordered_hash& rhs) {
- return lhs.m_values < rhs.m_values;
- }
-
- friend bool operator<=(const ordered_hash& lhs, const ordered_hash& rhs) {
- return lhs.m_values <= rhs.m_values;
- }
-
- friend bool operator>(const ordered_hash& lhs, const ordered_hash& rhs) {
- return lhs.m_values > rhs.m_values;
- }
-
- friend bool operator>=(const ordered_hash& lhs, const ordered_hash& rhs) {
- return lhs.m_values >= rhs.m_values;
- }
-
- private:
- template
- std::size_t hash_key(const K& key) const {
- return Hash::operator()(key);
- }
-
- template
- bool compare_keys(const K1& key1, const K2& key2) const {
- return KeyEqual::operator()(key1, key2);
- }
-
- template
- typename buckets_container_type::iterator find_key(const K& key,
- std::size_t hash) {
- auto it = static_cast(this)->find_key(key, hash);
- return m_buckets_data.begin() + std::distance(m_buckets_data.cbegin(), it);
- }
-
- /**
- * Return bucket which has the key 'key' or m_buckets_data.end() if none.
- *
- * From the bucket_for_hash, search for the value until we either find an
- * empty bucket or a bucket which has a value with a distance from its ideal
- * bucket longer than the probe length for the value we are looking for.
- */
- template
- typename buckets_container_type::const_iterator find_key(
- const K& key, std::size_t hash) const {
- for (std::size_t ibucket = bucket_for_hash(hash),
- dist_from_ideal_bucket = 0;
- ; ibucket = next_bucket(ibucket), dist_from_ideal_bucket++) {
- if (m_buckets[ibucket].empty()) {
- return m_buckets_data.end();
- } else if (m_buckets[ibucket].truncated_hash() ==
- bucket_entry::truncate_hash(hash) &&
- compare_keys(
- key, KeySelect()(m_values[m_buckets[ibucket].index()]))) {
- return m_buckets_data.begin() + ibucket;
- } else if (dist_from_ideal_bucket > distance_from_ideal_bucket(ibucket)) {
- return m_buckets_data.end();
- }
- }
- }
-
- void rehash_impl(size_type bucket_count) {
- tsl_oh_assert(bucket_count >=
- size_type(std::ceil(float(size()) / max_load_factor())));
-
- if (bucket_count > max_bucket_count()) {
- TSL_OH_THROW_OR_TERMINATE(std::length_error,
- "The map exceeds its maximum size.");
- }
-
- if (bucket_count > 0) {
- bucket_count = round_up_to_power_of_two(bucket_count);
- }
-
- if (bucket_count == this->bucket_count()) {
- return;
- }
-
- buckets_container_type old_buckets(bucket_count);
- m_buckets_data.swap(old_buckets);
- m_buckets = m_buckets_data.empty() ? static_empty_bucket_ptr()
- : m_buckets_data.data();
- // Everything should be noexcept from here.
-
- m_hash_mask = (bucket_count > 0) ? (bucket_count - 1) : 0;
- this->max_load_factor(m_max_load_factor);
- m_grow_on_next_insert = false;
-
- for (const bucket_entry& old_bucket : old_buckets) {
- if (old_bucket.empty()) {
- continue;
- }
-
- truncated_hash_type insert_hash = old_bucket.truncated_hash();
- index_type insert_index = old_bucket.index();
-
- for (std::size_t ibucket = bucket_for_hash(insert_hash),
- dist_from_ideal_bucket = 0;
- ; ibucket = next_bucket(ibucket), dist_from_ideal_bucket++) {
- if (m_buckets[ibucket].empty()) {
- m_buckets[ibucket].set_index(insert_index);
- m_buckets[ibucket].set_hash(insert_hash);
- break;
- }
-
- const std::size_t distance = distance_from_ideal_bucket(ibucket);
- if (dist_from_ideal_bucket > distance) {
- std::swap(insert_index, m_buckets[ibucket].index_ref());
- std::swap(insert_hash, m_buckets[ibucket].truncated_hash_ref());
- dist_from_ideal_bucket = distance;
- }
- }
- }
- }
-
- template ::value>::type* = nullptr>
- void reserve_space_for_values(size_type count) {
- m_values.reserve(count);
- }
-
- template ::value>::type* = nullptr>
- void reserve_space_for_values(size_type /*count*/) {}
-
- /**
- * Swap the empty bucket with the values on its right until we cross another
- * empty bucket or if the other bucket has a distance_from_ideal_bucket == 0.
- */
- void backward_shift(std::size_t empty_ibucket) noexcept {
- tsl_oh_assert(m_buckets[empty_ibucket].empty());
-
- std::size_t previous_ibucket = empty_ibucket;
- for (std::size_t current_ibucket = next_bucket(previous_ibucket);
- !m_buckets[current_ibucket].empty() &&
- distance_from_ideal_bucket(current_ibucket) > 0;
- previous_ibucket = current_ibucket,
- current_ibucket = next_bucket(current_ibucket)) {
- std::swap(m_buckets[current_ibucket], m_buckets[previous_ibucket]);
- }
- }
-
- void erase_value_from_bucket(
- typename buckets_container_type::iterator it_bucket) {
- tsl_oh_assert(it_bucket != m_buckets_data.end() && !it_bucket->empty());
-
- m_values.erase(m_values.begin() + it_bucket->index());
-
- /*
- * m_values.erase shifted all the values on the right of the erased value,
- * shift the indexes by -1 in the buckets array for these values.
- */
- if (it_bucket->index() != m_values.size()) {
- shift_indexes_in_buckets(it_bucket->index() + 1, -1);
- }
-
- // Mark the bucket as empty and do a backward shift of the values on the
- // right
- it_bucket->clear();
- backward_shift(
- std::size_t(std::distance(m_buckets_data.begin(), it_bucket)));
- }
-
- /**
- * Shift any index >= index_above_or_equal in m_buckets_data by delta.
- *
- * delta must be equal to 1 or -1.
- */
- void shift_indexes_in_buckets(index_type index_above_or_equal,
- int delta) noexcept {
- tsl_oh_assert(delta == 1 || delta == -1);
-
- for (bucket_entry& bucket : m_buckets_data) {
- if (!bucket.empty() && bucket.index() >= index_above_or_equal) {
- tsl_oh_assert(delta >= 0 ||
- bucket.index() >= static_cast(-delta));
- tsl_oh_assert(delta <= 0 ||
- (bucket_entry::max_size() - bucket.index()) >=
- static_cast(delta));
- bucket.set_index(static_cast(bucket.index() + delta));
- }
- }
- }
-
- template
- size_type erase_impl(const K& key, std::size_t hash) {
- auto it_bucket = find_key(key, hash);
- if (it_bucket != m_buckets_data.end()) {
- erase_value_from_bucket(it_bucket);
-
- return 1;
- } else {
- return 0;
- }
- }
-
- /**
- * Insert the element at the end.
- */
- template
- std::pair insert_impl(const K& key,
- Args&&... value_type_args) {
- const std::size_t hash = hash_key(key);
-
- std::size_t ibucket = bucket_for_hash(hash);
- std::size_t dist_from_ideal_bucket = 0;
-
- while (!m_buckets[ibucket].empty() &&
- dist_from_ideal_bucket <= distance_from_ideal_bucket(ibucket)) {
- if (m_buckets[ibucket].truncated_hash() ==
- bucket_entry::truncate_hash(hash) &&
- compare_keys(key,
- KeySelect()(m_values[m_buckets[ibucket].index()]))) {
- return std::make_pair(begin() + m_buckets[ibucket].index(), false);
- }
-
- ibucket = next_bucket(ibucket);
- dist_from_ideal_bucket++;
- }
-
- if (size() >= max_size()) {
- TSL_OH_THROW_OR_TERMINATE(
- std::length_error, "We reached the maximum size for the hash table.");
- }
-
- if (grow_on_high_load()) {
- ibucket = bucket_for_hash(hash);
- dist_from_ideal_bucket = 0;
- }
-
- m_values.emplace_back(std::forward(value_type_args)...);
- insert_index(ibucket, dist_from_ideal_bucket,
- index_type(m_values.size() - 1),
- bucket_entry::truncate_hash(hash));
-
- return std::make_pair(std::prev(end()), true);
- }
-
- /**
- * Insert the element before insert_position.
- */
- template
- std::pair insert_at_position_impl(
- typename values_container_type::const_iterator insert_position,
- const K& key, Args&&... value_type_args) {
- const std::size_t hash = hash_key(key);
-
- std::size_t ibucket = bucket_for_hash(hash);
- std::size_t dist_from_ideal_bucket = 0;
-
- while (!m_buckets[ibucket].empty() &&
- dist_from_ideal_bucket <= distance_from_ideal_bucket(ibucket)) {
- if (m_buckets[ibucket].truncated_hash() ==
- bucket_entry::truncate_hash(hash) &&
- compare_keys(key,
- KeySelect()(m_values[m_buckets[ibucket].index()]))) {
- return std::make_pair(begin() + m_buckets[ibucket].index(), false);
- }
-
- ibucket = next_bucket(ibucket);
- dist_from_ideal_bucket++;
- }
-
- if (size() >= max_size()) {
- TSL_OH_THROW_OR_TERMINATE(
- std::length_error, "We reached the maximum size for the hash table.");
- }
-
- if (grow_on_high_load()) {
- ibucket = bucket_for_hash(hash);
- dist_from_ideal_bucket = 0;
- }
-
- const index_type index_insert_position =
- index_type(std::distance(m_values.cbegin(), insert_position));
-
-#ifdef TSL_OH_NO_CONTAINER_EMPLACE_CONST_ITERATOR
- m_values.emplace(
- m_values.begin() + std::distance(m_values.cbegin(), insert_position),
- std::forward(value_type_args)...);
-#else
- m_values.emplace(insert_position, std::forward(value_type_args)...);
-#endif
-
- /*
- * The insertion didn't happened at the end of the m_values container,
- * we need to shift the indexes in m_buckets_data.
- */
- if (index_insert_position != m_values.size() - 1) {
- shift_indexes_in_buckets(index_insert_position, 1);
- }
-
- insert_index(ibucket, dist_from_ideal_bucket, index_insert_position,
- bucket_entry::truncate_hash(hash));
-
- return std::make_pair(iterator(m_values.begin() + index_insert_position),
- true);
- }
-
- void insert_index(std::size_t ibucket, std::size_t dist_from_ideal_bucket,
- index_type index_insert,
- truncated_hash_type hash_insert) noexcept {
- while (!m_buckets[ibucket].empty()) {
- const std::size_t distance = distance_from_ideal_bucket(ibucket);
- if (dist_from_ideal_bucket > distance) {
- std::swap(index_insert, m_buckets[ibucket].index_ref());
- std::swap(hash_insert, m_buckets[ibucket].truncated_hash_ref());
-
- dist_from_ideal_bucket = distance;
- }
-
- ibucket = next_bucket(ibucket);
- dist_from_ideal_bucket++;
-
- if (dist_from_ideal_bucket > REHASH_ON_HIGH_NB_PROBES__NPROBES &&
- !m_grow_on_next_insert &&
- load_factor() >= REHASH_ON_HIGH_NB_PROBES__MIN_LOAD_FACTOR) {
- // We don't want to grow the map now as we need this method to be
- // noexcept. Do it on next insert.
- m_grow_on_next_insert = true;
- }
- }
-
- m_buckets[ibucket].set_index(index_insert);
- m_buckets[ibucket].set_hash(hash_insert);
- }
-
- std::size_t distance_from_ideal_bucket(std::size_t ibucket) const noexcept {
- const std::size_t ideal_bucket =
- bucket_for_hash(m_buckets[ibucket].truncated_hash());
-
- if (ibucket >= ideal_bucket) {
- return ibucket - ideal_bucket;
- }
- // If the bucket is smaller than the ideal bucket for the value, there was a
- // wrapping at the end of the bucket array due to the modulo.
- else {
- return (bucket_count() + ibucket) - ideal_bucket;
- }
- }
-
- std::size_t next_bucket(std::size_t index) const noexcept {
- tsl_oh_assert(index < m_buckets_data.size());
-
- index++;
- return (index < m_buckets_data.size()) ? index : 0;
- }
-
- std::size_t bucket_for_hash(std::size_t hash) const noexcept {
- return hash & m_hash_mask;
- }
-
- std::size_t iterator_to_index(const_iterator it) const noexcept {
- const auto dist = std::distance(cbegin(), it);
- tsl_oh_assert(dist >= 0);
-
- return std::size_t(dist);
- }
-
- /**
- * Return true if the map has been rehashed.
- */
- bool grow_on_high_load() {
- if (m_grow_on_next_insert || size() >= m_load_threshold) {
- rehash_impl(std::max(size_type(1), bucket_count() * 2));
- m_grow_on_next_insert = false;
-
- return true;
- } else {
- return false;
- }
- }
-
- template
- void serialize_impl(Serializer& serializer) const {
- const slz_size_type version = SERIALIZATION_PROTOCOL_VERSION;
- serializer(version);
-
- const slz_size_type nb_elements = m_values.size();
- serializer(nb_elements);
-
- const slz_size_type bucket_count = m_buckets_data.size();
- serializer(bucket_count);
-
- const float max_load_factor = m_max_load_factor;
- serializer(max_load_factor);
-
- for (const value_type& value : m_values) {
- serializer(value);
- }
-
- for (const bucket_entry& bucket : m_buckets_data) {
- bucket.serialize(serializer);
- }
- }
-
- template
- void deserialize_impl(Deserializer& deserializer, bool hash_compatible) {
- tsl_oh_assert(m_buckets_data.empty()); // Current hash table must be empty
-
- const slz_size_type version =
- deserialize_value(deserializer);
- // For now we only have one version of the serialization protocol.
- // If it doesn't match there is a problem with the file.
- if (version != SERIALIZATION_PROTOCOL_VERSION) {
- TSL_OH_THROW_OR_TERMINATE(std::runtime_error,
- "Can't deserialize the ordered_map/set. "
- "The protocol version header is invalid.");
- }
-
- const slz_size_type nb_elements =
- deserialize_value(deserializer);
- const slz_size_type bucket_count_ds =
- deserialize_value(deserializer);
- const float max_load_factor = deserialize_value(deserializer);
-
- if (max_load_factor < MAX_LOAD_FACTOR__MINIMUM ||
- max_load_factor > MAX_LOAD_FACTOR__MAXIMUM) {
- TSL_OH_THROW_OR_TERMINATE(
- std::runtime_error,
- "Invalid max_load_factor. Check that the serializer "
- "and deserializer support floats correctly as they "
- "can be converted implicitly to ints.");
- }
-
- this->max_load_factor(max_load_factor);
-
- if (bucket_count_ds == 0) {
- tsl_oh_assert(nb_elements == 0);
- return;
- }
-
- if (!hash_compatible) {
- reserve(numeric_cast(nb_elements,
- "Deserialized nb_elements is too big."));
- for (slz_size_type el = 0; el < nb_elements; el++) {
- insert(deserialize_value(deserializer));
- }
- } else {
- m_buckets_data.reserve(numeric_cast(
- bucket_count_ds, "Deserialized bucket_count is too big."));
- m_buckets = m_buckets_data.data(),
- m_hash_mask = m_buckets_data.capacity() - 1;
-
- reserve_space_for_values(numeric_cast(
- nb_elements, "Deserialized nb_elements is too big."));
- for (slz_size_type el = 0; el < nb_elements; el++) {
- m_values.push_back(deserialize_value(deserializer));
- }
-
- for (slz_size_type b = 0; b < bucket_count_ds; b++) {
- m_buckets_data.push_back(bucket_entry::deserialize(deserializer));
- }
- }
- }
-
- static std::size_t round_up_to_power_of_two(std::size_t value) {
- if (is_power_of_two(value)) {
- return value;
- }
-
- if (value == 0) {
- return 1;
- }
-
- --value;
- for (std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) {
- value |= value >> i;
- }
-
- return value + 1;
- }
-
- static constexpr bool is_power_of_two(std::size_t value) {
- return value != 0 && (value & (value - 1)) == 0;
- }
-
- public:
- static const size_type DEFAULT_INIT_BUCKETS_SIZE = 0;
- static constexpr float DEFAULT_MAX_LOAD_FACTOR = 0.75f;
-
- private:
- static constexpr float MAX_LOAD_FACTOR__MINIMUM = 0.1f;
- static constexpr float MAX_LOAD_FACTOR__MAXIMUM = 0.95f;
-
- static const size_type REHASH_ON_HIGH_NB_PROBES__NPROBES = 128;
- static constexpr float REHASH_ON_HIGH_NB_PROBES__MIN_LOAD_FACTOR = 0.15f;
-
- /**
- * Protocol version currently used for serialization.
- */
- static const slz_size_type SERIALIZATION_PROTOCOL_VERSION = 1;
-
- /**
- * Return an always valid pointer to an static empty bucket_entry with
- * last_bucket() == true.
- */
- bucket_entry* static_empty_bucket_ptr() {
- static bucket_entry empty_bucket;
- return &empty_bucket;
- }
-
- private:
- buckets_container_type m_buckets_data;
-
- /**
- * Points to m_buckets_data.data() if !m_buckets_data.empty() otherwise points
- * to static_empty_bucket_ptr. This variable is useful to avoid the cost of
- * checking if m_buckets_data is empty when trying to find an element.
- *
- * TODO Remove m_buckets_data and only use a pointer+size instead of a
- * pointer+vector to save some space in the ordered_hash object.
- */
- bucket_entry* m_buckets;
-
- size_type m_hash_mask;
-
- values_container_type m_values;
-
- size_type m_load_threshold;
- float m_max_load_factor;
-
- bool m_grow_on_next_insert;
-};
-
-} // end namespace detail_ordered_hash
-
-} // end namespace tsl
-
-#endif
diff --git a/rmw_zenoh_cpp/src/detail/ordered_map.hpp b/rmw_zenoh_cpp/src/detail/ordered_map.hpp
deleted file mode 100644
index 14303f94..00000000
--- a/rmw_zenoh_cpp/src/detail/ordered_map.hpp
+++ /dev/null
@@ -1,999 +0,0 @@
-/**
- * MIT License
- *
- * Copyright (c) 2017 Thibaut Goetghebuer-Planchon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-// Copied from https://github.com/Tessil/ordered-map/blob/bd8d5ef4149cd40783a486011778a2e7eedde441/include/tsl/ordered_map.h
-
-#ifndef TSL_ORDERED_MAP_H
-#define TSL_ORDERED_MAP_H
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "ordered_hash.hpp"
-
-namespace tsl {
-
-/**
- * Implementation of an hash map using open addressing with robin hood with
- * backshift delete to resolve collisions.
- *
- * The particularity of this hash map is that it remembers the order in which
- * the elements were added and provide a way to access the structure which
- * stores these values through the 'values_container()' method. The used
- * container is defined by ValueTypeContainer, by default a std::deque is used
- * (grows faster) but a std::vector may be used. In this case the map provides a
- * 'data()' method which give a direct access to the memory used to store the
- * values (which can be useful to communicate with C API's).
- *
- * The Key and T must be copy constructible and/or move constructible. To use
- * `unordered_erase` they both must be swappable.
- *
- * The behaviour of the hash map is undefined if the destructor of Key or T
- * throws an exception.
- *
- * By default the maximum size of a map is limited to 2^32 - 1 values, if needed
- * this can be changed through the IndexType template parameter. Using an
- * `uint64_t` will raise this limit to 2^64 - 1 values but each bucket will use
- * 16 bytes instead of 8 bytes in addition to the space needed to store the
- * values.
- *
- * Iterators invalidation:
- * - clear, operator=, reserve, rehash: always invalidate the iterators (also
- * invalidate end()).
- * - insert, emplace, emplace_hint, operator[]: when a std::vector is used as
- * ValueTypeContainer and if size() < capacity(), only end(). Otherwise all the
- * iterators are invalidated if an insert occurs.
- * - erase, unordered_erase: when a std::vector is used as ValueTypeContainer
- * invalidate the iterator of the erased element and all the ones after the
- * erased element (including end()). Otherwise all the iterators are invalidated
- * if an erase occurs.
- */
-template ,
- class KeyEqual = std::equal_to,
- class Allocator = std::allocator>,
- class ValueTypeContainer = std::deque, Allocator>,
- class IndexType = std::uint_least32_t>
-class ordered_map {
- private:
- template
- using has_is_transparent = tsl::detail_ordered_hash::has_is_transparent;
-
- class KeySelect {
- public:
- using key_type = Key;
-
- const key_type& operator()(
- const std::pair& key_value) const noexcept {
- return key_value.first;
- }
-
- key_type& operator()(std::pair& key_value) noexcept {
- return key_value.first;
- }
- };
-
- class ValueSelect {
- public:
- using value_type = T;
-
- const value_type& operator()(
- const std::pair& key_value) const noexcept {
- return key_value.second;
- }
-
- value_type& operator()(std::pair& key_value) noexcept {
- return key_value.second;
- }
- };
-
- using ht =
- detail_ordered_hash::ordered_hash, KeySelect,
- ValueSelect, Hash, KeyEqual, Allocator,
- ValueTypeContainer, IndexType>;
-
- public:
- using key_type = typename ht::key_type;
- using mapped_type = T;
- using value_type = typename ht::value_type;
- using size_type = typename ht::size_type;
- using difference_type = typename ht::difference_type;
- using hasher = typename ht::hasher;
- using key_equal = typename ht::key_equal;
- using allocator_type = typename ht::allocator_type;
- using reference = typename ht::reference;
- using const_reference = typename ht::const_reference;
- using pointer = typename ht::pointer;
- using const_pointer = typename ht::const_pointer;
- using iterator = typename ht::iterator;
- using const_iterator = typename ht::const_iterator;
- using reverse_iterator = typename ht::reverse_iterator;
- using const_reverse_iterator = typename ht::const_reverse_iterator;
-
- using values_container_type = typename ht::values_container_type;
-
- /*
- * Constructors
- */
- ordered_map() : ordered_map(ht::DEFAULT_INIT_BUCKETS_SIZE) {}
-
- explicit ordered_map(size_type bucket_count, const Hash& hash = Hash(),
- const KeyEqual& equal = KeyEqual(),
- const Allocator& alloc = Allocator())
- : m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR) {}
-
- ordered_map(size_type bucket_count, const Allocator& alloc)
- : ordered_map(bucket_count, Hash(), KeyEqual(), alloc) {}
-
- ordered_map(size_type bucket_count, const Hash& hash, const Allocator& alloc)
- : ordered_map(bucket_count, hash, KeyEqual(), alloc) {}
-
- explicit ordered_map(const Allocator& alloc)
- : ordered_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {}
-
- template
- ordered_map(InputIt first, InputIt last,
- size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
- const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(),
- const Allocator& alloc = Allocator())
- : ordered_map(bucket_count, hash, equal, alloc) {
- insert(first, last);
- }
-
- template
- ordered_map(InputIt first, InputIt last, size_type bucket_count,
- const Allocator& alloc)
- : ordered_map(first, last, bucket_count, Hash(), KeyEqual(), alloc) {}
-
- template
- ordered_map(InputIt first, InputIt last, size_type bucket_count,
- const Hash& hash, const Allocator& alloc)
- : ordered_map(first, last, bucket_count, hash, KeyEqual(), alloc) {}
-
- ordered_map(std::initializer_list init,
- size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
- const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual(),
- const Allocator& alloc = Allocator())
- : ordered_map(init.begin(), init.end(), bucket_count, hash, equal,
- alloc) {}
-
- ordered_map(std::initializer_list init, size_type bucket_count,
- const Allocator& alloc)
- : ordered_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(),
- alloc) {}
-
- ordered_map(std::initializer_list init, size_type bucket_count,
- const Hash& hash, const Allocator& alloc)
- : ordered_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(),
- alloc) {}
-
- ordered_map& operator=(std::initializer_list ilist) {
- m_ht.clear();
-
- m_ht.reserve(ilist.size());
- m_ht.insert(ilist.begin(), ilist.end());
-
- return *this;
- }
-
- allocator_type get_allocator() const { return m_ht.get_allocator(); }
-
- /*
- * Iterators
- */
- iterator begin() noexcept { return m_ht.begin(); }
- const_iterator begin() const noexcept { return m_ht.begin(); }
- const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
-
- iterator end() noexcept { return m_ht.end(); }
- const_iterator end() const noexcept { return m_ht.end(); }
- const_iterator cend() const noexcept { return m_ht.cend(); }
-
- reverse_iterator rbegin() noexcept { return m_ht.rbegin(); }
- const_reverse_iterator rbegin() const noexcept { return m_ht.rbegin(); }
- const_reverse_iterator rcbegin() const noexcept { return m_ht.rcbegin(); }
-
- reverse_iterator rend() noexcept { return m_ht.rend(); }
- const_reverse_iterator rend() const noexcept { return m_ht.rend(); }
- const_reverse_iterator rcend() const noexcept { return m_ht.rcend(); }
-
- /*
- * Capacity
- */
- bool empty() const noexcept { return m_ht.empty(); }
- size_type size() const noexcept { return m_ht.size(); }
- size_type max_size() const noexcept { return m_ht.max_size(); }
-
- /*
- * Modifiers
- */
- void clear() noexcept { m_ht.clear(); }
-
- std::pair insert(const value_type& value) {
- return m_ht.insert(value);
- }
-
- template ::value>::type* = nullptr>
- std::pair insert(P&& value) {
- return m_ht.emplace(std::forward(value));
- }
-
- std::pair insert(value_type&& value) {
- return m_ht.insert(std::move(value));
- }
-
- iterator insert(const_iterator hint, const value_type& value) {
- return m_ht.insert_hint(hint, value);
- }
-
- template ::value>::type* = nullptr>
- iterator insert(const_iterator hint, P&& value) {
- return m_ht.emplace_hint(hint, std::forward(value));
- }
-
- iterator insert(const_iterator hint, value_type&& value) {
- return m_ht.insert_hint(hint, std::move(value));
- }
-
- template
- void insert(InputIt first, InputIt last) {
- m_ht.insert(first, last);
- }
- void insert(std::initializer_list ilist) {
- m_ht.insert(ilist.begin(), ilist.end());
- }
-
- template
- std::pair insert_or_assign(const key_type& k, M&& obj) {
- return m_ht.insert_or_assign(k, std::forward(obj));
- }
-
- template
- std::pair insert_or_assign(key_type&& k, M&& obj) {
- return m_ht.insert_or_assign(std::move(k), std::forward(obj));
- }
-
- template
- iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) {
- return m_ht.insert_or_assign(hint, k, std::forward(obj));
- }
-
- template
- iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) {
- return m_ht.insert_or_assign(hint, std::move(k), std::forward(obj));
- }
-
- /**
- * Due to the way elements are stored, emplace will need to move or copy the
- * key-value once. The method is equivalent to
- * insert(value_type(std::forward(args)...));
- *
- * Mainly here for compatibility with the std::unordered_map interface.
- */
- template
- std::pair emplace(Args&&... args) {
- return m_ht.emplace(std::forward(args)...);
- }
-
- /**
- * Due to the way elements are stored, emplace_hint will need to move or copy
- * the key-value once. The method is equivalent to insert(hint,
- * value_type(std::forward(args)...));
- *
- * Mainly here for compatibility with the std::unordered_map interface.
- */
- template
- iterator emplace_hint(const_iterator hint, Args&&... args) {
- return m_ht.emplace_hint(hint, std::forward