diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index 3f2bb793..3679df58 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -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 + friend bool operator==( + concurrent_flat_map const& lhs, + concurrent_flat_map const& rhs) + { + return lhs.table_ == rhs.table_; + } + + template + friend bool operator!=( + concurrent_flat_map const& lhs, + concurrent_flat_map const& rhs) + { + return !(lhs == rhs); + } }; } // namespace unordered } // namespace boost diff --git a/include/boost/unordered/detail/foa/concurrent_table.hpp b/include/boost/unordered/detail/foa/concurrent_table.hpp index 7eee515e..1b9ade9c 100644 --- a/include/boost/unordered/detail/foa/concurrent_table.hpp +++ b/include/boost/unordered/detail/foa/concurrent_table.hpp @@ -697,13 +697,13 @@ public: boost::ignore_unused(); 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 @@ -773,6 +773,17 @@ public: return x.erase_if(std::forward(pr)); } + friend bool operator==(const concurrent_table& x,const concurrent_table& y) + { + auto lck=exclusive_access(x,y); + return static_cast(x)==static_cast(y); + } + + friend bool operator!=(const concurrent_table& x,const concurrent_table& y) + { + return !(x==y); + } + private: using mutex_type=cacheline_protected; using multimutex_type=multimutex; // 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 - inline exclusive_bilock_guard exclusive_access( + static inline exclusive_bilock_guard exclusive_access( const concurrent_table& x, const concurrent_table& 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_ml)){ this->unchecked_emplace_at(pos0,hash,std::forward(args)...); diff --git a/include/boost/unordered/detail/foa/core.hpp b/include/boost/unordered/detail/foa/core.hpp index 7e47568f..295f580f 100644 --- a/include/boost/unordered/detail/foa/core.hpp +++ b/include/boost/unordered/detail/foa/core.hpp @@ -1097,9 +1097,14 @@ static constexpr float mlf=0.875f; template 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 + 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 + 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(type_policy::value_from(*p))== + const_cast(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 - 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 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 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; diff --git a/include/boost/unordered/detail/foa/table.hpp b/include/boost/unordered/detail/foa/table.hpp index 1946bd9f..554e762a 100644 --- a/include/boost/unordered/detail/foa/table.hpp +++ b/include/boost/unordered/detail/foa/table.hpp @@ -404,8 +404,7 @@ public: template 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 @@ -440,6 +439,13 @@ public: return std::size_t(s-x.size()); } + friend bool operator==(const table& x,const table& y) + { + return static_cast(x)==static_cast(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 - 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 BOOST_FORCEINLINE std::pair emplace_impl(Args&&... args) { const auto &k=this->key_from(std::forward(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_ml)){ return { diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index a7b6482b..8a844dd3 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -695,35 +695,26 @@ namespace boost { hasher hash_function() const { return table_.hash_function(); } key_equal key_eq() const { return table_.key_eq(); } - }; - template - bool operator==( - unordered_flat_map const& lhs, - unordered_flat_map const& rhs) - { - if (&lhs == &rhs) { - return true; + /// Equality + /// + + template + friend bool operator==( + unordered_flat_map const& lhs, + unordered_flat_map 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 - bool operator!=( - unordered_flat_map const& lhs, - unordered_flat_map const& rhs) - { - return !(lhs == rhs); - } + template + friend bool operator!=( + unordered_flat_map const& lhs, + unordered_flat_map const& rhs) + { + return !(lhs == rhs); + } + }; template void swap(unordered_flat_map& lhs, diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 4562b1e5..b9ded1ff 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -492,35 +492,26 @@ namespace boost { hasher hash_function() const { return table_.hash_function(); } key_equal key_eq() const { return table_.key_eq(); } - }; - template - bool operator==( - unordered_flat_set const& lhs, - unordered_flat_set const& rhs) - { - if (&lhs == &rhs) { - return true; + /// Equality + /// + + template + friend bool operator==( + unordered_flat_set const& lhs, + unordered_flat_set 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 - bool operator!=( - unordered_flat_set const& lhs, - unordered_flat_set const& rhs) - { - return !(lhs == rhs); - } + template + friend bool operator!=( + unordered_flat_set const& lhs, + unordered_flat_set const& rhs) + { + return !(lhs == rhs); + } + }; template void swap(unordered_flat_set& lhs, diff --git a/include/boost/unordered/unordered_node_map.hpp b/include/boost/unordered/unordered_node_map.hpp index 6c598354..513eab95 100644 --- a/include/boost/unordered/unordered_node_map.hpp +++ b/include/boost/unordered/unordered_node_map.hpp @@ -847,35 +847,26 @@ namespace boost { hasher hash_function() const { return table_.hash_function(); } key_equal key_eq() const { return table_.key_eq(); } - }; - template - bool operator==( - unordered_node_map const& lhs, - unordered_node_map const& rhs) - { - if (&lhs == &rhs) { - return true; + /// Equality + /// + + template + friend bool operator==( + unordered_node_map const& lhs, + unordered_node_map 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 - bool operator!=( - unordered_node_map const& lhs, - unordered_node_map const& rhs) - { - return !(lhs == rhs); - } + template + friend bool operator!=( + unordered_node_map const& lhs, + unordered_node_map const& rhs) + { + return !(lhs == rhs); + } + }; template void swap(unordered_node_map& lhs, diff --git a/include/boost/unordered/unordered_node_set.hpp b/include/boost/unordered/unordered_node_set.hpp index 2e2a9dd4..3758802e 100644 --- a/include/boost/unordered/unordered_node_set.hpp +++ b/include/boost/unordered/unordered_node_set.hpp @@ -631,35 +631,26 @@ namespace boost { hasher hash_function() const { return table_.hash_function(); } key_equal key_eq() const { return table_.key_eq(); } - }; - template - bool operator==( - unordered_node_set const& lhs, - unordered_node_set const& rhs) - { - if (&lhs == &rhs) { - return true; + /// Equality + /// + + template + friend bool operator==( + unordered_node_set const& lhs, + unordered_node_set 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 - bool operator!=( - unordered_node_set const& lhs, - unordered_node_set const& rhs) - { - return !(lhs == rhs); - } + template + friend bool operator!=( + unordered_node_set const& lhs, + unordered_node_set const& rhs) + { + return !(lhs == rhs); + } + }; template void swap(unordered_node_set& lhs,