Update robin_map to v1.2.1

This commit is contained in:
halx99 2023-01-10 22:16:38 +08:00
parent 100a688ce5
commit b032ba2f56
4 changed files with 43 additions and 21 deletions

View File

@ -196,7 +196,7 @@
## robin-map ## robin-map
- [![Upstream](https://img.shields.io/github/v/tag/Tessil/robin-map?label=Upstream)](https://github.com/Tessil/robin-map) - [![Upstream](https://img.shields.io/github/v/tag/Tessil/robin-map?label=Upstream)](https://github.com/Tessil/robin-map)
- Version: 1.0.1 with modified for more compatible with stl - Version: 1.2.1 with modified for more compatible with stl
- Modify `robin_map::iterator->second` to mutable same with `stl map/unordered_map` - Modify `robin_map::iterator->second` to mutable same with `stl map/unordered_map`
- Forward `robin_map::operator[]` key by `std::forward` same with `stl map/unordered_map` - Forward `robin_map::operator[]` key by `std::forward` same with `stl map/unordered_map`
- License: MIT - License: MIT

View File

@ -51,15 +51,15 @@
#define TSL_RH_THROW_OR_TERMINATE(ex, msg) throw ex(msg) #define TSL_RH_THROW_OR_TERMINATE(ex, msg) throw ex(msg)
#else #else
#define TSL_RH_NO_EXCEPTIONS #define TSL_RH_NO_EXCEPTIONS
#ifdef NDEBUG #ifdef TSL_DEBUG
#define TSL_RH_THROW_OR_TERMINATE(ex, msg) std::terminate()
#else
#include <iostream> #include <iostream>
#define TSL_RH_THROW_OR_TERMINATE(ex, msg) \ #define TSL_RH_THROW_OR_TERMINATE(ex, msg) \
do { \ do { \
std::cerr << msg << std::endl; \ std::cerr << msg << std::endl; \
std::terminate(); \ std::terminate(); \
} while (0) } while (0)
#else
#define TSL_RH_THROW_OR_TERMINATE(ex, msg) std::terminate()
#endif #endif
#endif #endif

View File

@ -33,6 +33,7 @@
#include <iterator> #include <iterator>
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <new>
#include <stdexcept> #include <stdexcept>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
@ -195,6 +196,7 @@ class bucket_entry : public bucket_entry_hash<StoreHash> {
value_type(other.value()); value_type(other.value());
m_dist_from_ideal_bucket = other.m_dist_from_ideal_bucket; m_dist_from_ideal_bucket = other.m_dist_from_ideal_bucket;
} }
tsl_rh_assert(empty() == other.empty());
} }
/** /**
@ -212,6 +214,7 @@ class bucket_entry : public bucket_entry_hash<StoreHash> {
value_type(std::move(other.value())); value_type(std::move(other.value()));
m_dist_from_ideal_bucket = other.m_dist_from_ideal_bucket; m_dist_from_ideal_bucket = other.m_dist_from_ideal_bucket;
} }
tsl_rh_assert(empty() == other.empty());
} }
bucket_entry& operator=(const bucket_entry& other) noexcept( bucket_entry& operator=(const bucket_entry& other) noexcept(
@ -249,12 +252,22 @@ class bucket_entry : public bucket_entry_hash<StoreHash> {
value_type& value() noexcept { value_type& value() noexcept {
tsl_rh_assert(!empty()); tsl_rh_assert(!empty());
#if defined(__cplusplus) && __cplusplus >= 201703L
return *std::launder(
reinterpret_cast<value_type*>(std::addressof(m_value)));
#else
return *reinterpret_cast<value_type*>(std::addressof(m_value)); return *reinterpret_cast<value_type*>(std::addressof(m_value));
#endif
} }
const value_type& value() const noexcept { const value_type& value() const noexcept {
tsl_rh_assert(!empty()); tsl_rh_assert(!empty());
#if defined(__cplusplus) && __cplusplus >= 201703L
return *std::launder(
reinterpret_cast<const value_type*>(std::addressof(m_value)));
#else
return *reinterpret_cast<const value_type*>(std::addressof(m_value)); return *reinterpret_cast<const value_type*>(std::addressof(m_value));
#endif
} }
distance_type dist_from_ideal_bucket() const noexcept { distance_type dist_from_ideal_bucket() const noexcept {
@ -283,6 +296,7 @@ class bucket_entry : public bucket_entry_hash<StoreHash> {
void swap_with_value_in_bucket(distance_type& dist_from_ideal_bucket, void swap_with_value_in_bucket(distance_type& dist_from_ideal_bucket,
truncated_hash_type& hash, value_type& value) { truncated_hash_type& hash, value_type& value) {
tsl_rh_assert(!empty()); tsl_rh_assert(!empty());
tsl_rh_assert(dist_from_ideal_bucket > m_dist_from_ideal_bucket);
using std::swap; using std::swap;
swap(value, this->value()); swap(value, this->value());
@ -310,19 +324,16 @@ class bucket_entry : public bucket_entry_hash<StoreHash> {
public: public:
static const distance_type EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET = -1; static const distance_type EMPTY_MARKER_DIST_FROM_IDEAL_BUCKET = -1;
static const distance_type DIST_FROM_IDEAL_BUCKET_LIMIT = 4096; static const distance_type DIST_FROM_IDEAL_BUCKET_LIMIT = 8192;
static_assert(DIST_FROM_IDEAL_BUCKET_LIMIT <= static_assert(DIST_FROM_IDEAL_BUCKET_LIMIT <=
(std::numeric_limits<distance_type>::max)() - 1, (std::numeric_limits<distance_type>::max)() - 1,
"DIST_FROM_IDEAL_BUCKET_LIMIT must be <= " "DIST_FROM_IDEAL_BUCKET_LIMIT must be <= "
"std::numeric_limits<distance_type>::max() - 1."); "std::numeric_limits<distance_type>::max() - 1.");
private: private:
using storage = typename std::aligned_storage<sizeof(value_type),
alignof(value_type)>::type;
distance_type m_dist_from_ideal_bucket; distance_type m_dist_from_ideal_bucket;
bool m_last_bucket; bool m_last_bucket;
storage m_value; alignas(value_type) unsigned char m_value[sizeof(value_type)];
}; };
/** /**
@ -415,14 +426,15 @@ class robin_hash : private Hash, private KeyEqual, private GrowthPolicy {
} }
} }
public:
using bucket_entry = using bucket_entry =
tsl::detail_robin_hash::bucket_entry<value_type, STORE_HASH>; tsl::detail_robin_hash::bucket_entry<value_type, STORE_HASH>;
using distance_type = typename bucket_entry::distance_type; using distance_type = typename bucket_entry::distance_type;
using buckets_allocator = typename std::allocator_traits<allocator_type>::template rebind_alloc<bucket_entry>; using buckets_allocator = typename std::allocator_traits<
allocator_type>::template rebind_alloc<bucket_entry>;
using buckets_container_type = std::vector<bucket_entry, buckets_allocator>; using buckets_container_type = std::vector<bucket_entry, buckets_allocator>;
public:
/** /**
* The 'operator*()' and 'operator->()' methods return a const reference and * The 'operator*()' and 'operator->()' methods return a const reference and
* const pointer respectively to the stored value type. * const pointer respectively to the stored value type.
@ -716,7 +728,7 @@ public:
robin_hash& operator=(robin_hash&& other) { robin_hash& operator=(robin_hash&& other) {
other.swap(*this); other.swap(*this);
other.clear(); other.clear_and_shrink();
return *this; return *this;
} }
@ -1125,6 +1137,7 @@ public:
m_max_load_factor = clamp(ml, float(MINIMUM_MAX_LOAD_FACTOR), m_max_load_factor = clamp(ml, float(MINIMUM_MAX_LOAD_FACTOR),
float(MAXIMUM_MAX_LOAD_FACTOR)); float(MAXIMUM_MAX_LOAD_FACTOR));
m_load_threshold = size_type(float(bucket_count()) * m_max_load_factor); m_load_threshold = size_type(float(bucket_count()) * m_max_load_factor);
tsl_rh_assert(bucket_count() == 0 || m_load_threshold < bucket_count());
} }
void rehash(size_type count_) { void rehash(size_type count_) {
@ -1276,7 +1289,7 @@ public:
dist_from_ideal_bucket++; dist_from_ideal_bucket++;
} }
if (rehash_on_extreme_load()) { while (rehash_on_extreme_load(dist_from_ideal_bucket)) {
ibucket = bucket_for_hash(hash); ibucket = bucket_for_hash(hash);
dist_from_ideal_bucket = 0; dist_from_ideal_bucket = 0;
@ -1328,6 +1341,8 @@ public:
void insert_value_impl(std::size_t ibucket, void insert_value_impl(std::size_t ibucket,
distance_type dist_from_ideal_bucket, distance_type dist_from_ideal_bucket,
truncated_hash_type hash, value_type& value) { truncated_hash_type hash, value_type& value) {
tsl_rh_assert(dist_from_ideal_bucket >
m_buckets[ibucket].dist_from_ideal_bucket());
m_buckets[ibucket].swap_with_value_in_bucket(dist_from_ideal_bucket, hash, m_buckets[ibucket].swap_with_value_in_bucket(dist_from_ideal_bucket, hash,
value); value);
ibucket = next_bucket(ibucket); ibucket = next_bucket(ibucket);
@ -1336,7 +1351,7 @@ public:
while (!m_buckets[ibucket].empty()) { while (!m_buckets[ibucket].empty()) {
if (dist_from_ideal_bucket > if (dist_from_ideal_bucket >
m_buckets[ibucket].dist_from_ideal_bucket()) { m_buckets[ibucket].dist_from_ideal_bucket()) {
if (dist_from_ideal_bucket >= if (dist_from_ideal_bucket >
bucket_entry::DIST_FROM_IDEAL_BUCKET_LIMIT) { bucket_entry::DIST_FROM_IDEAL_BUCKET_LIMIT) {
/** /**
* The number of probes is really high, rehash the map on the next * The number of probes is really high, rehash the map on the next
@ -1361,6 +1376,7 @@ public:
robin_hash new_table(count_, static_cast<Hash&>(*this), robin_hash new_table(count_, static_cast<Hash&>(*this),
static_cast<KeyEqual&>(*this), get_allocator(), static_cast<KeyEqual&>(*this), get_allocator(),
m_min_load_factor, m_max_load_factor); m_min_load_factor, m_max_load_factor);
tsl_rh_assert(size() <= new_table.m_load_threshold);
const bool use_stored_hash = const bool use_stored_hash =
USE_STORED_HASH_ON_REHASH(new_table.bucket_count()); USE_STORED_HASH_ON_REHASH(new_table.bucket_count());
@ -1421,8 +1437,11 @@ public:
* *
* Return true if the table has been rehashed. * Return true if the table has been rehashed.
*/ */
bool rehash_on_extreme_load() { bool rehash_on_extreme_load(distance_type curr_dist_from_ideal_bucket) {
if (m_grow_on_next_insert || size() >= m_load_threshold) { if (m_grow_on_next_insert ||
curr_dist_from_ideal_bucket >
bucket_entry::DIST_FROM_IDEAL_BUCKET_LIMIT ||
size() >= m_load_threshold) {
rehash_impl(GrowthPolicy::next_bucket_count()); rehash_impl(GrowthPolicy::next_bucket_count());
m_grow_on_next_insert = false; m_grow_on_next_insert = false;
@ -1628,6 +1647,7 @@ public:
*/ */
bucket_entry* static_empty_bucket_ptr() noexcept { bucket_entry* static_empty_bucket_ptr() noexcept {
static bucket_entry empty_bucket(true); static bucket_entry empty_bucket(true);
tsl_rh_assert(empty_bucket.empty());
return &empty_bucket; return &empty_bucket;
} }

View File

@ -97,8 +97,8 @@ class robin_map {
public: public:
using key_type = Key; using key_type = Key;
const key_type& operator()(const std::pair<Key, T>& key_value) const const key_type& operator()(
noexcept { const std::pair<Key, T>& key_value) const noexcept {
return key_value.first; return key_value.first;
} }
@ -111,8 +111,8 @@ class robin_map {
public: public:
using value_type = T; using value_type = T;
const value_type& operator()(const std::pair<Key, T>& key_value) const const value_type& operator()(
noexcept { const std::pair<Key, T>& key_value) const noexcept {
return key_value.second; return key_value.second;
} }
@ -120,7 +120,9 @@ class robin_map {
return key_value.second; return key_value.second;
} }
value_type& operator()(std::pair<const Key, T>& key_value) noexcept { return key_value.second; } value_type& operator()(std::pair<const Key, T>& key_value) noexcept {
return key_value.second;
}
}; };
using ht = detail_robin_hash::robin_hash<std::pair<Key, T>, std::pair<const Key, T>, KeySelect, using ht = detail_robin_hash::robin_hash<std::pair<Key, T>, std::pair<const Key, T>, KeySelect,