refactored to provide equality comparison from table_core

This commit is contained in:
joaquintides
2023-05-12 11:24:20 +02:00
parent bcf5d0cf13
commit 511e2b3272
8 changed files with 200 additions and 171 deletions

View File

@ -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

View File

@ -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)...);

View File

@ -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;

View File

@ -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 {

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,