File indexing completed on 2025-07-01 08:33:08
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef BOOST_UNORDERED_DETAIL_FOA_TABLE_HPP
0014 #define BOOST_UNORDERED_DETAIL_FOA_TABLE_HPP
0015
0016 #include <boost/assert.hpp>
0017 #include <boost/config.hpp>
0018 #include <boost/config/workaround.hpp>
0019 #include <boost/core/serialization.hpp>
0020 #include <boost/unordered/detail/foa/core.hpp>
0021 #include <boost/unordered/detail/serialize_tracked_address.hpp>
0022 #include <boost/unordered/detail/type_traits.hpp>
0023 #include <cstddef>
0024 #include <iterator>
0025 #include <memory>
0026 #include <type_traits>
0027 #include <utility>
0028
0029 namespace boost{
0030 namespace unordered{
0031 namespace detail{
0032 namespace foa{
0033
0034
0035
0036 template<typename Integral>
0037 struct plain_integral
0038 {
0039 operator Integral()const{return n;}
0040 void operator=(Integral m){n=m;}
0041
0042 #if BOOST_WORKAROUND(BOOST_GCC,>=50000 && BOOST_GCC<60000)
0043 void operator|=(Integral m){n=static_cast<Integral>(n|m);}
0044 void operator&=(Integral m){n=static_cast<Integral>(n&m);}
0045 #else
0046 void operator|=(Integral m){n|=m;}
0047 void operator&=(Integral m){n&=m;}
0048 #endif
0049
0050 Integral n;
0051 };
0052
0053 struct plain_size_control
0054 {
0055 std::size_t ml;
0056 std::size_t size;
0057 };
0058
0059 template<typename,typename,typename,typename>
0060 class table;
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084 struct const_iterator_cast_tag{};
0085
0086 template<typename TypePolicy,typename GroupPtr,bool Const>
0087 class table_iterator
0088 {
0089 using group_pointer_traits=boost::pointer_traits<GroupPtr>;
0090 using type_policy=TypePolicy;
0091 using table_element_type=typename type_policy::element_type;
0092 using group_type=typename group_pointer_traits::element_type;
0093 using table_element_pointer=
0094 typename group_pointer_traits::template rebind<table_element_type>;
0095 using char_pointer=
0096 typename group_pointer_traits::template rebind<unsigned char>;
0097 static constexpr auto N=group_type::N;
0098 static constexpr auto regular_layout=group_type::regular_layout;
0099
0100 public:
0101 using difference_type=std::ptrdiff_t;
0102 using value_type=typename type_policy::value_type;
0103 using pointer=
0104 typename std::conditional<Const,value_type const*,value_type*>::type;
0105 using reference=
0106 typename std::conditional<Const,value_type const&,value_type&>::type;
0107 using iterator_category=std::forward_iterator_tag;
0108 using element_type=
0109 typename std::conditional<Const,value_type const,value_type>::type;
0110
0111 table_iterator():pc_{nullptr},p_{nullptr}{};
0112 template<bool Const2,typename std::enable_if<!Const2>::type* =nullptr>
0113 table_iterator(const table_iterator<TypePolicy,GroupPtr,Const2>& x):
0114 pc_{x.pc_},p_{x.p_}{}
0115 table_iterator(
0116 const_iterator_cast_tag, const table_iterator<TypePolicy,GroupPtr,true>& x):
0117 pc_{x.pc_},p_{x.p_}{}
0118
0119 inline reference operator*()const noexcept
0120 {return type_policy::value_from(*p());}
0121 inline pointer operator->()const noexcept
0122 {return std::addressof(type_policy::value_from(*p()));}
0123 inline table_iterator& operator++()noexcept{increment();return *this;}
0124 inline table_iterator operator++(int)noexcept
0125 {auto x=*this;increment();return x;}
0126 friend inline bool operator==(
0127 const table_iterator& x,const table_iterator& y)
0128 {return x.p()==y.p();}
0129 friend inline bool operator!=(
0130 const table_iterator& x,const table_iterator& y)
0131 {return !(x==y);}
0132
0133 private:
0134 template<typename,typename,bool> friend class table_iterator;
0135 template<typename> friend class table_erase_return_type;
0136 template<typename,typename,typename,typename> friend class table;
0137
0138 table_iterator(group_type* pg,std::size_t n,const table_element_type* ptet):
0139 pc_{to_pointer<char_pointer>(
0140 reinterpret_cast<unsigned char*>(const_cast<group_type*>(pg))+n)},
0141 p_{to_pointer<table_element_pointer>(const_cast<table_element_type*>(ptet))}
0142 {}
0143
0144 unsigned char* pc()const noexcept{return boost::to_address(pc_);}
0145 table_element_type* p()const noexcept{return boost::to_address(p_);}
0146
0147 inline void increment()noexcept
0148 {
0149 BOOST_ASSERT(p()!=nullptr);
0150 increment(std::integral_constant<bool,regular_layout>{});
0151 }
0152
0153 inline void increment(std::true_type )noexcept
0154 {
0155 using diff_type=
0156 typename boost::pointer_traits<char_pointer>::difference_type;
0157
0158 for(;;){
0159 ++p_;
0160 if(reinterpret_cast<uintptr_t>(pc())%sizeof(group_type)==N-1){
0161 pc_+=static_cast<diff_type>(sizeof(group_type)-(N-1));
0162 break;
0163 }
0164 ++pc_;
0165 if(!group_type::is_occupied(pc()))continue;
0166 if(BOOST_UNLIKELY(group_type::is_sentinel(pc())))p_=nullptr;
0167 return;
0168 }
0169
0170 for(;;){
0171 int mask=reinterpret_cast<group_type*>(pc())->match_occupied();
0172 if(mask!=0){
0173 auto n=unchecked_countr_zero(mask);
0174 if(BOOST_UNLIKELY(reinterpret_cast<group_type*>(pc())->is_sentinel(n))){
0175 p_=nullptr;
0176 }
0177 else{
0178 pc_+=static_cast<diff_type>(n);
0179 p_+=static_cast<diff_type>(n);
0180 }
0181 return;
0182 }
0183 pc_+=static_cast<diff_type>(sizeof(group_type));
0184 p_+=static_cast<diff_type>(N);
0185 }
0186 }
0187
0188 inline void increment(std::false_type )noexcept
0189 {
0190 using diff_type=
0191 typename boost::pointer_traits<char_pointer>::difference_type;
0192
0193 std::size_t n0=reinterpret_cast<uintptr_t>(pc())%sizeof(group_type);
0194 pc_-=static_cast<diff_type>(n0);
0195
0196 int mask=(
0197 reinterpret_cast<group_type*>(pc())->match_occupied()>>(n0+1))<<(n0+1);
0198 if(!mask){
0199 do{
0200 pc_+=sizeof(group_type);
0201 p_+=N;
0202 }
0203 while((mask=reinterpret_cast<group_type*>(pc())->match_occupied())==0);
0204 }
0205
0206 auto n=unchecked_countr_zero(mask);
0207 if(BOOST_UNLIKELY(reinterpret_cast<group_type*>(pc())->is_sentinel(n))){
0208 p_=nullptr;
0209 }
0210 else{
0211 pc_+=static_cast<diff_type>(n);
0212 p_-=static_cast<diff_type>(n0);
0213 p_+=static_cast<diff_type>(n);
0214 }
0215 }
0216
0217 template<typename Archive>
0218 friend void serialization_track(Archive& ar,const table_iterator& x)
0219 {
0220 if(x.p()){
0221 track_address(ar,x.pc_);
0222 track_address(ar,x.p_);
0223 }
0224 }
0225
0226 friend class boost::serialization::access;
0227
0228 template<typename Archive>
0229 void serialize(Archive& ar,unsigned int)
0230 {
0231 if(!p())pc_=nullptr;
0232 serialize_tracked_address(ar,pc_);
0233 serialize_tracked_address(ar,p_);
0234 }
0235
0236 char_pointer pc_=nullptr;
0237 table_element_pointer p_=nullptr;
0238 };
0239
0240
0241
0242
0243
0244 template<typename Iterator>
0245 class table_erase_return_type;
0246
0247 template<typename TypePolicy,typename GroupPtr,bool Const>
0248 class table_erase_return_type<table_iterator<TypePolicy,GroupPtr,Const>>
0249 {
0250 using iterator=table_iterator<TypePolicy,GroupPtr,Const>;
0251 using const_iterator=table_iterator<TypePolicy,GroupPtr,true>;
0252
0253 public:
0254
0255 table_erase_return_type(const table_erase_return_type&);
0256
0257 operator iterator()const noexcept
0258 {
0259 auto it=pos;
0260 it.increment();
0261 return iterator(const_iterator_cast_tag{},it);
0262 }
0263
0264 template<
0265 bool dependent_value=false,
0266 typename std::enable_if<!Const||dependent_value>::type* =nullptr
0267 >
0268 operator const_iterator()const noexcept{return this->operator iterator();}
0269
0270 private:
0271 template<typename,typename,typename,typename> friend class table;
0272
0273 table_erase_return_type(const_iterator pos_):pos{pos_}{}
0274 table_erase_return_type& operator=(const table_erase_return_type&)=delete;
0275
0276 const_iterator pos;
0277 };
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305 template<typename,typename,typename,typename>
0306 class concurrent_table;
0307
0308 template <typename TypePolicy,typename Hash,typename Pred,typename Allocator>
0309 using table_core_impl=
0310 table_core<TypePolicy,group15<plain_integral>,table_arrays,
0311 plain_size_control,Hash,Pred,Allocator>;
0312
0313 #include <boost/unordered/detail/foa/ignore_wshadow.hpp>
0314
0315 #if defined(BOOST_MSVC)
0316 #pragma warning(push)
0317 #pragma warning(disable:4714)
0318 #endif
0319
0320 template<typename TypePolicy,typename Hash,typename Pred,typename Allocator>
0321 class table:table_core_impl<TypePolicy,Hash,Pred,Allocator>
0322 {
0323 using super=table_core_impl<TypePolicy,Hash,Pred,Allocator>;
0324 using type_policy=typename super::type_policy;
0325 using group_type=typename super::group_type;
0326 using super::N;
0327 using prober=typename super::prober;
0328 using arrays_type=typename super::arrays_type;
0329 using size_ctrl_type=typename super::size_ctrl_type;
0330 using locator=typename super::locator;
0331 using compatible_concurrent_table=
0332 concurrent_table<TypePolicy,Hash,Pred,Allocator>;
0333 using group_type_pointer=typename boost::pointer_traits<
0334 typename boost::allocator_pointer<Allocator>::type
0335 >::template rebind<group_type>;
0336 friend compatible_concurrent_table;
0337
0338 public:
0339 using key_type=typename super::key_type;
0340 using init_type=typename super::init_type;
0341 using value_type=typename super::value_type;
0342 using element_type=typename super::element_type;
0343
0344 private:
0345 static constexpr bool has_mutable_iterator=
0346 !std::is_same<key_type,value_type>::value;
0347 public:
0348 using hasher=typename super::hasher;
0349 using key_equal=typename super::key_equal;
0350 using allocator_type=typename super::allocator_type;
0351 using pointer=typename super::pointer;
0352 using const_pointer=typename super::const_pointer;
0353 using reference=typename super::reference;
0354 using const_reference=typename super::const_reference;
0355 using size_type=typename super::size_type;
0356 using difference_type=typename super::difference_type;
0357 using const_iterator=table_iterator<type_policy,group_type_pointer,true>;
0358 using iterator=typename std::conditional<
0359 has_mutable_iterator,
0360 table_iterator<type_policy,group_type_pointer,false>,
0361 const_iterator>::type;
0362 using erase_return_type=table_erase_return_type<iterator>;
0363
0364 #if defined(BOOST_UNORDERED_ENABLE_STATS)
0365 using stats=typename super::stats;
0366 #endif
0367
0368 table(
0369 std::size_t n=default_bucket_count,const Hash& h_=Hash(),
0370 const Pred& pred_=Pred(),const Allocator& al_=Allocator()):
0371 super{n,h_,pred_,al_}
0372 {}
0373
0374 table(const table& x)=default;
0375 table(table&& x)=default;
0376 table(const table& x,const Allocator& al_):super{x,al_}{}
0377 table(table&& x,const Allocator& al_):super{std::move(x),al_}{}
0378 table(compatible_concurrent_table&& x):
0379 table(std::move(x),x.exclusive_access()){}
0380 ~table()=default;
0381
0382 table& operator=(const table& x)=default;
0383 table& operator=(table&& x)=default;
0384
0385 using super::get_allocator;
0386
0387 iterator begin()noexcept
0388 {
0389 iterator it{this->arrays.groups(),0,this->arrays.elements()};
0390 if(this->arrays.elements()&&
0391 !(this->arrays.groups()[0].match_occupied()&0x1))++it;
0392 return it;
0393 }
0394
0395 const_iterator begin()const noexcept
0396 {return const_cast<table*>(this)->begin();}
0397 iterator end()noexcept{return {};}
0398 const_iterator end()const noexcept{return const_cast<table*>(this)->end();}
0399 const_iterator cbegin()const noexcept{return begin();}
0400 const_iterator cend()const noexcept{return end();}
0401
0402 using super::empty;
0403 using super::size;
0404 using super::max_size;
0405
0406 template<typename... Args>
0407 BOOST_FORCEINLINE std::pair<iterator,bool> emplace(Args&&... args)
0408 {
0409 alloc_cted_insert_type<type_policy,Allocator,Args...> x(
0410 this->al(),std::forward<Args>(args)...);
0411 return emplace_impl(type_policy::move(x.value()));
0412 }
0413
0414
0415 template <typename T>
0416 BOOST_FORCEINLINE typename std::enable_if<
0417 detail::is_similar_to_any<T, value_type, init_type>::value,
0418 std::pair<iterator, bool> >::type
0419 emplace(T&& x)
0420 {
0421 return emplace_impl(std::forward<T>(x));
0422 }
0423
0424
0425 template <typename K, typename V>
0426 BOOST_FORCEINLINE
0427 typename std::enable_if<is_emplace_kv_able<table, K>::value,
0428 std::pair<iterator, bool> >::type
0429 emplace(K&& k, V&& v)
0430 {
0431 alloc_cted_or_fwded_key_type<type_policy, Allocator, K&&> x(
0432 this->al(), std::forward<K>(k));
0433 return emplace_impl(
0434 try_emplace_args_t{}, x.move_or_fwd(), std::forward<V>(v));
0435 }
0436
0437 template<typename Key,typename... Args>
0438 BOOST_FORCEINLINE std::pair<iterator,bool> try_emplace(
0439 Key&& x,Args&&... args)
0440 {
0441 return emplace_impl(
0442 try_emplace_args_t{},std::forward<Key>(x),std::forward<Args>(args)...);
0443 }
0444
0445 BOOST_FORCEINLINE std::pair<iterator,bool>
0446 insert(const init_type& x){return emplace_impl(x);}
0447
0448 BOOST_FORCEINLINE std::pair<iterator,bool>
0449 insert(init_type&& x){return emplace_impl(std::move(x));}
0450
0451
0452
0453 template<typename=void>
0454 BOOST_FORCEINLINE std::pair<iterator,bool>
0455 insert(const value_type& x){return emplace_impl(x);}
0456
0457 template<typename=void>
0458 BOOST_FORCEINLINE std::pair<iterator,bool>
0459 insert(value_type&& x){return emplace_impl(std::move(x));}
0460
0461 template<typename T=element_type>
0462 BOOST_FORCEINLINE
0463 typename std::enable_if<
0464 !std::is_same<T,value_type>::value,
0465 std::pair<iterator,bool>
0466 >::type
0467 insert(element_type&& x){return emplace_impl(std::move(x));}
0468
0469 template<
0470 bool dependent_value=false,
0471 typename std::enable_if<
0472 has_mutable_iterator||dependent_value>::type* =nullptr
0473 >
0474 erase_return_type erase(iterator pos)noexcept
0475 {return erase(const_iterator(pos));}
0476
0477 BOOST_FORCEINLINE
0478 erase_return_type erase(const_iterator pos)noexcept
0479 {
0480 super::erase(pos.pc(),pos.p());
0481 return {pos};
0482 }
0483
0484 template<typename Key>
0485 BOOST_FORCEINLINE
0486 auto erase(Key&& x) -> typename std::enable_if<
0487 !std::is_convertible<Key,iterator>::value&&
0488 !std::is_convertible<Key,const_iterator>::value, std::size_t>::type
0489 {
0490 auto it=find(x);
0491 if(it!=end()){
0492 erase(it);
0493 return 1;
0494 }
0495 else return 0;
0496 }
0497
0498 void swap(table& x)
0499 noexcept(noexcept(std::declval<super&>().swap(std::declval<super&>())))
0500 {
0501 super::swap(x);
0502 }
0503
0504 using super::clear;
0505
0506 element_type extract(const_iterator pos)
0507 {
0508 BOOST_ASSERT(pos!=end());
0509 erase_on_exit e{*this,pos};
0510 (void)e;
0511 return std::move(*pos.p());
0512 }
0513
0514
0515 template<typename Hash2,typename Pred2>
0516 void merge(table<TypePolicy,Hash2,Pred2,Allocator>& x)
0517 {
0518 x.for_all_elements([&,this](group_type* pg,unsigned int n,element_type* p){
0519 erase_on_exit e{x,{pg,n,p}};
0520 if(!emplace_impl(type_policy::move(*p)).second)e.rollback();
0521 });
0522 }
0523
0524 template<typename Hash2,typename Pred2>
0525 void merge(table<TypePolicy,Hash2,Pred2,Allocator>&& x){merge(x);}
0526
0527 using super::hash_function;
0528 using super::key_eq;
0529
0530 template<typename Key>
0531 BOOST_FORCEINLINE iterator find(const Key& x)
0532 {
0533 return make_iterator(super::find(x));
0534 }
0535
0536 template<typename Key>
0537 BOOST_FORCEINLINE const_iterator find(const Key& x)const
0538 {
0539 return const_cast<table*>(this)->find(x);
0540 }
0541
0542 using super::capacity;
0543 using super::load_factor;
0544 using super::max_load_factor;
0545 using super::max_load;
0546 using super::rehash;
0547 using super::reserve;
0548
0549 #if defined(BOOST_UNORDERED_ENABLE_STATS)
0550 using super::get_stats;
0551 using super::reset_stats;
0552 #endif
0553
0554 template<typename Predicate>
0555 friend std::size_t erase_if(table& x,Predicate& pr)
0556 {
0557 using value_reference=typename std::conditional<
0558 std::is_same<key_type,value_type>::value,
0559 const_reference,
0560 reference
0561 >::type;
0562
0563 std::size_t s=x.size();
0564 x.for_all_elements(
0565 [&](group_type* pg,unsigned int n,element_type* p){
0566 if(pr(const_cast<value_reference>(type_policy::value_from(*p)))){
0567 x.super::erase(pg,n,p);
0568 }
0569 });
0570 return std::size_t(s-x.size());
0571 }
0572
0573 friend bool operator==(const table& x,const table& y)
0574 {
0575 return static_cast<const super&>(x)==static_cast<const super&>(y);
0576 }
0577
0578 friend bool operator!=(const table& x,const table& y){return !(x==y);}
0579
0580 private:
0581 template<typename ArraysType>
0582 table(compatible_concurrent_table&& x,arrays_holder<ArraysType,Allocator>&& ah):
0583 super{
0584 std::move(x.h()),std::move(x.pred()),std::move(x.al()),
0585 [&x]{return arrays_type{
0586 x.arrays.groups_size_index,x.arrays.groups_size_mask,
0587 to_pointer<group_type_pointer>(
0588 reinterpret_cast<group_type*>(x.arrays.groups())),
0589 x.arrays.elements_};},
0590 size_ctrl_type{x.size_ctrl.ml,x.size_ctrl.size}}
0591 {
0592 compatible_concurrent_table::arrays_type::delete_group_access(x.al(),x.arrays);
0593 x.arrays=ah.release();
0594 x.size_ctrl.ml=x.initial_max_load();
0595 x.size_ctrl.size=0;
0596 BOOST_UNORDERED_SWAP_STATS(this->cstats,x.cstats);
0597 }
0598
0599 template<typename ExclusiveLockGuard>
0600 table(compatible_concurrent_table&& x,ExclusiveLockGuard):
0601 table(std::move(x),x.make_empty_arrays())
0602 {}
0603
0604 struct erase_on_exit
0605 {
0606 erase_on_exit(table& x_,const_iterator it_):x(x_),it(it_){}
0607 ~erase_on_exit(){if(!rollback_)x.erase(it);}
0608
0609 void rollback(){rollback_=true;}
0610
0611 table& x;
0612 const_iterator it;
0613 bool rollback_=false;
0614 };
0615
0616 static inline iterator make_iterator(const locator& l)noexcept
0617 {
0618 return {l.pg,l.n,l.p};
0619 }
0620
0621 template<typename... Args>
0622 BOOST_FORCEINLINE std::pair<iterator,bool> emplace_impl(Args&&... args)
0623 {
0624 const auto &k=this->key_from(std::forward<Args>(args)...);
0625 auto hash=this->hash_for(k);
0626 auto pos0=this->position_for(hash);
0627 auto loc=super::find(k,pos0,hash);
0628
0629 if(loc){
0630 return {make_iterator(loc),false};
0631 }
0632 if(BOOST_LIKELY(this->size_ctrl.size<this->size_ctrl.ml)){
0633 return {
0634 make_iterator(
0635 this->unchecked_emplace_at(pos0,hash,std::forward<Args>(args)...)),
0636 true
0637 };
0638 }
0639 else{
0640 return {
0641 make_iterator(
0642 this->unchecked_emplace_with_rehash(
0643 hash,std::forward<Args>(args)...)),
0644 true
0645 };
0646 }
0647 }
0648 };
0649
0650 #if defined(BOOST_MSVC)
0651 #pragma warning(pop)
0652 #endif
0653
0654 #include <boost/unordered/detail/foa/restore_wshadow.hpp>
0655
0656 }
0657 }
0658 }
0659 }
0660
0661 #endif