Clean-up insertion code and speed upt single value insertion for proxies having that trait.

This commit is contained in:
Ion Gaztañaga
2020-08-10 00:02:26 +02:00
parent bff516315b
commit 844b779a7d

View File

@@ -1514,7 +1514,7 @@ private:
BOOST_CONTAINER_FORCEINLINE void reserve(size_type new_cap)
{
if (this->capacity() < new_cap){
this->priv_reserve_no_capacity(new_cap, alloc_version());
this->priv_move_to_new_buffer(new_cap, alloc_version());
}
}
@@ -1762,9 +1762,9 @@ private:
return *p;
}
else{
typedef dtl::insert_emplace_proxy<allocator_type, T*, Args...> type;
return *this->priv_forward_range_insert_no_capacity
(this->back_ptr(), 1, type(::boost::forward<Args>(args)...), alloc_version());
typedef dtl::insert_emplace_proxy<allocator_type, T*, Args...> proxy_t;
return *this->priv_insert_forward_range_no_capacity
(this->back_ptr(), 1, proxy_t(::boost::forward<Args>(args)...), alloc_version());
}
}
@@ -1803,9 +1803,9 @@ private:
{
BOOST_ASSERT(this->priv_in_range_or_end(position));
//Just call more general insert(pos, size, value) and return iterator
typedef dtl::insert_emplace_proxy<allocator_type, T*, Args...> type;
return this->priv_forward_range_insert( vector_iterator_get_ptr(position), 1
, type(::boost::forward<Args>(args)...));
typedef dtl::insert_emplace_proxy<allocator_type, T*, Args...> proxy_t;
return this->priv_insert_forward_range( vector_iterator_get_ptr(position), 1
, proxy_t(::boost::forward<Args>(args)...));
}
#else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
@@ -1822,9 +1822,9 @@ private:
return *p;\
}\
else{\
typedef dtl::insert_emplace_proxy_arg##N<allocator_type, T* BOOST_MOVE_I##N BOOST_MOVE_TARG##N> type;\
return *this->priv_forward_range_insert_no_capacity\
( this->back_ptr(), 1, type(BOOST_MOVE_FWD##N), alloc_version());\
typedef dtl::insert_emplace_proxy_arg##N<allocator_type, T* BOOST_MOVE_I##N BOOST_MOVE_TARG##N> proxy_t;\
return *this->priv_insert_forward_range_no_capacity\
( this->back_ptr(), 1, proxy_t(BOOST_MOVE_FWD##N), alloc_version());\
}\
}\
\
@@ -1844,8 +1844,8 @@ private:
BOOST_CONTAINER_FORCEINLINE iterator emplace(const_iterator pos BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
{\
BOOST_ASSERT(this->priv_in_range_or_end(pos));\
typedef dtl::insert_emplace_proxy_arg##N<allocator_type, T* BOOST_MOVE_I##N BOOST_MOVE_TARG##N> type;\
return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), 1, type(BOOST_MOVE_FWD##N));\
typedef dtl::insert_emplace_proxy_arg##N<allocator_type, T* BOOST_MOVE_I##N BOOST_MOVE_TARG##N> proxy_t;\
return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), 1, proxy_t(BOOST_MOVE_FWD##N));\
}\
//
BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_VECTOR_EMPLACE_CODE)
@@ -1911,7 +1911,7 @@ private:
{
BOOST_ASSERT(this->priv_in_range_or_end(p));
dtl::insert_n_copies_proxy<allocator_type, T*> proxy(x);
return this->priv_forward_range_insert(vector_iterator_get_ptr(p), n, proxy);
return this->priv_insert_forward_range(vector_iterator_get_ptr(p), n, proxy);
}
//! <b>Requires</b>: p must be a valid iterator of *this.
@@ -1957,7 +1957,7 @@ private:
{
BOOST_ASSERT(this->priv_in_range_or_end(pos));
dtl::insert_range_proxy<allocator_type, FwdIt, T*> proxy(first);
return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), boost::container::iterator_distance(first, last), proxy);
return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), boost::container::iterator_distance(first, last), proxy);
}
#endif
@@ -1985,7 +1985,7 @@ private:
num == static_cast<size_type>(boost::container::iterator_distance(first, last)));
(void)last;
dtl::insert_range_proxy<allocator_type, InIt, T*> proxy(first);
return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), num, proxy);
return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), num, proxy);
}
#endif
@@ -2504,7 +2504,7 @@ private:
dtl::swap_alloc(this->m_holder.alloc(), x.m_holder.alloc(), dtl::bool_<propagate_alloc>());
}
void priv_reserve_no_capacity(size_type, version_0)
BOOST_CONTAINER_FORCEINLINE void priv_move_to_new_buffer(size_type, version_0)
{ alloc_holder_t::on_capacity_overflow(); }
BOOST_CONTAINER_FORCEINLINE dtl::insert_range_proxy<allocator_type, boost::move_iterator<T*>, T*> priv_dummy_empty_proxy()
@@ -2513,7 +2513,7 @@ private:
(::boost::make_move_iterator((T *)0));
}
void priv_reserve_no_capacity(size_type new_cap, version_1)
BOOST_CONTAINER_FORCEINLINE void priv_move_to_new_buffer(size_type new_cap, version_1)
{
//There is not enough memory, allocate a new buffer
//Pass the hint so that allocators can take advantage of this.
@@ -2522,11 +2522,11 @@ private:
++this->num_alloc;
#endif
//We will reuse insert code, so create a dummy input iterator
this->priv_forward_range_insert_new_allocation
this->priv_insert_forward_range_new_allocation
( boost::movelib::to_raw_pointer(p), new_cap, this->priv_raw_end(), 0, this->priv_dummy_empty_proxy());
}
void priv_reserve_no_capacity(size_type new_cap, version_2)
void priv_move_to_new_buffer(size_type new_cap, version_2)
{
//There is not enough memory, allocate a new
//buffer or expand the old one.
@@ -2550,14 +2550,14 @@ private:
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_expand_bwd;
#endif
this->priv_forward_range_insert_expand_backwards
this->priv_insert_forward_range_expand_backwards
( new_mem , real_cap, ins_pos, 0, this->priv_dummy_empty_proxy());
}
else{ //New buffer
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_alloc;
#endif
this->priv_forward_range_insert_new_allocation
this->priv_insert_forward_range_new_allocation
( new_mem, real_cap, ins_pos, 0, this->priv_dummy_empty_proxy());
}
}
@@ -2600,19 +2600,17 @@ private:
}
template<class U>
iterator priv_insert(const const_iterator &p, BOOST_FWD_REF(U) x)
BOOST_CONTAINER_FORCEINLINE iterator priv_insert(const const_iterator &p, BOOST_FWD_REF(U) u)
{
BOOST_ASSERT(this->priv_in_range_or_end(p));
return this->priv_forward_range_insert
( vector_iterator_get_ptr(p), 1, dtl::get_insert_value_proxy<T*, allocator_type>(::boost::forward<U>(x)));
typedef typename dtl::if_c < boost::move_detail::is_rvalue_reference<BOOST_FWD_REF(U)>::value
, dtl::insert_move_proxy<allocator_type, T*>
, dtl::insert_copy_proxy<allocator_type, T*>
>::type proxy_t;
return this->priv_insert_forward_range
( vector_iterator_get_ptr(p), 1, proxy_t((reference)u));
}
BOOST_CONTAINER_FORCEINLINE dtl::insert_copy_proxy<allocator_type, T*> priv_single_insert_proxy(const T &x)
{ return dtl::insert_copy_proxy<allocator_type, T*> (x); }
BOOST_CONTAINER_FORCEINLINE dtl::insert_move_proxy<allocator_type, T*> priv_single_insert_proxy(BOOST_RV_REF(T) x)
{ return dtl::insert_move_proxy<allocator_type, T*> (x); }
template <class U>
BOOST_CONTAINER_FORCEINLINE void priv_push_back(BOOST_FWD_REF(U) u)
{
@@ -2623,9 +2621,12 @@ private:
++this->m_holder.m_size;
}
else{
this->priv_forward_range_insert_no_capacity
( this->back_ptr(), 1
, this->priv_single_insert_proxy(::boost::forward<U>(u)), alloc_version());
typedef typename dtl::if_c < boost::move_detail::is_rvalue_reference<BOOST_FWD_REF(U)>::value
, dtl::insert_move_proxy<allocator_type, T*>
, dtl::insert_copy_proxy<allocator_type, T*>
>::type proxy_t;
this->priv_insert_forward_range_no_capacity
( this->back_ptr(), 1, proxy_t((reference)u), alloc_version());
}
}
@@ -2638,20 +2639,6 @@ private:
BOOST_CONTAINER_FORCEINLINE dtl::insert_value_initialized_n_proxy<allocator_type, T*> priv_resize_proxy(value_init_t)
{ return dtl::insert_value_initialized_n_proxy<allocator_type, T*>(); }
template <class U>
void priv_resize(size_type new_size, const U& u)
{
const size_type sz = this->size();
if (new_size < sz){
//Destroy last elements
this->priv_destroy_last_n(sz - new_size);
}
else{
const size_type n = new_size - this->size();
this->priv_forward_range_insert_at_end(n, this->priv_resize_proxy(u), alloc_version());
}
}
BOOST_CONTAINER_FORCEINLINE void priv_shrink_to_fit(version_0) BOOST_NOEXCEPT_OR_NOTHROW
{}
@@ -2667,17 +2654,7 @@ private:
this->m_holder.m_capacity = 0;
}
else if(sz < cp){
//Allocate a new buffer.
//Pass the hint so that allocators can take advantage of this.
pointer const p = this->m_holder.allocate(sz);
//We will reuse insert code, so create a dummy input iterator
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_alloc;
#endif
this->priv_forward_range_insert_new_allocation
( boost::movelib::to_raw_pointer(p), sz
, this->priv_raw_begin(), 0, this->priv_dummy_empty_proxy());
this->priv_move_to_new_buffer(sz, alloc_version());
}
}
}
@@ -2708,15 +2685,14 @@ private:
}
template <class InsertionProxy>
iterator priv_forward_range_insert_no_capacity
(const pointer &pos, const size_type, const InsertionProxy , version_0)
BOOST_CONTAINER_FORCEINLINE iterator priv_insert_forward_range_no_capacity
(const pointer &, const size_type, const InsertionProxy , version_0)
{
alloc_holder_t::on_capacity_overflow();
return iterator(pos);
return alloc_holder_t::on_capacity_overflow(), iterator();
}
template <class InsertionProxy>
iterator priv_forward_range_insert_no_capacity
BOOST_CONTAINER_FORCEINLINE iterator priv_insert_forward_range_no_capacity
(const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, version_1)
{
//Check if we have enough memory or try to expand current memory
@@ -2729,13 +2705,12 @@ private:
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_alloc;
#endif
this->priv_forward_range_insert_new_allocation
( new_buf, new_cap, raw_pos, n, insert_range_proxy);
this->priv_insert_forward_range_new_allocation(new_buf, new_cap, raw_pos, n, insert_range_proxy);
return iterator(this->m_holder.start() + n_pos);
}
template <class InsertionProxy>
iterator priv_forward_range_insert_no_capacity
iterator priv_insert_forward_range_no_capacity
(const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, version_2)
{
//Check if we have enough memory or try to expand current memory
@@ -2758,14 +2733,14 @@ private:
#endif
this->m_holder.capacity(real_cap);
//Expand forward
this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy);
this->priv_insert_forward_range_expand_forward(raw_pos, n, insert_range_proxy);
}
//Backwards (and possibly forward) expansion
else{
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_expand_bwd;
#endif
this->priv_forward_range_insert_expand_backwards
this->priv_insert_forward_range_expand_backwards
(boost::movelib::to_raw_pointer(ret), real_cap, raw_pos, n, insert_range_proxy);
}
}
@@ -2774,7 +2749,7 @@ private:
#ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
++this->num_alloc;
#endif
this->priv_forward_range_insert_new_allocation
this->priv_insert_forward_range_new_allocation
( boost::movelib::to_raw_pointer(ret), real_cap, raw_pos, n, insert_range_proxy);
}
@@ -2782,46 +2757,52 @@ private:
}
template <class InsertionProxy>
iterator priv_forward_range_insert
BOOST_CONTAINER_FORCEINLINE iterator priv_insert_forward_range
(const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy)
{
BOOST_ASSERT(this->m_holder.capacity() >= this->m_holder.m_size);
//Check if we have enough memory or try to expand current memory
const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size;
bool same_buffer_start = n <= remaining;
if (!same_buffer_start){
return priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version());
if (BOOST_LIKELY(n <= (this->m_holder.capacity() - this->m_holder.m_size))){
//Expand forward
this->priv_insert_forward_range_expand_forward(boost::movelib::to_raw_pointer(pos), n, insert_range_proxy);
return iterator(pos);
}
else{
//Expand forward
T *const raw_pos = boost::movelib::to_raw_pointer(pos);
const size_type n_pos = raw_pos - this->priv_raw_begin();
this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy);
return iterator(this->m_holder.start() + n_pos);
return this->priv_insert_forward_range_no_capacity(pos, n, insert_range_proxy, alloc_version());
}
}
template <class InsertionProxy>
iterator priv_forward_range_insert_at_end
(const size_type n, const InsertionProxy insert_range_proxy, version_0)
template <class U>
void priv_resize(const size_type new_size, const U &u, version_0)
{
//Check if we have enough memory or try to expand current memory
const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size;
if (n > remaining){
const size_type sz = this->m_holder.m_size;
if (new_size > this->capacity()){
//This will trigger an error
alloc_holder_t::on_capacity_overflow();
}
this->priv_forward_range_insert_at_end_expand_forward(n, insert_range_proxy);
return this->end();
else if (new_size < sz){
//Destroy last elements
this->priv_destroy_last_n(sz - new_size);
}
else{
T* const old_finish = this->priv_raw_end();
this->priv_resize_proxy(u).uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, new_size - sz);
this->m_holder.set_stored_size(new_size);
}
}
template <class InsertionProxy, class AllocVersion>
BOOST_CONTAINER_FORCEINLINE iterator priv_forward_range_insert_at_end
(const size_type n, const InsertionProxy insert_range_proxy, AllocVersion)
template <class U, class AllocVersion>
BOOST_CONTAINER_FORCEINLINE void priv_resize
(const size_type new_size, const U &u, AllocVersion)
{
return this->priv_forward_range_insert(this->back_ptr(), n, insert_range_proxy);
const size_type sz = this->m_holder.m_size;
if (new_size < sz){
//Destroy last elements
this->priv_destroy_last_n(sz - new_size);
}
else {
this->priv_insert_forward_range(this->back_ptr(), new_size - sz, this->priv_resize_proxy(u));
}
}
//Takes the range pointed by [first_pos, last_pos) and shifts it to the right
@@ -2918,86 +2899,89 @@ private:
{ return this->priv_raw_begin() + this->m_holder.m_size; }
template <class InsertionProxy>
void priv_forward_range_insert_at_end_expand_forward(const size_type n, InsertionProxy insert_range_proxy)
{
T* const old_finish = this->priv_raw_end();
insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, n);
this->m_holder.m_size += n;
}
template <class InsertionProxy>
void priv_forward_range_insert_expand_forward(T* const pos, const size_type n, InsertionProxy insert_range_proxy)
BOOST_CONTAINER_FORCEINLINE void priv_insert_forward_range_expand_forward(T* const raw_pos, const size_type n, InsertionProxy insert_range_proxy)
{
//n can't be 0, because there is nothing to do in that case
if(BOOST_UNLIKELY(!n)) return;
bool const single_value_proxy = dtl::is_single_value_proxy<InsertionProxy>::value;
//bool const single_value_proxy = false;
if(BOOST_UNLIKELY(!single_value_proxy && !n))
return;
//There is enough memory
T* const old_finish = this->priv_raw_end();
const size_type elems_after = old_finish - pos;
const size_type elems_after = old_finish - raw_pos;
allocator_type & a = this->m_holder.alloc();
if (!elems_after){
insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, n);
this->m_holder.m_size += n;
insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, n);
this->m_holder.m_size += static_cast<stored_size_type>(n);
}
else if (elems_after >= n){
else if(single_value_proxy){
//New elements can be just copied.
//Move to uninitialized memory last objects
::boost::container::uninitialized_move_alloc
(this->m_holder.alloc(), old_finish - n, old_finish, old_finish);
this->m_holder.m_size += n;
allocator_traits_type::construct(a, old_finish, ::boost::move(*(old_finish-1)));
++this->m_holder.m_size;
//Copy previous to last objects to the initialized end
boost::container::move_backward(pos, old_finish - n, old_finish);
//Insert new objects in the pos
insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), pos, n);
boost::container::move_backward(raw_pos, old_finish - 1, old_finish);
//Insert new objects in the raw_pos
insert_range_proxy.copy_n_and_update(a, raw_pos, 1);
}
else if(elems_after >= n){
//New elements can be just copied.
//Move to uninitialized memory last objects
::boost::container::uninitialized_move_alloc_n(a, old_finish - n, n, old_finish);
this->m_holder.m_size += static_cast<stored_size_type>(n);
//Copy previous to last objects to the initialized end
boost::container::move_backward(raw_pos, old_finish - n, old_finish);
//Insert new objects in the raw_pos
insert_range_proxy.copy_n_and_update(a, raw_pos, n);
}
else {
//The new elements don't fit in the [pos, end()) range.
//Copy old [pos, end()) elements to the uninitialized memory (a gap is created)
::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), pos, old_finish, pos + n);
BOOST_TRY{
//Copy first new elements in pos (gap is still there)
insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), pos, elems_after);
//Copy to the beginning of the unallocated zone the last new elements (the gap is closed).
insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, n - elems_after);
this->m_holder.m_size += n;
}
BOOST_CATCH(...){
boost::container::destroy_alloc_n(this->get_stored_allocator(), pos + n, elems_after);
BOOST_RETHROW
}
BOOST_CATCH_END
//The new elements don't fit in the [raw_pos, end()) range.
//Copy old [raw_pos, end()) elements to the uninitialized memory (a gap is created)
::boost::container::uninitialized_move_alloc(a, raw_pos, old_finish, raw_pos + n);
typename value_traits::ArrayDestructor on_exception(raw_pos + n, a, elems_after);
//Copy first new elements in raw_pos (gap is still there)
insert_range_proxy.copy_n_and_update(a, raw_pos, elems_after);
//Copy to the beginning of the unallocated zone the last new elements (the gap is closed).
insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, n - elems_after);
this->m_holder.m_size += static_cast<stored_size_type>(n);
on_exception.release();
}
}
template <class InsertionProxy>
void priv_forward_range_insert_new_allocation
void priv_insert_forward_range_new_allocation
(T* const new_start, size_type new_cap, T* const pos, const size_type n, InsertionProxy insert_range_proxy)
{
//n can be zero, if we want to reallocate!
T *new_finish = new_start;
T *old_finish;
allocator_type &a = this->m_holder.alloc();
//Anti-exception rollbacks
typename value_traits::ArrayDeallocator new_buffer_deallocator(new_start, this->m_holder.alloc(), new_cap);
typename value_traits::ArrayDestructor new_values_destroyer(new_start, this->m_holder.alloc(), 0u);
typename value_traits::ArrayDeallocator new_buffer_deallocator(new_start, a, new_cap);
typename value_traits::ArrayDestructor new_values_destroyer(new_start, a, 0u);
//Initialize with [begin(), pos) old buffer
//the start of the new buffer
T * const old_buffer = this->priv_raw_begin();
if(old_buffer){
new_finish = ::boost::container::uninitialized_move_alloc
(this->m_holder.alloc(), this->priv_raw_begin(), pos, old_finish = new_finish);
(a, this->priv_raw_begin(), pos, old_finish = new_finish);
new_values_destroyer.increment_size(new_finish - old_finish);
}
//Initialize new objects, starting from previous point
old_finish = new_finish;
insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, n);
insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, n);
new_finish += n;
new_values_destroyer.increment_size(new_finish - old_finish);
//Initialize from the rest of the old buffer,
//starting from previous point
if(old_buffer){
new_finish = ::boost::container::uninitialized_move_alloc
(this->m_holder.alloc(), pos, old_buffer + this->m_holder.m_size, new_finish);
(a, pos, old_buffer + this->m_holder.m_size, new_finish);
//Destroy and deallocate old elements
//If there is allocated memory, destroy and deallocate
if(!value_traits::trivial_dctr_after_move)
@@ -3005,7 +2989,7 @@ private:
this->m_holder.deallocate(this->m_holder.start(), this->m_holder.capacity());
}
this->m_holder.start(new_start);
this->m_holder.m_size = size_type(new_finish - new_start);
m_holder.set_stored_size(new_finish - new_start);
this->m_holder.capacity(new_cap);
//All construction successful, disable rollbacks
new_values_destroyer.release();
@@ -3013,7 +2997,7 @@ private:
}
template <class InsertionProxy>
void priv_forward_range_insert_expand_backwards
void priv_insert_forward_range_expand_backwards
(T* const new_start, const size_type new_capacity,
T* const pos, const size_type n, InsertionProxy insert_range_proxy)
{
@@ -3022,27 +3006,30 @@ private:
T* const old_start = this->priv_raw_begin();
const size_type old_size = this->m_holder.m_size;
T* const old_finish = old_start + old_size;
//We can have 8 possibilities:
const size_type elemsbefore = static_cast<size_type>(pos - old_start);
const size_type s_before = static_cast<size_type>(old_start - new_start);
const size_type before_plus_new = elemsbefore + n;
allocator_type &a = this->m_holder.alloc();
//Update the vector buffer information to a safe state
this->m_holder.start(new_start);
this->m_holder.capacity(new_capacity);
this->m_holder.m_size = 0;
//We can have 8 possibilities:
const size_type elemsbefore = static_cast<size_type>(pos - old_start);
const size_type s_before = static_cast<size_type>(old_start - new_start);
const size_type before_plus_new = elemsbefore + n;
typedef typename value_traits::ArrayDestructor array_destructor_t;
//If anything goes wrong, this object will destroy
//all the old objects to fulfill previous vector state
typename value_traits::ArrayDestructor old_values_destroyer(old_start, this->m_holder.alloc(), old_size);
array_destructor_t old_values_destroyer(old_start, a, old_size);
//Check if s_before is big enough to hold the beginning of old data + new data
if(s_before >= before_plus_new){
//Copy first old values before pos, after that the new objects
T *const new_elem_pos =
::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), old_start, pos, new_start);
::boost::container::uninitialized_move_alloc(a, old_start, pos, new_start);
this->m_holder.set_stored_size(elemsbefore);
insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), new_elem_pos, n);
insert_range_proxy.uninitialized_copy_n_and_update(a, new_elem_pos, n);
this->m_holder.set_stored_size(before_plus_new);
const size_type new_size = old_size + n;
//Check if s_before is so big that even copying the old data + new data
@@ -3060,15 +3047,14 @@ private:
//
//Now initialize the rest of memory with the last old values
if(before_plus_new != new_size){ //Special case to avoid operations in back insertion
::boost::container::uninitialized_move_alloc
(this->m_holder.alloc(), pos, old_finish, new_start + before_plus_new);
::boost::container::uninitialized_move_alloc(a, pos, old_finish, new_start + before_plus_new);
//All new elements correctly constructed, avoid new element destruction
this->m_holder.set_stored_size(new_size);
}
//Old values destroyed automatically with "old_values_destroyer"
//when "old_values_destroyer" goes out of scope unless the have trivial
//destructor after move.
if(value_traits::trivial_dctr_after_move)
BOOST_IF_CONSTEXPR(value_traits::trivial_dctr_after_move)
old_values_destroyer.release();
}
//s_before is so big that divides old_end
@@ -3086,11 +3072,10 @@ private:
//Now initialize the rest of memory with the last old values
//All new elements correctly constructed, avoid new element destruction
const size_type raw_gap = s_before - before_plus_new;
if(!value_traits::trivial_dctr){
BOOST_IF_CONSTEXPR(!value_traits::trivial_dctr){
//Now initialize the rest of s_before memory with the
//first of elements after new values
::boost::container::uninitialized_move_alloc_n
(this->m_holder.alloc(), pos, raw_gap, new_start + before_plus_new);
::boost::container::uninitialized_move_alloc_n(a, pos, raw_gap, new_start + before_plus_new);
//Now we have a contiguous buffer so program trailing element destruction
//and update size to the final size.
old_values_destroyer.shrink_forward(new_size-s_before);
@@ -3101,13 +3086,13 @@ private:
::boost::container::move(remaining_pos, old_finish, old_start);
}
//Once moved, avoid calling the destructors if trivial after move
if(value_traits::trivial_dctr_after_move){
BOOST_IF_CONSTEXPR(value_traits::trivial_dctr_after_move){
old_values_destroyer.release();
}
}
else{ //If trivial destructor, we can uninitialized copy + copy in a single uninitialized copy
::boost::container::uninitialized_move_alloc_n
(this->m_holder.alloc(), pos, static_cast<size_type>(old_finish - pos), new_start + before_plus_new);
(a, pos, static_cast<size_type>(old_finish - pos), new_start + before_plus_new);
this->m_holder.set_stored_size(new_size);
old_values_destroyer.release();
}
@@ -3162,8 +3147,7 @@ private:
//|___________|_____|_________|_____________________|
//
//Copy the first part of old_begin to raw_mem
::boost::container::uninitialized_move_alloc_n
(this->m_holder.alloc(), old_start, s_before, new_start);
::boost::container::uninitialized_move_alloc_n(a, old_start, s_before, new_start);
//The buffer is all constructed until old_end,
//so program trailing destruction and assign final size
//if !do_after, s_before+n otherwise.
@@ -3175,8 +3159,9 @@ private:
}
else{
new_1st_range = n;
if(value_traits::trivial_dctr_after_move)
BOOST_IF_CONSTEXPR(value_traits::trivial_dctr_after_move){
old_values_destroyer.release();
}
else{
old_values_destroyer.shrink_forward(old_size - (s_before - n));
}
@@ -3185,7 +3170,7 @@ private:
//Now copy the second part of old_begin overwriting itself
T *const next = ::boost::container::move(old_start + s_before, pos, old_start);
//Now copy the new_beg elements
insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), next, new_1st_range);
insert_range_proxy.copy_n_and_update(a, next, new_1st_range);
//If there is no after work and the last old part needs to be moved to front, do it
if(!do_after && (n != s_before)){
@@ -3221,10 +3206,10 @@ private:
//
//First copy whole old_begin and part of new to raw_mem
T * const new_pos = ::boost::container::uninitialized_move_alloc
(this->m_holder.alloc(), old_start, pos, new_start);
(a, old_start, pos, new_start);
this->m_holder.set_stored_size(elemsbefore);
const size_type mid_n = s_before - elemsbefore;
insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), new_pos, mid_n);
insert_range_proxy.uninitialized_copy_n_and_update(a, new_pos, mid_n);
//The buffer is all constructed until old_end,
//release destroyer
this->m_holder.set_stored_size(old_size + s_before);
@@ -3232,12 +3217,12 @@ private:
if(do_after){
//Copy new_beg part
insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), old_start, elemsbefore);
insert_range_proxy.copy_n_and_update(a, old_start, elemsbefore);
}
else{
//Copy all new elements
const size_type rest_new = n - mid_n;
insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), old_start, rest_new);
insert_range_proxy.copy_n_and_update(a, old_start, rest_new);
T* const move_start = old_start + rest_new;
//Displace old_end, but make sure data has to be moved
T* const move_end = move_start != pos ? ::boost::container::move(pos, old_finish, move_start)
@@ -3245,8 +3230,9 @@ private:
//Destroy remaining moved elements from old_end except if they
//have trivial destructor after being moved
size_type n_destroy = s_before - n;
if(!value_traits::trivial_dctr_after_move)
boost::container::destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy);
BOOST_IF_CONSTEXPR(!value_traits::trivial_dctr_after_move){
boost::container::destroy_alloc_n(a, move_end, n_destroy);
}
this->m_holder.set_stored_size(this->size() - n_destroy);
}
}
@@ -3289,14 +3275,13 @@ private:
//
//First copy the part of old_end raw_mem
T* finish_n = old_finish - n_after;
::boost::container::uninitialized_move_alloc
(this->m_holder.alloc(), finish_n, old_finish, old_finish);
::boost::container::uninitialized_move_alloc(a, finish_n, old_finish, old_finish);
this->m_holder.set_stored_size(this->size() + n_after);
//Displace the rest of old_end to the new position
boost::container::move_backward(pos, finish_n, old_finish);
//Now overwrite with new_end
//The new_end part is [first + (n - n_after), last)
insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), pos, n_after);
insert_range_proxy.copy_n_and_update(a, pos, n_after);
}
else {
//The raw_mem from end will divide new_end part
@@ -3310,22 +3295,19 @@ private:
// _____________________________________________________________
//| old_begin + new_beg | new_end |old_end | raw_mem |
//|__________________________|_______________|________|_________|
//
const size_type mid_last_dist = n_after - elemsafter;
//First initialize data in raw memory
const size_type mid_last_dist = n_after - elemsafter;
//Copy to the old_end part to the uninitialized zone leaving a gap.
::boost::container::uninitialized_move_alloc
(this->m_holder.alloc(), pos, old_finish, old_finish + mid_last_dist);
::boost::container::uninitialized_move_alloc(a, pos, old_finish, old_finish + mid_last_dist);
typename value_traits::ArrayDestructor old_end_destroyer
(old_finish + mid_last_dist, this->m_holder.alloc(), old_finish - pos);
array_destructor_t old_end_destroyer(old_finish + mid_last_dist, a, old_finish - pos);
//Copy the first part to the already constructed old_end zone
insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), pos, elemsafter);
insert_range_proxy.copy_n_and_update(a, pos, elemsafter);
//Copy the rest to the uninitialized zone filling the gap
insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, mid_last_dist);
insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, mid_last_dist);
this->m_holder.set_stored_size(this->size() + n_after);
old_end_destroyer.release();
}