diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index 181c8987..10712c9e 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -355,6 +355,106 @@ namespace boost { } #endif + template bool visit_until(F f) + { + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) + return table_.visit_until(f); + } + + template bool visit_until(F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.visit_until(f); + } + + template bool cvisit_until(F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.cvisit_until(f); + } + +#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS) + template + typename std::enable_if::value, + bool>::type + visit_until(ExecPolicy&& p, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) + return table_.visit_until(p, f); + } + + template + typename std::enable_if::value, + bool>::type + visit_until(ExecPolicy&& p, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) + return table_.visit_until(p, f); + } + + template + typename std::enable_if::value, + bool>::type + cvisit_until(ExecPolicy&& p, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) + return table_.cvisit_until(p, f); + } +#endif + + template bool visit_while(F f) + { + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) + return table_.visit_while(f); + } + + template bool visit_while(F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.visit_while(f); + } + + template bool cvisit_while(F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.cvisit_while(f); + } + +#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS) + template + typename std::enable_if::value, + bool>::type + visit_while(ExecPolicy&& p, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) + return table_.visit_while(p, f); + } + + template + typename std::enable_if::value, + bool>::type + visit_while(ExecPolicy&& p, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) + return table_.visit_while(p, f); + } + + template + typename std::enable_if::value, + bool>::type + cvisit_while(ExecPolicy&& p, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) + return table_.cvisit_while(p, f); + } +#endif + /// Modifiers /// diff --git a/include/boost/unordered/detail/foa/concurrent_table.hpp b/include/boost/unordered/detail/foa/concurrent_table.hpp index 0f1f1145..5a28f782 100644 --- a/include/boost/unordered/detail/foa/concurrent_table.hpp +++ b/include/boost/unordered/detail/foa/concurrent_table.hpp @@ -539,6 +539,86 @@ public: } #endif + template bool visit_until(F&& f) + { + return !visit_while([&](value_type& x){return !f(x);}); + } + + template bool visit_until(F&& f)const + { + return !visit_while([&](const value_type& x){return !f(x);}); + } + + template bool cvisit_until(F&& f)const + { + return visit_while(std::forward(f)); + } + +#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS) + template + bool visit_until(ExecutionPolicy&& policy,F&& f) + { + return !visit_while( + std::forward(policy), + [&](value_type& x){return !f(x);}); + } + + template + bool visit_until(ExecutionPolicy&& policy,F&& f)const + { + return !visit_while( + std::forward(policy), + [&](const value_type& x){return !f(x);}); + } + + template + bool cvisit_until(ExecutionPolicy&& policy,F&& f)const + { + return visit_until( + std::forward(policy),std::forward(f)); + } +#endif + + template bool visit_while(F&& f) + { + return visit_while_impl(group_exclusive{},std::forward(f)); + } + + template bool visit_while(F&& f)const + { + return visit_while_impl(group_shared{},std::forward(f)); + } + + template bool cvisit_while(F&& f)const + { + return visit_while(std::forward(f)); + } + +#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS) + template + bool visit_while(ExecutionPolicy&& policy,F&& f) + { + return visit_while_impl( + group_exclusive{}, + std::forward(policy),std::forward(f)); + } + + template + bool visit_while(ExecutionPolicy&& policy,F&& f)const + { + return visit_while_impl( + group_shared{}, + std::forward(policy),std::forward(f)); + } + + template + bool cvisit_while(ExecutionPolicy&& policy,F&& f)const + { + return visit_while( + std::forward(policy),std::forward(f)); + } +#endif + bool empty()const noexcept{return size()==0;} std::size_t size()const noexcept @@ -970,6 +1050,29 @@ private: } #endif + template + bool visit_while_impl(GroupAccessMode access_mode,F&& f)const + { + auto lck=shared_access(); + return for_all_elements_while(access_mode,[&](element_type* p){ + return f(cast_for(access_mode,type_policy::value_from(*p))); + }); + } + +#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS) + template + bool visit_while_impl( + GroupAccessMode access_mode,ExecutionPolicy&& policy,F&& f)const + { + auto lck=shared_access(); + return for_all_elements_while( + access_mode,std::forward(policy), + [&](element_type* p){ + return f(cast_for(access_mode,type_policy::value_from(*p))); + }); + } +#endif + template BOOST_FORCEINLINE std::size_t unprotected_visit( GroupAccessMode access_mode, @@ -1253,19 +1356,38 @@ private: template auto for_all_elements(GroupAccessMode access_mode,F f)const ->decltype(f(nullptr,0,nullptr),void()) + { + for_all_elements_while( + access_mode,[&](group_type* pg,unsigned int n,element_type* p) + {f(pg,n,p);return true;}); + } + + template + auto for_all_elements_while(GroupAccessMode access_mode,F f)const + ->decltype(f(nullptr),bool()) + { + return for_all_elements_while( + access_mode,[&](group_type*,unsigned int,element_type* p){return f(p);}); + } + + template + auto for_all_elements_while(GroupAccessMode access_mode,F f)const + ->decltype(f(nullptr,0,nullptr),bool()) { auto p=this->arrays.elements; - if(!p)return; - for(auto pg=this->arrays.groups,last=pg+this->arrays.groups_size_mask+1; - pg!=last;++pg,p+=N){ - auto lck=access(access_mode,(std::size_t)(pg-this->arrays.groups)); - auto mask=this->match_really_occupied(pg,last); - while(mask){ - auto n=unchecked_countr_zero(mask); - f(pg,n,p+n); - mask&=mask-1; + if(p){ + for(auto pg=this->arrays.groups,last=pg+this->arrays.groups_size_mask+1; + pg!=last;++pg,p+=N){ + auto lck=access(access_mode,(std::size_t)(pg-this->arrays.groups)); + auto mask=this->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; } #if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS) @@ -1289,10 +1411,10 @@ private: last=first+this->arrays.groups_size_mask+1; std::for_each(std::forward(policy),first,last, [&,this](group_type& g){ - std::size_t pos=static_cast(&g-first); - auto p=this->arrays.elements+pos*N; - auto lck=access(access_mode,pos); - auto mask=this->match_really_occupied(&g,last); + auto pos=static_cast(&g-first); + auto p=this->arrays.elements+pos*N; + auto lck=access(access_mode,pos); + auto mask=this->match_really_occupied(&g,last); while(mask){ auto n=unchecked_countr_zero(mask); f(&g,n,p+n); @@ -1301,6 +1423,29 @@ private: } ); } + + template + bool for_all_elements_while( + GroupAccessMode access_mode,ExecutionPolicy&& policy,F f)const + { + if(!this->arrays.elements)return true; + auto first=this->arrays.groups, + last=first+this->arrays.groups_size_mask+1; + return std::all_of(std::forward(policy),first,last, + [&,this](group_type& g){ + auto pos=static_cast(&g-first); + auto p=this->arrays.elements+pos*N; + auto lck=access(access_mode,pos); + auto mask=this->match_really_occupied(&g,last); + while(mask){ + auto n=unchecked_countr_zero(mask); + if(!f(p+n))return false; + mask&=mask-1; + } + return true; + } + ); + } #endif static std::atomic thread_counter;