Fixes #280 ("Several containers don't support non-movable types when move assigning")

This commit is contained in:
Ion Gaztañaga
2024-05-23 23:28:54 +02:00
parent c38fe90e9a
commit 397fbda8be
26 changed files with 729 additions and 362 deletions
+38 -20
View File
@@ -2531,6 +2531,38 @@ private:
x.clear();
}
template<class OtherA>
void priv_move_assign_steal_or_assign(BOOST_RV_REF_BEG vector<T, OtherA, Options> BOOST_RV_REF_END x, dtl::true_type /*data_can_be_always_stolen*/)
{
this->clear();
if (BOOST_LIKELY(!!this->m_holder.m_start))
this->m_holder.deallocate(this->m_holder.m_start, this->m_holder.m_capacity);
this->m_holder.steal_resources(x.m_holder);
}
template<class OtherA>
void priv_move_assign_steal_or_assign(BOOST_RV_REF_BEG vector<T, OtherA, Options> BOOST_RV_REF_END x, dtl::false_type /*data_can_be_always_stolen*/)
{
const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value;
allocator_type& this_alloc = this->m_holder.alloc();
allocator_type& x_alloc = x.m_holder.alloc();
//In this allocator move constructor the allocator might will be propagated, but to support small_vector-like
//types, we need to check the currently owned buffers to know if they are propagable.
const bool is_buffer_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc);
if (is_buffer_propagable_from_x) {
this->priv_move_assign_steal_or_assign(boost::move(x), dtl::true_type());
}
//Else do a one by one move. Also, clear the source as users find confusing
//elements are still alive in the source container.
else {
this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin()))
, boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end())) );
x.clear();
}
}
template<class OtherA>
void priv_move_assign(BOOST_RV_REF_BEG vector<T, OtherA, Options> BOOST_RV_REF_END x
, typename dtl::disable_if_or
@@ -2542,30 +2574,16 @@ private:
//for move assignment, no aliasing (&x != this) is assumed.
//x.size() == 0 is allowed for buggy std libraries.
BOOST_ASSERT(this != &x || x.size() == 0);
allocator_type &this_alloc = this->m_holder.alloc();
allocator_type &x_alloc = x.m_holder.alloc();
const bool alloc_is_always_equal = allocator_traits_type::is_always_equal::value;
const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value;
const bool partially_propagable_alloc = allocator_traits_type::is_partially_propagable::value;
const bool data_can_be_always_be_stolen = alloc_is_always_equal || (propagate_alloc && !partially_propagable_alloc);
//In this allocator move constructor the allocator maybe will be propagated -----------------------v
const bool is_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc);
this->priv_move_assign_steal_or_assign(boost::move(x), dtl::bool_<data_can_be_always_be_stolen>());
//Resources can be transferred if both allocators are
//going to be equal after this function (either propagated or already equal)
if(is_propagable_from_x){
this->clear();
if(BOOST_LIKELY(!!this->m_holder.m_start))
this->m_holder.deallocate(this->m_holder.m_start, this->m_holder.m_capacity);
this->m_holder.steal_resources(x.m_holder);
}
//Else do a one by one move. Also, clear the source as users find confusing
//elements are still alive in the source container.
else{
this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin()))
, boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end() ))
);
x.clear();
}
//Move allocator if needed
allocator_type& this_alloc = this->m_holder.alloc();
allocator_type& x_alloc = x.m_holder.alloc();
dtl::move_alloc(this_alloc, x_alloc, dtl::bool_<propagate_alloc>());
}