src/cxx_supportlib/vendor-modified/boost/container/vector.hpp in passenger-6.0.8 vs src/cxx_supportlib/vendor-modified/boost/container/vector.hpp in passenger-6.0.9

- old
+ new

@@ -106,14 +106,16 @@ typedef typename dtl::if_c< IsConst , vec_iterator<Pointer, false> , nat>::type nonconst_iterator; public: - BOOST_CONTAINER_FORCEINLINE const Pointer &get_ptr() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE + const Pointer &get_ptr() const BOOST_NOEXCEPT_OR_NOTHROW { return m_ptr; } - BOOST_CONTAINER_FORCEINLINE Pointer &get_ptr() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE + Pointer &get_ptr() BOOST_NOEXCEPT_OR_NOTHROW { return m_ptr; } BOOST_CONTAINER_FORCEINLINE explicit vec_iterator(Pointer ptr) BOOST_NOEXCEPT_OR_NOTHROW : m_ptr(ptr) {} @@ -136,17 +138,20 @@ BOOST_CONTAINER_FORCEINLINE vec_iterator & operator=(const vec_iterator& other) BOOST_NOEXCEPT_OR_NOTHROW { m_ptr = other.get_ptr(); return *this; } //Pointer like operators - BOOST_CONTAINER_FORCEINLINE reference operator*() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + reference operator*() const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!!m_ptr); return *m_ptr; } - BOOST_CONTAINER_FORCEINLINE pointer operator->() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + pointer operator->() const BOOST_NOEXCEPT_OR_NOTHROW { return m_ptr; } - BOOST_CONTAINER_FORCEINLINE reference operator[](difference_type off) const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + reference operator[](difference_type off) const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!!m_ptr); return m_ptr[off]; } //Increment / Decrement BOOST_CONTAINER_FORCEINLINE vec_iterator& operator++() BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!!m_ptr); ++m_ptr; return *this; } @@ -165,39 +170,49 @@ { BOOST_ASSERT(m_ptr || !off); m_ptr += off; return *this; } BOOST_CONTAINER_FORCEINLINE vec_iterator& operator-=(difference_type off) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(m_ptr || !off); m_ptr -= off; return *this; } - BOOST_CONTAINER_FORCEINLINE friend vec_iterator operator+(const vec_iterator &x, difference_type off) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend vec_iterator operator+(const vec_iterator &x, difference_type off) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(x.m_ptr || !off); return vec_iterator(x.m_ptr+off); } - BOOST_CONTAINER_FORCEINLINE friend vec_iterator operator+(difference_type off, vec_iterator right) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend vec_iterator operator+(difference_type off, vec_iterator right) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(right.m_ptr || !off); right.m_ptr += off; return right; } - BOOST_CONTAINER_FORCEINLINE friend vec_iterator operator-(vec_iterator left, difference_type off) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend vec_iterator operator-(vec_iterator left, difference_type off) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(left.m_ptr || !off); left.m_ptr -= off; return left; } - BOOST_CONTAINER_FORCEINLINE friend difference_type operator-(const vec_iterator &left, const vec_iterator& right) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend difference_type operator-(const vec_iterator &left, const vec_iterator& right) BOOST_NOEXCEPT_OR_NOTHROW { return left.m_ptr - right.m_ptr; } //Comparison operators - BOOST_CONTAINER_FORCEINLINE friend bool operator== (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator== (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW { return l.m_ptr == r.m_ptr; } - BOOST_CONTAINER_FORCEINLINE friend bool operator!= (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator!= (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW { return l.m_ptr != r.m_ptr; } - BOOST_CONTAINER_FORCEINLINE friend bool operator< (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator< (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW { return l.m_ptr < r.m_ptr; } - BOOST_CONTAINER_FORCEINLINE friend bool operator<= (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator<= (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW { return l.m_ptr <= r.m_ptr; } - BOOST_CONTAINER_FORCEINLINE friend bool operator> (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator> (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW { return l.m_ptr > r.m_ptr; } - BOOST_CONTAINER_FORCEINLINE friend bool operator>= (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator>= (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW { return l.m_ptr >= r.m_ptr; } }; template<class BiDirPosConstIt, class BiDirValueIt> struct vector_insert_ordered_cursor @@ -245,14 +260,10 @@ template <class T> 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> struct vector_value_traits : public vector_value_traits_base<typename Allocator::value_type> @@ -286,19 +297,21 @@ typedef boost::container::allocator_traits<allocator_type> allocator_traits_type; typedef typename allocator_traits_type::pointer pointer; typedef typename allocator_traits_type::size_type size_type; typedef typename allocator_traits_type::value_type value_type; - BOOST_CONTAINER_FORCEINLINE static bool is_propagable_from(const allocator_type &from_alloc, pointer p, const allocator_type &to_alloc, bool const propagate_allocator) + BOOST_CONTAINER_FORCEINLINE + static bool is_propagable_from(const allocator_type &from_alloc, pointer p, const allocator_type &to_alloc, bool const propagate_allocator) { (void)propagate_allocator; (void)p; (void)to_alloc; (void)from_alloc; const bool all_storage_propagable = !allocator_traits_type::is_partially_propagable::value || !allocator_traits_type::storage_is_unpropagable(from_alloc, p); return all_storage_propagable && (propagate_allocator || allocator_traits_type::equal(from_alloc, to_alloc)); } - BOOST_CONTAINER_FORCEINLINE static bool are_swap_propagable(const allocator_type &l_a, pointer l_p, const allocator_type &r_a, pointer r_p, bool const propagate_allocator) + BOOST_CONTAINER_FORCEINLINE + static bool are_swap_propagable(const allocator_type &l_a, pointer l_p, const allocator_type &r_a, pointer r_p, bool const propagate_allocator) { (void)propagate_allocator; (void)l_p; (void)r_p; (void)l_a; (void)r_a; const bool all_storage_propagable = !allocator_traits_type::is_partially_propagable::value || !(allocator_traits_type::storage_is_unpropagable(l_a, l_p) || allocator_traits_type::storage_is_unpropagable(r_a, r_p)); return all_storage_propagable && (propagate_allocator || allocator_traits_type::equal(l_a, r_a)); @@ -315,39 +328,46 @@ explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_NOEXCEPT_OR_NOTHROW : allocator_type(boost::forward<AllocConvertible>(a)), m_start(), m_size(), m_capacity() {} //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); - m_capacity = static_cast<stored_size_type>(final_cap); + 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_capacity = static_cast<stored_size_type>(final_cap); + m_start = this->allocation_command(allocate_new, final_cap, final_cap, reuse); + this->set_stored_capacity(final_cap); } } vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) BOOST_NOEXCEPT_OR_NOTHROW : allocator_type(BOOST_MOVE_BASE(allocator_type, holder)) @@ -381,12 +401,24 @@ if(this->m_capacity){ this->deallocate(this->m_start, this->m_capacity); } } + BOOST_CONTAINER_FORCEINLINE void set_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_size = static_cast<stored_size_type>(s); } + + BOOST_CONTAINER_FORCEINLINE void dec_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_size -= static_cast<stored_size_type>(s); } + + BOOST_CONTAINER_FORCEINLINE void inc_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_size += static_cast<stored_size_type>(s); } + + BOOST_CONTAINER_FORCEINLINE void set_stored_capacity(size_type c) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_capacity = static_cast<stored_size_type>(c); } + BOOST_CONTAINER_FORCEINLINE pointer allocation_command(boost::container::allocation_type command, - size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse) + size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse) { typedef typename dtl::version<allocator_type>::type alloc_version; return this->priv_allocation_command(alloc_version(), command, limit_size, prefer_in_recvd_out_size, reuse); } @@ -425,11 +457,11 @@ template<class GrowthFactorType> size_type next_capacity(size_type additional_objects) const { BOOST_ASSERT(additional_objects > size_type(this->m_capacity - this->m_size)); size_type max = allocator_traits_type::max_size(this->alloc()); - (clamp_by_stored_size_type)(max, stored_size_type()); + (clamp_by_stored_size_type<size_type>)(max, stored_size_type()); const size_type remaining_cap = max - size_type(this->m_capacity); const size_type min_additional_cap = additional_objects - size_type(this->m_capacity - this->m_size); if ( remaining_cap < min_additional_cap ) boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); @@ -468,11 +500,11 @@ BOOST_CONTAINER_FORCEINLINE size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW { return m_capacity; } BOOST_CONTAINER_FORCEINLINE void start(const pointer &p) BOOST_NOEXCEPT_OR_NOTHROW { m_start = p; } BOOST_CONTAINER_FORCEINLINE void capacity(const size_type &c) BOOST_NOEXCEPT_OR_NOTHROW - { BOOST_ASSERT( c <= stored_size_type(-1)); m_capacity = c; } + { BOOST_ASSERT( c <= stored_size_type(-1)); this->set_stored_capacity(c); } static BOOST_CONTAINER_FORCEINLINE void on_capacity_overflow() { } private: @@ -486,21 +518,11 @@ ++this->num_alloc; #endif } } - BOOST_CONTAINER_FORCEINLINE static void clamp_by_stored_size_type(size_type &, size_type) - {} - - template<class SomeStoredSizeType> - BOOST_CONTAINER_FORCEINLINE static void clamp_by_stored_size_type(size_type &s, SomeStoredSizeType) - { - if (s >= SomeStoredSizeType(-1) ) - s = SomeStoredSizeType(-1); - } - - BOOST_CONTAINER_FORCEINLINE pointer priv_allocation_command(version_1, boost::container::allocation_type command, + pointer priv_allocation_command(version_1, boost::container::allocation_type command, size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse) { (void)command; @@ -508,11 +530,11 @@ BOOST_ASSERT(!(command & nothrow_allocation)); //First detect overflow on smaller stored_size_types if (limit_size > stored_size_type(-1)){ boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); } - (clamp_by_stored_size_type)(prefer_in_recvd_out_size, stored_size_type()); + (clamp_by_stored_size_type<size_type>)(prefer_in_recvd_out_size, stored_size_type()); pointer const p = this->allocate(prefer_in_recvd_out_size); reuse = pointer(); return p; } @@ -523,15 +545,15 @@ { //First detect overflow on smaller stored_size_types if (limit_size > stored_size_type(-1)){ boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); } - (clamp_by_stored_size_type)(prefer_in_recvd_out_size, stored_size_type()); + (clamp_by_stored_size_type<size_type>)(prefer_in_recvd_out_size, stored_size_type()); //Allocate memory pointer p = this->alloc().allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); //If after allocation prefer_in_recvd_out_size is not representable by stored_size_type, truncate it. - (clamp_by_stored_size_type)(prefer_in_recvd_out_size, stored_size_type()); + (clamp_by_stored_size_type<size_type>)(prefer_in_recvd_out_size, stored_size_type()); return p; } }; //!This struct deallocates and allocated memory @@ -609,10 +631,19 @@ } static BOOST_CONTAINER_FORCEINLINE void on_capacity_overflow() { allocator_type::on_capacity_overflow(); } + BOOST_CONTAINER_FORCEINLINE void set_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_size = static_cast<stored_size_type>(s); } + + BOOST_CONTAINER_FORCEINLINE void dec_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_size -= static_cast<stored_size_type>(s); } + + BOOST_CONTAINER_FORCEINLINE void inc_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_size += static_cast<stored_size_type>(s); } + BOOST_CONTAINER_FORCEINLINE void priv_first_allocation(size_type cap) { if(cap > allocator_type::internal_capacity){ on_capacity_overflow(); } @@ -654,11 +685,11 @@ { return !at_least; } BOOST_CONTAINER_FORCEINLINE pointer start() const BOOST_NOEXCEPT_OR_NOTHROW { return allocator_type::internal_storage(); } - BOOST_CONTAINER_FORCEINLINE size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW { return allocator_type::internal_capacity; } stored_size_type m_size; private: @@ -1001,11 +1032,11 @@ #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS this->num_alloc += il.size() != 0; #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 #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -1022,11 +1053,11 @@ < dtl::is_version<typename real_allocator<T, OtherA>::type, 0>::value>::type * = 0 ) : m_holder(boost::move(x.m_holder)) {} - #endif //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + #endif // defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! <b>Effects</b>: Copy constructs a vector using the specified allocator. //! //! <b>Postcondition</b>: x == *this. //! @@ -1249,11 +1280,16 @@ >::type * = 0) ) { //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; pointer reuse(this->m_holder.start()); pointer const ret(this->m_holder.allocation_command(allocate_new|expand_fwd, input_sz, real_cap = input_sz, reuse)); @@ -1280,11 +1316,11 @@ //Forward expansion, use assignment + back deletion/construction that comes later } } boost::container::copy_assign_range_alloc_n(this->m_holder.alloc(), first, input_sz, this->priv_raw_begin(), this->size()); - this->m_holder.m_size = input_sz; + m_holder.set_stored_size(input_sz); } //! <b>Effects</b>: Assigns the n copies of val to *this. //! //! <b>Throws</b>: If memory allocation throws or @@ -1297,31 +1333,33 @@ //! <b>Effects</b>: Returns a copy of the internal allocator. //! //! <b>Throws</b>: If allocator's copy constructor throws. //! //! <b>Complexity</b>: Constant. - allocator_type get_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const BOOST_NOEXCEPT_OR_NOTHROW { return this->m_holder.alloc(); } //! <b>Effects</b>: Returns a reference to the internal allocator. //! //! <b>Throws</b>: Nothing //! //! <b>Complexity</b>: Constant. //! //! <b>Note</b>: Non-standard extension. - BOOST_CONTAINER_FORCEINLINE stored_allocator_type &get_stored_allocator() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + stored_allocator_type &get_stored_allocator() BOOST_NOEXCEPT_OR_NOTHROW { return this->m_holder.alloc(); } //! <b>Effects</b>: Returns a reference to the internal allocator. //! //! <b>Throws</b>: Nothing //! //! <b>Complexity</b>: Constant. //! //! <b>Note</b>: Non-standard extension. - BOOST_CONTAINER_FORCEINLINE const stored_allocator_type &get_stored_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const stored_allocator_type &get_stored_allocator() const BOOST_NOEXCEPT_OR_NOTHROW { return this->m_holder.alloc(); } ////////////////////////////////////////////// // // iterators @@ -1331,114 +1369,113 @@ //! <b>Effects</b>: Returns an iterator to the first element contained in the vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE iterator begin() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE iterator begin() BOOST_NOEXCEPT_OR_NOTHROW { return iterator(this->m_holder.start()); } //! <b>Effects</b>: Returns a const_iterator to the first element contained in the vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE const_iterator begin() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_iterator begin() const BOOST_NOEXCEPT_OR_NOTHROW { return const_iterator(this->m_holder.start()); } //! <b>Effects</b>: Returns an iterator to the end of the vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE iterator end() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE iterator end() BOOST_NOEXCEPT_OR_NOTHROW { - pointer const bg = this->m_holder.start(); - size_type const sz = this->m_holder.m_size; - return iterator(BOOST_LIKELY(sz) ? bg + sz : bg); //Avoid UB on null-pointer arithmetic + iterator it (this->m_holder.start()); + it += this->m_holder.m_size; + return it; //Adding zero to null pointer is allowed (non-UB) } //! <b>Effects</b>: Returns a const_iterator to the end of the vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE const_iterator end() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_iterator end() const BOOST_NOEXCEPT_OR_NOTHROW { return this->cend(); } //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning //! of the reversed vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE reverse_iterator rbegin() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE reverse_iterator rbegin() BOOST_NOEXCEPT_OR_NOTHROW { return reverse_iterator(this->end()); } //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning //! of the reversed vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rbegin() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rbegin() const BOOST_NOEXCEPT_OR_NOTHROW { return this->crbegin(); } //! <b>Effects</b>: Returns a reverse_iterator pointing to the end //! of the reversed vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE reverse_iterator rend() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE reverse_iterator rend() BOOST_NOEXCEPT_OR_NOTHROW { return reverse_iterator(this->begin()); } //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end //! of the reversed vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rend() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rend() const BOOST_NOEXCEPT_OR_NOTHROW { return this->crend(); } //! <b>Effects</b>: Returns a const_iterator to the first element contained in the vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const BOOST_NOEXCEPT_OR_NOTHROW { return const_iterator(this->m_holder.start()); } //! <b>Effects</b>: Returns a const_iterator to the end of the vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE const_iterator cend() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_iterator cend() const BOOST_NOEXCEPT_OR_NOTHROW { - pointer const bg = this->m_holder.start(); - size_type const sz = this->m_holder.m_size; - return const_iterator(BOOST_LIKELY(sz) ? bg + sz : bg); //Avoid UB on null-pointer arithmetic + const_iterator it (this->m_holder.start()); + it += this->m_holder.m_size; + return it; //Adding zero to null pointer is allowed (non-UB) } - //{ return const_iterator(this->m_holder.start() + this->m_holder.m_size); } //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning //! of the reversed vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crbegin() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crbegin() const BOOST_NOEXCEPT_OR_NOTHROW { return const_reverse_iterator(this->end());} //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end //! of the reversed vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW { return const_reverse_iterator(this->begin()); } ////////////////////////////////////////////// // // capacity @@ -1448,65 +1485,65 @@ //! <b>Effects</b>: Returns true if the vector contains no elements. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE bool empty() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE bool empty() const BOOST_NOEXCEPT_OR_NOTHROW { return !this->m_holder.m_size; } //! <b>Effects</b>: Returns the number of the elements contained in the vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE size_type size() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE size_type size() const BOOST_NOEXCEPT_OR_NOTHROW { return this->m_holder.m_size; } //! <b>Effects</b>: Returns the largest possible size of the vector. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW { return allocator_traits_type::max_size(this->m_holder.alloc()); } //! <b>Effects</b>: Inserts or erases elements at the end such that //! the size becomes n. New elements are value initialized. //! //! <b>Throws</b>: If memory allocation throws, or T's copy/move or value initialization throws. //! //! <b>Complexity</b>: Linear to the difference between size() and new_size. - void resize(size_type new_size) - { this->priv_resize(new_size, value_init); } + BOOST_CONTAINER_FORCEINLINE void resize(size_type new_size) + { this->priv_resize(new_size, value_init, alloc_version()); } //! <b>Effects</b>: Inserts or erases elements at the end such that //! the size becomes n. New elements are default initialized. //! //! <b>Throws</b>: If memory allocation throws, or T's copy/move or default initialization throws. //! //! <b>Complexity</b>: Linear to the difference between size() and new_size. //! //! <b>Note</b>: Non-standard extension - void resize(size_type new_size, default_init_t) - { this->priv_resize(new_size, default_init); } + BOOST_CONTAINER_FORCEINLINE void resize(size_type new_size, default_init_t) + { this->priv_resize(new_size, default_init, alloc_version()); } //! <b>Effects</b>: Inserts or erases elements at the end such that //! the size becomes n. New elements are copy constructed from x. //! //! <b>Throws</b>: If memory allocation throws, or T's copy/move constructor throws. //! //! <b>Complexity</b>: Linear to the difference between size() and new_size. - void resize(size_type new_size, const T& x) - { this->priv_resize(new_size, x); } + BOOST_CONTAINER_FORCEINLINE void resize(size_type new_size, const T& x) + { this->priv_resize(new_size, x, alloc_version()); } //! <b>Effects</b>: Number of elements for which memory has been allocated. //! capacity() is always greater than or equal to size(). //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - BOOST_CONTAINER_FORCEINLINE size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW { return this->m_holder.capacity(); } //! <b>Effects</b>: If n is less than or equal to capacity(), this call has no //! effect. Otherwise, it is a request for allocation of additional memory. //! If the request is successful, then capacity() is greater than or equal to @@ -1514,11 +1551,11 @@ //! //! <b>Throws</b>: If memory allocation allocation throws or T's copy/move constructor throws. 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()); } } //! <b>Effects</b>: Tries to deallocate the excess of memory created //! with previous allocations. The size of the vector is unchanged @@ -1541,11 +1578,11 @@ //! element of the container. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - reference front() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE reference front() BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); return *this->m_holder.start(); } @@ -1555,11 +1592,11 @@ //! element of the container. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - const_reference front() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reference front() const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); return *this->m_holder.start(); } @@ -1569,11 +1606,11 @@ //! element of the container. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - reference back() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE reference back() BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); return this->m_holder.start()[this->m_holder.m_size - 1]; } @@ -1583,11 +1620,11 @@ //! element of the container. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - const_reference back() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reference back() const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); return this->m_holder.start()[this->m_holder.m_size - 1]; } @@ -1597,11 +1634,11 @@ //! from the beginning of the container. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - reference operator[](size_type n) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE reference operator[](size_type n) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(this->m_holder.m_size > n); return this->m_holder.start()[n]; } @@ -1611,11 +1648,12 @@ //! from the beginning of the container. //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - const_reference operator[](size_type n) const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_reference operator[](size_type n) const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(this->m_holder.m_size > n); return this->m_holder.start()[n]; } @@ -1628,11 +1666,12 @@ //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. //! //! <b>Note</b>: Non-standard extension - iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(this->m_holder.m_size >= n); return iterator(this->m_holder.start()+n); } @@ -1645,11 +1684,12 @@ //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. //! //! <b>Note</b>: Non-standard extension - const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(this->m_holder.m_size >= n); return const_iterator(this->m_holder.start()+n); } @@ -1661,11 +1701,12 @@ //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. //! //! <b>Note</b>: Non-standard extension - size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW { //Range check assert done in priv_index_of return this->priv_index_of(vector_iterator_get_ptr(p)); } @@ -1677,39 +1718,40 @@ //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. //! //! <b>Note</b>: Non-standard extension - size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW { //Range check assert done in priv_index_of return this->priv_index_of(vector_iterator_get_ptr(p)); } //! <b>Requires</b>: size() > n. //! //! <b>Effects</b>: Returns a reference to the nth element //! from the beginning of the container. //! - //! <b>Throws</b>: std::range_error if n >= size() + //! <b>Throws</b>: range_error if n >= size() //! //! <b>Complexity</b>: Constant. - reference at(size_type n) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE reference at(size_type n) { this->priv_throw_if_out_of_range(n); return this->m_holder.start()[n]; } //! <b>Requires</b>: size() > n. //! //! <b>Effects</b>: Returns a const reference to the nth element //! from the beginning of the container. //! - //! <b>Throws</b>: std::range_error if n >= size() + //! <b>Throws</b>: range_error if n >= size() //! //! <b>Complexity</b>: Constant. - const_reference at(size_type n) const + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reference at(size_type n) const { this->priv_throw_if_out_of_range(n); return this->m_holder.start()[n]; } @@ -1723,20 +1765,20 @@ //! For a non-empty vector, data() == &front(). //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - T* data() BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE T* data() BOOST_NOEXCEPT_OR_NOTHROW { return this->priv_raw_begin(); } //! <b>Returns</b>: A pointer such that [data(),data() + size()) is a valid range. //! For a non-empty vector, data() == &front(). //! //! <b>Throws</b>: Nothing. //! //! <b>Complexity</b>: Constant. - const T * data() const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const T * data() const BOOST_NOEXCEPT_OR_NOTHROW { return this->priv_raw_begin(); } ////////////////////////////////////////////// // // modifiers @@ -1754,21 +1796,21 @@ //! //! <b>Complexity</b>: Amortized constant time. template<class ...Args> BOOST_CONTAINER_FORCEINLINE reference emplace_back(BOOST_FWD_REF(Args)...args) { + T* const p = this->priv_raw_end(); if (BOOST_LIKELY(this->room_enough())){ //There is more memory, just construct a new object at the end - T* const p = this->priv_raw_end(); allocator_traits_type::construct(this->m_holder.alloc(), p, ::boost::forward<Args>(args)...); ++this->m_holder.m_size; 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 + (p, 1, proxy_t(::boost::forward<Args>(args)...), alloc_version()); } } //! <b>Effects</b>: Inserts an object of type T constructed with //! std::forward<Args>(args)... in the end of the vector. @@ -1799,36 +1841,36 @@ //! T's copy/move constructor/assignment throws. //! //! <b>Complexity</b>: If position is end(), amortized constant time //! Linear time otherwise. template<class ...Args> - iterator emplace(const_iterator position, BOOST_FWD_REF(Args) ...args) + BOOST_CONTAINER_FORCEINLINE iterator emplace(const_iterator position, BOOST_FWD_REF(Args) ...args) { 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) #define BOOST_CONTAINER_VECTOR_EMPLACE_CODE(N) \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_CONTAINER_FORCEINLINE reference emplace_back(BOOST_MOVE_UREF##N)\ {\ + T* const p = this->priv_raw_end();\ if (BOOST_LIKELY(this->room_enough())){\ - T* const p = this->priv_raw_end();\ allocator_traits_type::construct (this->m_holder.alloc()\ , this->priv_raw_end() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ ++this->m_holder.m_size;\ 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\ + ( p, 1, proxy_t(BOOST_MOVE_FWD##N), alloc_version());\ }\ }\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_CONTAINER_FORCEINLINE bool stable_emplace_back(BOOST_MOVE_UREF##N)\ @@ -1841,15 +1883,15 @@ }\ return is_room_enough;\ }\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ - iterator emplace(const_iterator pos BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + 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) #undef BOOST_CONTAINER_VECTOR_EMPLACE_CODE @@ -1907,15 +1949,15 @@ //! <b>Returns</b>: an iterator to the first inserted element or p if n is 0. //! //! <b>Throws</b>: If memory allocation throws or T's copy/move constructor throws. //! //! <b>Complexity</b>: Linear to n. - iterator insert(const_iterator p, size_type n, const T& x) + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, size_type n, const T& x) { 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. //! //! <b>Effects</b>: Insert a copy of the [first, last) range before pos. @@ -1947,21 +1989,26 @@ return iterator(this->m_holder.start() + n_pos); } #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) template <class FwdIt> - iterator insert(const_iterator pos, FwdIt first, FwdIt last + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator pos, FwdIt first, FwdIt last , typename dtl::disable_if_or < void , dtl::is_convertible<FwdIt, size_type> , dtl::is_input_iterator<FwdIt> >::type * = 0 ) { 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_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), static_cast<size_type>(sz), proxy); } #endif //! <b>Requires</b>: p must be a valid iterator of *this. num, must //! be equal to boost::container::iterator_distance(first, last) @@ -1978,18 +2025,18 @@ //! <b>Note</b>: This function avoids a linear operation to calculate boost::container::iterator_distance[first, last) //! for forward and bidirectional iterators, and a one by one insertion for input iterators. This is a //! a non-standard extension. #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) template <class InIt> - iterator insert(const_iterator pos, size_type num, InIt first, InIt last) + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator pos, size_type num, InIt first, InIt last) { BOOST_ASSERT(this->priv_in_range_or_end(pos)); BOOST_ASSERT(dtl::is_input_iterator<InIt>::value || 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 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) //! <b>Requires</b>: position must be a valid iterator of *this. @@ -1997,11 +2044,11 @@ //! <b>Effects</b>: Insert a copy of the [il.begin(), il.end()) range before position. //! //! <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()); } #endif @@ -2009,15 +2056,16 @@ //! <b>Effects</b>: Removes the last element from the container. //! //! <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. //! //! <b>Throws</b>: Nothing. @@ -2027,14 +2075,20 @@ iterator erase(const_iterator position) { 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); } //! <b>Effects</b>: Erases the elements pointed by [first, last). //! @@ -2042,19 +2096,23 @@ //! //! <b>Complexity</b>: Linear to the distance between first and last //! 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)); } //! <b>Effects</b>: Swaps the contents of *this and x. @@ -2100,47 +2158,48 @@ { this->priv_destroy_all(); } //! <b>Effects</b>: Returns true if x and y are equal //! //! <b>Complexity</b>: Linear to the number of elements in the container. - BOOST_CONTAINER_FORCEINLINE friend bool operator==(const vector& x, const vector& y) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE friend bool operator==(const vector& x, const vector& y) { return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); } //! <b>Effects</b>: Returns true if x and y are unequal //! //! <b>Complexity</b>: Linear to the number of elements in the container. - BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const vector& x, const vector& y) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const vector& x, const vector& y) { return !(x == y); } //! <b>Effects</b>: Returns true if x is less than y //! //! <b>Complexity</b>: Linear to the number of elements in the container. - friend bool operator<(const vector& x, const vector& y) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD friend bool operator<(const vector& x, const vector& y) { return boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } //! <b>Effects</b>: Returns true if x is greater than y //! //! <b>Complexity</b>: Linear to the number of elements in the container. - BOOST_CONTAINER_FORCEINLINE friend bool operator>(const vector& x, const vector& y) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE friend bool operator>(const vector& x, const vector& y) { return y < x; } //! <b>Effects</b>: Returns true if x is equal or less than y //! //! <b>Complexity</b>: Linear to the number of elements in the container. - BOOST_CONTAINER_FORCEINLINE friend bool operator<=(const vector& x, const vector& y) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE friend bool operator<=(const vector& x, const vector& y) { return !(y < x); } //! <b>Effects</b>: Returns true if x is equal or greater than y //! //! <b>Complexity</b>: Linear to the number of elements in the container. - BOOST_CONTAINER_FORCEINLINE friend bool operator>=(const vector& x, const vector& y) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE friend bool operator>=(const vector& x, const vector& y) { return !(x < y); } //! <b>Effects</b>: x.swap(y) //! //! <b>Complexity</b>: Constant. BOOST_CONTAINER_FORCEINLINE friend void swap(vector& x, vector& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED //! <b>Effects</b>: If n is less than or equal to capacity(), this call has no //! effect. Otherwise, it is a request for allocation of additional memory @@ -2243,18 +2302,18 @@ 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; + this->m_holder.inc_stored_size(element_count); } } else{ 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; + this->m_holder.inc_stored_size(element_count); } //Insert the new value in the already constructed range begin_ptr[pos + insertions_left - 1] = position_value.get_val(); } --insertions_left; @@ -2351,24 +2410,24 @@ size_type const old_cap = this->m_holder.capacity(); boost::container::destroy_alloc_n(a, boost::movelib::to_raw_pointer(old_p), old_size); if (old_cap > 0) { this->m_holder.deallocate(old_p, old_cap); } - this->m_holder.m_size = old_size + added; + m_holder.set_stored_size(old_size + added); this->m_holder.start(new_storage); this->m_holder.capacity(new_cap); new_buffer_deallocator.release(); new_values_destroyer.release(); } BOOST_CONTAINER_FORCEINLINE bool room_enough() const - { return this->m_holder.m_size < this->m_holder.capacity(); } + { return this->m_holder.m_size != this->m_holder.capacity(); } BOOST_CONTAINER_FORCEINLINE pointer back_ptr() const { return this->m_holder.start() + this->m_holder.m_size; } - size_type priv_index_of(pointer p) const + BOOST_CONTAINER_FORCEINLINE size_type priv_index_of(pointer p) const { BOOST_ASSERT(this->m_holder.start() <= p); BOOST_ASSERT(p <= (this->m_holder.start()+this->size())); return static_cast<size_type>(p - this->m_holder.start()); } @@ -2385,11 +2444,11 @@ T* const this_start = this->priv_raw_begin(); T* const other_start = x.priv_raw_begin(); const size_type this_sz = m_holder.m_size; const size_type other_sz = static_cast<size_type>(x.m_holder.m_size); boost::container::move_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz); - this->m_holder.m_size = other_sz; + m_holder.set_stored_size(other_sz); //Not emptying the source container seems to be confusing for users as drop-in //replacement for non-static vectors, so clear it. x.clear(); } @@ -2443,11 +2502,11 @@ T* const this_start = this->priv_raw_begin(); T* const other_start = x.priv_raw_begin(); const size_type this_sz = m_holder.m_size; const size_type other_sz = static_cast<size_type>(x.m_holder.m_size); boost::container::copy_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz); - this->m_holder.m_size = other_sz; + m_holder.set_stored_size(other_sz); } template<class OtherA> typename dtl::disable_if_or < void @@ -2467,11 +2526,11 @@ dtl::assign_alloc(this_alloc, x_alloc, flag); this->assign( x.priv_raw_begin(), x.priv_raw_end() ); } template<class Vector> //Template it to avoid it in explicit instantiations - void priv_swap(Vector &x, dtl::true_type) //version_0 + BOOST_CONTAINER_FORCEINLINE void priv_swap(Vector &x, dtl::true_type) //version_0 { this->m_holder.deep_swap(x.m_holder); } template<class Vector> //Template it to avoid it in explicit instantiations void priv_swap(Vector &x, dtl::false_type) //version_N { @@ -2504,30 +2563,33 @@ } //And now swap the allocator 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(); } - dtl::insert_range_proxy<allocator_type, boost::move_iterator<T*>, T*> priv_dummy_empty_proxy() + BOOST_CONTAINER_FORCEINLINE dtl::insert_range_proxy<allocator_type, boost::move_iterator<T*>, T*> priv_dummy_empty_proxy() { return dtl::insert_range_proxy<allocator_type, boost::move_iterator<T*>, T*> (::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. pointer const p = this->m_holder.allocate(new_cap); + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++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. bool same_buffer_start; size_type real_cap = 0; @@ -2547,112 +2609,73 @@ T * const ins_pos = this->priv_raw_end(); if(reuse){ //Backwards (and possibly forward) expansion #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()); } } } - 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); - } - this->m_holder.m_size -= n; + boost::container::destroy_alloc_n(this->get_stored_allocator(), this->priv_raw_end() - n, n); + this->m_holder.dec_stored_size(n); } template<class InpIt> void priv_uninitialized_construct_at_end(InpIt first, InpIt last) { 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.m_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 { boost::container::destroy_alloc_n (this->get_stored_allocator(), this->priv_raw_begin(), this->m_holder.m_size); this->m_holder.m_size = 0; } 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))); + return this->emplace(p, ::boost::forward<U>(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> - void priv_push_back(BOOST_FWD_REF(U) u) + BOOST_CONTAINER_FORCEINLINE void priv_push_back(BOOST_FWD_REF(U) u) { - if (BOOST_LIKELY(this->room_enough())){ - //There is more memory, just construct a new object at the end - allocator_traits_type::construct - ( this->m_holder.alloc(), this->priv_raw_end(), ::boost::forward<U>(u) ); - ++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()); - } + 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); } BOOST_CONTAINER_FORCEINLINE dtl::insert_default_initialized_n_proxy<allocator_type, T*> priv_resize_proxy(default_init_t) { return dtl::insert_default_initialized_n_proxy<allocator_type, T*>(); } 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 {} void priv_shrink_to_fit(version_1) { @@ -2664,21 +2687,11 @@ this->m_holder.deallocate(this->m_holder.m_start, cp); this->m_holder.m_start = pointer(); 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()); } } } void priv_shrink_to_fit(version_2) BOOST_NOEXCEPT_OR_NOTHROW @@ -2705,42 +2718,38 @@ } } } 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 + (T * const, 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 - (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, version_1) + BOOST_CONTAINER_NOINLINE iterator priv_insert_forward_range_no_capacity + (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 = pos - this->m_holder.start(); - T *const raw_pos = boost::movelib::to_raw_pointer(pos); + 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. T * const new_buf = boost::movelib::to_raw_pointer(this->m_holder.allocate(new_cap)); #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 - (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, version_2) + BOOST_CONTAINER_NOINLINE iterator priv_insert_forward_range_no_capacity + (T *const raw_pos, const size_type n, const InsertionProxy insert_range_proxy, version_2) { //Check if we have enough memory or try to expand current memory - T *const raw_pos = boost::movelib::to_raw_pointer(pos); const size_type n_pos = raw_pos - this->priv_raw_begin(); //There is not enough memory, allocate a new //buffer or expand the old one. size_type real_cap = this->m_holder.template next_capacity<growth_factor_type>(n); @@ -2755,74 +2764,82 @@ #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_expand_fwd; #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, dtl::bool_<dtl::is_single_value_proxy<InsertionProxy>::value>()); } //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); } } //New buffer else{ #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); } return iterator(this->m_holder.start() + n_pos); } 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); + T *const p = boost::movelib::to_raw_pointer(pos); //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 + (p, n, insert_range_proxy, dtl::bool_<dtl::is_single_value_proxy<InsertionProxy>::value>()); + 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(p, 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> + 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 //by 'shift_count'. 'limit_pos' marks the end of constructed elements. // @@ -2914,137 +2931,106 @@ { return boost::movelib::to_raw_pointer(m_holder.start()); } BOOST_CONTAINER_FORCEINLINE T* priv_raw_end() const { 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) + template <class InsertionProxy> //inline single-element version as it is significantly smaller + BOOST_CONTAINER_FORCEINLINE void priv_insert_forward_range_expand_forward + (T* const raw_pos, const size_type, InsertionProxy insert_range_proxy, dtl::true_type) { - 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) - { - //n can't be 0, because there is nothing to do in that case - if(BOOST_UNLIKELY(!n)) return; + BOOST_ASSERT(this->room_enough()); //There is enough memory T* const old_finish = this->priv_raw_end(); - const size_type elems_after = old_finish - 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; + if (old_finish == raw_pos){ + insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, 1); + ++this->m_holder.m_size; } - else if (elems_after >= n){ + else{ //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; + T * const before_old_finish = old_finish-1; + + 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 - 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, before_old_finish, old_finish); + //Insert new objects in the raw_pos + insert_range_proxy.copy_n_and_update(a, raw_pos, 1); } - 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 - } + template <class InsertionProxy> + 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) + { + //There is enough memory + 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> - 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; - //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); + allocator_type &a = this->m_holder.alloc(); + T * const raw_old_buffer = this->priv_raw_begin(); - //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); - 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); - 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); - //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); + typename value_traits::ArrayDeallocator new_buffer_deallocator(new_start, a, new_cap); + 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(); + + //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); - this->m_holder.m_size = size_type(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> - 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) { //n can be zero to just expand capacity //Backup old data 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; + 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; - //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; + 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); - this->m_holder.m_size = elemsbefore; - insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), new_elem_pos, n); - this->m_holder.m_size = before_plus_new; + ::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(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 //there is a gap between the new data and the old data if(s_before >= new_size){ //Old situation: @@ -3057,19 +3043,18 @@ //| old_begin | new | old_end | raw_mem | //|___________|__________|_________|________________________| // //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.m_size = new_size; + 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 else{ //Old situation: @@ -3082,34 +3067,33 @@ //| old_begin | new | old_end | raw_mem | //|___________|__________|_________|_________________| // //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){ + const size_type raw_gap = s_before - before_plus_new; //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); - this->m_holder.m_size = new_size; + this->m_holder.set_stored_size(new_size); //Now move remaining last objects in the old buffer begin T * const remaining_pos = pos + raw_gap; if(remaining_pos != old_start){ //Make sure data has to be moved ::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); - this->m_holder.m_size = new_size; + (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(); } } } else{ @@ -3159,12 +3143,11 @@ // _________________________________________________ //| old_begin | new | old_end | raw_mem | //|___________|_____|_________|_____________________| // //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. size_type new_1st_range; if(do_after){ @@ -3172,21 +3155,22 @@ //release destroyer and update size old_values_destroyer.release(); } 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)); } } - this->m_holder.m_size = old_size + new_1st_range; + this->m_holder.set_stored_size(old_size + new_1st_range); //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)){ //Now displace old_end elements ::boost::container::move(pos, old_finish, next + new_1st_range); @@ -3218,37 +3202,41 @@ //| old_begin | new | old_end | raw_mem | //|___________|_____|_________|__________________________| // //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); - this->m_holder.m_size = elemsbefore; + (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.m_size = old_size + s_before; + this->m_holder.set_stored_size(old_size + s_before); old_values_destroyer.release(); 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) : old_finish; + (void)move_end; //To avoid warnings of unused initialization for move_end in case + //trivial_dctr_after_move is true //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); - this->m_holder.m_size -= n_destroy; + const size_type n_destroy = s_before - n; + BOOST_IF_CONSTEXPR(!value_traits::trivial_dctr_after_move){ + boost::container::destroy_alloc_n(a, move_end, n_destroy); + } + this->m_holder.dec_stored_size(n_destroy); } } //This is only executed if two phase construction is needed if(do_after){ @@ -3286,18 +3274,17 @@ //| old_begin + new_beg | new_end |old_end | raw_mem | //|__________________________|_________|________|_________| // //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); - this->m_holder.m_size += n_after; + ::boost::container::uninitialized_move_alloc(a, finish_n, old_finish, old_finish); + this->m_holder.inc_stored_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 // //Old situation: @@ -3307,26 +3294,23 @@ // //New situation with do_after(2): // _____________________________________________________________ //| 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, 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(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); - this->m_holder.m_size += n_after; + insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, mid_last_dist); + this->m_holder.inc_stored_size(n_after); old_end_destroyer.release(); } } } }