Fixes #156: ("Compile error with vector") and remove warnings about precission loss due to integer narrowing

This commit is contained in:
Ion Gaztañaga
2020-10-22 01:10:07 +02:00
parent 6ca40b9e86
commit 03f030af69
7 changed files with 282 additions and 125 deletions

View File

@@ -1,5 +1,5 @@
[/
/ Copyright (c) 2009-2018 Ion Gaztañaga
/ Copyright (c) 2009-2020 Ion Gazta<EFBFBD>aga
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -1342,12 +1342,14 @@ use [*Boost.Container]? There are several reasons for that:
* New [classref boost::container::devector devector] container.
* Fixed bugs/issues:
* [@https://github.com/boostorg/container/issues/156 GitHub #156: ['"Compile error with vector"]].
* [@https://github.com/boostorg/container/pull/157 GitHub #157: ['"Add missing include"]].
* [@https://github.com/boostorg/container/issues/159 GitHub #159: ['"pmr::monotonic_buffer_resource crashes on large single allocations"]].
* [@https://github.com/boostorg/container/issues/160 GitHub #160: ['"Usage of uses_allocator needs a remove_cvref_t"]].
* [@https://github.com/boostorg/container/issues/161 GitHub #161: ['"polymorphic_allocator(memory_resource*) non-standard extension causes headache"]].
* [@https://github.com/boostorg/container/pull/163 GitHub #163: ['"container_rebind for small_vector with options"]].
* [@https://github.com/boostorg/container/pull/167 GitHub #167: ['"error: the address of 'msg' will always evaluate as 'true' warning with GCC 4.4"]].
[endsect]
[section:release_notes_boost_1_74_00 Boost 1.74 Release]

View File

@@ -426,7 +426,6 @@ struct insert_emplace_proxy_arg##N\
{\
BOOST_ASSERT(n == 1); (void)n;\
typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;\
BOOST_ASSERT((((size_type)(&v)) % alignment_of<value_type>::value) == 0);\
value_type *vp = reinterpret_cast<value_type *>(v.data);\
alloc_traits::construct(a, vp BOOST_MOVE_I##N BOOST_MOVE_MFWD##N);\
BOOST_TRY{\

View File

@@ -26,6 +26,7 @@
#include <boost/container/detail/mpl.hpp>
#include <boost/container/detail/type_traits.hpp>
#include <boost/container/detail/construct_in_place.hpp>
#include <boost/container/detail/destroyers.hpp>
// move
#include <boost/move/adl_move_swap.hpp>
@@ -180,7 +181,7 @@ BOOST_CONTAINER_FORCEINLINE F memmove(I f, I l, F r) BOOST_NOEXCEPT_OR_NOTHROW
if(BOOST_LIKELY(beg_raw != end_raw && dest_raw && beg_raw)){
const typename boost::container::iterator_traits<I>::difference_type n = end_raw - beg_raw;
std::memmove(dest_raw, beg_raw, sizeof(value_type)*n);
boost::container::iterator_advance(r, n);
r += n;
}
return r;
}
@@ -194,7 +195,7 @@ BOOST_CONTAINER_FORCEINLINE F memmove_n(I f, U n, F r) BOOST_NOEXCEPT_OR_NOTHROW
typedef typename boost::container::iterator_traits<I>::value_type value_type;
if(BOOST_LIKELY(n)){
std::memmove(boost::movelib::iterator_to_raw_pointer(r), boost::movelib::iterator_to_raw_pointer(f), sizeof(value_type)*n);
boost::container::iterator_advance(r, n);
r += n;
}
return r;
@@ -209,7 +210,7 @@ BOOST_CONTAINER_FORCEINLINE I memmove_n_source(I f, U n, F r) BOOST_NOEXCEPT_OR_
if(BOOST_LIKELY(n)){
typedef typename boost::container::iterator_traits<I>::value_type value_type;
std::memmove(boost::movelib::iterator_to_raw_pointer(r), boost::movelib::iterator_to_raw_pointer(f), sizeof(value_type)*n);
boost::container::iterator_advance(f, n);
f += n;
}
return f;
}
@@ -223,8 +224,8 @@ BOOST_CONTAINER_FORCEINLINE I memmove_n_source_dest(I f, U n, F &r) BOOST_NOEXCE
typedef typename boost::container::iterator_traits<I>::value_type value_type;
if(BOOST_LIKELY(n)){
std::memmove(boost::movelib::iterator_to_raw_pointer(r), boost::movelib::iterator_to_raw_pointer(f), sizeof(value_type)*n);
boost::container::iterator_advance(f, n);
boost::container::iterator_advance(r, n);
f += n;
r += n;
}
return f;
}
@@ -593,7 +594,7 @@ BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memzero_initializable<F, F>:
typedef typename boost::container::iterator_traits<F>::value_type value_type;
if (BOOST_LIKELY(n)){
std::memset((void*)boost::movelib::iterator_to_raw_pointer(r), 0, sizeof(value_type)*n);
boost::container::iterator_advance(r, n);
r += n;
}
return r;
}
@@ -1172,6 +1173,100 @@ void move_assign_range_alloc_n( Allocator &a, I inp_start, typename allocator_tr
}
}
template<class Allocator, class Iterator>
struct array_destructor
{
typedef typename ::boost::container::iterator_traits<Iterator>::value_type value_type;
typedef typename dtl::if_c
<dtl::is_trivially_destructible<value_type>::value
,dtl::null_scoped_destructor_range<Allocator>
,dtl::scoped_destructor_range<Allocator>
>::type type;
};
template
<typename Allocator
,typename F // F models ForwardIterator
,typename O // G models OutputIterator
,typename InsertionProxy
>
void uninitialized_move_and_insert_alloc
( Allocator &a
, F first
, F pos
, F last
, O d_first
, typename allocator_traits<Allocator>::size_type n
, InsertionProxy insert_range_proxy)
{
typedef typename array_destructor<Allocator, F>::type array_destructor_t;
//Anti-exception rollbacks
array_destructor_t new_values_destroyer(d_first, d_first, a);
//Initialize with [begin(), pos) old buffer
//the start of the new buffer
O d_last = ::boost::container::uninitialized_move_alloc(a, first, pos, d_first);
new_values_destroyer.set_end(d_last);
//Initialize new objects, starting from previous point
insert_range_proxy.uninitialized_copy_n_and_update(a, d_last, n);
d_last += n;
new_values_destroyer.set_end(d_last);
//Initialize from the rest of the old buffer,
//starting from previous point
(void) ::boost::container::uninitialized_move_alloc(a, pos, last, d_last);
//All construction successful, disable rollbacks
new_values_destroyer.release();
}
template
<typename Allocator
,typename F // F models ForwardIterator
,typename InsertionProxy
>
void expand_forward_and_insert_alloc
( Allocator &a
, F pos
, F last
, typename allocator_traits<Allocator>::size_type n
, InsertionProxy insert_range_proxy)
{
typedef typename array_destructor<Allocator, F>::type array_destructor_t;
if (BOOST_UNLIKELY(!n)){
return;
}
else if (last == pos){
insert_range_proxy.uninitialized_copy_n_and_update(a, last, n);
}
else{
typedef typename allocator_traits<Allocator>::size_type alloc_size_type;
const alloc_size_type elems_after = static_cast<alloc_size_type>(last - pos);
if(elems_after >= n){
//New elements can be just copied.
//Move to uninitialized memory last objects
::boost::container::uninitialized_move_alloc_n(a, last - n, n, last);
array_destructor_t on_exception(last, last, a);
//Copy previous to last objects to the initialized end
boost::container::move_backward(pos, last - n, last);
//Insert new objects in the pos
insert_range_proxy.copy_n_and_update(a, pos, n);
on_exception.release();
}
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)
F new_last = ::boost::container::uninitialized_move_alloc(a, pos, last, pos + n);
array_destructor_t on_exception(pos + n, new_last, a);
//Copy first new elements in pos (gap is still there)
insert_range_proxy.copy_n_and_update(a, 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, last, n - elems_after);
on_exception.release();
}
}
}
} //namespace container {
} //namespace boost {

View File

@@ -242,6 +242,72 @@ struct null_scoped_destructor_n
{}
};
//!A deleter for scoped_ptr that destroys
//!an object using a STL allocator.
template <class Allocator>
struct scoped_destructor_range
{
typedef boost::container::allocator_traits<Allocator> AllocTraits;
typedef typename AllocTraits::pointer pointer;
typedef typename AllocTraits::value_type value_type;
BOOST_CONTAINER_FORCEINLINE scoped_destructor_range(pointer p, pointer e, Allocator& a)
: m_p(p), m_e(e), m_a(a)
{}
BOOST_CONTAINER_FORCEINLINE void release()
{ m_p = pointer(); m_e = pointer(); }
BOOST_CONTAINER_FORCEINLINE void set_end(pointer e)
{ m_e = e; }
BOOST_CONTAINER_FORCEINLINE void set_begin(pointer b)
{ m_p = b; }
BOOST_CONTAINER_FORCEINLINE void set_range(pointer b, pointer e)
{ m_p = b; m_e = e; }
~scoped_destructor_range()
{
while(m_p != m_e){
value_type *raw_ptr = boost::movelib::to_raw_pointer(m_p);
AllocTraits::destroy(m_a, raw_ptr);
++m_p;
}
}
private:
pointer m_p;
pointer m_e;
Allocator & m_a;
};
//!A deleter for scoped_ptr that destroys
//!an object using a STL allocator.
template <class Allocator>
struct null_scoped_destructor_range
{
typedef boost::container::allocator_traits<Allocator> AllocTraits;
typedef typename AllocTraits::pointer pointer;
BOOST_CONTAINER_FORCEINLINE null_scoped_destructor_range(pointer, pointer, Allocator&)
{}
BOOST_CONTAINER_FORCEINLINE void release()
{}
BOOST_CONTAINER_FORCEINLINE void set_end(pointer)
{}
BOOST_CONTAINER_FORCEINLINE void set_begin(pointer)
{}
BOOST_CONTAINER_FORCEINLINE void set_range(pointer, pointer)
{}
};
template<class Allocator>
class scoped_destructor
{

View File

@@ -56,7 +56,12 @@ struct grow_factor_ratio
else{
new_cap *= Numerator;
}
return max_value(SizeType(Minimum), max_value(cur_cap+add_min_cap, min_value(max_cap, new_cap)));
return max_value<SizeType>
( SizeType(Minimum)
, max_value<SizeType>
( SizeType(cur_cap+add_min_cap)
, min_value<SizeType>(max_cap, new_cap))
);
}
};

