diff --git a/doc/container.qbk b/doc/container.qbk index 2c4d17a..6add10e 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1,5 +1,5 @@ [/ - / Copyright (c) 2009-2018 Ion Gaztañaga + / Copyright (c) 2009-2020 Ion Gaztañ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] diff --git a/include/boost/container/detail/advanced_insert_int.hpp b/include/boost/container/detail/advanced_insert_int.hpp index dcc8c9f..585b8ce 100644 --- a/include/boost/container/detail/advanced_insert_int.hpp +++ b/include/boost/container/detail/advanced_insert_int.hpp @@ -426,7 +426,6 @@ struct insert_emplace_proxy_arg##N\ {\ BOOST_ASSERT(n == 1); (void)n;\ typename dtl::aligned_storage::value>::type v;\ - BOOST_ASSERT((((size_type)(&v)) % alignment_of::value) == 0);\ value_type *vp = reinterpret_cast(v.data);\ alloc_traits::construct(a, vp BOOST_MOVE_I##N BOOST_MOVE_MFWD##N);\ BOOST_TRY{\ diff --git a/include/boost/container/detail/copy_move_algo.hpp b/include/boost/container/detail/copy_move_algo.hpp index 2212281..8325cc6 100644 --- a/include/boost/container/detail/copy_move_algo.hpp +++ b/include/boost/container/detail/copy_move_algo.hpp @@ -26,6 +26,7 @@ #include #include #include +#include // move #include @@ -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::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::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::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::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: typedef typename boost::container::iterator_traits::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 +struct array_destructor +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + typedef typename dtl::if_c + ::value + ,dtl::null_scoped_destructor_range + ,dtl::scoped_destructor_range + >::type type; +}; + +template + +void uninitialized_move_and_insert_alloc + ( Allocator &a + , F first + , F pos + , F last + , O d_first + , typename allocator_traits::size_type n + , InsertionProxy insert_range_proxy) +{ + typedef typename array_destructor::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 + +void expand_forward_and_insert_alloc + ( Allocator &a + , F pos + , F last + , typename allocator_traits::size_type n + , InsertionProxy insert_range_proxy) +{ + typedef typename array_destructor::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::size_type alloc_size_type; + const alloc_size_type elems_after = static_cast(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 { diff --git a/include/boost/container/detail/destroyers.hpp b/include/boost/container/detail/destroyers.hpp index ab492f5..604c2b9 100644 --- a/include/boost/container/detail/destroyers.hpp +++ b/include/boost/container/detail/destroyers.hpp @@ -242,6 +242,72 @@ struct null_scoped_destructor_n {} }; + +//!A deleter for scoped_ptr that destroys +//!an object using a STL allocator. +template +struct scoped_destructor_range +{ + typedef boost::container::allocator_traits 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 +struct null_scoped_destructor_range +{ + typedef boost::container::allocator_traits 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 scoped_destructor { diff --git a/include/boost/container/detail/next_capacity.hpp b/include/boost/container/detail/next_capacity.hpp index 12fc35e..0ad62ba 100644 --- a/include/boost/container/detail/next_capacity.hpp +++ b/include/boost/container/detail/next_capacity.hpp @@ -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(Minimum) + , max_value + ( SizeType(cur_cap+add_min_cap) + , min_value(max_cap, new_cap)) + ); } }; diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 3268683..3bf405a 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -247,10 +247,6 @@ struct vector_value_traits_base { static const bool trivial_dctr = dtl::is_trivially_destructible::value; static const bool trivial_dctr_after_move = has_trivial_destructor_after_move::value; - static const bool trivial_copy = dtl::is_trivially_copy_constructible::value; - static const bool nothrow_copy = dtl::is_nothrow_copy_constructible::value || trivial_copy; - static const bool trivial_assign = dtl::is_trivially_copy_assignable::value; - static const bool nothrow_assign = dtl::is_nothrow_copy_assignable::value || trivial_assign; }; template @@ -317,34 +313,41 @@ struct vector_alloc_holder {} //Constructor, does not throw - template - vector_alloc_holder(vector_uninitialized_size_t, BOOST_FWD_REF(AllocConvertible) a, size_type initial_size) + template + vector_alloc_holder(vector_uninitialized_size_t, BOOST_FWD_REF(AllocConvertible) a, SizeType initial_size) : allocator_type(boost::forward(a)) , m_start() //Size is initialized here so vector should only call uninitialized_xxx after this , m_size(static_cast(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(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 + 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(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(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(boost::container::iterator_distance(first, last)); + const typename iterator_traits::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(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::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 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(sz), proxy); } #endif @@ -2009,7 +2022,7 @@ private: //! Returns: an iterator to the first inserted element or position if first == last. //! //! Complexity: Linear to the range [il.begin(), il.end()). - iterator insert(const_iterator position, std::initializer_list il) + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator position, std::initializer_list il) { //Assertion done in insert() return this->insert(position, il.begin(), il.end()); @@ -2021,11 +2034,12 @@ private: //! Throws: Nothing. //! //! Complexity: 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; } //! Effects: 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(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(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)); } + //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 priv_resize_proxy(const T &x) { return dtl::insert_n_copies_proxy(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(raw_pos - this->priv_raw_begin()); const size_type new_cap = this->m_holder.template next_capacity(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 - 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 @@ -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) + 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 @@ -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(old_finish - pos)); //Copy the first part to the already constructed old_end zone insert_range_proxy.copy_n_and_update(a, pos, elemsafter); diff --git a/test/explicit_inst_vector_test.cpp b/test/explicit_inst_vector_test.cpp index c6700fe..6d2a2cc 100644 --- a/test/explicit_inst_vector_test.cpp +++ b/test/explicit_inst_vector_test.cpp @@ -23,6 +23,29 @@ volatile ::boost::container::vector 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 >::type >; +//test custom allocator with small size_type +template class boost::container::vector; + } //namespace boost { } //namespace container {