diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index a06ec31f..2f1bd43c 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -244,6 +244,14 @@ namespace boost { return table_.visit(k, f); } + template + BOOST_FORCEINLINE + std::size_t bulk_visit(const std::array& keys,F f)const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.bulk_visit(keys, f); + } + template BOOST_FORCEINLINE typename std::enable_if< detail::are_transparent::value, size_type>::type diff --git a/include/boost/unordered/detail/foa/concurrent_table.hpp b/include/boost/unordered/detail/foa/concurrent_table.hpp index 11c7bb39..ebce2660 100644 --- a/include/boost/unordered/detail/foa/concurrent_table.hpp +++ b/include/boost/unordered/detail/foa/concurrent_table.hpp @@ -12,6 +12,7 @@ #define BOOST_UNORDERED_DETAIL_FOA_CONCURRENT_TABLE_HPP #include +#include #include #include #include @@ -564,6 +565,101 @@ public: return visit(x,std::forward(f)); } +#if 1 + template + BOOST_FORCEINLINE + std::size_t bulk_visit(const std::array& keys,F&& f)const + { + auto lck=shared_access(); + std::size_t res=0, + hashes[M]; + int masks[M]; + + for(std::size_t i=0;ihash_for(keys[i]); + auto pos=this->position_for(hashes[i]); + BOOST_UNORDERED_PREFETCH(this->arrays.groups+pos); + } + + for(std::size_t i=0;iposition_for(hash); + masks[i]=(this->arrays.groups+pos)->match(hash); + if(masks[i]){ + BOOST_UNORDERED_PREFETCH(this->arrays.group_accesses+pos); + BOOST_UNORDERED_PREFETCH_ELEMENTS(this->arrays.elements+pos*N,N); + } + } + + for(std::size_t i=0;iposition_for(hashes[i])); + auto pos=pb.get(); + auto pg=this->arrays.groups+pos; + auto mask=masks[i]; + element_type *p; + if(mask){ + p=this->arrays.elements+pos*N; + goto post_prefetch; + } + else{ + goto post_mask; + } + do{ + pos=pb.get(); + pg=this->arrays.groups+pos; + mask=pg->match(hashes[i]); + if(mask){ + p=this->arrays.elements+pos*N; + BOOST_UNORDERED_PREFETCH_ELEMENTS(p,N); + post_prefetch: + auto lck=access(group_shared{},pos); + do{ + auto n=unchecked_countr_zero(mask); + if(BOOST_LIKELY( + pg->is_occupied(n)&& + bool(this->pred()(keys[i],this->key_from(p[n]))))){ + f(p+n); + ++res; + goto next_key; + } + mask&=mask-1; + }while(mask); + } + post_mask: + if(BOOST_LIKELY(pg->is_not_overflowed(hashes[i]))){ + goto next_key; + } + } + while(BOOST_LIKELY(pb.next(this->arrays.groups_size_mask))); + next_key:; + } + return res; + } +#else + template + BOOST_FORCEINLINE + std::size_t bulk_visit(const std::array& keys,F&& f)const + { + auto lck=shared_access(); + std::size_t res=0, + hashes[M]; + + for(std::size_t i=0;ihash_for(keys[i]); + auto pos=this->position_for(hashes[i]); + BOOST_UNORDERED_PREFETCH(this->arrays.groups+pos); + BOOST_UNORDERED_PREFETCH(this->arrays.group_accesses+pos); + BOOST_UNORDERED_PREFETCH_ELEMENTS(this->arrays.elements+pos*N,N); + } + for(std::size_t i=0;iposition_for(hashes[i]),hashes[i], + std::forward(f)); + } + return res; + } +#endif + template std::size_t visit_all(F&& f) { return visit_all_impl(group_exclusive{},std::forward(f));