forked from boostorg/unordered
made slot setting on insertion exception safe
This commit is contained in:
committed by
Christian Mazakas
parent
f244ba55de
commit
c35e9fc631
@@ -580,6 +580,26 @@ private:
|
|||||||
bool commit_=false;
|
bool commit_=false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct reserve_slot
|
||||||
|
{
|
||||||
|
reserve_slot(group_type* pg_,std::size_t pos_,std::size_t hash):
|
||||||
|
pg{pg_},pos{pos_}
|
||||||
|
{
|
||||||
|
pg->set(pos,hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
~reserve_slot()
|
||||||
|
{
|
||||||
|
if(!commit_)pg->reset(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void commit(){commit_=true;}
|
||||||
|
|
||||||
|
group_type *pg;
|
||||||
|
std::size_t pos;
|
||||||
|
bool commit_=false;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename F,typename... Args>
|
template<typename F,typename... Args>
|
||||||
BOOST_FORCEINLINE int
|
BOOST_FORCEINLINE int
|
||||||
unprotected_norehash_emplace_or_visit(F&& f,Args&&... args)
|
unprotected_norehash_emplace_or_visit(F&& f,Args&&... args)
|
||||||
@@ -593,8 +613,40 @@ private:
|
|||||||
boost::uint32_t counter=insert_counter(pos0);
|
boost::uint32_t counter=insert_counter(pos0);
|
||||||
if(unprotected_visit(k,pos0,hash,std::forward<F>(f)))return 0;
|
if(unprotected_visit(k,pos0,hash,std::forward<F>(f)))return 0;
|
||||||
|
|
||||||
reserve_size rs(*this);
|
#if 1
|
||||||
if(BOOST_LIKELY(rs.succeeded())){
|
reserve_size rsize(*this);
|
||||||
|
if(BOOST_LIKELY(rsize.succeeded())){
|
||||||
|
for(prober pb(pos0);;pb.next(this->arrays.groups_size_mask)){
|
||||||
|
auto pos=pb.get();
|
||||||
|
auto pg=this->arrays.groups+pos;
|
||||||
|
auto mask=pg->match_available();
|
||||||
|
if(BOOST_LIKELY(mask!=0)){
|
||||||
|
auto lck=exclusive_access(pos);
|
||||||
|
do{
|
||||||
|
auto n=unchecked_countr_zero(mask);
|
||||||
|
if(BOOST_LIKELY(!pg->is_occupied(n))){
|
||||||
|
reserve_slot rslot{pg,n,hash};
|
||||||
|
if(BOOST_UNLIKELY(insert_counter(pos0)++!=counter)){
|
||||||
|
/* other thread inserted from pos0, need to start over */
|
||||||
|
goto startover;
|
||||||
|
}
|
||||||
|
auto p=this->arrays.elements+pos*N+n;
|
||||||
|
this->construct_element(p,std::forward<Args>(args)...);
|
||||||
|
rslot.commit();
|
||||||
|
rsize.commit();
|
||||||
|
f(type_policy::value_from(*p));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
mask&=mask-1;
|
||||||
|
}while(mask);
|
||||||
|
}
|
||||||
|
pg->mark_overflow(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else return -1;
|
||||||
|
#else
|
||||||
|
if(BOOST_LIKELY(++(this->size_)<=this->ml)){
|
||||||
|
BOOST_TRY{
|
||||||
for(prober pb(pos0);;pb.next(this->arrays.groups_size_mask)){
|
for(prober pb(pos0);;pb.next(this->arrays.groups_size_mask)){
|
||||||
auto pos=pb.get();
|
auto pos=pb.get();
|
||||||
auto pg=this->arrays.groups+pos;
|
auto pg=this->arrays.groups+pos;
|
||||||
@@ -608,12 +660,11 @@ private:
|
|||||||
if(BOOST_UNLIKELY(insert_counter(pos0)++!=counter)){
|
if(BOOST_UNLIKELY(insert_counter(pos0)++!=counter)){
|
||||||
/* other thread inserted from pos0, need to start over */
|
/* other thread inserted from pos0, need to start over */
|
||||||
pg->reset(n);
|
pg->reset(n);
|
||||||
|
--(this->size_);
|
||||||
goto startover;
|
goto startover;
|
||||||
}
|
}
|
||||||
auto p=this->arrays.elements+pos*N+n;
|
auto p=this->arrays.elements+pos*N+n;
|
||||||
this->construct_element(p,std::forward<Args>(args)...);
|
this->construct_element(p,std::forward<Args>(args)...);
|
||||||
rs.commit();
|
|
||||||
f(type_policy::value_from(*p));
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
mask&=mask-1;
|
mask&=mask-1;
|
||||||
@@ -622,7 +673,17 @@ private:
|
|||||||
pg->mark_overflow(hash);
|
pg->mark_overflow(hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return -1;
|
BOOST_CATCH(...){
|
||||||
|
--(this->size_);
|
||||||
|
BOOST_RETHROW
|
||||||
|
}
|
||||||
|
BOOST_CATCH_END
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
--(this->size_);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user