mirror of
https://github.com/boostorg/unordered.git
synced 2025-07-29 19:07:15 +02:00
refactored to provide equality comparison from table_core
This commit is contained in:
@ -766,6 +766,25 @@ namespace boost {
|
||||
|
||||
hasher hash_function() const { return table_.hash_function(); }
|
||||
key_equal key_eq() const { return table_.key_eq(); }
|
||||
|
||||
/// Equality
|
||||
///
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
friend bool operator==(
|
||||
concurrent_flat_map<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
concurrent_flat_map<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return lhs.table_ == rhs.table_;
|
||||
}
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
friend bool operator!=(
|
||||
concurrent_flat_map<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
concurrent_flat_map<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
@ -697,13 +697,13 @@ public:
|
||||
boost::ignore_unused<super2>();
|
||||
|
||||
auto lck=exclusive_access(*this,x);
|
||||
size_type s=unprotected_size();
|
||||
size_type s=super::size();
|
||||
x.super2::for_all_elements( /* super2::for_all_elements -> unprotected */
|
||||
[&,this](group_type* pg,unsigned int n,element_type* p){
|
||||
typename merge_table_type::erase_on_exit e{x,pg,n,p};
|
||||
if(!unprotected_emplace(type_policy::move(*p)))e.rollback();
|
||||
});
|
||||
return size_type{unprotected_size()-s};
|
||||
return size_type{super::size()-s};
|
||||
}
|
||||
|
||||
template<typename Hash2,typename Pred2>
|
||||
@ -773,6 +773,17 @@ public:
|
||||
return x.erase_if(std::forward<Predicate>(pr));
|
||||
}
|
||||
|
||||
friend bool operator==(const concurrent_table& x,const concurrent_table& y)
|
||||
{
|
||||
auto lck=exclusive_access(x,y);
|
||||
return static_cast<const super&>(x)==static_cast<const super&>(y);
|
||||
}
|
||||
|
||||
friend bool operator!=(const concurrent_table& x,const concurrent_table& y)
|
||||
{
|
||||
return !(x==y);
|
||||
}
|
||||
|
||||
private:
|
||||
using mutex_type=cacheline_protected<rw_spinlock>;
|
||||
using multimutex_type=multimutex<mutex_type,128>; // TODO: adapt 128 to the machine
|
||||
@ -806,14 +817,14 @@ private:
|
||||
return exclusive_lock_guard{mutexes};
|
||||
}
|
||||
|
||||
inline exclusive_bilock_guard exclusive_access(
|
||||
static inline exclusive_bilock_guard exclusive_access(
|
||||
const concurrent_table& x,const concurrent_table& y)
|
||||
{
|
||||
return {x.mutexes,y.mutexes};
|
||||
}
|
||||
|
||||
template<typename Hash2,typename Pred2>
|
||||
inline exclusive_bilock_guard exclusive_access(
|
||||
static inline exclusive_bilock_guard exclusive_access(
|
||||
const concurrent_table& x,
|
||||
const concurrent_table<TypePolicy,Hash2,Pred2,Allocator>& y)
|
||||
{
|
||||
@ -1079,9 +1090,7 @@ private:
|
||||
auto hash=this->hash_for(k);
|
||||
auto pos0=this->position_for(hash);
|
||||
|
||||
// TODO: could be made more efficient (nonconcurrent scenario)
|
||||
if(unprotected_visit(
|
||||
group_shared{},k,pos0,hash,[](const value_type&){}))return false;
|
||||
if(!this->find(k,pos0,hash))return false;
|
||||
|
||||
if(BOOST_LIKELY(this->size_<this->ml)){
|
||||
this->unchecked_emplace_at(pos0,hash,std::forward<Args>(args)...);
|
||||
|
@ -1097,9 +1097,14 @@ static constexpr float mlf=0.875f;
|
||||
template<typename Group,typename Element>
|
||||
struct table_locator
|
||||
{
|
||||
Group *pg;
|
||||
unsigned int n;
|
||||
Element *p;
|
||||
table_locator()=default;
|
||||
table_locator(Group* pg_,unsigned int n_,Element* p_):pg{pg_},n{n_},p{p_}{}
|
||||
|
||||
explicit operator bool()const noexcept{return p!=nullptr;}
|
||||
|
||||
Group *pg=nullptr;
|
||||
unsigned int n=0;
|
||||
Element *p=nullptr;
|
||||
};
|
||||
|
||||
struct try_emplace_args_t{};
|
||||
@ -1425,6 +1430,52 @@ public:
|
||||
recover_slot(pc);
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
BOOST_FORCEINLINE locator find(const Key& x)const
|
||||
{
|
||||
auto hash=hash_for(x);
|
||||
return find(x,position_for(hash),hash);
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
/* warning: forcing value to bool 'true' or 'false' in bool(pred()...) */
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4800)
|
||||
#endif
|
||||
|
||||
template<typename Key>
|
||||
BOOST_FORCEINLINE locator find(
|
||||
const Key& x,std::size_t pos0,std::size_t hash)const
|
||||
{
|
||||
prober pb(pos0);
|
||||
do{
|
||||
auto pos=pb.get();
|
||||
auto pg=arrays.groups+pos;
|
||||
auto mask=pg->match(hash);
|
||||
if(mask){
|
||||
BOOST_UNORDERED_ASSUME(arrays.elements!=nullptr);
|
||||
auto p=arrays.elements+pos*N;
|
||||
prefetch_elements(p);
|
||||
do{
|
||||
auto n=unchecked_countr_zero(mask);
|
||||
if(BOOST_LIKELY(bool(pred()(x,key_from(p[n]))))){
|
||||
return {pg,n,p+n};
|
||||
}
|
||||
mask&=mask-1;
|
||||
}while(mask);
|
||||
}
|
||||
if(BOOST_LIKELY(pg->is_not_overflowed(hash))){
|
||||
return {};
|
||||
}
|
||||
}
|
||||
while(BOOST_LIKELY(pb.next(arrays.groups_size_mask)));
|
||||
return {};
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop) /* C4800 */
|
||||
#endif
|
||||
|
||||
void swap(table_core& x)
|
||||
noexcept(
|
||||
alloc_traits::propagate_on_container_swap::value||
|
||||
@ -1503,6 +1554,23 @@ public:
|
||||
rehash(std::size_t(std::ceil(float(n)/mlf)));
|
||||
}
|
||||
|
||||
friend bool operator==(const table_core& x,const table_core& y)
|
||||
{
|
||||
return
|
||||
x.size()==y.size()&&
|
||||
x.for_all_elements_while([&](element_type* p){
|
||||
auto loc=y.find(key_from(*p));
|
||||
return loc&&
|
||||
const_cast<const value_type&>(type_policy::value_from(*p))==
|
||||
const_cast<const value_type&>(type_policy::value_from(*loc.p));
|
||||
});
|
||||
}
|
||||
|
||||
friend bool operator!=(const table_core& x,const table_core& y)
|
||||
{
|
||||
return !(x==y);
|
||||
}
|
||||
|
||||
struct clear_on_exit
|
||||
{
|
||||
~clear_on_exit(){x.clear();}
|
||||
@ -1683,34 +1751,36 @@ public:
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void for_all_elements_while(F f)const
|
||||
bool for_all_elements_while(F f)const
|
||||
{
|
||||
for_all_elements_while(arrays,f);
|
||||
return for_all_elements_while(arrays,f);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
static auto for_all_elements_while(const arrays_type& arrays_,F f)
|
||||
->decltype(f(nullptr),void())
|
||||
->decltype(f(nullptr),bool())
|
||||
{
|
||||
for_all_elements_while(
|
||||
return for_all_elements_while(
|
||||
arrays_,[&](group_type*,unsigned int,element_type* p){return f(p);});
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
static auto for_all_elements_while(const arrays_type& arrays_,F f)
|
||||
->decltype(f(nullptr,0,nullptr),void())
|
||||
->decltype(f(nullptr,0,nullptr),bool())
|
||||
{
|
||||
auto p=arrays_.elements;
|
||||
if(!p){return;}
|
||||
for(auto pg=arrays_.groups,last=pg+arrays_.groups_size_mask+1;
|
||||
pg!=last;++pg,p+=N){
|
||||
auto mask=match_really_occupied(pg,last);
|
||||
while(mask){
|
||||
auto n=unchecked_countr_zero(mask);
|
||||
if(!f(pg,n,p+n))return;
|
||||
mask&=mask-1;
|
||||
if(p){
|
||||
for(auto pg=arrays_.groups,last=pg+arrays_.groups_size_mask+1;
|
||||
pg!=last;++pg,p+=N){
|
||||
auto mask=match_really_occupied(pg,last);
|
||||
while(mask){
|
||||
auto n=unchecked_countr_zero(mask);
|
||||
if(!f(pg,n,p+n))return false;
|
||||
mask&=mask-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
arrays_type arrays;
|
||||
|
@ -404,8 +404,7 @@ public:
|
||||
template<typename Key>
|
||||
BOOST_FORCEINLINE iterator find(const Key& x)
|
||||
{
|
||||
auto hash=this->hash_for(x);
|
||||
return find_impl(x,this->position_for(hash),hash);
|
||||
return make_iterator(super::find(x));
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
@ -440,6 +439,13 @@ public:
|
||||
return std::size_t(s-x.size());
|
||||
}
|
||||
|
||||
friend bool operator==(const table& x,const table& y)
|
||||
{
|
||||
return static_cast<const super&>(x)==static_cast<const super&>(y);
|
||||
}
|
||||
|
||||
friend bool operator!=(const table& x,const table& y){return !(x==y);}
|
||||
|
||||
private:
|
||||
struct erase_on_exit
|
||||
{
|
||||
@ -458,55 +464,16 @@ private:
|
||||
return {l.pg,l.n,l.p};
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
/* warning: forcing value to bool 'true' or 'false' in bool(pred()...) */
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4800)
|
||||
#endif
|
||||
|
||||
template<typename Key>
|
||||
BOOST_FORCEINLINE iterator find_impl(
|
||||
const Key& x,std::size_t pos0,std::size_t hash)const
|
||||
{
|
||||
prober pb(pos0);
|
||||
do{
|
||||
auto pos=pb.get();
|
||||
auto pg=this->arrays.groups+pos;
|
||||
auto mask=pg->match(hash);
|
||||
if(mask){
|
||||
BOOST_UNORDERED_ASSUME(this->arrays.elements!=nullptr);
|
||||
auto p=this->arrays.elements+pos*N;
|
||||
this->prefetch_elements(p);
|
||||
do{
|
||||
auto n=unchecked_countr_zero(mask);
|
||||
if(BOOST_LIKELY(bool(this->pred()(x,this->key_from(p[n]))))){
|
||||
return {pg,n,p+n};
|
||||
}
|
||||
mask&=mask-1;
|
||||
}while(mask);
|
||||
}
|
||||
if(BOOST_LIKELY(pg->is_not_overflowed(hash))){
|
||||
return {}; /* end() */
|
||||
}
|
||||
}
|
||||
while(BOOST_LIKELY(pb.next(this->arrays.groups_size_mask)));
|
||||
return {}; /* end() */
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop) /* C4800 */
|
||||
#endif
|
||||
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> emplace_impl(Args&&... args)
|
||||
{
|
||||
const auto &k=this->key_from(std::forward<Args>(args)...);
|
||||
auto hash=this->hash_for(k);
|
||||
auto pos0=this->position_for(hash);
|
||||
auto it=find_impl(k,pos0,hash);
|
||||
auto loc=super::find(k,pos0,hash);
|
||||
|
||||
if(it!=end()){
|
||||
return {it,false};
|
||||
if(loc){
|
||||
return {make_iterator(loc),false};
|
||||
}
|
||||
if(BOOST_LIKELY(this->size_<this->ml)){
|
||||
return {
|
||||
|
@ -695,35 +695,26 @@ namespace boost {
|
||||
hasher hash_function() const { return table_.hash_function(); }
|
||||
|
||||
key_equal key_eq() const { return table_.key_eq(); }
|
||||
};
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator==(
|
||||
unordered_flat_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_flat_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
if (&lhs == &rhs) {
|
||||
return true;
|
||||
/// Equality
|
||||
///
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
friend bool operator==(
|
||||
unordered_flat_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_flat_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return lhs.table_ == rhs.table_;
|
||||
}
|
||||
|
||||
return (lhs.size() == rhs.size()) && ([&] {
|
||||
for (auto const& kvp : lhs) {
|
||||
auto pos = rhs.find(kvp.first);
|
||||
if ((pos == rhs.end()) || (*pos != kvp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
}
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator!=(
|
||||
unordered_flat_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_flat_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
friend bool operator!=(
|
||||
unordered_flat_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_flat_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
void swap(unordered_flat_map<Key, T, Hash, KeyEqual, Allocator>& lhs,
|
||||
|
@ -492,35 +492,26 @@ namespace boost {
|
||||
hasher hash_function() const { return table_.hash_function(); }
|
||||
|
||||
key_equal key_eq() const { return table_.key_eq(); }
|
||||
};
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator==(
|
||||
unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
if (&lhs == &rhs) {
|
||||
return true;
|
||||
/// Equality
|
||||
///
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
friend bool operator==(
|
||||
unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return lhs.table_ == rhs.table_;
|
||||
}
|
||||
|
||||
return (lhs.size() == rhs.size()) && ([&] {
|
||||
for (auto const& key : lhs) {
|
||||
auto pos = rhs.find(key);
|
||||
if ((pos == rhs.end()) || (key != *pos)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
}
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator!=(
|
||||
unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
friend bool operator!=(
|
||||
unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
void swap(unordered_flat_set<Key, Hash, KeyEqual, Allocator>& lhs,
|
||||
|
@ -847,35 +847,26 @@ namespace boost {
|
||||
hasher hash_function() const { return table_.hash_function(); }
|
||||
|
||||
key_equal key_eq() const { return table_.key_eq(); }
|
||||
};
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator==(
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
if (&lhs == &rhs) {
|
||||
return true;
|
||||
/// Equality
|
||||
///
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
friend bool operator==(
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return lhs.table_ == rhs.table_;
|
||||
}
|
||||
|
||||
return (lhs.size() == rhs.size()) && ([&] {
|
||||
for (auto const& kvp : lhs) {
|
||||
auto pos = rhs.find(kvp.first);
|
||||
if ((pos == rhs.end()) || (*pos != kvp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
}
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator!=(
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
friend bool operator!=(
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
void swap(unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& lhs,
|
||||
|
@ -631,35 +631,26 @@ namespace boost {
|
||||
hasher hash_function() const { return table_.hash_function(); }
|
||||
|
||||
key_equal key_eq() const { return table_.key_eq(); }
|
||||
};
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator==(
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
if (&lhs == &rhs) {
|
||||
return true;
|
||||
/// Equality
|
||||
///
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
friend bool operator==(
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return lhs.table_ == rhs.table_;
|
||||
}
|
||||
|
||||
return (lhs.size() == rhs.size()) && ([&] {
|
||||
for (auto const& key : lhs) {
|
||||
auto pos = rhs.find(key);
|
||||
if ((pos == rhs.end()) || (key != *pos)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
}
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator!=(
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
friend bool operator!=(
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
void swap(unordered_node_set<Key, Hash, KeyEqual, Allocator>& lhs,
|
||||
|
Reference in New Issue
Block a user