View File

@@ -247,10 +247,6 @@ struct vector_value_traits_base
{
static const bool trivial_dctr = dtl::is_trivially_destructible<T>::value;
static const bool trivial_dctr_after_move = has_trivial_destructor_after_move<T>::value;
static const bool trivial_copy = dtl::is_trivially_copy_constructible<T>::value;
static const bool nothrow_copy = dtl::is_nothrow_copy_constructible<T>::value || trivial_copy;
static const bool trivial_assign = dtl::is_trivially_copy_assignable<T>::value;
static const bool nothrow_assign = dtl::is_nothrow_copy_assignable<T>::value || trivial_assign;
};
template <class Allocator>
@@ -317,34 +313,41 @@ struct vector_alloc_holder
{}
//Constructor, does not throw
template<class AllocConvertible>
vector_alloc_holder(vector_uninitialized_size_t, BOOST_FWD_REF(AllocConvertible) a, size_type initial_size)
template<class AllocConvertible, class SizeType>
vector_alloc_holder(vector_uninitialized_size_t, BOOST_FWD_REF(AllocConvertible) a, SizeType initial_size)
: allocator_type(boost::forward<AllocConvertible>(a))
, m_start()
//Size is initialized here so vector should only call uninitialized_xxx after this
, m_size(static_cast<stored_size_type>(initial_size))
, m_capacity()
{
if(initial_size){
if (initial_size > size_type(-1)){
boost::container::throw_length_error("get_next_capacity, allocator's max size reached");
}
else if(initial_size){
pointer reuse = pointer();
size_type final_cap = initial_size;
m_start = this->allocation_command(allocate_new, initial_size, final_cap, reuse);
size_type final_cap = static_cast<size_type>(initial_size);
m_start = this->allocation_command(allocate_new, final_cap, final_cap, reuse);
this->set_stored_capacity(final_cap);
}
}
//Constructor, does not throw
vector_alloc_holder(vector_uninitialized_size_t, size_type initial_size)
template<class SizeType>
vector_alloc_holder(vector_uninitialized_size_t, SizeType initial_size)
: allocator_type()
, m_start()
//Size is initialized here so vector should only call uninitialized_xxx after this
, m_size(static_cast<stored_size_type>(initial_size))
, m_capacity()
{
if(initial_size){
if (initial_size > size_type(-1)){
boost::container::throw_length_error("get_next_capacity, allocator's max size reached");
}
else if(initial_size){
pointer reuse = pointer();
size_type final_cap = initial_size;
m_start = this->allocation_command(allocate_new, initial_size, final_cap, reuse);
m_start = this->allocation_command(allocate_new, final_cap, final_cap, reuse);
this->set_stored_capacity(final_cap);
}
}
@@ -1014,7 +1017,7 @@ private:
#endif
::boost::container::uninitialized_copy_alloc_n_source
( this->m_holder.alloc(), il.begin()
, il.size(), this->priv_raw_begin());
, static_cast<size_type>(il.size()), this->priv_raw_begin());
}
#endif
@@ -1262,7 +1265,12 @@ private:
{
//For Fwd iterators the standard only requires EmplaceConstructible and assignable from *first
//so we can't do any backwards allocation
const size_type input_sz = static_cast<size_type>(boost::container::iterator_distance(first, last));
const typename iterator_traits<FwdIt>::size_type sz = boost::container::iterator_distance(first, last);
if (sz > size_type(-1)){
boost::container::throw_length_error("vector::assign, FwdIt's max length reached");
}
const size_type input_sz = static_cast<size_type>(sz);
const size_type old_capacity = this->capacity();
if(input_sz > old_capacity){ //If input range is too big, we need to reallocate
size_type real_cap = 0;
@@ -1968,8 +1976,13 @@ private:
)
{
BOOST_ASSERT(this->priv_in_range_or_end(pos));
const typename iterator_traits<FwdIt>::size_type sz = boost::container::iterator_distance(first, last);
if (sz > size_type(-1)){
boost::container::throw_length_error("vector::insert, FwdIt's max length reached");
}
dtl::insert_range_proxy<allocator_type, FwdIt, T*> proxy(first);
return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), boost::container::iterator_distance(first, last), proxy);
return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), static_cast<size_type>(sz), proxy);
}
#endif
@@ -2009,7 +2022,7 @@ private:
//! <b>Returns</b>: an iterator to the first inserted element or position if first == last.
//!
//! <b>Complexity</b>: Linear to the range [il.begin(), il.end()).
iterator insert(const_iterator position, std::initializer_list<value_type> il)
BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator position, std::initializer_list<value_type> il)
{
//Assertion done in insert()
return this->insert(position, il.begin(), il.end());
@@ -2021,11 +2034,12 @@ private:
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant time.
void pop_back() BOOST_NOEXCEPT_OR_NOTHROW
BOOST_CONTAINER_FORCEINLINE void pop_back() BOOST_NOEXCEPT_OR_NOTHROW
{
BOOST_ASSERT(!this->empty());
//Destroy last element
this->priv_destroy_last();
allocator_traits_type::destroy(this->get_stored_allocator(), this->priv_raw_end() - 1);
--this->m_holder.m_size;
}
//! <b>Effects</b>: Erases the element at position pos.
@@ -2039,10 +2053,16 @@ private:
BOOST_ASSERT(this->priv_in_range(position));
const pointer p = vector_iterator_get_ptr(position);
T *const pos_ptr = boost::movelib::to_raw_pointer(p);
T *const beg_ptr = this->priv_raw_begin();
T *const new_end_ptr = ::boost::container::move(pos_ptr + 1, beg_ptr + this->m_holder.m_size, pos_ptr);
T *const end_ptr = this->priv_raw_end();
//Move elements forward and destroy last
this->priv_destroy_last(pos_ptr != new_end_ptr);
(void)::boost::container::move(pos_ptr + 1, end_ptr, pos_ptr);
T *const last_ptr = end_ptr-1;
if(!value_traits::trivial_dctr_after_move || pos_ptr == last_ptr){
allocator_traits_type::destroy(this->get_stored_allocator(), last_ptr);
}
--this->m_holder.m_size;
return iterator(p);
}
@@ -2054,15 +2074,19 @@ private:
//! plus linear to the elements between pos and the last element.
iterator erase(const_iterator first, const_iterator last)
{
if (first != last){
BOOST_ASSERT(this->priv_in_range(first));
BOOST_ASSERT(this->priv_in_range_or_end(last));
BOOST_ASSERT(first < last);
BOOST_ASSERT(this->priv_in_range_or_end(first));
BOOST_ASSERT(this->priv_in_range_or_end(last));
BOOST_ASSERT(first <= last);
if(first != last){
T* const old_end_ptr = this->priv_raw_end();
T* const first_ptr = boost::movelib::to_raw_pointer(vector_iterator_get_ptr(first));
T* const last_ptr = boost::movelib::to_raw_pointer(vector_iterator_get_ptr(last));
T* const ptr = boost::movelib::to_raw_pointer(boost::container::move(last_ptr, old_end_ptr, first_ptr));
this->priv_destroy_last_n(old_end_ptr - ptr);
T* const new_last_ptr = boost::movelib::to_raw_pointer(boost::container::move(last_ptr, old_end_ptr, first_ptr));
const size_type n = static_cast<size_type>(old_end_ptr - new_last_ptr);
if(!value_traits::trivial_dctr_after_move || old_end_ptr == last_ptr){
boost::container::destroy_alloc_n(this->get_stored_allocator(), new_last_ptr, n);
}
this->m_holder.dec_stored_size(n);
}
return iterator(vector_iterator_get_ptr(first));
}
@@ -2575,24 +2599,10 @@ private:
}
}
void priv_destroy_last(const bool moved = false) BOOST_NOEXCEPT_OR_NOTHROW
{
(void)moved;
const bool skip_destructor = value_traits::trivial_dctr || (value_traits::trivial_dctr_after_move && moved);
if(!skip_destructor){
value_type* const p = this->priv_raw_end() - 1;
allocator_traits_type::destroy(this->get_stored_allocator(), p);
}
--this->m_holder.m_size;
}
void priv_destroy_last_n(const size_type n) BOOST_NOEXCEPT_OR_NOTHROW
{
BOOST_ASSERT(n <= this->m_holder.m_size);
if(!value_traits::trivial_dctr){
T* const destroy_pos = this->priv_raw_begin() + (this->m_holder.m_size-n);
boost::container::destroy_alloc_n(this->get_stored_allocator(), destroy_pos, n);
}
boost::container::destroy_alloc_n(this->get_stored_allocator(), this->priv_raw_end() - n, n);
this->m_holder.dec_stored_size(n);
}
@@ -2601,7 +2611,7 @@ private:
{
T* const old_end_pos = this->priv_raw_end();
T* const new_end_pos = boost::container::uninitialized_copy_alloc(this->m_holder.alloc(), first, last, old_end_pos);
this->m_holder.inc_stored_size(new_end_pos - old_end_pos);
this->m_holder.inc_stored_size(static_cast<size_type>(new_end_pos - old_end_pos));
}
void priv_destroy_all() BOOST_NOEXCEPT_OR_NOTHROW
@@ -2623,6 +2633,13 @@ private:
this->emplace_back(::boost::forward<U>(u));
}
//Overload to support compiler errors that instantiate too much
BOOST_CONTAINER_FORCEINLINE void priv_push_back(::boost::move_detail::nat)
{}
BOOST_CONTAINER_FORCEINLINE iterator priv_insert(const_iterator, ::boost::move_detail::nat)
{ return iterator(); }
BOOST_CONTAINER_FORCEINLINE dtl::insert_n_copies_proxy<allocator_type, T*> priv_resize_proxy(const T &x)
{ return dtl::insert_n_copies_proxy<allocator_type, T*>(x); }
@@ -2689,7 +2706,7 @@ private:
(T *const raw_pos, const size_type n, const InsertionProxy insert_range_proxy, version_1)
{
//Check if we have enough memory or try to expand current memory
const size_type n_pos = raw_pos - this->priv_raw_begin();
const size_type n_pos = static_cast<size_type>(raw_pos - this->priv_raw_begin());
const size_type new_cap = this->m_holder.template next_capacity<growth_factor_type>(n);
//Pass the hint so that allocators can take advantage of this.
@@ -2898,16 +2915,17 @@ private:
BOOST_ASSERT(this->room_enough());
//There is enough memory
T* const old_finish = this->priv_raw_end();
allocator_type & a = this->m_holder.alloc();
if (old_finish == raw_pos){
insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, 1);
insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, 1);
++this->m_holder.m_size;
}
else{
//New elements can be just copied.
//Move to uninitialized memory last objects
T * const before_old_finish = old_finish-1;
allocator_type & a = this->m_holder.alloc();
allocator_traits_type::construct(a, old_finish, ::boost::move(*before_old_finish));
++this->m_holder.m_size;
//Copy previous to last objects to the initialized end
@@ -2918,45 +2936,12 @@ private:
}
template <class InsertionProxy>
void priv_insert_forward_range_expand_forward(T* const raw_pos, const size_type n, InsertionProxy insert_range_proxy, dtl::false_type)
BOOST_CONTAINER_FORCEINLINE void priv_insert_forward_range_expand_forward(T* const raw_pos, const size_type n, InsertionProxy insert_range_proxy, dtl::false_type)
{
//In case n is 0 there is nothing to do
if(BOOST_UNLIKELY(!n))
return;
//There is enough memory
T* const raw_old_finish = this->priv_raw_end();
if (raw_old_finish == raw_pos){
insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), raw_old_finish, n);
this->m_holder.inc_stored_size(n);
}
else{
const size_type elems_after = raw_old_finish - raw_pos;
allocator_type & a = this->m_holder.alloc();
if(elems_after >= n){
//New elements can be just copied.
//Move to uninitialized memory last objects
::boost::container::uninitialized_move_alloc_n(a, raw_old_finish - n, n, raw_old_finish);
this->m_holder.inc_stored_size(n);
//Copy previous to last objects to the initialized end
boost::container::move_backward(raw_pos, raw_old_finish - n, raw_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 [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, raw_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, raw_old_finish, n - elems_after);
this->m_holder.inc_stored_size(n);
on_exception.release();
}
}
boost::container::expand_forward_and_insert_alloc
( this->m_holder.alloc(), raw_pos, this->priv_raw_end(), n, insert_range_proxy);
this->m_holder.inc_stored_size(n);
}
template <class InsertionProxy>
@@ -2964,45 +2949,24 @@ private:
(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();
T * const raw_old_buffer = this->priv_raw_begin();
//Anti-exception rollbacks
typename value_traits::ArrayDeallocator new_buffer_deallocator(new_start, a, new_cap);
typename value_traits::ArrayDestructor new_values_destroyer(new_start, a, 0u);
boost::container::uninitialized_move_and_insert_alloc
(a, raw_old_buffer, pos, this->priv_raw_end(), new_start, n, insert_range_proxy);
new_buffer_deallocator.release();
//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
(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(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
(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)
boost::container::destroy_alloc_n(this->get_stored_allocator(), old_buffer, this->m_holder.m_size);
//Destroy and deallocate old elements
if(raw_old_buffer){
BOOST_IF_CONSTEXPR(!has_trivial_destructor_after_move<value_type>::value)
boost::container::destroy_alloc_n(a, raw_old_buffer, this->m_holder.m_size);
this->m_holder.deallocate(this->m_holder.start(), this->m_holder.capacity());
}
this->m_holder.start(new_start);
m_holder.set_stored_size(new_finish - new_start);
this->m_holder.inc_stored_size(n);
this->m_holder.capacity(new_cap);
//All construction successful, disable rollbacks
new_values_destroyer.release();
new_buffer_deallocator.release();
}
template <class InsertionProxy>
@@ -3314,7 +3278,7 @@ private:
//Copy to the old_end part to the uninitialized zone leaving a gap.
::boost::container::uninitialized_move_alloc(a, pos, old_finish, old_finish + mid_last_dist);
array_destructor_t old_end_destroyer(old_finish + mid_last_dist, a, old_finish - pos);
array_destructor_t old_end_destroyer(old_finish + mid_last_dist, a, static_cast<size_type>(old_finish - pos));
//Copy the first part to the already constructed old_end zone
insert_range_proxy.copy_n_and_update(a, pos, elemsafter);

View File

@@ -23,6 +23,29 @@ volatile ::boost::container::vector<empty> dummy;
#include "movable_int.hpp"
#include "dummy_test_allocator.hpp"
class CustomAllocator
{
public:
typedef int value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef unsigned short size_type;
typedef short difference_type;
pointer allocate(size_type count)
{ return (pointer)new char[sizeof(value_type)*count]; }
void deallocate(pointer ptr, size_type )
{ delete [](char*)ptr; }
friend bool operator==(CustomAllocator const&, CustomAllocator const&) BOOST_NOEXCEPT
{ return true; }
friend bool operator!=(CustomAllocator const& x, CustomAllocator const& y) BOOST_NOEXCEPT
{ return !(x == y); }
};
namespace boost {
namespace container {
@@ -44,6 +67,9 @@ template class boost::container::vector< test::movable_and_copyable_int
, vector_options< stored_size<unsigned short> >::type
>;
//test custom allocator with small size_type
template class boost::container::vector<int, CustomAllocator>;
} //namespace boost {
} //namespace container {