////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Ion Gaztanaga 2005-2012. 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) // // See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// #ifndef BOOST_CONTAINER_CONTAINER_VECTOR_HPP #define BOOST_CONTAINER_CONTAINER_VECTOR_HPP #if defined(_MSC_VER) # pragma once #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace container { /// @cond //#define BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER namespace container_detail { #ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER template class vec_iterator { public: typedef std::random_access_iterator_tag iterator_category; typedef typename boost::intrusive::pointer_traits::element_type value_type; typedef typename boost::intrusive::pointer_traits::difference_type difference_type; typedef typename if_c < IsConst , typename boost::intrusive::pointer_traits::template rebind_pointer::type , Pointer >::type pointer; typedef typename if_c < IsConst , const value_type& , value_type& >::type reference; /// @cond private: Pointer m_ptr; public: const Pointer &get_ptr() const BOOST_CONTAINER_NOEXCEPT { return m_ptr; } Pointer &get_ptr() BOOST_CONTAINER_NOEXCEPT { return m_ptr; } explicit vec_iterator(Pointer ptr) BOOST_CONTAINER_NOEXCEPT : m_ptr(ptr) {} /// @endcond public: //Constructors vec_iterator() BOOST_CONTAINER_NOEXCEPT #ifndef NDEBUG : m_ptr() #else // No value initialization of m_ptr() to speed up things a bit: #endif {} vec_iterator(vec_iterator const& other) BOOST_CONTAINER_NOEXCEPT : m_ptr(other.get_ptr()) {} //Pointer like operators reference operator*() const BOOST_CONTAINER_NOEXCEPT { return *m_ptr; } pointer operator->() const BOOST_CONTAINER_NOEXCEPT { return ::boost::intrusive::pointer_traits::pointer_to(this->operator*()); } reference operator[](difference_type off) const BOOST_CONTAINER_NOEXCEPT { return m_ptr[off]; } //Increment / Decrement vec_iterator& operator++() BOOST_CONTAINER_NOEXCEPT { ++m_ptr; return *this; } vec_iterator operator++(int) BOOST_CONTAINER_NOEXCEPT { return vec_iterator(m_ptr++); } vec_iterator& operator--() BOOST_CONTAINER_NOEXCEPT { --m_ptr; return *this; } vec_iterator operator--(int) BOOST_CONTAINER_NOEXCEPT { return vec_iterator(m_ptr--); } //Arithmetic vec_iterator& operator+=(difference_type off) BOOST_CONTAINER_NOEXCEPT { m_ptr += off; return *this; } vec_iterator& operator-=(difference_type off) BOOST_CONTAINER_NOEXCEPT { m_ptr -= off; return *this; } friend vec_iterator operator+(const vec_iterator &x, difference_type off) BOOST_CONTAINER_NOEXCEPT { return vec_iterator(x.m_ptr+off); } friend vec_iterator operator+(difference_type off, vec_iterator right) BOOST_CONTAINER_NOEXCEPT { right.m_ptr += off; return right; } friend vec_iterator operator-(vec_iterator left, difference_type off) BOOST_CONTAINER_NOEXCEPT { left.m_ptr -= off; return left; } friend difference_type operator-(const vec_iterator &left, const vec_iterator& right) BOOST_CONTAINER_NOEXCEPT { return left.m_ptr - right.m_ptr; } //Comparison operators friend bool operator== (const vec_iterator& l, const vec_iterator& r) BOOST_CONTAINER_NOEXCEPT { return l.m_ptr == r.m_ptr; } friend bool operator!= (const vec_iterator& l, const vec_iterator& r) BOOST_CONTAINER_NOEXCEPT { return l.m_ptr != r.m_ptr; } friend bool operator< (const vec_iterator& l, const vec_iterator& r) BOOST_CONTAINER_NOEXCEPT { return l.m_ptr < r.m_ptr; } friend bool operator<= (const vec_iterator& l, const vec_iterator& r) BOOST_CONTAINER_NOEXCEPT { return l.m_ptr <= r.m_ptr; } friend bool operator> (const vec_iterator& l, const vec_iterator& r) BOOST_CONTAINER_NOEXCEPT { return l.m_ptr > r.m_ptr; } friend bool operator>= (const vec_iterator& l, const vec_iterator& r) BOOST_CONTAINER_NOEXCEPT { return l.m_ptr >= r.m_ptr; } }; } //namespace container_detail { template const Pointer &vector_iterator_get_ptr(const container_detail::vec_iterator &it) BOOST_CONTAINER_NOEXCEPT { return it.get_ptr(); } template Pointer &get_ptr(container_detail::vec_iterator &it) BOOST_CONTAINER_NOEXCEPT { return it.get_ptr(); } namespace container_detail { #else //ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER template< class MaybeConstPointer , bool ElementTypeIsConst = is_const< typename boost::intrusive::pointer_traits::element_type>::value > struct vector_get_ptr_pointer_to_non_const { typedef MaybeConstPointer const_pointer; typedef boost::intrusive::pointer_traits pointer_traits_t; typedef typename pointer_traits_t::element_type element_type; typedef typename remove_const::type non_const_element_type; typedef typename pointer_traits_t ::template rebind_pointer::type return_type; static return_type get_ptr(const const_pointer &ptr) BOOST_CONTAINER_NOEXCEPT { return boost::intrusive::pointer_traits::const_cast_from(ptr); } }; template struct vector_get_ptr_pointer_to_non_const { typedef const Pointer & return_type; static return_type get_ptr(const Pointer &ptr) BOOST_CONTAINER_NOEXCEPT { return ptr; } }; } //namespace container_detail { template typename container_detail::vector_get_ptr_pointer_to_non_const::return_type vector_iterator_get_ptr(const MaybeConstPointer &ptr) BOOST_CONTAINER_NOEXCEPT { return container_detail::vector_get_ptr_pointer_to_non_const::get_ptr(ptr); } namespace container_detail { #endif //#ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER template struct vector_value_traits { typedef T value_type; typedef Allocator allocator_type; static const bool trivial_dctr = boost::has_trivial_destructor::value; static const bool trivial_dctr_after_move = ::boost::has_trivial_destructor_after_move::value; static const bool trivial_copy = has_trivial_copy::value; static const bool nothrow_copy = has_nothrow_copy::value || trivial_copy; static const bool trivial_assign = has_trivial_assign::value; static const bool nothrow_assign = has_nothrow_assign::value || trivial_assign; //This is the anti-exception array destructor //to deallocate values already constructed typedef typename container_detail::if_c ,container_detail::scoped_destructor_n >::type OldArrayDestructor; //This is the anti-exception array destructor //to destroy objects created with copy construction typedef typename container_detail::if_c ,container_detail::scoped_destructor_n >::type ArrayDestructor; //This is the anti-exception array deallocator typedef typename container_detail::if_c ,container_detail::scoped_array_deallocator >::type ArrayDeallocator; }; //!This struct deallocates and allocated memory template < class Allocator , class AllocatorVersion = container_detail::integral_constant < unsigned , boost::container::container_detail::version::value > > struct vector_alloc_holder : public Allocator { private: BOOST_MOVABLE_BUT_NOT_COPYABLE(vector_alloc_holder) public: typedef boost::container::allocator_traits 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; //Constructor, does not throw vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor::value) : Allocator(), m_start(), m_size(), m_capacity() {} //Constructor, does not throw template explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT : Allocator(boost::forward(a)), m_start(), m_size(), m_capacity() {} //Constructor, does not throw template explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type initial_size) : Allocator(boost::forward(a)) , m_start() , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this , m_capacity() { if(initial_size){ m_start = this->allocation_command(allocate_new, initial_size, initial_size, m_capacity, m_start).first; } } //Constructor, does not throw explicit vector_alloc_holder(size_type initial_size) : Allocator() , m_start() , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this , m_capacity() { if(initial_size){ m_start = this->allocation_command (allocate_new, initial_size, initial_size, m_capacity, m_start).first; } } vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) BOOST_CONTAINER_NOEXCEPT : Allocator(boost::move(static_cast(holder))) , m_start(holder.m_start) , m_size(holder.m_size) , m_capacity(holder.m_capacity) { holder.m_start = pointer(); holder.m_size = holder.m_capacity = 0; } void first_allocation(size_type cap) { if(cap){ m_start = this->allocation_command (allocate_new, cap, cap, m_capacity, m_start).first; } } void first_allocation_same_allocator_type(size_type cap) { this->first_allocation(cap); } ~vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT { if(this->m_capacity){ this->alloc().deallocate(this->m_start, this->m_capacity); } } std::pair allocation_command(allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = pointer()) { return allocator_version_traits::allocation_command (this->alloc(), command, limit_size, preferred_size, received_size, reuse); } size_type next_capacity(size_type additional_objects) const { std::size_t num_objects = this->m_size + additional_objects; std::size_t next_cap = this->m_capacity + this->m_capacity/2; return num_objects > next_cap ? num_objects : next_cap;/* return get_next_capacity( allocator_traits_type::max_size(this->m_holder.alloc()) , this->m_capacity, additional_objects);*/ } pointer m_start; size_type m_size; size_type m_capacity; void swap(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT { boost::container::swap_dispatch(this->m_start, x.m_start); boost::container::swap_dispatch(this->m_size, x.m_size); boost::container::swap_dispatch(this->m_capacity, x.m_capacity); } void move_from_empty(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT { this->m_start = x.m_start; this->m_size = x.m_size; this->m_capacity = x.m_capacity; x.m_start = pointer(); x.m_size = x.m_capacity = 0; } Allocator &alloc() BOOST_CONTAINER_NOEXCEPT { return *this; } const Allocator &alloc() const BOOST_CONTAINER_NOEXCEPT { return *this; } const pointer &start() const BOOST_CONTAINER_NOEXCEPT { return m_start; } const size_type &capacity() const BOOST_CONTAINER_NOEXCEPT { return m_capacity; } void start(const pointer &p) BOOST_CONTAINER_NOEXCEPT { m_start = p; } void capacity(const size_type &c) BOOST_CONTAINER_NOEXCEPT { m_capacity = c; } }; //!This struct deallocates and allocated memory template struct vector_alloc_holder > : public Allocator { private: BOOST_MOVABLE_BUT_NOT_COPYABLE(vector_alloc_holder) public: typedef boost::container::allocator_traits 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; template friend struct vector_alloc_holder; //Constructor, does not throw vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor::value) : Allocator(), m_size() {} //Constructor, does not throw template explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT : Allocator(boost::forward(a)), m_size() {} //Constructor, does not throw template explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type initial_size) : Allocator(boost::forward(a)) , m_size(initial_size) //Size is initialized here... { //... and capacity here, so vector, must call uninitialized_xxx in the derived constructor this->first_allocation(initial_size); } //Constructor, does not throw explicit vector_alloc_holder(size_type initial_size) : Allocator() , m_size(initial_size) //Size is initialized here... { //... and capacity here, so vector, must call uninitialized_xxx in the derived constructor this->first_allocation(initial_size); } vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) : Allocator(boost::move(static_cast(holder))) , m_size(holder.m_size) //Size is initialized here so vector should only call uninitialized_xxx after this { ::boost::container::uninitialized_move_alloc_n (this->alloc(), container_detail::to_raw_pointer(holder.start()), m_size, container_detail::to_raw_pointer(this->start())); } template vector_alloc_holder(BOOST_RV_REF_BEG vector_alloc_holder BOOST_RV_REF_END holder) : Allocator() , m_size(holder.m_size) //Initialize it to m_size as first_allocation can only succeed or abort { //Different allocator type so we must check we have enough storage const size_type n = holder.m_size; this->first_allocation(n); ::boost::container::uninitialized_move_alloc_n (this->alloc(), container_detail::to_raw_pointer(holder.start()), n, container_detail::to_raw_pointer(this->start())); } void first_allocation(size_type cap) { if(cap > Allocator::internal_capacity){ throw_bad_alloc(); } } void first_allocation_same_allocator_type(size_type) BOOST_CONTAINER_NOEXCEPT {} //Destructor ~vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT {} void swap(vector_alloc_holder &x) { this->priv_swap_members_impl(x); } template void swap(vector_alloc_holder &x) { if(this->m_size > OtherAllocator::internal_capacity || x.m_size > Allocator::internal_capacity){ throw_bad_alloc(); } this->priv_swap_members_impl(x); } void move_from_empty(vector_alloc_holder &) { //Containers with version 0 allocators can't be moved without move elements one by one throw_bad_alloc(); } Allocator &alloc() BOOST_CONTAINER_NOEXCEPT { return *this; } const Allocator &alloc() const BOOST_CONTAINER_NOEXCEPT { return *this; } pointer start() const BOOST_CONTAINER_NOEXCEPT { return Allocator::internal_storage(); } size_type capacity() const BOOST_CONTAINER_NOEXCEPT { return Allocator::internal_capacity; } size_type m_size; private: template void priv_swap_members_impl(vector_alloc_holder &x) { const std::size_t MaxTmpStorage = sizeof(value_type)*Allocator::internal_capacity; value_type *const first_this = container_detail::to_raw_pointer(this->start()); value_type *const first_x = container_detail::to_raw_pointer(x.start()); if(this->m_size < x.m_size){ boost::container::deep_swap_alloc_n(this->alloc(), first_this, this->m_size, first_x, x.m_size); } else{ boost::container::deep_swap_alloc_n(this->alloc(), first_x, x.m_size, first_this, this->m_size); } boost::container::swap_dispatch(this->m_size, x.m_size); } }; } //namespace container_detail { /// @endcond //! \class vector //! A vector is a sequence that supports random access to elements, constant //! time insertion and removal of elements at the end, and linear time insertion //! and removal of elements at the beginning or in the middle. The number of //! elements in a vector may vary dynamically; memory management is automatic. //! boost::container::vector is similar to std::vector but it's compatible //! with shared memory and memory mapped files. #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED template > #else template #endif class vector { /// @cond typedef container_detail::integral_constant ::value > alloc_version; boost::container::container_detail::vector_alloc_holder m_holder; typedef allocator_traits allocator_traits_type; template friend class vector; typedef typename ::boost::container::allocator_traits ::pointer pointer_impl; typedef container_detail::vec_iterator iterator_impl; typedef container_detail::vec_iterator const_iterator_impl; /// @endcond public: ////////////////////////////////////////////// // // types // ////////////////////////////////////////////// typedef T value_type; typedef typename ::boost::container::allocator_traits::pointer pointer; typedef typename ::boost::container::allocator_traits::const_pointer const_pointer; typedef typename ::boost::container::allocator_traits::reference reference; typedef typename ::boost::container::allocator_traits::const_reference const_reference; typedef typename ::boost::container::allocator_traits::size_type size_type; typedef typename ::boost::container::allocator_traits::difference_type difference_type; typedef Allocator allocator_type; typedef Allocator stored_allocator_type; #if defined BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER && !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) typedef BOOST_CONTAINER_IMPDEF(pointer) iterator; typedef BOOST_CONTAINER_IMPDEF(const_pointer) const_iterator; #else typedef BOOST_CONTAINER_IMPDEF(iterator_impl) iterator; typedef BOOST_CONTAINER_IMPDEF(const_iterator_impl) const_iterator; #endif typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator) reverse_iterator; typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator) const_reverse_iterator; /// @cond private: BOOST_COPYABLE_AND_MOVABLE(vector) typedef container_detail::vector_value_traits value_traits; typedef container_detail::integral_constant allocator_v0; typedef container_detail::integral_constant allocator_v1; typedef container_detail::integral_constant allocator_v2; typedef constant_iterator cvalue_iterator; /// @endcond public: ////////////////////////////////////////////// // // construct/copy/destroy // ////////////////////////////////////////////// //! Effects: Constructs a vector taking the allocator as parameter. //! //! Throws: If allocator_type's default constructor throws. //! //! Complexity: Constant. vector() BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor::value) : m_holder() {} //! Effects: Constructs a vector taking the allocator as parameter. //! //! Throws: Nothing //! //! Complexity: Constant. explicit vector(const Allocator& a) BOOST_CONTAINER_NOEXCEPT : m_holder(a) {} //! Effects: Constructs a vector that will use a copy of allocator a //! and inserts n value initialized values. //! //! Throws: If allocator_type's default constructor or allocation //! throws or T's default constructor throws. //! //! Complexity: Linear to n. explicit vector(size_type n) : m_holder(n) { boost::container::uninitialized_value_init_alloc_n (this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Constructs a vector that will use a copy of allocator a //! and inserts n default initialized values. //! //! Throws: If allocator_type's default constructor or allocation //! throws or T's default constructor throws. //! //! Complexity: Linear to n. //! //! Note: Non-standard extension explicit vector(size_type n, default_init_t) : m_holder(n) { boost::container::uninitialized_default_init_alloc_n (this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Constructs a vector //! and inserts n copies of value. //! //! Throws: If allocator_type's default constructor or allocation //! throws or T's copy constructor throws. //! //! Complexity: Linear to n. vector(size_type n, const T& value) : m_holder(n) { boost::container::uninitialized_fill_alloc_n (this->m_holder.alloc(), value, n, container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Constructs a vector that will use a copy of allocator a //! and inserts n copies of value. //! //! Throws: If allocation //! throws or T's copy constructor throws. //! //! Complexity: Linear to n. vector(size_type n, const T& value, const allocator_type& a) : m_holder(a, n) { boost::container::uninitialized_fill_alloc_n (this->m_holder.alloc(), value, n, container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Constructs a vector //! and inserts a copy of the range [first, last) in the vector. //! //! Throws: If allocator_type's default constructor or allocation //! throws or T's constructor taking an dereferenced InIt throws. //! //! Complexity: Linear to the range [first, last). template vector(InIt first, InIt last) : m_holder() { this->insert(this->cend(), first, last); } //! Effects: Constructs a vector that will use a copy of allocator a //! and inserts a copy of the range [first, last) in the vector. //! //! Throws: If allocator_type's default constructor or allocation //! throws or T's constructor taking an dereferenced InIt throws. //! //! Complexity: Linear to the range [first, last). template vector(InIt first, InIt last, const allocator_type& a) : m_holder(a) { this->insert(this->cend(), first, last); } //! Effects: Copy constructs a vector. //! //! Postcondition: x == *this. //! //! Throws: If allocator_type's default constructor or allocation //! throws or T's copy constructor throws. //! //! Complexity: Linear to the elements x contains. vector(const vector &x) : m_holder(allocator_traits_type::select_on_container_copy_construction(x.m_holder.alloc()), x.size()) { ::boost::container::uninitialized_copy_alloc_n ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start()) , x.size(), container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Move constructor. Moves mx's resources to *this. //! //! Throws: Nothing //! //! Complexity: Constant. vector(BOOST_RV_REF(vector) mx) BOOST_CONTAINER_NOEXCEPT : m_holder(boost::move(mx.m_holder)) {} #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Move constructor. Moves mx's resources to *this. //! //! Throws: If T's move constructor or allocation throws //! //! Complexity: Linear. //! //! Note: Non-standard extension template vector(BOOST_RV_REF_BEG vector BOOST_RV_REF_END mx) : m_holder(boost::move(mx.m_holder)) {} #endif //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Copy constructs a vector using the specified allocator. //! //! Postcondition: x == *this. //! //! Throws: If allocation //! throws or T's copy constructor throws. //! //! Complexity: Linear to the elements x contains. vector(const vector &x, const allocator_type &a) : m_holder(a, x.size()) { ::boost::container::uninitialized_copy_alloc_n_source ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start()) , x.size(), container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Move constructor using the specified allocator. //! Moves mx's resources to *this if a == allocator_type(). //! Otherwise copies values from x to *this. //! //! Throws: If allocation or T's copy constructor throws. //! //! Complexity: Constant if a == mx.get_allocator(), linear otherwise. vector(BOOST_RV_REF(vector) mx, const allocator_type &a) : m_holder(a) { if(mx.m_holder.alloc() == a){ this->m_holder.move_from_empty(mx.m_holder); } else{ const size_type n = mx.size(); this->m_holder.first_allocation_same_allocator_type(n); ::boost::container::uninitialized_move_alloc_n_source ( this->m_holder.alloc(), container_detail::to_raw_pointer(mx.m_holder.start()) , n, container_detail::to_raw_pointer(this->m_holder.start())); this->m_holder.m_size = n; } } //! Effects: Destroys the vector. All stored values are destroyed //! and used memory is deallocated. //! //! Throws: Nothing. //! //! Complexity: Linear to the number of elements. ~vector() BOOST_CONTAINER_NOEXCEPT { boost::container::destroy_alloc_n (this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size); //vector_alloc_holder deallocates the data } //! Effects: Makes *this contain the same elements as x. //! //! Postcondition: this->size() == x.size(). *this contains a copy //! of each of x's elements. //! //! Throws: If memory allocation throws or T's copy/move constructor/assignment throws. //! //! Complexity: Linear to the number of elements in x. vector& operator=(BOOST_COPY_ASSIGN_REF(vector) x) { if (&x != this){ this->priv_copy_assign(boost::move(x), alloc_version()); } return *this; } //! Effects: Move assignment. All mx's values are transferred to *this. //! //! Postcondition: x.empty(). *this contains a the elements x had //! before the function. //! //! Throws: Nothing //! //! Complexity: Linear. vector& operator=(BOOST_RV_REF(vector) x) //iG BOOST_CONTAINER_NOEXCEPT_IF(!allocator_type::propagate_on_container_move_assignment::value || is_nothrow_move_assignable::value);) BOOST_CONTAINER_NOEXCEPT { this->priv_move_assign(boost::move(x), alloc_version()); return *this; } #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Move assignment. All mx's values are transferred to *this. //! //! Postcondition: x.empty(). *this contains a the elements x had //! before the function. //! //! Throws: If move constructor/assignment of T throws or allocation throws //! //! Complexity: Linear. template vector& operator=(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x) { this->priv_move_assign(boost::move(x), alloc_version()); return *this; } #endif //! Effects: Assigns the the range [first, last) to *this. //! //! Throws: If memory allocation throws or T's copy/move constructor/assignment or //! T's constructor/assignment from dereferencing InpIt throws. //! //! Complexity: Linear to n. template void assign(InIt first, InIt last #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) , typename container_detail::enable_if_c < !container_detail::is_convertible::value //&& container_detail::is_input_iterator::value >::type * = 0 #endif ) { //Overwrite all elements we can from [first, last) iterator cur = this->begin(); const iterator end_it = this->end(); for ( ; first != last && cur != end_it; ++cur, ++first){ *cur = *first; } if (first == last){ //There are no more elements in the sequence, erase remaining T* const end_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; size_type n = static_cast(end_pos - container_detail::to_raw_pointer(vector_iterator_get_ptr(cur))); this->priv_destroy_last_n(n); } else{ //There are more elements in the range, insert the remaining ones this->insert(this->cend(), first, last); } } //! Effects: Assigns the n copies of val to *this. //! //! Throws: If memory allocation throws or //! T's copy/move constructor/assignment throws. //! //! Complexity: Linear to n. void assign(size_type n, const value_type& val) { this->assign(cvalue_iterator(val, n), cvalue_iterator()); } //! Effects: Returns a copy of the internal allocator. //! //! Throws: If allocator's copy constructor throws. //! //! Complexity: Constant. allocator_type get_allocator() const BOOST_CONTAINER_NOEXCEPT { return this->m_holder.alloc(); } //! Effects: Returns a reference to the internal allocator. //! //! Throws: Nothing //! //! Complexity: Constant. //! //! Note: Non-standard extension. stored_allocator_type &get_stored_allocator() BOOST_CONTAINER_NOEXCEPT { return this->m_holder.alloc(); } //! Effects: Returns a reference to the internal allocator. //! //! Throws: Nothing //! //! Complexity: Constant. //! //! Note: Non-standard extension. const stored_allocator_type &get_stored_allocator() const BOOST_CONTAINER_NOEXCEPT { return this->m_holder.alloc(); } ////////////////////////////////////////////// // // iterators // ////////////////////////////////////////////// //! Effects: Returns an iterator to the first element contained in the vector. //! //! Throws: Nothing. //! //! Complexity: Constant. iterator begin() BOOST_CONTAINER_NOEXCEPT { return iterator(this->m_holder.start()); } //! Effects: Returns a const_iterator to the first element contained in the vector. //! //! Throws: Nothing. //! //! Complexity: Constant. const_iterator begin() const BOOST_CONTAINER_NOEXCEPT { return const_iterator(this->m_holder.start()); } //! Effects: Returns an iterator to the end of the vector. //! //! Throws: Nothing. //! //! Complexity: Constant. iterator end() BOOST_CONTAINER_NOEXCEPT { return iterator(this->m_holder.start() + this->m_holder.m_size); } //! Effects: Returns a const_iterator to the end of the vector. //! //! Throws: Nothing. //! //! Complexity: Constant. const_iterator end() const BOOST_CONTAINER_NOEXCEPT { return this->cend(); } //! Effects: Returns a reverse_iterator pointing to the beginning //! of the reversed vector. //! //! Throws: Nothing. //! //! Complexity: Constant. reverse_iterator rbegin() BOOST_CONTAINER_NOEXCEPT { return reverse_iterator(this->end()); } //! Effects: Returns a const_reverse_iterator pointing to the beginning //! of the reversed vector. //! //! Throws: Nothing. //! //! Complexity: Constant. const_reverse_iterator rbegin() const BOOST_CONTAINER_NOEXCEPT { return this->crbegin(); } //! Effects: Returns a reverse_iterator pointing to the end //! of the reversed vector. //! //! Throws: Nothing. //! //! Complexity: Constant. reverse_iterator rend() BOOST_CONTAINER_NOEXCEPT { return reverse_iterator(this->begin()); } //! Effects: Returns a const_reverse_iterator pointing to the end //! of the reversed vector. //! //! Throws: Nothing. //! //! Complexity: Constant. const_reverse_iterator rend() const BOOST_CONTAINER_NOEXCEPT { return this->crend(); } //! Effects: Returns a const_iterator to the first element contained in the vector. //! //! Throws: Nothing. //! //! Complexity: Constant. const_iterator cbegin() const BOOST_CONTAINER_NOEXCEPT { return const_iterator(this->m_holder.start()); } //! Effects: Returns a const_iterator to the end of the vector. //! //! Throws: Nothing. //! //! Complexity: Constant. const_iterator cend() const BOOST_CONTAINER_NOEXCEPT { return const_iterator(this->m_holder.start() + this->m_holder.m_size); } //! Effects: Returns a const_reverse_iterator pointing to the beginning //! of the reversed vector. //! //! Throws: Nothing. //! //! Complexity: Constant. const_reverse_iterator crbegin() const BOOST_CONTAINER_NOEXCEPT { return const_reverse_iterator(this->end());} //! Effects: Returns a const_reverse_iterator pointing to the end //! of the reversed vector. //! //! Throws: Nothing. //! //! Complexity: Constant. const_reverse_iterator crend() const BOOST_CONTAINER_NOEXCEPT { return const_reverse_iterator(this->begin()); } ////////////////////////////////////////////// // // capacity // ////////////////////////////////////////////// //! Effects: Returns true if the vector contains no elements. //! //! Throws: Nothing. //! //! Complexity: Constant. bool empty() const BOOST_CONTAINER_NOEXCEPT { return !this->m_holder.m_size; } //! Effects: Returns the number of the elements contained in the vector. //! //! Throws: Nothing. //! //! Complexity: Constant. size_type size() const BOOST_CONTAINER_NOEXCEPT { return this->m_holder.m_size; } //! Effects: Returns the largest possible size of the vector. //! //! Throws: Nothing. //! //! Complexity: Constant. size_type max_size() const BOOST_CONTAINER_NOEXCEPT { return allocator_traits_type::max_size(this->m_holder.alloc()); } //! Effects: Inserts or erases elements at the end such that //! the size becomes n. New elements are value initialized. //! //! Throws: If memory allocation throws, or T's constructor throws. //! //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size) { 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(); container_detail::insert_value_initialized_n_proxy proxy(this->m_holder.alloc()); this->priv_forward_range_insert_at_end(n, proxy, alloc_version()); } } //! Effects: Inserts or erases elements at the end such that //! the size becomes n. New elements are value initialized. //! //! Throws: If memory allocation throws, or T's constructor throws. //! //! Complexity: Linear to the difference between size() and new_size. //! //! Note: Non-standard extension void resize(size_type new_size, default_init_t) { 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(); container_detail::insert_default_initialized_n_proxy proxy(this->m_holder.alloc()); this->priv_forward_range_insert_at_end(n, proxy, alloc_version()); } } //! Effects: Inserts or erases elements at the end such that //! the size becomes n. New elements are copy constructed from x. //! //! Throws: If memory allocation throws, or T's copy constructor throws. //! //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size, const T& x) { 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(); container_detail::insert_n_copies_proxy proxy(this->m_holder.alloc(), x); this->priv_forward_range_insert_at_end(n, proxy, alloc_version()); } } //! Effects: Number of elements for which memory has been allocated. //! capacity() is always greater than or equal to size(). //! //! Throws: Nothing. //! //! Complexity: Constant. size_type capacity() const BOOST_CONTAINER_NOEXCEPT { return this->m_holder.capacity(); } //! Effects: 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 //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. //! //! Throws: If memory allocation allocation throws or T's copy/move constructor throws. void reserve(size_type new_cap) { if (this->capacity() < new_cap){ this->priv_reserve(new_cap, alloc_version()); } } //! Effects: Tries to deallocate the excess of memory created //! with previous allocations. The size of the vector is unchanged //! //! Throws: If memory allocation throws, or T's copy/move constructor throws. //! //! Complexity: Linear to size(). void shrink_to_fit() { this->priv_shrink_to_fit(alloc_version()); } ////////////////////////////////////////////// // // element access // ////////////////////////////////////////////// //! Requires: !empty() //! //! Effects: Returns a reference to the first //! element of the container. //! //! Throws: Nothing. //! //! Complexity: Constant. reference front() BOOST_CONTAINER_NOEXCEPT { return *this->m_holder.start(); } //! Requires: !empty() //! //! Effects: Returns a const reference to the first //! element of the container. //! //! Throws: Nothing. //! //! Complexity: Constant. const_reference front() const BOOST_CONTAINER_NOEXCEPT { return *this->m_holder.start(); } //! Requires: !empty() //! //! Effects: Returns a reference to the last //! element of the container. //! //! Throws: Nothing. //! //! Complexity: Constant. reference back() BOOST_CONTAINER_NOEXCEPT { return this->m_holder.start()[this->m_holder.m_size - 1]; } //! Requires: !empty() //! //! Effects: Returns a const reference to the last //! element of the container. //! //! Throws: Nothing. //! //! Complexity: Constant. const_reference back() const BOOST_CONTAINER_NOEXCEPT { return this->m_holder.start()[this->m_holder.m_size - 1]; } //! Requires: size() > n. //! //! Effects: Returns a reference to the nth element //! from the beginning of the container. //! //! Throws: Nothing. //! //! Complexity: Constant. reference operator[](size_type n) BOOST_CONTAINER_NOEXCEPT { return this->m_holder.start()[n]; } //! Requires: size() > n. //! //! Effects: Returns a const reference to the nth element //! from the beginning of the container. //! //! Throws: Nothing. //! //! Complexity: Constant. const_reference operator[](size_type n) const BOOST_CONTAINER_NOEXCEPT { return this->m_holder.start()[n]; } //! Requires: size() > n. //! //! Effects: Returns a reference to the nth element //! from the beginning of the container. //! //! Throws: std::range_error if n >= size() //! //! Complexity: Constant. reference at(size_type n) { this->priv_check_range(n); return this->m_holder.start()[n]; } //! Requires: size() > n. //! //! Effects: Returns a const reference to the nth element //! from the beginning of the container. //! //! Throws: std::range_error if n >= size() //! //! Complexity: Constant. const_reference at(size_type n) const { this->priv_check_range(n); return this->m_holder.start()[n]; } ////////////////////////////////////////////// // // data access // ////////////////////////////////////////////// //! Returns: Allocator pointer such that [data(),data() + size()) is a valid range. //! For a non-empty vector, data() == &front(). //! //! Throws: Nothing. //! //! Complexity: Constant. T* data() BOOST_CONTAINER_NOEXCEPT { return container_detail::to_raw_pointer(this->m_holder.start()); } //! Returns: Allocator pointer such that [data(),data() + size()) is a valid range. //! For a non-empty vector, data() == &front(). //! //! Throws: Nothing. //! //! Complexity: Constant. const T * data() const BOOST_CONTAINER_NOEXCEPT { return container_detail::to_raw_pointer(this->m_holder.start()); } ////////////////////////////////////////////// // // modifiers // ////////////////////////////////////////////// #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Inserts an object of type T constructed with //! std::forward(args)... in the end of the vector. //! //! Throws: If memory allocation throws or the in-place constructor throws or //! T's move constructor throws. //! //! Complexity: Amortized constant time. template void emplace_back(Args &&...args) { T* back_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; if (this->m_holder.m_size < this->m_holder.capacity()){ //There is more memory, just construct a new object at the end allocator_traits_type::construct(this->m_holder.alloc(), back_pos, ::boost::forward(args)...); ++this->m_holder.m_size; } else{ typedef container_detail::insert_emplace_proxy type; this->priv_forward_range_insert_no_capacity (vector_iterator_get_ptr(this->cend()), 1, type(this->m_holder.alloc(), ::boost::forward(args)...), alloc_version()); } } //! Requires: position must be a valid iterator of *this. //! //! Effects: Inserts an object of type T constructed with //! std::forward(args)... before position //! //! Throws: If memory allocation throws or the in-place constructor throws or //! T's move constructor/assignment throws. //! //! Complexity: If position is end(), amortized constant time //! Linear time otherwise. template iterator emplace(const_iterator position, Args && ...args) { //Just call more general insert(pos, size, value) and return iterator typedef container_detail::insert_emplace_proxy type; return this->priv_forward_range_insert( vector_iterator_get_ptr(position), 1, type(this->m_holder.alloc() , ::boost::forward(args)...), alloc_version()); } #else #define BOOST_PP_LOCAL_MACRO(n) \ BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ T* back_pos = container_detail::to_raw_pointer \ (this->m_holder.start()) + this->m_holder.m_size; \ if (this->m_holder.m_size < this->m_holder.capacity()){ \ allocator_traits_type::construct (this->m_holder.alloc() \ , back_pos BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ ++this->m_holder.m_size; \ } \ else{ \ container_detail::BOOST_PP_CAT(insert_emplace_proxy_arg, n) \ proxy \ (this->m_holder.alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ this->priv_forward_range_insert_no_capacity \ (vector_iterator_get_ptr(this->cend()), 1, proxy, alloc_version()); \ } \ } \ \ BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ iterator emplace(const_iterator pos \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ container_detail::BOOST_PP_CAT(insert_emplace_proxy_arg, n) \ proxy \ (this->m_holder.alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ return this->priv_forward_range_insert \ (container_detail::to_raw_pointer(vector_iterator_get_ptr(pos)), 1, proxy, alloc_version()); \ } \ //! #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Inserts a copy of x at the end of the vector. //! //! Throws: If memory allocation throws or //! T's copy/move constructor throws. //! //! Complexity: Amortized constant time. void push_back(const T &x); //! Effects: Constructs a new element in the end of the vector //! and moves the resources of mx to this new element. //! //! Throws: If memory allocation throws or //! T's move constructor throws. //! //! Complexity: Amortized constant time. void push_back(T &&x); #else BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) #endif #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Requires: position must be a valid iterator of *this. //! //! Effects: Insert a copy of x before position. //! //! Throws: If memory allocation throws or T's copy/move constructor/assignment throws. //! //! Complexity: If position is end(), amortized constant time //! Linear time otherwise. iterator insert(const_iterator position, const T &x); //! Requires: position must be a valid iterator of *this. //! //! Effects: Insert a new element before position with mx's resources. //! //! Throws: If memory allocation throws. //! //! Complexity: If position is end(), amortized constant time //! Linear time otherwise. iterator insert(const_iterator position, T &&x); #else BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator, const_iterator) #endif //! Requires: p must be a valid iterator of *this. //! //! Effects: Insert n copies of x before pos. //! //! Returns: an iterator to the first inserted element or p if n is 0. //! //! Throws: If memory allocation throws or T's copy constructor throws. //! //! Complexity: Linear to n. iterator insert(const_iterator p, size_type n, const T& x) { container_detail::insert_n_copies_proxy proxy(this->m_holder.alloc(), x); return this->priv_forward_range_insert(vector_iterator_get_ptr(p), n, proxy, alloc_version()); } //! Requires: p must be a valid iterator of *this. //! //! Effects: Insert a copy of the [first, last) range before pos. //! //! Returns: an iterator to the first inserted element or pos if first == last. //! //! Throws: If memory allocation throws, T's constructor from a //! dereferenced InpIt throws or T's copy/move constructor/assignment throws. //! //! Complexity: Linear to std::distance [first, last). template iterator insert(const_iterator pos, InIt first, InIt last #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) , typename container_detail::enable_if_c < !container_detail::is_convertible::value && container_detail::is_input_iterator::value >::type * = 0 #endif ) { const size_type n_pos = pos - this->cbegin(); iterator it(vector_iterator_get_ptr(pos)); for(;first != last; ++first){ it = this->emplace(it, *first); ++it; } return iterator(this->m_holder.start() + n_pos); } #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) template iterator insert(const_iterator pos, FwdIt first, FwdIt last , typename container_detail::enable_if_c < !container_detail::is_convertible::value && !container_detail::is_input_iterator::value >::type * = 0 ) { container_detail::insert_range_proxy proxy(this->m_holder.alloc(), first); return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), std::distance(first, last), proxy, alloc_version()); } #endif //! Effects: Removes the last element from the vector. //! //! Throws: Nothing. //! //! Complexity: Constant time. void pop_back() BOOST_CONTAINER_NOEXCEPT { //Destroy last element --this->m_holder.m_size; this->priv_destroy(container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size); } //! Effects: Erases the element at position pos. //! //! Throws: Nothing. //! //! Complexity: Linear to the elements between pos and the //! last element. Constant if pos is the last element. iterator erase(const_iterator position) { T *const pos = container_detail::to_raw_pointer(vector_iterator_get_ptr(position)); T *const beg = container_detail::to_raw_pointer(this->m_holder.start()); //Move elements forward and destroy last this->priv_destroy(::boost::move(pos + 1, beg + this->m_holder.m_size, pos)); --this->m_holder.m_size; return iterator(vector_iterator_get_ptr(position)); } //! Effects: Erases the elements pointed by [first, last). //! //! Throws: Nothing. //! //! Complexity: 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){ T* const end_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; T* const ptr = container_detail::to_raw_pointer(boost::move (container_detail::to_raw_pointer(vector_iterator_get_ptr(last)) ,end_pos ,container_detail::to_raw_pointer(vector_iterator_get_ptr(first)) )); const size_type destroyed = (end_pos - ptr); boost::container::destroy_alloc_n(this->get_stored_allocator(), ptr, destroyed); this->m_holder.m_size -= destroyed; } return iterator(vector_iterator_get_ptr(first)); } //! Effects: Swaps the contents of *this and x. //! //! Throws: Nothing. //! //! Complexity: Constant. void swap(vector& x) BOOST_CONTAINER_NOEXCEPT_IF((!container_detail::is_same::value)) { //Just swap internals in case of !allocator_v0. Otherwise, deep swap this->m_holder.swap(x.m_holder); //And now the allocator container_detail::bool_ flag; container_detail::swap_alloc(this->m_holder.alloc(), x.m_holder.alloc(), flag); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED //! Effects: Swaps the contents of *this and x. //! //! Throws: If T's move constructor throws. //! //! Complexity: Linear //! //! Note: non-standard extension. template void swap(vector & x) { this->m_holder.swap(x.m_holder); } #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED //! Effects: Erases all the elements of the vector. //! //! Throws: Nothing. //! //! Complexity: Linear to the number of elements in the vector. void clear() BOOST_CONTAINER_NOEXCEPT { this->priv_destroy_all(); } /// @cond //Absolutely experimental. This function might change, disappear or simply crash! template void insert_ordered_at(size_type element_count, BiDirPosConstIt last_position_it, BiDirValueIt last_value_it) { const size_type *dummy = 0; this->priv_insert_ordered_at(element_count, last_position_it, false, &dummy[0], last_value_it); } //Absolutely experimental. This function might change, disappear or simply crash! template void insert_ordered_at(size_type element_count, BiDirPosConstIt last_position_it, BiDirSkipConstIt last_skip_it, BiDirValueIt last_value_it) { this->priv_insert_ordered_at(element_count, last_position_it, true, last_skip_it, last_value_it); } private: template void priv_move_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x , AllocVersion , typename container_detail::enable_if_c < container_detail::is_same::value && !container_detail::is_same::value >::type * = 0) { if(this->capacity() < x.size()){ throw_bad_alloc(); } this->priv_move_assign_impl(boost::move(x), AllocVersion()); } template void priv_move_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x , AllocVersion , typename container_detail::enable_if_c < !container_detail::is_same::value || container_detail::is_same::value >::type * = 0) { this->priv_move_assign_impl(boost::move(x), AllocVersion()); } template void priv_move_assign_impl(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x , AllocVersion , typename container_detail::enable_if_c < container_detail::is_same::value >::type * = 0) { T* const this_start = container_detail::to_raw_pointer(m_holder.start()); T* const other_start = container_detail::to_raw_pointer(x.m_holder.start()); const size_type this_sz = m_holder.m_size; const size_type other_sz = static_cast(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; } template void priv_move_assign_impl(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x , AllocVersion , typename container_detail::enable_if_c < !container_detail::is_same::value >::type * = 0) { //for move constructor, no aliasing (&x != this) is assummed. allocator_type &this_alloc = this->m_holder.alloc(); allocator_type &x_alloc = x.m_holder.alloc(); //If allocators are equal we can just swap pointers if(this_alloc == x_alloc){ //Destroy objects but retain memory in case x reuses it in the future this->clear(); this->m_holder.swap(x.m_holder); //Move allocator if needed container_detail::bool_ flag; container_detail::move_alloc(this_alloc, x_alloc, flag); } //If unequal allocators, then do a one by one move else{ //TO-DO: optimize this this->assign( boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start())) , boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size))); } } template void priv_copy_assign(const vector &x, AllocVersion , typename container_detail::enable_if_c < container_detail::is_same::value >::type * = 0) { T* const this_start = container_detail::to_raw_pointer(m_holder.start()); T* const other_start = container_detail::to_raw_pointer(x.m_holder.start()); const size_type this_sz = m_holder.m_size; const size_type other_sz = static_cast(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; } template void priv_copy_assign(const vector &x, AllocVersion , typename container_detail::enable_if_c < !container_detail::is_same::value >::type * = 0) { allocator_type &this_alloc = this->m_holder.alloc(); const allocator_type &x_alloc = x.m_holder.alloc(); container_detail::bool_ flag; if(flag && this_alloc != x_alloc){ this->clear(); this->shrink_to_fit(); } container_detail::assign_alloc(this_alloc, x_alloc, flag); this->assign( container_detail::to_raw_pointer(x.m_holder.start()) , container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size)); } void priv_reserve(size_type, allocator_v0) { throw_bad_alloc(); } void priv_reserve(size_type new_cap, allocator_v1) { //There is not enough memory, allocate a new buffer pointer p = this->m_holder.allocate(new_cap); //Backwards (and possibly forward) expansion #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_alloc; #endif T * const raw_beg = container_detail::to_raw_pointer(this->m_holder.start()); const size_type sz = m_holder.m_size; ::boost::container::uninitialized_move_alloc_n_source ( this->m_holder.alloc(), raw_beg, sz, container_detail::to_raw_pointer(p) ); if(this->m_holder.capacity()){ if(!value_traits::trivial_dctr_after_move) boost::container::destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz); this->m_holder.deallocate(this->m_holder.start(), this->m_holder.capacity()); } this->m_holder.start(p); this->m_holder.capacity(new_cap); } void priv_reserve(size_type new_cap, allocator_v2) { //There is not enough memory, allocate a new //buffer or expand the old one. bool same_buffer_start; size_type real_cap = 0; std::pair ret = this->m_holder.allocation_command (allocate_new | expand_fwd | expand_bwd, new_cap, new_cap, real_cap, this->m_holder.start()); //Check for forward expansion same_buffer_start = ret.second && this->m_holder.start() == ret.first; if(same_buffer_start){ #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_expand_fwd; #endif this->m_holder.capacity(real_cap); } //If there is no forward expansion, move objects else{ //Backwards (and possibly forward) expansion if(ret.second){ //We will reuse insert code, so create a dummy input iterator container_detail::insert_range_proxy, T*> proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0)); #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_expand_bwd; #endif this->priv_forward_range_insert_expand_backwards ( container_detail::to_raw_pointer(ret.first) , real_cap , container_detail::to_raw_pointer(this->m_holder.start()) , 0 , proxy); } //New buffer else{ #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_alloc; #endif T * const raw_beg = container_detail::to_raw_pointer(this->m_holder.start()); const size_type sz = m_holder.m_size; ::boost::container::uninitialized_move_alloc_n_source ( this->m_holder.alloc(), raw_beg, sz, container_detail::to_raw_pointer(ret.first) ); if(this->m_holder.capacity()){ if(!value_traits::trivial_dctr_after_move) boost::container::destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz); this->m_holder.deallocate(this->m_holder.start(), this->m_holder.capacity()); } this->m_holder.start(ret.first); this->m_holder.capacity(real_cap); } } } template void priv_uninitialized_fill(Proxy proxy, size_type n) const { //Copy first new elements in pos proxy.uninitialized_copy_n_and_update (container_detail::to_raw_pointer(this->m_holder.start()), n); //m_holder.size was already initialized to n in vector_alloc_holder's constructor } void priv_destroy(value_type* p) BOOST_CONTAINER_NOEXCEPT { if(!value_traits::trivial_dctr) allocator_traits_type::destroy(this->get_stored_allocator(), p); } void priv_destroy_last_n(size_type n) BOOST_CONTAINER_NOEXCEPT { T* const end_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; boost::container::destroy_alloc_n(this->get_stored_allocator(), end_pos-n, n); this->m_holder.m_size -= n; } void priv_destroy_all() BOOST_CONTAINER_NOEXCEPT { boost::container::destroy_alloc_n (this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size); this->m_holder.m_size = 0; } template iterator priv_insert(const const_iterator &p, BOOST_FWD_REF(U) x) { return this->priv_forward_range_insert ( vector_iterator_get_ptr(p), 1, container_detail::get_insert_value_proxy(this->m_holder.alloc() , ::boost::forward(x)), alloc_version()); } void priv_push_back(const T &x) { if (this->m_holder.m_size < this->m_holder.capacity()){ //There is more memory, just construct a new object at the end allocator_traits_type::construct ( this->m_holder.alloc() , container_detail::to_raw_pointer(this->m_holder.start() + this->m_holder.m_size) , x ); ++this->m_holder.m_size; } else{ container_detail::insert_copy_proxy proxy(this->m_holder.alloc(), x); this->priv_forward_range_insert_no_capacity(vector_iterator_get_ptr(this->cend()), 1, proxy, alloc_version()); } } void priv_push_back(BOOST_RV_REF(T) x) { if (this->m_holder.m_size < this->m_holder.capacity()){ //There is more memory, just construct a new object at the end allocator_traits_type::construct ( this->m_holder.alloc() , container_detail::to_raw_pointer(this->m_holder.start() + this->m_holder.m_size) , ::boost::move(x) ); ++this->m_holder.m_size; } else{ container_detail::insert_move_proxy proxy(this->m_holder.alloc(), x); this->priv_forward_range_insert_no_capacity(vector_iterator_get_ptr(this->cend()), 1, proxy, alloc_version()); } } void priv_shrink_to_fit(allocator_v0) BOOST_CONTAINER_NOEXCEPT {} void priv_shrink_to_fit(allocator_v1) { const size_type cp = this->m_holder.capacity(); if(cp){ const size_type sz = this->size(); if(!sz){ this->m_holder.alloc().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. pointer p = this->m_holder.allocate(sz); //We will reuse insert code, so create a dummy input iterator container_detail::insert_range_proxy, T*> proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0)); #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_alloc; #endif this->priv_forward_range_insert_new_allocation ( container_detail::to_raw_pointer(p) , sz , container_detail::to_raw_pointer(this->m_holder.start()) , 0 , proxy); } } } void priv_shrink_to_fit(allocator_v2) BOOST_CONTAINER_NOEXCEPT { const size_type cp = this->m_holder.capacity(); if(cp){ const size_type sz = this->size(); if(!sz){ this->m_holder.alloc().deallocate(this->m_holder.m_start, cp); this->m_holder.m_start = pointer(); this->m_holder.m_capacity = 0; } else{ size_type received_size; if(this->m_holder.allocation_command ( shrink_in_place | nothrow_allocation , cp, sz, received_size, this->m_holder.start()).first){ this->m_holder.capacity(received_size); #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_shrink; #endif } } } } template iterator priv_forward_range_insert_no_capacity (const pointer &pos, const size_type, const InsertionProxy , allocator_v0) { throw_bad_alloc(); return iterator(pos); } template iterator priv_forward_range_insert_no_capacity (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) { //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 = container_detail::to_raw_pointer(pos); const size_type new_cap = this->m_holder.next_capacity(n); T * new_buf = container_detail::to_raw_pointer(this->m_holder.alloc().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); return iterator(this->m_holder.start() + n_pos); } template iterator priv_forward_range_insert_no_capacity (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v2) { //Check if we have enough memory or try to expand current memory T *const raw_pos = container_detail::to_raw_pointer(pos); const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start()); size_type real_cap = 0; //There is not enough memory, allocate a new //buffer or expand the old one. std::pair ret = (this->m_holder.allocation_command (allocate_new | expand_fwd | expand_bwd, this->m_holder.m_size + n, this->m_holder.next_capacity(n), real_cap, this->m_holder.start())); //Buffer reallocated if(ret.second){ //Forward expansion, delay insertion if(this->m_holder.start() == ret.first){ #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); } //Backwards (and possibly forward) expansion else{ #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_expand_bwd; #endif this->priv_forward_range_insert_expand_backwards ( container_detail::to_raw_pointer(ret.first) , 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 ( container_detail::to_raw_pointer(ret.first) , real_cap, raw_pos, n, insert_range_proxy); } return iterator(this->m_holder.start() + n_pos); } template iterator priv_forward_range_insert (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v0) { //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){ //This will trigger an error throw_bad_alloc(); } const size_type n_pos = pos - this->m_holder.start(); T *const raw_pos = container_detail::to_raw_pointer(pos); this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy); return iterator(this->m_holder.start() + n_pos); } template iterator priv_forward_range_insert (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) { //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; T *const raw_pos = container_detail::to_raw_pointer(pos); if (n <= remaining){ const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start()); this->priv_forward_range_insert_expand_forward (raw_pos, n, insert_range_proxy); return iterator(this->m_holder.start() + n_pos); } else{ return this->priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version()); } } template iterator priv_forward_range_insert (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v2) { //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()); } else{ //Expand forward T *const raw_pos = container_detail::to_raw_pointer(pos); const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start()); this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy); return iterator(this->m_holder.start() + n_pos); } } template iterator priv_forward_range_insert_at_end (const size_type n, const InsertionProxy insert_range_proxy, allocator_v0) { //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){ //This will trigger an error throw_bad_alloc(); } this->priv_forward_range_insert_at_end_expand_forward(n, insert_range_proxy); return this->end(); } template iterator priv_forward_range_insert_at_end (const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) { return this->priv_forward_range_insert(vector_iterator_get_ptr(this->cend()), n, insert_range_proxy, allocator_v1()); } template iterator priv_forward_range_insert_at_end (const size_type n, const InsertionProxy insert_range_proxy, allocator_v2) { return this->priv_forward_range_insert(vector_iterator_get_ptr(this->cend()), n, insert_range_proxy, allocator_v2()); } //Absolutely experimental. This function might change, disappear or simply crash! template void priv_insert_ordered_at( size_type element_count, BiDirPosConstIt last_position_it , bool do_skip, BiDirSkipConstIt last_skip_it, BiDirValueIt last_value_it) { const size_type old_size_pos = this->size(); this->reserve(old_size_pos + element_count); T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.start()); size_type insertions_left = element_count; size_type next_pos = old_size_pos; size_type hole_size = element_count; //Exception rollback. If any copy throws before the hole is filled, values //already inserted/copied at the end of the buffer will be destroyed. typename value_traits::ArrayDestructor past_hole_values_destroyer (begin_ptr + old_size_pos + element_count, this->m_holder.alloc(), size_type(0u)); //Loop for each insertion backwards, first moving the elements after the insertion point, //then inserting the element. while(insertions_left){ if(do_skip){ size_type n = *(--last_skip_it); std::advance(last_value_it, -difference_type(n)); } const size_type pos = static_cast(*(--last_position_it)); BOOST_ASSERT(pos <= old_size_pos); //If needed shift the range after the insertion point and the previous insertion point. //Function will take care if the shift crosses the size() boundary, using copy/move //or uninitialized copy/move if necessary. size_type new_hole_size = (pos != next_pos) ? priv_insert_ordered_at_shift_range(pos, next_pos, this->size(), insertions_left) : hole_size ; if(new_hole_size > 0){ //The hole was reduced by priv_insert_ordered_at_shift_range so expand exception rollback range backwards past_hole_values_destroyer.increment_size_backwards(next_pos - pos); //Insert the new value in the hole allocator_traits_type::construct(this->m_holder.alloc(), begin_ptr + pos + insertions_left - 1, *(--last_value_it)); --new_hole_size; if(new_hole_size == 0){ //Hole was just filled, disable exception rollback and change vector size past_hole_values_destroyer.release(); this->m_holder.m_size += element_count; } else{ //The hole was reduced by the new insertion by one past_hole_values_destroyer.increment_size_backwards(size_type(1u)); } } else{ if(hole_size){ //Hole was just filled by priv_insert_ordered_at_shift_range, disable exception rollback and change vector size past_hole_values_destroyer.release(); this->m_holder.m_size += element_count; } //Insert the new value in the already constructed range begin_ptr[pos + insertions_left - 1] = *(--last_value_it); } --insertions_left; hole_size = new_hole_size; next_pos = pos; } } //Takes the range pointed by [first_pos, last_pos) and shifts it to the right //by 'shift_count'. 'limit_pos' marks the end of constructed elements. // //Precondition: first_pos <= last_pos <= limit_pos // //The shift operation might cross limit_pos so elements to moved beyond limit_pos //are uninitialized_moved with an allocator. Other elements are moved. // //The shift operation might left uninitialized elements after limit_pos //and the number of uninitialized elements is returned by the function. // //Old situation: // first_pos last_pos old_limit // | | | // ____________V_______V__________________V_____________ //| prefix | range | suffix |raw_mem ~ //|____________|_______|__________________|_____________~ // //New situation in Case Allocator (hole_size == 0): // range is moved through move assignments // // first_pos last_pos limit_pos // | | | // ____________V_______V__________________V_____________ //| prefix' | | | range |suffix'|raw_mem ~ //|________________+______|___^___|_______|_____________~ // | | // |_>_>_>_>_>^ // // //New situation in Case B (hole_size > 0): // range is moved through uninitialized moves // // first_pos last_pos limit_pos // | | | // ____________V_______V__________________V________________ //| prefix' | | | [hole] | range | //|_______________________________________|________|___^___| // | | // |_>_>_>_>_>_>_>_>_>_>_>_>_>_>_>_>_>_^ // //New situation in Case C (hole_size == 0): // range is moved through move assignments and uninitialized moves // // first_pos last_pos limit_pos // | | | // ____________V_______V__________________V___ //| prefix' | | | range | //|___________________________________|___^___| // | | // |_>_>_>_>_>_>_>_>_>_>_>^ size_type priv_insert_ordered_at_shift_range (size_type first_pos, size_type last_pos, size_type limit_pos, size_type shift_count) { BOOST_ASSERT(first_pos <= last_pos); BOOST_ASSERT(last_pos <= limit_pos); // T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.start()); T* const first_ptr = begin_ptr + first_pos; T* const last_ptr = begin_ptr + last_pos; size_type hole_size = 0; //Case Allocator: if((last_pos + shift_count) <= limit_pos){ //All move assigned boost::move_backward(first_ptr, last_ptr, last_ptr + shift_count); } //Case B: else if((first_pos + shift_count) >= limit_pos){ //All uninitialized_moved ::boost::container::uninitialized_move_alloc (this->m_holder.alloc(), first_ptr, last_ptr, first_ptr + shift_count); hole_size = last_pos + shift_count - limit_pos; } //Case C: else{ //Some uninitialized_moved T* const limit_ptr = begin_ptr + limit_pos; T* const boundary_ptr = limit_ptr - shift_count; ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), boundary_ptr, last_ptr, limit_ptr); //The rest is move assigned boost::move_backward(first_ptr, boundary_ptr, limit_ptr); } return hole_size; } private: template void priv_forward_range_insert_at_end_expand_forward(const size_type n, InsertionProxy insert_range_proxy) { T* const old_finish = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; insert_range_proxy.uninitialized_copy_n_and_update(old_finish, n); this->m_holder.m_size += n; } template void priv_forward_range_insert_expand_forward(T* const pos, const size_type n, InsertionProxy insert_range_proxy) { //n can't be 0, because there is nothing to do in that case if(!n) return; //There is enough memory T* const old_finish = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; const size_type elems_after = old_finish - pos; if (!elems_after){ insert_range_proxy.uninitialized_copy_n_and_update(old_finish, n); this->m_holder.m_size += n; } else if (elems_after >= n){ //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; //Copy previous to last objects to the initialized end boost::move_backward(pos, old_finish - n, old_finish); //Insert new objects in the pos insert_range_proxy.copy_n_and_update(pos, n); } else { //The new elements don't fit in the [pos, end()) range. //Copy old [pos, end()) elements to the uninitialized memory (a gap is created) ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), pos, old_finish, pos + n); BOOST_TRY{ //Copy first new elements in pos (gap is still there) insert_range_proxy.copy_n_and_update(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(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 void priv_forward_range_insert_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 scoped_alloc(new_start, this->m_holder.alloc(), new_cap); typename value_traits::ArrayDestructor constructed_values_destroyer(new_start, this->m_holder.alloc(), 0u); //Initialize with [begin(), pos) old buffer //the start of the new buffer T *old_buffer = container_detail::to_raw_pointer(this->m_holder.start()); if(old_buffer){ new_finish = ::boost::container::uninitialized_move_alloc (this->m_holder.alloc(), container_detail::to_raw_pointer(this->m_holder.start()), pos, old_finish = new_finish); constructed_values_destroyer.increment_size(new_finish - old_finish); } //Initialize new objects, starting from previous point insert_range_proxy.uninitialized_copy_n_and_update(old_finish = new_finish, n); new_finish += n; constructed_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); this->m_holder.alloc().deallocate(this->m_holder.start(), this->m_holder.capacity()); } this->m_holder.start(new_start); this->m_holder.m_size = new_finish - new_start; this->m_holder.capacity(new_cap); //All construction successful, disable rollbacks constructed_values_destroyer.release(); scoped_alloc.release(); } template void priv_forward_range_insert_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 = container_detail::to_raw_pointer(this->m_holder.start()); T* const old_finish = old_start + this->m_holder.m_size; const size_type old_size = this->m_holder.m_size; //We can have 8 possibilities: const size_type elemsbefore = static_cast(pos - old_start); const size_type s_before = static_cast(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; //If anything goes wrong, this object will destroy //all the old objects to fulfill previous vector state typename value_traits::OldArrayDestructor old_values_destroyer(old_start, this->m_holder.alloc(), 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(new_elem_pos, n); this->m_holder.m_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 const size_type new_size = old_size + n; if(s_before >= new_size){ //Old situation: // _________________________________________________________ //| raw_mem | old_begin | old_end | //| __________________________________|___________|_________| // //New situation: // _________________________________________________________ //| old_begin | new | old_end | raw_mem | //|___________|__________|_________|________________________| // //Now initialize the rest of memory with the last old values ::boost::container::uninitialized_move_alloc (this->m_holder.alloc(), pos, old_finish, new_start + before_plus_new); //All new elements correctly constructed, avoid new element destruction this->m_holder.m_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) old_values_destroyer.release(); } //s_before is so big that divides old_end else{ //Old situation: // __________________________________________________ //| raw_mem | old_begin | old_end | //| ___________________________|___________|_________| // //New situation: // __________________________________________________ //| 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; //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); //Update size since we have a contiguous buffer this->m_holder.m_size = old_size + s_before; //All new elements correctly constructed, avoid old element destruction old_values_destroyer.release(); //Now copy remaining last objects in the old buffer begin T * const to_destroy = ::boost::move(pos + raw_gap, old_finish, old_start); //Now destroy redundant elements except if they were moved and //they have trivial destructor after move size_type n_destroy = old_finish - to_destroy; if(!value_traits::trivial_dctr_after_move) boost::container::destroy_alloc_n(this->get_stored_allocator(), to_destroy, n_destroy); this->m_holder.m_size -= n_destroy; } } else{ //Check if we have to do the insertion in two phases //since maybe s_before is not big enough and //the buffer was expanded both sides // //Old situation: // _________________________________________________ //| raw_mem | old_begin + old_end | raw_mem | //|_________|_____________________|_________________| // //New situation with do_after: // _________________________________________________ //| old_begin + new + old_end | raw_mem | //|___________________________________|_____________| // //New without do_after: // _________________________________________________ //| old_begin + new + old_end | raw_mem | //|____________________________|____________________| // const bool do_after = n > s_before; //Now we can have two situations: the raw_mem of the //beginning divides the old_begin, or the new elements: if (s_before <= elemsbefore) { //The raw memory divides the old_begin group: // //If we need two phase construction (do_after) //new group is divided in new = new_beg + new_end groups //In this phase only new_beg will be inserted // //Old situation: // _________________________________________________ //| raw_mem | old_begin | old_end | raw_mem | //|_________|___________|_________|_________________| // //New situation with do_after(1): //This is not definitive situation, the second phase //will include // _________________________________________________ //| old_begin | new_beg | old_end | raw_mem | //|___________|_________|_________|_________________| // //New situation without do_after: // _________________________________________________ //| 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); //The buffer is all constructed until old_end, //release destroyer and update size old_values_destroyer.release(); this->m_holder.m_size = old_size + s_before; //Now copy the second part of old_begin overwriting itself T *const next = ::boost::move(old_start + s_before, pos, old_start); if(do_after){ //Now copy the new_beg elements insert_range_proxy.copy_n_and_update(next, s_before); } else{ //Now copy the all the new elements insert_range_proxy.copy_n_and_update(next, n); //Now displace old_end elements T* const move_end = ::boost::move(pos, old_finish, next + n); //Destroy remaining moved elements from old_end except if //they have trivial destructor after being moved const 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; } } else { //If we have to expand both sides, //we will play if the first new values so //calculate the upper bound of new values //The raw memory divides the new elements // //If we need two phase construction (do_after) //new group is divided in new = new_beg + new_end groups //In this phase only new_beg will be inserted // //Old situation: // _______________________________________________________ //| raw_mem | old_begin | old_end | raw_mem | //|_______________|___________|_________|_________________| // //New situation with do_after(): // ____________________________________________________ //| old_begin | new_beg | old_end | raw_mem | //|___________|_______________|_________|______________| // //New situation without do_after: // ______________________________________________________ //| 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; const size_type mid_n = s_before - elemsbefore; insert_range_proxy.uninitialized_copy_n_and_update(new_pos, mid_n); //The buffer is all constructed until old_end, //release destroyer this->m_holder.m_size = old_size + s_before; old_values_destroyer.release(); if(do_after){ //Copy new_beg part insert_range_proxy.copy_n_and_update(old_start, elemsbefore); } else{ //Copy all new elements const size_type rest_new = n - mid_n; insert_range_proxy.copy_n_and_update(old_start, rest_new); T* move_start = old_start + rest_new; //Displace old_end T* move_end = ::boost::move(pos, old_finish, move_start); //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; } } //This is only executed if two phase construction is needed if(do_after){ //The raw memory divides the new elements // //Old situation: // ______________________________________________________ //| raw_mem | old_begin | old_end | raw_mem | //|______________|___________|____________|______________| // //New situation with do_after(1): // _______________________________________________________ //| old_begin + new_beg | new_end |old_end | raw_mem | //|__________________________|_________|________|_________| // //New situation with do_after(2): // ______________________________________________________ //| old_begin + new | old_end |raw | //|_______________________________________|_________|____| // const size_type n_after = n - s_before; const size_type elemsafter = old_size - elemsbefore; //We can have two situations: if (elemsafter >= n_after){ //The raw_mem from end will divide displaced old_end // //Old situation: // ______________________________________________________ //| raw_mem | old_begin | old_end | raw_mem | //|______________|___________|____________|______________| // //New situation with do_after(1): // _______________________________________________________ //| 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; //Displace the rest of old_end to the new position boost::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(pos, n_after); } else { //The raw_mem from end will divide new_end part // //Old situation: // _____________________________________________________________ //| raw_mem | old_begin | old_end | raw_mem | //|______________|___________|____________|_____________________| // //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 //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_TRY{ //Copy the first part to the already constructed old_end zone insert_range_proxy.copy_n_and_update(pos, elemsafter); //Copy the rest to the uninitialized zone filling the gap insert_range_proxy.uninitialized_copy_n_and_update(old_finish, mid_last_dist); this->m_holder.m_size += n_after; } BOOST_CATCH(...){ boost::container::destroy_alloc_n(this->get_stored_allocator(), pos, mid_last_dist); BOOST_RETHROW } BOOST_CATCH_END /* size_type mid_last_dist = n_after - elemsafter; //First initialize data in raw memory //The new_end part is [first + (n - n_after), last) insert_range_proxy.uninitialized_copy_last_and_update(old_finish, elemsafter); this->m_holder.m_size += mid_last_dist; ::boost::container::uninitialized_move_alloc (this->m_holder.alloc(), pos, old_finish, old_finish + mid_last_dist); this->m_holder.m_size += n_after - mid_last_dist; //Now copy the part of new_end over constructed elements insert_range_proxy.copy_remaining_to(pos);*/ } } } } void priv_check_range(size_type n) const { //If n is out of range, throw an out_of_range exception if (n >= this->size()){ throw_out_of_range("vector::at out of range"); } } #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS public: unsigned int num_expand_fwd; unsigned int num_expand_bwd; unsigned int num_shrink; unsigned int num_alloc; void reset_alloc_stats() { num_expand_fwd = num_expand_bwd = num_alloc = 0, num_shrink = 0; } #endif /// @endcond }; template inline bool operator==(const vector& x, const vector& y) { //Check first size and each element if needed return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); } template inline bool operator!=(const vector& x, const vector& y) { //Check first size and each element if needed return x.size() != y.size() || !std::equal(x.begin(), x.end(), y.begin()); } template inline bool operator<(const vector& x, const vector& y) { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } template inline void swap(vector& x, vector& y) { x.swap(y); } }} /// @cond namespace boost { //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations template struct has_trivial_destructor_after_move > : public ::boost::has_trivial_destructor_after_move {}; } //#define BOOST_CONTAINER_PUT_SWAP_OVERLOAD_IN_NAMESPACE_STD #ifdef BOOST_CONTAINER_PUT_SWAP_OVERLOAD_IN_NAMESPACE_STD namespace std { template inline void swap(boost::container::vector& x, boost::container::vector& y) { x.swap(y); } } //namespace std { #endif /// @endcond #include #endif // #ifndef BOOST_CONTAINER_CONTAINER_VECTOR_HPP