summaryrefslogtreecommitdiff
path: root/boost/container/vector.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/container/vector.hpp')
-rw-r--r--boost/container/vector.hpp471
1 files changed, 323 insertions, 148 deletions
diff --git a/boost/container/vector.hpp b/boost/container/vector.hpp
index 1b6d963934..1cf44c8e27 100644
--- a/boost/container/vector.hpp
+++ b/boost/container/vector.hpp
@@ -57,6 +57,7 @@
// other
#include <boost/core/no_exceptions_support.hpp>
#include <boost/assert.hpp>
+#include <boost/cstdint.hpp>
//std
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
@@ -179,6 +180,70 @@ class vec_iterator
{ return l.m_ptr >= r.m_ptr; }
};
+template<class BiDirPosConstIt, class BiDirValueIt>
+struct vector_insert_ordered_cursor
+{
+ typedef typename iterator_traits<BiDirPosConstIt>::value_type size_type;
+ typedef typename iterator_traits<BiDirValueIt>::reference reference;
+
+ vector_insert_ordered_cursor(BiDirPosConstIt posit, BiDirValueIt valueit)
+ : last_position_it(posit), last_value_it(valueit)
+ {}
+
+ void operator --()
+ {
+ --last_value_it;
+ --last_position_it;
+ while(this->get_pos() == size_type(-1)){
+ --last_value_it;
+ --last_position_it;
+ }
+ }
+
+ size_type get_pos() const
+ { return *last_position_it; }
+
+ reference get_val()
+ { return *last_value_it; }
+
+ BiDirPosConstIt last_position_it;
+ BiDirValueIt last_value_it;
+};
+
+template<class T, class SizeType, class BiDirValueIt, class Comp>
+struct vector_merge_cursor
+{
+ typedef SizeType size_type;
+ typedef typename iterator_traits<BiDirValueIt>::reference reference;
+
+ vector_merge_cursor(T *pbeg, T *plast, BiDirValueIt valueit, Comp cmp)
+ : m_pbeg(pbeg), m_pcur(--plast), m_valueit(valueit), m_cmp(cmp)
+ {}
+
+ void operator --()
+ {
+ --m_valueit;
+ const T &t = *m_valueit;
+ while((m_pcur + 1) != m_pbeg){
+ if(!m_cmp(t, *m_pcur)){
+ break;
+ }
+ --m_pcur;
+ }
+ }
+
+ size_type get_pos() const
+ { return static_cast<size_type>((m_pcur + 1) - m_pbeg); }
+
+ reference get_val()
+ { return *m_valueit; }
+
+ T *const m_pbeg;
+ T *m_pcur;
+ BiDirValueIt m_valueit;
+ Comp m_cmp;
+};
+
} //namespace container_detail {
template<class Pointer, bool IsConst>
@@ -640,6 +705,13 @@ class vector
{
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
+ struct value_less
+ {
+ typedef typename boost::container::allocator_traits<Allocator>::value_type value_type;
+ bool operator()(const value_type &a, const value_type &b) const
+ { return a < b; }
+ };
+
typedef typename container_detail::version<Allocator>::type alloc_version;
typedef boost::container::container_detail::vector_alloc_holder<Allocator> alloc_holder_t;
alloc_holder_t m_holder;
@@ -1043,10 +1115,11 @@ class vector
//!
//! <b>Note</b>: Non-standard extension to support static_vector
template<class OtherAllocator>
- typename container_detail::enable_if_c
- < container_detail::is_version<OtherAllocator, 0>::value &&
- !container_detail::is_same<OtherAllocator, allocator_type>::value
- , vector& >::type
+ typename container_detail::enable_if_and
+ < vector&
+ , container_detail::is_version<OtherAllocator, 0>
+ , container_detail::is_different<OtherAllocator, allocator_type>
+ >::type
operator=(BOOST_RV_REF_BEG vector<value_type, OtherAllocator> BOOST_RV_REF_END x)
{
this->priv_move_assign(boost::move(x));
@@ -1064,10 +1137,11 @@ class vector
//!
//! <b>Note</b>: Non-standard extension to support static_vector
template<class OtherAllocator>
- typename container_detail::enable_if_c
- < container_detail::is_version<OtherAllocator, 0>::value &&
- !container_detail::is_same<OtherAllocator, allocator_type>::value
- , vector& >::type
+ typename container_detail::enable_if_and
+ < vector&
+ , container_detail::is_version<OtherAllocator, 0>
+ , container_detail::is_different<OtherAllocator, allocator_type>
+ >::type
operator=(const vector<value_type, OtherAllocator> &x)
{
this->priv_copy_assign(x);
@@ -1084,11 +1158,15 @@ class vector
//! <b>Complexity</b>: Linear to n.
template <class InIt>
void assign(InIt first, InIt last
- BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename container_detail::enable_if_c
- < !container_detail::is_convertible<InIt BOOST_MOVE_I size_type>::value &&
- ( container_detail::is_input_iterator<InIt>::value ||
- container_detail::is_same<alloc_version BOOST_MOVE_I version_0>::value )
- >::type * = 0) )
+ BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename container_detail::disable_if_or
+ < void
+ BOOST_MOVE_I container_detail::is_convertible<InIt BOOST_MOVE_I size_type>
+ BOOST_MOVE_I container_detail::and_
+ < container_detail::is_different<alloc_version BOOST_MOVE_I version_0>
+ BOOST_MOVE_I container_detail::is_not_input_iterator<InIt>
+ >
+ >::type * = 0)
+ )
{
//Overwrite all elements we can from [first, last)
iterator cur = this->begin();
@@ -1129,10 +1207,11 @@ class vector
//! <b>Complexity</b>: Linear to n.
template <class FwdIt>
void assign(FwdIt first, FwdIt last
- BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename container_detail::enable_if_c
- < !container_detail::is_convertible<FwdIt BOOST_MOVE_I size_type>::value &&
- ( !container_detail::is_input_iterator<FwdIt>::value &&
- !container_detail::is_same<alloc_version BOOST_MOVE_I version_0>::value )
+ BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename container_detail::disable_if_or
+ < void
+ BOOST_MOVE_I container_detail::is_same<alloc_version BOOST_MOVE_I version_0>
+ BOOST_MOVE_I container_detail::is_convertible<FwdIt BOOST_MOVE_I size_type>
+ BOOST_MOVE_I container_detail::is_input_iterator<FwdIt>
>::type * = 0)
)
{
@@ -1791,10 +1870,13 @@ class vector
//! <b>Complexity</b>: Linear to boost::container::iterator_distance [first, last).
template <class InIt>
iterator insert(const_iterator pos, InIt first, InIt last
- BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename container_detail::enable_if_c
- < !container_detail::is_convertible<InIt BOOST_MOVE_I size_type>::value
- && container_detail::is_input_iterator<InIt>::value
- >::type * = 0)
+ #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
+ , typename container_detail::disable_if_or
+ < void
+ , container_detail::is_convertible<InIt, size_type>
+ , container_detail::is_not_input_iterator<InIt>
+ >::type * = 0
+ #endif
)
{
const size_type n_pos = pos - this->cbegin();
@@ -1809,9 +1891,10 @@ class vector
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
template <class FwdIt>
iterator insert(const_iterator pos, FwdIt first, FwdIt last
- , typename container_detail::enable_if_c
- < !container_detail::is_convertible<FwdIt, size_type>::value
- && !container_detail::is_input_iterator<FwdIt>::value
+ , typename container_detail::disable_if_or
+ < void
+ , container_detail::is_convertible<FwdIt, size_type>
+ , container_detail::is_input_iterator<FwdIt>
>::type * = 0
)
{
@@ -1902,7 +1985,7 @@ class vector
T* const first_ptr = container_detail::to_raw_pointer(vector_iterator_get_ptr(first));
T* const last_ptr = container_detail::to_raw_pointer(vector_iterator_get_ptr(last));
T* const ptr = container_detail::to_raw_pointer(boost::container::move(last_ptr, old_end_ptr, first_ptr));
- this->priv_destroy_last_n(old_end_ptr - ptr, last_ptr == old_end_ptr);
+ this->priv_destroy_last_n(old_end_ptr - ptr);
}
return iterator(vector_iterator_get_ptr(first));
}
@@ -1931,9 +2014,11 @@ class vector
//! <b>Note</b>: Non-standard extension to support static_vector
template<class OtherAllocator>
void swap(vector<T, OtherAllocator> & x
- , typename container_detail::enable_if_c
- < container_detail::is_version<OtherAllocator, 0>::value &&
- !container_detail::is_same<OtherAllocator, allocator_type>::value >::type * = 0
+ , typename container_detail::enable_if_and
+ < void
+ , container_detail::is_version<OtherAllocator, 0>
+ , container_detail::is_different<OtherAllocator, allocator_type>
+ >::type * = 0
)
{ this->m_holder.deep_swap(x.m_holder); }
@@ -2017,12 +2102,36 @@ class vector
template<class BiDirPosConstIt, class BiDirValueIt>
void insert_ordered_at(const size_type element_count, BiDirPosConstIt last_position_it, BiDirValueIt last_value_it)
{
+ typedef container_detail::vector_insert_ordered_cursor<BiDirPosConstIt, BiDirValueIt> inserter_t;
+ return this->priv_insert_ordered_at(element_count, inserter_t(last_position_it, last_value_it));
+ }
+
+ template<class BidirIt>
+ void merge(BidirIt first, BidirIt last)
+ { this->merge(first, last, value_less()); }
+
+ template<class BidirIt, class Compare>
+ void merge(BidirIt first, BidirIt last, Compare comp)
+ { this->priv_merge(container_detail::false_type(), first, last, comp); }
+
+ template<class BidirIt>
+ void merge_unique(BidirIt first, BidirIt last)
+ { this->priv_merge(container_detail::true_type(), first, last, value_less()); }
+
+ template<class BidirIt, class Compare>
+ void merge_unique(BidirIt first, BidirIt last, Compare comp)
+ { this->priv_merge(container_detail::true_type(), first, last, comp); }
+
+ private:
+ template<class PositionValue>
+ void priv_insert_ordered_at(const size_type element_count, PositionValue position_value)
+ {
const size_type old_size_pos = this->size();
this->reserve(old_size_pos + element_count);
T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.start());
size_type insertions_left = element_count;
- size_type next_pos = old_size_pos;
- size_type hole_size = element_count;
+ size_type prev_pos = old_size_pos;
+ size_type old_hole_size = element_count;
//Exception rollback. If any copy throws before the hole is filled, values
//already inserted/copied at the end of the buffer will be destroyed.
@@ -2031,52 +2140,197 @@ class vector
//Loop for each insertion backwards, first moving the elements after the insertion point,
//then inserting the element.
while(insertions_left){
- size_type pos = static_cast<size_type>(*(--last_position_it));
- while(pos == size_type(-1)){
- --last_value_it;
- pos = static_cast<size_type>(*(--last_position_it));
- }
-
- BOOST_ASSERT(pos != size_type(-1) && pos <= old_size_pos);
+ --position_value;
+ size_type const pos = position_value.get_pos();
+ BOOST_ASSERT(pos != size_type(-1) && pos <= old_size_pos && pos <= prev_pos);
//If needed shift the range after the insertion point and the previous insertion point.
//Function will take care if the shift crosses the size() boundary, using copy/move
//or uninitialized copy/move if necessary.
- size_type new_hole_size = (pos != next_pos)
- ? priv_insert_ordered_at_shift_range(pos, next_pos, this->size(), insertions_left)
- : hole_size
+ size_type new_hole_size = (pos != prev_pos)
+ ? priv_insert_ordered_at_shift_range(pos, prev_pos, this->size(), insertions_left)
+ : old_hole_size
;
- if(new_hole_size > 0){
+ if(new_hole_size){
//The hole was reduced by priv_insert_ordered_at_shift_range so expand exception rollback range backwards
- past_hole_values_destroyer.increment_size_backwards(next_pos - pos);
+ past_hole_values_destroyer.increment_size_backwards(prev_pos - pos);
//Insert the new value in the hole
- allocator_traits_type::construct(this->m_holder.alloc(), begin_ptr + pos + insertions_left - 1, *(--last_value_it));
- --new_hole_size;
- if(new_hole_size == 0){
+ allocator_traits_type::construct(this->m_holder.alloc(), begin_ptr + pos + insertions_left - 1, position_value.get_val());
+ if(--new_hole_size){
+ //The hole was reduced by the new insertion by one
+ past_hole_values_destroyer.increment_size_backwards(size_type(1u));
+ }
+ else{
//Hole was just filled, disable exception rollback and change vector size
past_hole_values_destroyer.release();
this->m_holder.m_size += element_count;
}
- else{
- //The hole was reduced by the new insertion by one
- past_hole_values_destroyer.increment_size_backwards(size_type(1u));
- }
}
else{
- if(hole_size){
+ if(old_hole_size){
//Hole was just filled by priv_insert_ordered_at_shift_range, disable exception rollback and change vector size
past_hole_values_destroyer.release();
this->m_holder.m_size += element_count;
}
//Insert the new value in the already constructed range
- begin_ptr[pos + insertions_left - 1] = *(--last_value_it);
+ begin_ptr[pos + insertions_left - 1] = position_value.get_val();
}
--insertions_left;
- hole_size = new_hole_size;
- next_pos = pos;
+ old_hole_size = new_hole_size;
+ prev_pos = pos;
}
}
- private:
+ template<class UniqueBool, class BidirIt, class Compare>
+ void priv_merge(UniqueBool, BidirIt first, BidirIt last, Compare comp)
+ {
+ size_type const n = static_cast<size_type>(boost::container::iterator_distance(first, last));
+ if(BOOST_LIKELY(n)){
+ size_type const s = this->size();
+ if(BOOST_LIKELY(s)){
+ size_type const c = this->capacity();
+ size_type const free_c = (c - s);
+ //Use a new buffer if current one is too small for new elements,
+ //or there is no room for position indexes
+ bool new_buffer = false;
+ if(free_c < n){
+ new_buffer = true;
+ }
+ else if(!UniqueBool::value && free_c >= n){
+ typedef container_detail::vector_merge_cursor<T, size_type, BidirIt, Compare> inserter_t;
+ T* const pbeg = container_detail::to_raw_pointer(m_holder.start());
+ return this->priv_insert_ordered_at(n, inserter_t(pbeg, pbeg + s, last, comp));
+ }
+ else if(UniqueBool::value){ //Query for room to store n + 1 indexes (+1 to guarantee potential alignment overhead).
+ //No need to destroy them as they are integral types, which simplifies things a lot.
+ std::size_t const sz_vlt = sizeof(value_type);
+ std::size_t const sz_szt = sizeof(size_type);
+ new_buffer = (c-s-n)*sz_vlt/sz_szt < (n+1);
+ }
+
+ if(new_buffer){
+ size_type const new_size = s + n;
+ size_type new_cap = new_size;
+ pointer p = pointer();
+ p = this->m_holder.allocation_command(allocate_new, new_size, new_cap, p);
+ this->priv_merge_in_new_buffer(UniqueBool(), first, n, comp, p, new_cap);
+ }
+ else{
+ //Use trailing memory to store position offsets
+ uintptr_t const szt_align_mask = container_detail::alignment_of<size_type>::value - 1;
+ boost::uintptr_t const addr = boost::uintptr_t(container_detail::to_raw_pointer(m_holder.start()) + s + n);
+ //Align memory before casting to address
+ size_type *const paddr = reinterpret_cast<size_type *>((addr + szt_align_mask) & ~szt_align_mask);
+ this->priv_insert_ordered_range(UniqueBool(), n, first, last, paddr, comp);
+ }
+ }
+ else{
+ this->insert(this->cend(), n, first, last);
+ }
+ }
+ }
+
+ template <class UniqueBool, class BidirIt, class Compare>
+ void priv_insert_ordered_range
+ (UniqueBool, size_type const n, BidirIt first, BidirIt const last, size_type positions[], Compare comp)
+ {
+ //Linear: at most N + M -1 comparisons
+ //Log: MlogN
+ //Average
+ //Linear: N + M - 2
+ //Log: MlogN
+ //N+M - 2
+ //N
+ //(N+M)/2 < MlogN
+ //(N/M+1)/2 <= logN
+ //bool const linear = !s || !n || (s <= n) || ((s+n)/n/2 < logN);
+ size_type const s = this->size();
+ size_type remaining = n;
+ T* const pbeg = container_detail::to_raw_pointer(m_holder.start());
+ T* const pend = pbeg + s;
+ T* pcur = pbeg;
+ size_type *position = positions;
+ size_type added_in_middle = 0;
+ if(first != last && pcur != pend){
+ while(1){
+ //maintain stability moving external values only if they are strictly less
+ if(comp(*first, *pcur)) {
+ *position = static_cast<size_type>(pcur - pbeg);
+ BOOST_ASSERT((position == positions) || (*(position-1) == size_type(-1)) || (*(position-1) <= *position));
+ ++position;
+ ++added_in_middle;
+ --remaining;
+ if(++first == last) break;
+ }
+ else if(UniqueBool::value && !comp(*pcur, *first)){
+ *position = size_type(-1);
+ ++position;
+ --remaining;
+ if(++first == last) break;
+ }
+ else{
+ if(++pcur == pend) break;
+ }
+ }
+ }
+ this->insert_ordered_at(added_in_middle, position, first);
+ this->insert(this->cend(), remaining, first, last);
+ }
+
+ template<class UniqueBool, class FwdIt, class Compare>
+ void priv_merge_in_new_buffer
+ (UniqueBool, FwdIt first, size_type n, Compare comp, pointer new_storage, size_type const new_cap)
+ {
+ BOOST_ASSERT((new_cap >= this->size() ) && (new_cap - this->size()) >= n);
+ allocator_type &a = this->m_holder.alloc();
+ typename value_traits::ArrayDeallocator new_buffer_deallocator(new_storage, a, new_cap);
+ typename value_traits::ArrayDestructor new_values_destroyer(new_storage, a, 0u);
+ T* pbeg = container_detail::to_raw_pointer(m_holder.start());
+ size_type const old_size = this->size();
+ T* const pend = pbeg + old_size;
+ T* d_first = container_detail::to_raw_pointer(new_storage);
+ size_type added = n;
+ //Merge in new buffer loop
+ while(1){
+ if(!n) {
+ ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), pbeg, pend, d_first);
+ break;
+ }
+ else if(pbeg == pend) {
+ ::boost::container::uninitialized_move_alloc_n(this->m_holder.alloc(), first, n, d_first);
+ break;
+ }
+ //maintain stability moving external values only if they are strictly less
+ else if(comp(*first, *pbeg)) {
+ allocator_traits_type::construct( this->m_holder.alloc(), d_first, ::boost::move(*first) );
+ new_values_destroyer.increment_size(1u);
+ ++first;
+ --n;
+ ++d_first;
+ }
+ else if(UniqueBool::value && !comp(*pbeg, *first)){
+ ++first;
+ --n;
+ --added;
+ }
+ else{
+ allocator_traits_type::construct( this->m_holder.alloc(), d_first, ::boost::move(*pbeg) );
+ new_values_destroyer.increment_size(1u);
+ ++pbeg;
+ ++d_first;
+ }
+ }
+
+ //Nothrow operations
+ pointer const old_p = this->m_holder.start();
+ size_type const old_cap = this->m_holder.capacity();
+ boost::container::destroy_alloc_n(a, container_detail::to_raw_pointer(old_p), old_size);
+ a.deallocate(old_p, old_cap);
+ this->m_holder.m_size = old_size + added;
+ this->m_holder.start(new_storage);
+ this->m_holder.capacity(new_cap);
+ new_buffer_deallocator.release();
+ new_values_destroyer.release();
+ }
bool room_enough() const
{ return this->m_holder.m_size < this->m_holder.capacity(); }
@@ -2113,9 +2367,11 @@ class vector
template<class OtherAllocator>
void priv_move_assign(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
- , typename container_detail::enable_if_c
- < !container_detail::is_version<OtherAllocator, 0>::value &&
- container_detail::is_same<OtherAllocator, allocator_type>::value>::type * = 0)
+ , typename container_detail::disable_if_or
+ < void
+ , container_detail::is_version<OtherAllocator, 0>
+ , container_detail::is_different<OtherAllocator, allocator_type>
+ >::type * = 0)
{
//for move constructor, no aliasing (&x != this) is assummed.
BOOST_ASSERT(this != &x);
@@ -2167,10 +2423,12 @@ class vector
}
template<class OtherAllocator>
- void priv_copy_assign(const vector<T, OtherAllocator> &x
- , typename container_detail::enable_if_c
- < !container_detail::is_version<OtherAllocator, 0>::value &&
- container_detail::is_same<OtherAllocator, allocator_type>::value >::type * = 0)
+ typename container_detail::disable_if_or
+ < void
+ , container_detail::is_version<OtherAllocator, 0>
+ , container_detail::is_different<OtherAllocator, allocator_type>
+ >::type
+ priv_copy_assign(const vector<T, OtherAllocator> &x)
{
allocator_type &this_alloc = this->m_holder.alloc();
const allocator_type &x_alloc = x.m_holder.alloc();
@@ -2274,16 +2532,7 @@ class vector
}
}
- void priv_destroy_last() BOOST_NOEXCEPT_OR_NOTHROW
- {
- if(!value_traits::trivial_dctr){
- value_type* const p = this->back_raw() - 1;
- allocator_traits_type::destroy(this->get_stored_allocator(), p);
- }
- --this->m_holder.m_size;
- }
-
- void priv_destroy_last(const bool moved) BOOST_NOEXCEPT_OR_NOTHROW
+ void priv_destroy_last(const bool moved = false) BOOST_NOEXCEPT_OR_NOTHROW
{
(void)moved;
if(!(value_traits::trivial_dctr || (value_traits::trivial_dctr_after_move && moved))){
@@ -2303,17 +2552,6 @@ class vector
this->m_holder.m_size -= n;
}
- void priv_destroy_last_n(const size_type n, const bool moved) BOOST_NOEXCEPT_OR_NOTHROW
- {
- BOOST_ASSERT(n <= this->m_holder.m_size);
- (void)moved;
- if(!(value_traits::trivial_dctr || (value_traits::trivial_dctr_after_move && moved))){
- T* const destroy_pos = container_detail::to_raw_pointer(this->m_holder.start()) + (this->m_holder.m_size-n);
- boost::container::destroy_alloc_n(this->get_stored_allocator(), destroy_pos, n);
- }
- this->m_holder.m_size -= n;
- }
-
template<class InpIt>
void priv_uninitialized_construct_at_end(InpIt first, InpIt last)
{
@@ -2554,69 +2792,6 @@ class vector
return this->priv_forward_range_insert(this->back_ptr(), n, insert_range_proxy);
}
- //Absolutely experimental. This function might change, disappear or simply crash!
- template<class BiDirPosConstIt, class BiDirSkipConstIt, class BiDirValueIt>
- void priv_insert_ordered_at( size_type element_count, BiDirPosConstIt last_position_it
- , bool do_skip, BiDirSkipConstIt last_skip_it, BiDirValueIt last_value_it)
- {
- const size_type old_size_pos = this->size();
- this->reserve(old_size_pos + element_count);
- T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.start());
- size_type insertions_left = element_count;
- size_type next_pos = old_size_pos;
- size_type hole_size = element_count;
-
- //Exception rollback. If any copy throws before the hole is filled, values
- //already inserted/copied at the end of the buffer will be destroyed.
- typename value_traits::ArrayDestructor past_hole_values_destroyer
- (begin_ptr + old_size_pos + element_count, this->m_holder.alloc(), size_type(0u));
- //Loop for each insertion backwards, first moving the elements after the insertion point,
- //then inserting the element.
- while(insertions_left){
- if(do_skip){
- size_type n = *(--last_skip_it);
- boost::container::iterator_advance(last_value_it, -difference_type(n));
- }
- const size_type pos = static_cast<size_type>(*(--last_position_it));
- BOOST_ASSERT(pos <= old_size_pos);
- //If needed shift the range after the insertion point and the previous insertion point.
- //Function will take care if the shift crosses the size() boundary, using copy/move
- //or uninitialized copy/move if necessary.
- size_type new_hole_size = (pos != next_pos)
- ? priv_insert_ordered_at_shift_range(pos, next_pos, this->size(), insertions_left)
- : hole_size
- ;
- if(new_hole_size > 0){
- //The hole was reduced by priv_insert_ordered_at_shift_range so expand exception rollback range backwards
- past_hole_values_destroyer.increment_size_backwards(next_pos - pos);
- //Insert the new value in the hole
- allocator_traits_type::construct(this->m_holder.alloc(), begin_ptr + pos + insertions_left - 1, *(--last_value_it));
- --new_hole_size;
- if(new_hole_size == 0){
- //Hole was just filled, disable exception rollback and change vector size
- past_hole_values_destroyer.release();
- this->m_holder.m_size += element_count;
- }
- else{
- //The hole was reduced by the new insertion by one
- past_hole_values_destroyer.increment_size_backwards(size_type(1u));
- }
- }
- else{
- if(hole_size){
- //Hole was just filled by priv_insert_ordered_at_shift_range, disable exception rollback and change vector size
- past_hole_values_destroyer.release();
- this->m_holder.m_size += element_count;
- }
- //Insert the new value in the already constructed range
- begin_ptr[pos + insertions_left - 1] = *(--last_value_it);
- }
- --insertions_left;
- hole_size = new_hole_size;
- next_pos = pos;
- }
- }
-
//Takes the range pointed by [first_pos, last_pos) and shifts it to the right
//by 'shift_count'. 'limit_pos' marks the end of constructed elements.
//
@@ -2647,7 +2822,7 @@ class vector
// |_>_>_>_>_>^
//
//
- //New situation in Case B (hole_size > 0):
+ //New situation in Case B (hole_size >= 0):
// range is moved through uninitialized moves
//
// first_pos last_pos limit_pos
@@ -2689,7 +2864,7 @@ class vector
//All uninitialized_moved
::boost::container::uninitialized_move_alloc
(this->m_holder.alloc(), first_ptr, last_ptr, first_ptr + shift_count);
- hole_size = last_pos + shift_count - limit_pos;
+ hole_size = first_pos + shift_count - limit_pos;
}
//Case C:
else{
@@ -2716,7 +2891,7 @@ class vector
void priv_forward_range_insert_expand_forward(T* const pos, const size_type n, InsertionProxy insert_range_proxy)
{
//n can't be 0, because there is nothing to do in that case
- if(!n) return;
+ if(BOOST_UNLIKELY(!n)) return;
//There is enough memory
T* const old_finish = this->back_raw();
const size_type elems_after = old_finish - pos;