Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@101: // (C) Copyright Ion Gaztanaga 2005-2014. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: // See http://www.boost.org/libs/container for documentation. Chris@16: // Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: #ifndef BOOST_CONTAINER_CONTAINER_VECTOR_HPP Chris@16: #define BOOST_CONTAINER_CONTAINER_VECTOR_HPP Chris@16: Chris@101: #ifndef BOOST_CONFIG_HPP Chris@101: # include Chris@101: #endif Chris@101: Chris@101: #if defined(BOOST_HAS_PRAGMA_ONCE) Chris@16: # pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@101: Chris@101: // container Chris@16: #include Chris@101: #include Chris@101: #include //new_allocator Chris@101: #include Chris@101: // container detail Chris@101: #include Chris@101: #include //equal() Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: // intrusive Chris@101: #include Chris@101: // move Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: // move/detail Chris@101: #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) Chris@101: #include Chris@101: #endif Chris@101: #include Chris@101: // other Chris@101: #include Chris@101: #include Chris@16: Chris@101: //std Chris@101: #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) Chris@101: #include //for std::initializer_list Chris@101: #endif Chris@16: Chris@16: namespace boost { Chris@16: namespace container { Chris@16: Chris@101: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@16: Chris@16: //#define BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER Chris@16: Chris@16: namespace container_detail { Chris@16: Chris@16: #ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER Chris@16: Chris@16: template Chris@16: class vec_iterator Chris@16: { Chris@16: public: Chris@101: typedef std::random_access_iterator_tag iterator_category; Chris@16: typedef typename boost::intrusive::pointer_traits::element_type value_type; Chris@16: typedef typename boost::intrusive::pointer_traits::difference_type difference_type; Chris@16: typedef typename if_c Chris@16: < IsConst Chris@16: , typename boost::intrusive::pointer_traits::template Chris@16: rebind_pointer::type Chris@16: , Pointer Chris@16: >::type pointer; Chris@101: typedef typename boost::intrusive::pointer_traits ptr_traits; Chris@101: typedef typename ptr_traits::reference reference; Chris@16: Chris@101: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@16: private: Chris@16: Pointer m_ptr; Chris@16: Chris@16: public: Chris@101: const Pointer &get_ptr() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return m_ptr; } Chris@16: Chris@101: Pointer &get_ptr() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return m_ptr; } Chris@16: Chris@101: explicit vec_iterator(Pointer ptr) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: : m_ptr(ptr) Chris@16: {} Chris@101: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@16: Chris@16: public: Chris@16: Chris@16: //Constructors Chris@101: vec_iterator() BOOST_NOEXCEPT_OR_NOTHROW Chris@101: : m_ptr() //Value initialization to achieve "null iterators" (N3644) Chris@16: {} Chris@16: Chris@101: vec_iterator(vec_iterator const& other) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: : m_ptr(other.get_ptr()) Chris@16: {} Chris@16: Chris@16: //Pointer like operators Chris@101: reference operator*() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return *m_ptr; } Chris@16: Chris@101: pointer operator->() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return ::boost::intrusive::pointer_traits::pointer_to(this->operator*()); } Chris@16: Chris@101: reference operator[](difference_type off) const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return m_ptr[off]; } Chris@16: Chris@16: //Increment / Decrement Chris@101: vec_iterator& operator++() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { ++m_ptr; return *this; } Chris@16: Chris@101: vec_iterator operator++(int) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return vec_iterator(m_ptr++); } Chris@16: Chris@101: vec_iterator& operator--() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { --m_ptr; return *this; } Chris@16: Chris@101: vec_iterator operator--(int) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return vec_iterator(m_ptr--); } Chris@16: Chris@16: //Arithmetic Chris@101: vec_iterator& operator+=(difference_type off) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { m_ptr += off; return *this; } Chris@16: Chris@101: vec_iterator& operator-=(difference_type off) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { m_ptr -= off; return *this; } Chris@16: Chris@101: friend vec_iterator operator+(const vec_iterator &x, difference_type off) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return vec_iterator(x.m_ptr+off); } Chris@16: Chris@101: friend vec_iterator operator+(difference_type off, vec_iterator right) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { right.m_ptr += off; return right; } Chris@16: Chris@101: friend vec_iterator operator-(vec_iterator left, difference_type off) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { left.m_ptr -= off; return left; } Chris@16: Chris@101: friend difference_type operator-(const vec_iterator &left, const vec_iterator& right) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return left.m_ptr - right.m_ptr; } Chris@16: Chris@16: //Comparison operators Chris@101: friend bool operator== (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return l.m_ptr == r.m_ptr; } Chris@16: Chris@101: friend bool operator!= (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return l.m_ptr != r.m_ptr; } Chris@16: Chris@101: friend bool operator< (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return l.m_ptr < r.m_ptr; } Chris@16: Chris@101: friend bool operator<= (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return l.m_ptr <= r.m_ptr; } Chris@16: Chris@101: friend bool operator> (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return l.m_ptr > r.m_ptr; } Chris@16: Chris@101: friend bool operator>= (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return l.m_ptr >= r.m_ptr; } Chris@16: }; Chris@16: Chris@16: } //namespace container_detail { Chris@16: Chris@16: template Chris@101: const Pointer &vector_iterator_get_ptr(const container_detail::vec_iterator &it) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return it.get_ptr(); } Chris@16: Chris@16: template Chris@101: Pointer &get_ptr(container_detail::vec_iterator &it) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return it.get_ptr(); } Chris@16: Chris@16: namespace container_detail { Chris@16: Chris@16: #else //ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER Chris@16: Chris@16: template< class MaybeConstPointer Chris@16: , bool ElementTypeIsConst Chris@16: = is_const< typename boost::intrusive::pointer_traits::element_type>::value > Chris@16: struct vector_get_ptr_pointer_to_non_const Chris@16: { Chris@16: typedef MaybeConstPointer const_pointer; Chris@16: typedef boost::intrusive::pointer_traits pointer_traits_t; Chris@16: typedef typename pointer_traits_t::element_type element_type; Chris@16: typedef typename remove_const::type non_const_element_type; Chris@16: typedef typename pointer_traits_t Chris@16: ::template rebind_pointer::type return_type; Chris@16: Chris@101: static return_type get_ptr(const const_pointer &ptr) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return boost::intrusive::pointer_traits::const_cast_from(ptr); } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct vector_get_ptr_pointer_to_non_const Chris@16: { Chris@16: typedef const Pointer & return_type; Chris@101: static return_type get_ptr(const Pointer &ptr) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return ptr; } Chris@16: }; Chris@16: Chris@16: } //namespace container_detail { Chris@16: Chris@16: template Chris@16: typename container_detail::vector_get_ptr_pointer_to_non_const::return_type Chris@101: vector_iterator_get_ptr(const MaybeConstPointer &ptr) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { Chris@16: return container_detail::vector_get_ptr_pointer_to_non_const::get_ptr(ptr); Chris@16: } Chris@16: Chris@16: namespace container_detail { Chris@16: Chris@16: #endif //#ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER Chris@16: Chris@101: struct uninitialized_size_t {}; Chris@101: static const uninitialized_size_t uninitialized_size = uninitialized_size_t(); Chris@101: Chris@101: template Chris@101: struct vector_value_traits_base Chris@101: { Chris@101: static const bool trivial_dctr = is_trivially_destructible::value; Chris@101: static const bool trivial_dctr_after_move = has_trivial_destructor_after_move::value; Chris@101: static const bool trivial_copy = is_trivially_copy_constructible::value; Chris@101: static const bool nothrow_copy = is_nothrow_copy_constructible::value || trivial_copy; Chris@101: static const bool trivial_assign = is_trivially_copy_assignable::value; Chris@101: static const bool nothrow_assign = is_nothrow_copy_assignable::value || trivial_assign; Chris@101: }; Chris@101: Chris@101: Chris@101: template Chris@16: struct vector_value_traits Chris@101: : public vector_value_traits_base Chris@16: { Chris@101: typedef vector_value_traits_base base_t; Chris@16: //This is the anti-exception array destructor Chris@16: //to deallocate values already constructed Chris@16: typedef typename container_detail::if_c Chris@101: Chris@16: ,container_detail::scoped_destructor_n Chris@16: >::type ArrayDestructor; Chris@16: //This is the anti-exception array deallocator Chris@101: typedef container_detail::scoped_array_deallocator ArrayDeallocator; Chris@16: }; Chris@16: Chris@16: //!This struct deallocates and allocated memory Chris@16: template < class Allocator Chris@101: , class AllocatorVersion = typename container_detail::version::type Chris@16: > Chris@16: struct vector_alloc_holder Chris@16: : public Allocator Chris@16: { Chris@16: private: Chris@16: BOOST_MOVABLE_BUT_NOT_COPYABLE(vector_alloc_holder) Chris@16: Chris@16: public: Chris@101: typedef Allocator allocator_type; Chris@16: typedef boost::container::allocator_traits allocator_traits_type; Chris@16: typedef typename allocator_traits_type::pointer pointer; Chris@16: typedef typename allocator_traits_type::size_type size_type; Chris@16: typedef typename allocator_traits_type::value_type value_type; Chris@16: Chris@101: static bool is_propagable_from(const allocator_type &from_alloc, pointer p, const allocator_type &to_alloc, bool const propagate_allocator) Chris@101: { Chris@101: (void)propagate_allocator; (void)p; (void)to_alloc; (void)from_alloc; Chris@101: return (!allocator_traits_type::is_partially_propagable::value || Chris@101: !allocator_traits_type::storage_is_unpropagable(from_alloc, p)) && Chris@101: (propagate_allocator || allocator_traits_type::equal(from_alloc, to_alloc)); Chris@101: } Chris@101: Chris@101: 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) Chris@101: { Chris@101: (void)propagate_allocator; (void)l_p; (void)r_p; (void)l_a; (void)r_a; Chris@101: return (!allocator_traits_type::is_partially_propagable::value || Chris@101: (!allocator_traits_type::storage_is_unpropagable(r_a, r_p) && Chris@101: !allocator_traits_type::storage_is_unpropagable(l_a, l_p)) Chris@101: ) && (propagate_allocator || allocator_traits_type::equal(l_a, r_a)); Chris@101: } Chris@101: Chris@16: //Constructor, does not throw Chris@16: vector_alloc_holder() Chris@101: BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value) Chris@16: : Allocator(), m_start(), m_size(), m_capacity() Chris@16: {} Chris@16: Chris@16: //Constructor, does not throw Chris@16: template Chris@101: explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: : Allocator(boost::forward(a)), m_start(), m_size(), m_capacity() Chris@16: {} Chris@16: Chris@16: //Constructor, does not throw Chris@16: template Chris@101: vector_alloc_holder(uninitialized_size_t, BOOST_FWD_REF(AllocConvertible) a, size_type initial_size) Chris@16: : Allocator(boost::forward(a)) Chris@16: , m_start() Chris@16: , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this Chris@16: , m_capacity() Chris@16: { Chris@16: if(initial_size){ Chris@101: pointer reuse = 0; Chris@101: m_start = this->allocation_command(allocate_new, initial_size, m_capacity = initial_size, reuse); Chris@16: } Chris@16: } Chris@16: Chris@16: //Constructor, does not throw Chris@101: vector_alloc_holder(uninitialized_size_t, size_type initial_size) Chris@16: : Allocator() Chris@16: , m_start() Chris@16: , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this Chris@16: , m_capacity() Chris@16: { Chris@16: if(initial_size){ Chris@101: pointer reuse = 0; Chris@101: m_start = this->allocation_command(allocate_new, initial_size, m_capacity = initial_size, reuse); Chris@16: } Chris@16: } Chris@16: Chris@101: vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) BOOST_NOEXCEPT_OR_NOTHROW Chris@101: : Allocator(BOOST_MOVE_BASE(Allocator, holder)) Chris@16: , m_start(holder.m_start) Chris@16: , m_size(holder.m_size) Chris@16: , m_capacity(holder.m_capacity) Chris@16: { Chris@16: holder.m_start = pointer(); Chris@16: holder.m_size = holder.m_capacity = 0; Chris@16: } Chris@16: Chris@101: vector_alloc_holder(pointer p, size_type capacity, BOOST_RV_REF(vector_alloc_holder) holder) Chris@101: : Allocator(BOOST_MOVE_BASE(Allocator, holder)) Chris@101: , m_start(p) Chris@101: , m_size(holder.m_size) Chris@101: , m_capacity(capacity) Chris@16: { Chris@101: allocator_type &this_alloc = this->alloc(); Chris@101: allocator_type &x_alloc = holder.alloc(); Chris@101: if(this->is_propagable_from(x_alloc, holder.start(), this_alloc, true)){ Chris@101: if(this->m_capacity){ Chris@101: this->alloc().deallocate(this->m_start, this->m_capacity); Chris@101: } Chris@101: m_start = holder.m_start; Chris@101: m_capacity = holder.m_capacity; Chris@101: holder.m_start = pointer(); Chris@101: holder.m_capacity = holder.m_size = 0; Chris@101: } Chris@101: else if(this->m_capacity < holder.m_size){ Chris@101: size_type const n = holder.m_size; Chris@101: pointer reuse = pointer(); Chris@101: m_start = this->allocation_command(allocate_new, n, m_capacity = n, reuse); Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: this->num_alloc += n != 0; Chris@101: #endif Chris@16: } Chris@16: } Chris@16: Chris@101: vector_alloc_holder(pointer p, size_type n) Chris@101: BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value) Chris@101: : Allocator() Chris@101: , m_start(p) Chris@101: , m_size() Chris@101: , m_capacity(n) Chris@101: {} Chris@16: Chris@101: template Chris@101: vector_alloc_holder(pointer p, size_type n, BOOST_FWD_REF(AllocFwd) a) Chris@101: : Allocator(::boost::forward(a)) Chris@101: , m_start(p) Chris@101: , m_size() Chris@101: , m_capacity(n) Chris@101: {} Chris@101: Chris@101: ~vector_alloc_holder() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { Chris@16: if(this->m_capacity){ Chris@16: this->alloc().deallocate(this->m_start, this->m_capacity); Chris@16: } Chris@16: } Chris@16: Chris@101: pointer allocation_command(boost::container::allocation_type command, Chris@101: size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse) Chris@16: { Chris@101: typedef typename container_detail::version::type alloc_version; Chris@101: return this->priv_allocation_command(alloc_version(), command, limit_size, prefer_in_recvd_out_size, reuse); Chris@101: } Chris@101: Chris@101: bool try_expand_fwd(size_type at_least) Chris@101: { Chris@101: //There is not enough memory, try to expand the old one Chris@101: const size_type new_cap = this->capacity() + at_least; Chris@101: size_type real_cap = new_cap; Chris@101: pointer reuse = this->start(); Chris@101: bool const success = !!this->allocation_command(expand_fwd, new_cap, real_cap, reuse); Chris@101: //Check for forward expansion Chris@101: if(success){ Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: ++this->num_expand_fwd; Chris@101: #endif Chris@101: this->capacity(real_cap); Chris@101: } Chris@101: return success; Chris@16: } Chris@16: Chris@16: size_type next_capacity(size_type additional_objects) const Chris@16: { Chris@101: return next_capacity_calculator Chris@101: ::get( allocator_traits_type::max_size(this->alloc()) Chris@101: , this->m_capacity, additional_objects ); Chris@16: } Chris@16: Chris@16: pointer m_start; Chris@16: size_type m_size; Chris@16: size_type m_capacity; Chris@16: Chris@101: void swap_resources(vector_alloc_holder &x) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { Chris@101: boost::adl_move_swap(this->m_start, x.m_start); Chris@101: boost::adl_move_swap(this->m_size, x.m_size); Chris@101: boost::adl_move_swap(this->m_capacity, x.m_capacity); Chris@16: } Chris@16: Chris@101: void steal_resources(vector_alloc_holder &x) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { Chris@16: this->m_start = x.m_start; Chris@16: this->m_size = x.m_size; Chris@16: this->m_capacity = x.m_capacity; Chris@16: x.m_start = pointer(); Chris@16: x.m_size = x.m_capacity = 0; Chris@16: } Chris@16: Chris@101: Allocator &alloc() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return *this; } Chris@16: Chris@101: const Allocator &alloc() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return *this; } Chris@16: Chris@101: const pointer &start() const BOOST_NOEXCEPT_OR_NOTHROW { return m_start; } Chris@101: const size_type &capacity() const BOOST_NOEXCEPT_OR_NOTHROW { return m_capacity; } Chris@101: void start(const pointer &p) BOOST_NOEXCEPT_OR_NOTHROW { m_start = p; } Chris@101: void capacity(const size_type &c) BOOST_NOEXCEPT_OR_NOTHROW { m_capacity = c; } Chris@101: Chris@101: private: Chris@101: void priv_first_allocation(size_type cap) Chris@101: { Chris@101: if(cap){ Chris@101: pointer reuse = 0; Chris@101: m_start = this->allocation_command(allocate_new, cap, cap, reuse); Chris@101: m_capacity = cap; Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: ++this->num_alloc; Chris@101: #endif Chris@101: } Chris@101: } Chris@101: Chris@101: pointer priv_allocation_command(version_1, boost::container::allocation_type command, Chris@101: size_type , Chris@101: size_type &prefer_in_recvd_out_size, Chris@101: pointer &reuse) Chris@101: { Chris@101: (void)command; Chris@101: BOOST_ASSERT( (command & allocate_new)); Chris@101: BOOST_ASSERT(!(command & nothrow_allocation)); Chris@101: pointer const p = allocator_traits_type::allocate(this->alloc(), prefer_in_recvd_out_size, reuse); Chris@101: reuse = pointer(); Chris@101: return p; Chris@101: } Chris@101: Chris@101: pointer priv_allocation_command(version_2, boost::container::allocation_type command, Chris@101: size_type limit_size, Chris@101: size_type &prefer_in_recvd_out_size, Chris@101: pointer &reuse) Chris@101: { Chris@101: return this->alloc().allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); Chris@101: } Chris@16: }; Chris@16: Chris@16: //!This struct deallocates and allocated memory Chris@16: template Chris@101: struct vector_alloc_holder Chris@16: : public Allocator Chris@16: { Chris@16: private: Chris@16: BOOST_MOVABLE_BUT_NOT_COPYABLE(vector_alloc_holder) Chris@16: Chris@16: public: Chris@16: typedef boost::container::allocator_traits allocator_traits_type; Chris@16: typedef typename allocator_traits_type::pointer pointer; Chris@16: typedef typename allocator_traits_type::size_type size_type; Chris@16: typedef typename allocator_traits_type::value_type value_type; Chris@16: Chris@16: template Chris@16: friend struct vector_alloc_holder; Chris@16: Chris@16: //Constructor, does not throw Chris@16: vector_alloc_holder() Chris@101: BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value) Chris@16: : Allocator(), m_size() Chris@16: {} Chris@16: Chris@16: //Constructor, does not throw Chris@16: template Chris@101: explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: : Allocator(boost::forward(a)), m_size() Chris@16: {} Chris@16: Chris@16: //Constructor, does not throw Chris@16: template Chris@101: vector_alloc_holder(uninitialized_size_t, BOOST_FWD_REF(AllocConvertible) a, size_type initial_size) Chris@16: : Allocator(boost::forward(a)) Chris@16: , m_size(initial_size) //Size is initialized here... Chris@16: { Chris@16: //... and capacity here, so vector, must call uninitialized_xxx in the derived constructor Chris@101: this->priv_first_allocation(initial_size); Chris@16: } Chris@16: Chris@16: //Constructor, does not throw Chris@101: vector_alloc_holder(uninitialized_size_t, size_type initial_size) Chris@16: : Allocator() Chris@16: , m_size(initial_size) //Size is initialized here... Chris@16: { Chris@16: //... and capacity here, so vector, must call uninitialized_xxx in the derived constructor Chris@101: this->priv_first_allocation(initial_size); Chris@16: } Chris@16: Chris@16: vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) Chris@101: : Allocator(BOOST_MOVE_BASE(Allocator, holder)) Chris@16: , m_size(holder.m_size) //Size is initialized here so vector should only call uninitialized_xxx after this Chris@16: { Chris@16: ::boost::container::uninitialized_move_alloc_n Chris@16: (this->alloc(), container_detail::to_raw_pointer(holder.start()), m_size, container_detail::to_raw_pointer(this->start())); Chris@16: } Chris@16: Chris@16: template Chris@16: vector_alloc_holder(BOOST_RV_REF_BEG vector_alloc_holder BOOST_RV_REF_END holder) Chris@16: : Allocator() Chris@16: , m_size(holder.m_size) //Initialize it to m_size as first_allocation can only succeed or abort Chris@16: { Chris@16: //Different allocator type so we must check we have enough storage Chris@16: const size_type n = holder.m_size; Chris@101: this->priv_first_allocation(n); Chris@16: ::boost::container::uninitialized_move_alloc_n Chris@16: (this->alloc(), container_detail::to_raw_pointer(holder.start()), n, container_detail::to_raw_pointer(this->start())); Chris@16: } Chris@16: Chris@101: void priv_first_allocation(size_type cap) Chris@16: { Chris@16: if(cap > Allocator::internal_capacity){ Chris@16: throw_bad_alloc(); Chris@16: } Chris@16: } Chris@16: Chris@101: void deep_swap(vector_alloc_holder &x) Chris@16: { Chris@101: this->priv_deep_swap(x); Chris@16: } Chris@16: Chris@16: template Chris@101: void deep_swap(vector_alloc_holder &x) Chris@16: { Chris@16: if(this->m_size > OtherAllocator::internal_capacity || x.m_size > Allocator::internal_capacity){ Chris@16: throw_bad_alloc(); Chris@16: } Chris@101: this->priv_deep_swap(x); Chris@16: } Chris@16: Chris@101: void swap_resources(vector_alloc_holder &x) BOOST_NOEXCEPT_OR_NOTHROW Chris@101: { //Containers with version 0 allocators can't be moved without moving elements one by one Chris@16: throw_bad_alloc(); Chris@16: } Chris@16: Chris@101: Chris@101: void steal_resources(vector_alloc_holder &) Chris@101: { //Containers with version 0 allocators can't be moved without moving elements one by one Chris@101: throw_bad_alloc(); Chris@101: } Chris@101: Chris@101: Allocator &alloc() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return *this; } Chris@16: Chris@101: const Allocator &alloc() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return *this; } Chris@16: Chris@101: bool try_expand_fwd(size_type at_least) Chris@101: { return !at_least; } Chris@101: Chris@101: pointer start() const BOOST_NOEXCEPT_OR_NOTHROW { return Allocator::internal_storage(); } Chris@101: size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW { return Allocator::internal_capacity; } Chris@16: size_type m_size; Chris@16: Chris@16: private: Chris@16: Chris@16: template Chris@101: void priv_deep_swap(vector_alloc_holder &x) Chris@16: { Chris@101: const size_type MaxTmpStorage = sizeof(value_type)*Allocator::internal_capacity; Chris@16: value_type *const first_this = container_detail::to_raw_pointer(this->start()); Chris@16: value_type *const first_x = container_detail::to_raw_pointer(x.start()); Chris@16: Chris@16: if(this->m_size < x.m_size){ Chris@16: boost::container::deep_swap_alloc_n(this->alloc(), first_this, this->m_size, first_x, x.m_size); Chris@16: } Chris@16: else{ Chris@16: boost::container::deep_swap_alloc_n(this->alloc(), first_x, x.m_size, first_this, this->m_size); Chris@16: } Chris@101: boost::adl_move_swap(this->m_size, x.m_size); Chris@16: } Chris@16: }; Chris@16: Chris@16: } //namespace container_detail { Chris@16: Chris@101: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@16: Chris@16: //! A vector is a sequence that supports random access to elements, constant Chris@16: //! time insertion and removal of elements at the end, and linear time insertion Chris@16: //! and removal of elements at the beginning or in the middle. The number of Chris@16: //! elements in a vector may vary dynamically; memory management is automatic. Chris@101: //! Chris@101: //! \tparam T The type of object that is stored in the vector Chris@101: //! \tparam Allocator The allocator used for all internal memory management Chris@101: template ) > Chris@16: class vector Chris@16: { Chris@101: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@101: Chris@101: typedef typename container_detail::version::type alloc_version; Chris@101: typedef boost::container::container_detail::vector_alloc_holder alloc_holder_t; Chris@101: alloc_holder_t m_holder; Chris@16: typedef allocator_traits allocator_traits_type; Chris@16: template Chris@16: friend class vector; Chris@16: Chris@101: typedef typename allocator_traits_type::pointer pointer_impl; Chris@16: typedef container_detail::vec_iterator iterator_impl; Chris@16: typedef container_detail::vec_iterator const_iterator_impl; Chris@16: Chris@101: protected: Chris@101: static bool is_propagable_from(const Allocator &from_alloc, pointer_impl p, const Allocator &to_alloc, bool const propagate_allocator) Chris@101: { return alloc_holder_t::is_propagable_from(from_alloc, p, to_alloc, propagate_allocator); } Chris@101: Chris@101: static bool are_swap_propagable( const Allocator &l_a, pointer_impl l_p Chris@101: , const Allocator &r_a, pointer_impl r_p, bool const propagate_allocator) Chris@101: { return alloc_holder_t::are_swap_propagable(l_a, l_p, r_a, r_p, propagate_allocator); } Chris@101: Chris@101: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@16: public: Chris@16: ////////////////////////////////////////////// Chris@16: // Chris@16: // types Chris@16: // Chris@16: ////////////////////////////////////////////// Chris@16: Chris@16: typedef T value_type; Chris@16: typedef typename ::boost::container::allocator_traits::pointer pointer; Chris@16: typedef typename ::boost::container::allocator_traits::const_pointer const_pointer; Chris@16: typedef typename ::boost::container::allocator_traits::reference reference; Chris@16: typedef typename ::boost::container::allocator_traits::const_reference const_reference; Chris@16: typedef typename ::boost::container::allocator_traits::size_type size_type; Chris@16: typedef typename ::boost::container::allocator_traits::difference_type difference_type; Chris@16: typedef Allocator allocator_type; Chris@16: typedef Allocator stored_allocator_type; Chris@101: #if defined BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER Chris@16: typedef BOOST_CONTAINER_IMPDEF(pointer) iterator; Chris@16: typedef BOOST_CONTAINER_IMPDEF(const_pointer) const_iterator; Chris@16: #else Chris@16: typedef BOOST_CONTAINER_IMPDEF(iterator_impl) iterator; Chris@16: typedef BOOST_CONTAINER_IMPDEF(const_iterator_impl) const_iterator; Chris@16: #endif Chris@101: typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) reverse_iterator; Chris@101: typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) const_reverse_iterator; Chris@16: Chris@101: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@16: private: Chris@16: BOOST_COPYABLE_AND_MOVABLE(vector) Chris@101: typedef container_detail::vector_value_traits value_traits; Chris@101: typedef constant_iterator cvalue_iterator; Chris@16: Chris@101: protected: Chris@16: Chris@101: void steal_resources(vector &x) Chris@101: { return this->m_holder.steal_resources(x.m_holder); } Chris@101: Chris@101: struct initial_capacity_t{}; Chris@101: template Chris@101: vector(initial_capacity_t, pointer initial_memory, size_type capacity, BOOST_FWD_REF(AllocFwd) a) Chris@101: : m_holder(initial_memory, capacity, ::boost::forward(a)) Chris@101: {} Chris@101: Chris@101: vector(initial_capacity_t, pointer initial_memory, size_type capacity) Chris@101: : m_holder(initial_memory, capacity) Chris@101: {} Chris@101: Chris@101: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@16: Chris@16: public: Chris@16: ////////////////////////////////////////////// Chris@16: // Chris@16: // construct/copy/destroy Chris@16: // Chris@16: ////////////////////////////////////////////// Chris@16: Chris@16: //! Effects: Constructs a vector taking the allocator as parameter. Chris@16: //! Chris@101: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: vector() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: : m_holder() Chris@16: {} Chris@16: Chris@16: //! Effects: Constructs a vector taking the allocator as parameter. Chris@16: //! Chris@16: //! Throws: Nothing Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: explicit vector(const allocator_type& a) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: : m_holder(a) Chris@16: {} Chris@16: Chris@101: //! Effects: Constructs a vector and inserts n value initialized values. Chris@16: //! Chris@101: //! Throws: If allocator_type's allocation Chris@101: //! throws or T's value initialization throws. Chris@16: //! Chris@16: //! Complexity: Linear to n. Chris@16: explicit vector(size_type n) Chris@101: : m_holder(container_detail::uninitialized_size, n) Chris@16: { Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: this->num_alloc += n != 0; Chris@101: #endif Chris@16: boost::container::uninitialized_value_init_alloc_n Chris@16: (this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start())); Chris@16: } Chris@16: Chris@16: //! Effects: Constructs a vector that will use a copy of allocator a Chris@16: //! and inserts n default initialized values. Chris@16: //! Chris@101: //! Throws: If allocator_type's allocation Chris@101: //! throws or T's default initialization throws. Chris@16: //! Chris@16: //! Complexity: Linear to n. Chris@16: //! Chris@16: //! Note: Non-standard extension Chris@101: vector(size_type n, default_init_t) Chris@101: : m_holder(container_detail::uninitialized_size, n) Chris@16: { Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: this->num_alloc += n != 0; Chris@101: #endif Chris@101: boost::container::uninitialized_default_init_alloc_n Chris@101: (this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start())); Chris@101: } Chris@101: Chris@101: //! Effects: Constructs a vector that will use a copy of allocator a Chris@101: //! and inserts n value initialized values. Chris@101: //! Chris@101: //! Throws: If allocator_type's allocation Chris@101: //! throws or T's value initialization throws. Chris@101: //! Chris@101: //! Complexity: Linear to n. Chris@101: explicit vector(size_type n, const allocator_type &a) Chris@101: : m_holder(container_detail::uninitialized_size, a, n) Chris@101: { Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: this->num_alloc += n != 0; Chris@101: #endif Chris@101: boost::container::uninitialized_value_init_alloc_n Chris@101: (this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start())); Chris@101: } Chris@101: Chris@101: //! Effects: Constructs a vector that will use a copy of allocator a Chris@101: //! and inserts n default initialized values. Chris@101: //! Chris@101: //! Throws: If allocator_type's allocation Chris@101: //! throws or T's default initialization throws. Chris@101: //! Chris@101: //! Complexity: Linear to n. Chris@101: //! Chris@101: //! Note: Non-standard extension Chris@101: vector(size_type n, default_init_t, const allocator_type &a) Chris@101: : m_holder(container_detail::uninitialized_size, a, n) Chris@101: { Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: this->num_alloc += n != 0; Chris@101: #endif Chris@16: boost::container::uninitialized_default_init_alloc_n Chris@16: (this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start())); Chris@16: } Chris@16: Chris@16: //! Effects: Constructs a vector Chris@16: //! and inserts n copies of value. Chris@16: //! Chris@101: //! Throws: If allocator_type's allocation Chris@16: //! throws or T's copy constructor throws. Chris@16: //! Chris@16: //! Complexity: Linear to n. Chris@16: vector(size_type n, const T& value) Chris@101: : m_holder(container_detail::uninitialized_size, n) Chris@16: { Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: this->num_alloc += n != 0; Chris@101: #endif Chris@16: boost::container::uninitialized_fill_alloc_n Chris@16: (this->m_holder.alloc(), value, n, container_detail::to_raw_pointer(this->m_holder.start())); Chris@16: } Chris@16: Chris@16: //! Effects: Constructs a vector that will use a copy of allocator a Chris@16: //! and inserts n copies of value. Chris@16: //! Chris@16: //! Throws: If allocation Chris@16: //! throws or T's copy constructor throws. Chris@16: //! Chris@16: //! Complexity: Linear to n. Chris@16: vector(size_type n, const T& value, const allocator_type& a) Chris@101: : m_holder(container_detail::uninitialized_size, a, n) Chris@16: { Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: this->num_alloc += n != 0; Chris@101: #endif Chris@16: boost::container::uninitialized_fill_alloc_n Chris@16: (this->m_holder.alloc(), value, n, container_detail::to_raw_pointer(this->m_holder.start())); Chris@16: } Chris@16: Chris@16: //! Effects: Constructs a vector Chris@16: //! and inserts a copy of the range [first, last) in the vector. Chris@16: //! Chris@101: //! Throws: If allocator_type's allocation Chris@101: //! throws or T's constructor taking a dereferenced InIt throws. Chris@16: //! Chris@16: //! Complexity: Linear to the range [first, last). Chris@16: template Chris@16: vector(InIt first, InIt last) Chris@16: : m_holder() Chris@101: { this->assign(first, last); } Chris@16: Chris@16: //! Effects: Constructs a vector that will use a copy of allocator a Chris@16: //! and inserts a copy of the range [first, last) in the vector. Chris@16: //! Chris@101: //! Throws: If allocator_type's allocation Chris@101: //! throws or T's constructor taking a dereferenced InIt throws. Chris@16: //! Chris@16: //! Complexity: Linear to the range [first, last). Chris@16: template Chris@16: vector(InIt first, InIt last, const allocator_type& a) Chris@16: : m_holder(a) Chris@101: { this->assign(first, last); } Chris@16: Chris@16: //! Effects: Copy constructs a vector. Chris@16: //! Chris@16: //! Postcondition: x == *this. Chris@16: //! Chris@101: //! Throws: If allocator_type's allocation Chris@16: //! throws or T's copy constructor throws. Chris@16: //! Chris@16: //! Complexity: Linear to the elements x contains. Chris@16: vector(const vector &x) Chris@101: : m_holder( container_detail::uninitialized_size Chris@101: , allocator_traits_type::select_on_container_copy_construction(x.m_holder.alloc()) Chris@101: , x.size()) Chris@16: { Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: this->num_alloc += x.size() != 0; Chris@101: #endif Chris@16: ::boost::container::uninitialized_copy_alloc_n Chris@16: ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start()) Chris@16: , x.size(), container_detail::to_raw_pointer(this->m_holder.start())); Chris@16: } Chris@16: Chris@101: //! Effects: Move constructor. Moves x's resources to *this. Chris@16: //! Chris@16: //! Throws: Nothing Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: vector(BOOST_RV_REF(vector) x) BOOST_NOEXCEPT_OR_NOTHROW Chris@101: : m_holder(boost::move(x.m_holder)) Chris@101: { BOOST_STATIC_ASSERT((!allocator_traits_type::is_partially_propagable::value)); } Chris@101: Chris@101: #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) Chris@101: //! Effects: Constructs a vector that will use a copy of allocator a Chris@101: //! and inserts a copy of the range [il.begin(), il.last()) in the vector Chris@101: //! Chris@101: //! Throws: If T's constructor taking a dereferenced initializer_list iterator throws. Chris@101: //! Chris@101: //! Complexity: Linear to the range [il.begin(), il.end()). Chris@101: vector(std::initializer_list il, const allocator_type& a = allocator_type()) Chris@101: : m_holder(a) Chris@101: { Chris@101: this->assign(il.begin(), il.end()); Chris@101: } Chris@101: #endif Chris@16: Chris@16: #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) Chris@16: Chris@101: //! Effects: Move constructor. Moves x's resources to *this. Chris@16: //! Chris@16: //! Throws: If T's move constructor or allocation throws Chris@16: //! Chris@16: //! Complexity: Linear. Chris@16: //! Chris@101: //! Note: Non-standard extension to support static_vector Chris@16: template Chris@101: vector(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x Chris@101: , typename container_detail::enable_if_c Chris@101: < container_detail::is_version::value>::type * = 0 Chris@101: ) Chris@101: : m_holder(boost::move(x.m_holder)) Chris@16: {} Chris@16: Chris@16: #endif //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED) Chris@16: Chris@16: //! Effects: Copy constructs a vector using the specified allocator. Chris@16: //! Chris@16: //! Postcondition: x == *this. Chris@16: //! Chris@16: //! Throws: If allocation Chris@16: //! throws or T's copy constructor throws. Chris@16: //! Chris@16: //! Complexity: Linear to the elements x contains. Chris@16: vector(const vector &x, const allocator_type &a) Chris@101: : m_holder(container_detail::uninitialized_size, a, x.size()) Chris@16: { Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: this->num_alloc += x.size() != 0; Chris@101: #endif Chris@16: ::boost::container::uninitialized_copy_alloc_n_source Chris@16: ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start()) Chris@16: , x.size(), container_detail::to_raw_pointer(this->m_holder.start())); Chris@16: } Chris@16: Chris@16: //! Effects: Move constructor using the specified allocator. Chris@101: //! Moves x's resources to *this if a == allocator_type(). Chris@16: //! Otherwise copies values from x to *this. Chris@16: //! Chris@16: //! Throws: If allocation or T's copy constructor throws. Chris@16: //! Chris@101: //! Complexity: Constant if a == x.get_allocator(), linear otherwise. Chris@101: vector(BOOST_RV_REF(vector) x, const allocator_type &a) Chris@101: : m_holder( container_detail::uninitialized_size, a Chris@101: , is_propagable_from(x.get_stored_allocator(), x.m_holder.start(), a, true) ? 0 : x.size() Chris@101: ) Chris@16: { Chris@101: if(is_propagable_from(x.get_stored_allocator(), x.m_holder.start(), a, true)){ Chris@101: this->m_holder.steal_resources(x.m_holder); Chris@16: } Chris@16: else{ Chris@101: const size_type n = x.size(); Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: this->num_alloc += n != 0; Chris@101: #endif Chris@16: ::boost::container::uninitialized_move_alloc_n_source Chris@101: ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start()) Chris@16: , n, container_detail::to_raw_pointer(this->m_holder.start())); Chris@16: } Chris@16: } Chris@16: Chris@16: //! Effects: Destroys the vector. All stored values are destroyed Chris@16: //! and used memory is deallocated. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Linear to the number of elements. Chris@101: ~vector() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { Chris@16: boost::container::destroy_alloc_n Chris@16: (this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size); Chris@16: //vector_alloc_holder deallocates the data Chris@101: } Chris@16: Chris@16: //! Effects: Makes *this contain the same elements as x. Chris@16: //! Chris@16: //! Postcondition: this->size() == x.size(). *this contains a copy Chris@16: //! of each of x's elements. Chris@16: //! Chris@16: //! Throws: If memory allocation throws or T's copy/move constructor/assignment throws. Chris@16: //! Chris@16: //! Complexity: Linear to the number of elements in x. Chris@16: vector& operator=(BOOST_COPY_ASSIGN_REF(vector) x) Chris@16: { Chris@16: if (&x != this){ Chris@101: this->priv_copy_assign(x); Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: Chris@101: #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) Chris@101: //! Effects: Make *this container contains elements from il. Chris@101: //! Chris@101: //! Complexity: Linear to the range [il.begin(), il.end()). Chris@101: vector& operator=(std::initializer_list il) Chris@101: { Chris@101: this->assign(il.begin(), il.end()); Chris@101: return *this; Chris@101: } Chris@101: #endif Chris@101: Chris@101: //! Effects: Move assignment. All x's values are transferred to *this. Chris@16: //! Chris@16: //! Postcondition: x.empty(). *this contains a the elements x had Chris@16: //! before the function. Chris@16: //! Chris@101: //! Throws: If allocator_traits_type::propagate_on_container_move_assignment Chris@101: //! is false and (allocation throws or value_type's move constructor throws) Chris@16: //! Chris@101: //! Complexity: Constant if allocator_traits_type:: Chris@101: //! propagate_on_container_move_assignment is true or Chris@101: //! this->get>allocator() == x.get_allocator(). Linear otherwise. Chris@16: vector& operator=(BOOST_RV_REF(vector) x) Chris@101: BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value Chris@101: || allocator_traits_type::is_always_equal::value) Chris@16: { Chris@101: this->priv_move_assign(boost::move(x)); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) Chris@16: Chris@101: //! Effects: Move assignment. All x's values are transferred to *this. Chris@16: //! Chris@16: //! Postcondition: x.empty(). *this contains a the elements x had Chris@16: //! before the function. Chris@16: //! Chris@16: //! Throws: If move constructor/assignment of T throws or allocation throws Chris@16: //! Chris@16: //! Complexity: Linear. Chris@101: //! Chris@101: //! Note: Non-standard extension to support static_vector Chris@101: template Chris@101: typename container_detail::enable_if_c Chris@101: < container_detail::is_version::value && Chris@101: !container_detail::is_same::value Chris@101: , vector& >::type Chris@101: operator=(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x) Chris@16: { Chris@101: this->priv_move_assign(boost::move(x)); Chris@101: return *this; Chris@101: } Chris@101: Chris@101: //! Effects: Copy assignment. All x's values are copied to *this. Chris@101: //! Chris@101: //! Postcondition: x.empty(). *this contains a the elements x had Chris@101: //! before the function. Chris@101: //! Chris@101: //! Throws: If move constructor/assignment of T throws or allocation throws Chris@101: //! Chris@101: //! Complexity: Linear. Chris@101: //! Chris@101: //! Note: Non-standard extension to support static_vector Chris@101: template Chris@101: typename container_detail::enable_if_c Chris@101: < container_detail::is_version::value && Chris@101: !container_detail::is_same::value Chris@101: , vector& >::type Chris@101: operator=(const vector &x) Chris@101: { Chris@101: this->priv_copy_assign(x); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: #endif Chris@16: Chris@16: //! Effects: Assigns the the range [first, last) to *this. Chris@16: //! Chris@16: //! Throws: If memory allocation throws or T's copy/move constructor/assignment or Chris@16: //! T's constructor/assignment from dereferencing InpIt throws. Chris@16: //! Chris@16: //! Complexity: Linear to n. Chris@16: template Chris@16: void assign(InIt first, InIt last Chris@101: BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename container_detail::enable_if_c Chris@101: < !container_detail::is_convertible::value && Chris@101: ( container_detail::is_input_iterator::value || Chris@101: container_detail::is_same::value ) Chris@101: >::type * = 0) ) Chris@16: { Chris@16: //Overwrite all elements we can from [first, last) Chris@16: iterator cur = this->begin(); Chris@16: const iterator end_it = this->end(); Chris@16: for ( ; first != last && cur != end_it; ++cur, ++first){ Chris@16: *cur = *first; Chris@16: } Chris@16: Chris@16: if (first == last){ Chris@16: //There are no more elements in the sequence, erase remaining Chris@101: T* const end_pos = this->back_raw(); Chris@101: const size_type n = static_cast(end_pos - container_detail::iterator_to_raw_pointer(cur)); Chris@16: this->priv_destroy_last_n(n); Chris@16: } Chris@16: else{ Chris@16: //There are more elements in the range, insert the remaining ones Chris@16: this->insert(this->cend(), first, last); Chris@16: } Chris@16: } Chris@16: Chris@101: #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) Chris@101: //! Effects: Assigns the the range [il.begin(), il.end()) to *this. Chris@101: //! Chris@101: //! Throws: If memory allocation throws or Chris@101: //! T's constructor from dereferencing iniializer_list iterator throws. Chris@101: //! Chris@101: void assign(std::initializer_list il) Chris@101: { Chris@101: this->assign(il.begin(), il.end()); Chris@101: } Chris@101: #endif Chris@101: Chris@101: //! Effects: Assigns the the range [first, last) to *this. Chris@101: //! Chris@101: //! Throws: If memory allocation throws or T's copy/move constructor/assignment or Chris@101: //! T's constructor/assignment from dereferencing InpIt throws. Chris@101: //! Chris@101: //! Complexity: Linear to n. Chris@101: template Chris@101: void assign(FwdIt first, FwdIt last Chris@101: BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename container_detail::enable_if_c Chris@101: < !container_detail::is_convertible::value && Chris@101: ( !container_detail::is_input_iterator::value && Chris@101: !container_detail::is_same::value ) Chris@101: >::type * = 0) Chris@101: ) Chris@101: { Chris@101: //For Fwd iterators the standard only requires EmplaceConstructible and assignable from *first Chris@101: //so we can't do any backwards allocation Chris@101: const size_type input_sz = static_cast(boost::container::iterator_distance(first, last)); Chris@101: const size_type old_capacity = this->capacity(); Chris@101: if(input_sz > old_capacity){ //If input range is too big, we need to reallocate Chris@101: size_type real_cap = 0; Chris@101: pointer reuse(this->m_holder.start()); Chris@101: pointer const ret(this->m_holder.allocation_command(allocate_new|expand_fwd, input_sz, real_cap = input_sz, reuse)); Chris@101: if(!reuse){ //New allocation, just emplace new values Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: ++this->num_alloc; Chris@101: #endif Chris@101: pointer const old_p = this->m_holder.start(); Chris@101: if(old_p){ Chris@101: this->priv_destroy_all(); Chris@101: this->m_holder.alloc().deallocate(old_p, old_capacity); Chris@101: } Chris@101: this->m_holder.start(ret); Chris@101: this->m_holder.capacity(real_cap); Chris@101: this->m_holder.m_size = 0; Chris@101: this->priv_uninitialized_construct_at_end(first, last); Chris@101: return; Chris@101: } Chris@101: else{ Chris@101: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@101: ++this->num_expand_fwd; Chris@101: #endif Chris@101: this->m_holder.capacity(real_cap); Chris@101: //Forward expansion, use assignment + back deletion/construction that comes later Chris@101: } Chris@101: } Chris@101: //Overwrite all elements we can from [first, last) Chris@101: iterator cur = this->begin(); Chris@101: const iterator end_it = this->end(); Chris@101: for ( ; first != last && cur != end_it; ++cur, ++first){ Chris@101: *cur = *first; Chris@101: } Chris@101: Chris@101: if (first == last){ Chris@101: //There are no more elements in the sequence, erase remaining Chris@101: this->priv_destroy_last_n(this->size() - input_sz); Chris@101: } Chris@101: else{ Chris@101: //Uninitialized construct at end the remaining range Chris@101: this->priv_uninitialized_construct_at_end(first, last); Chris@101: } Chris@101: } Chris@101: Chris@16: //! Effects: Assigns the n copies of val to *this. Chris@16: //! Chris@16: //! Throws: If memory allocation throws or Chris@16: //! T's copy/move constructor/assignment throws. Chris@16: //! Chris@16: //! Complexity: Linear to n. Chris@16: void assign(size_type n, const value_type& val) Chris@16: { this->assign(cvalue_iterator(val, n), cvalue_iterator()); } Chris@16: Chris@16: //! Effects: Returns a copy of the internal allocator. Chris@16: //! Chris@16: //! Throws: If allocator's copy constructor throws. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: allocator_type get_allocator() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return this->m_holder.alloc(); } Chris@16: Chris@16: //! Effects: Returns a reference to the internal allocator. Chris@16: //! Chris@16: //! Throws: Nothing Chris@16: //! Chris@16: //! Complexity: Constant. Chris@16: //! Chris@16: //! Note: Non-standard extension. Chris@101: stored_allocator_type &get_stored_allocator() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return this->m_holder.alloc(); } Chris@16: Chris@16: //! Effects: Returns a reference to the internal allocator. Chris@16: //! Chris@16: //! Throws: Nothing Chris@16: //! Chris@16: //! Complexity: Constant. Chris@16: //! Chris@16: //! Note: Non-standard extension. Chris@101: const stored_allocator_type &get_stored_allocator() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return this->m_holder.alloc(); } Chris@16: Chris@16: ////////////////////////////////////////////// Chris@16: // Chris@16: // iterators Chris@16: // Chris@16: ////////////////////////////////////////////// Chris@16: Chris@16: //! Effects: Returns an iterator to the first element contained in the vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: iterator begin() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return iterator(this->m_holder.start()); } Chris@16: Chris@16: //! Effects: Returns a const_iterator to the first element contained in the vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: const_iterator begin() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return const_iterator(this->m_holder.start()); } Chris@16: Chris@16: //! Effects: Returns an iterator to the end of the vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: iterator end() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return iterator(this->m_holder.start() + this->m_holder.m_size); } Chris@16: Chris@16: //! Effects: Returns a const_iterator to the end of the vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: const_iterator end() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return this->cend(); } Chris@16: Chris@16: //! Effects: Returns a reverse_iterator pointing to the beginning Chris@16: //! of the reversed vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: reverse_iterator rbegin() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return reverse_iterator(this->end()); } Chris@16: Chris@16: //! Effects: Returns a const_reverse_iterator pointing to the beginning Chris@16: //! of the reversed vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: const_reverse_iterator rbegin() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return this->crbegin(); } Chris@16: Chris@16: //! Effects: Returns a reverse_iterator pointing to the end Chris@16: //! of the reversed vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: reverse_iterator rend() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return reverse_iterator(this->begin()); } Chris@16: Chris@16: //! Effects: Returns a const_reverse_iterator pointing to the end Chris@16: //! of the reversed vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: const_reverse_iterator rend() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return this->crend(); } Chris@16: Chris@16: //! Effects: Returns a const_iterator to the first element contained in the vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: const_iterator cbegin() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return const_iterator(this->m_holder.start()); } Chris@16: Chris@16: //! Effects: Returns a const_iterator to the end of the vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: const_iterator cend() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return const_iterator(this->m_holder.start() + this->m_holder.m_size); } Chris@16: Chris@16: //! Effects: Returns a const_reverse_iterator pointing to the beginning Chris@16: //! of the reversed vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: const_reverse_iterator crbegin() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return const_reverse_iterator(this->end());} Chris@16: Chris@16: //! Effects: Returns a const_reverse_iterator pointing to the end Chris@16: //! of the reversed vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return const_reverse_iterator(this->begin()); } Chris@16: Chris@16: ////////////////////////////////////////////// Chris@16: // Chris@16: // capacity Chris@16: // Chris@16: ////////////////////////////////////////////// Chris@16: Chris@16: //! Effects: Returns true if the vector contains no elements. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: bool empty() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return !this->m_holder.m_size; } Chris@16: Chris@16: //! Effects: Returns the number of the elements contained in the vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: size_type size() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return this->m_holder.m_size; } Chris@16: Chris@16: //! Effects: Returns the largest possible size of the vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return allocator_traits_type::max_size(this->m_holder.alloc()); } Chris@16: Chris@16: //! Effects: Inserts or erases elements at the end such that Chris@16: //! the size becomes n. New elements are value initialized. Chris@16: //! Chris@101: //! Throws: If memory allocation throws, or T's copy/move or value initialization throws. Chris@16: //! Chris@16: //! Complexity: Linear to the difference between size() and new_size. Chris@16: void resize(size_type new_size) Chris@101: { this->priv_resize(new_size, value_init); } Chris@16: Chris@16: //! Effects: Inserts or erases elements at the end such that Chris@101: //! the size becomes n. New elements are default initialized. Chris@16: //! Chris@101: //! Throws: If memory allocation throws, or T's copy/move or default initialization throws. Chris@16: //! Chris@16: //! Complexity: Linear to the difference between size() and new_size. Chris@16: //! Chris@16: //! Note: Non-standard extension Chris@16: void resize(size_type new_size, default_init_t) Chris@101: { this->priv_resize(new_size, default_init); } Chris@16: Chris@16: //! Effects: Inserts or erases elements at the end such that Chris@16: //! the size becomes n. New elements are copy constructed from x. Chris@16: //! Chris@101: //! Throws: If memory allocation throws, or T's copy/move constructor throws. Chris@16: //! Chris@16: //! Complexity: Linear to the difference between size() and new_size. Chris@16: void resize(size_type new_size, const T& x) Chris@101: { this->priv_resize(new_size, x); } Chris@16: Chris@16: //! Effects: Number of elements for which memory has been allocated. Chris@16: //! capacity() is always greater than or equal to size(). Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return this->m_holder.capacity(); } Chris@16: Chris@16: //! Effects: If n is less than or equal to capacity(), this call has no Chris@16: //! effect. Otherwise, it is a request for allocation of additional memory. Chris@16: //! If the request is successful, then capacity() is greater than or equal to Chris@16: //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. Chris@16: //! Chris@16: //! Throws: If memory allocation allocation throws or T's copy/move constructor throws. Chris@16: void reserve(size_type new_cap) Chris@16: { Chris@16: if (this->capacity() < new_cap){ Chris@101: this->priv_reserve_no_capacity(new_cap, alloc_version()); Chris@16: } Chris@16: } Chris@16: Chris@16: //! Effects: Tries to deallocate the excess of memory created Chris@16: //! with previous allocations. The size of the vector is unchanged Chris@16: //! Chris@16: //! Throws: If memory allocation throws, or T's copy/move constructor throws. Chris@16: //! Chris@16: //! Complexity: Linear to size(). Chris@16: void shrink_to_fit() Chris@16: { this->priv_shrink_to_fit(alloc_version()); } Chris@16: Chris@16: ////////////////////////////////////////////// Chris@16: // Chris@16: // element access Chris@16: // Chris@16: ////////////////////////////////////////////// Chris@16: Chris@16: //! Requires: !empty() Chris@16: //! Chris@16: //! Effects: Returns a reference to the first Chris@16: //! element of the container. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: reference front() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return *this->m_holder.start(); } Chris@16: Chris@16: //! Requires: !empty() Chris@16: //! Chris@16: //! Effects: Returns a const reference to the first Chris@16: //! element of the container. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: const_reference front() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return *this->m_holder.start(); } Chris@16: Chris@16: //! Requires: !empty() Chris@16: //! Chris@16: //! Effects: Returns a reference to the last Chris@16: //! element of the container. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: reference back() BOOST_NOEXCEPT_OR_NOTHROW Chris@101: { Chris@101: BOOST_ASSERT(this->m_holder.m_size > 0); Chris@101: return this->m_holder.start()[this->m_holder.m_size - 1]; Chris@101: } Chris@16: Chris@16: //! Requires: !empty() Chris@16: //! Chris@16: //! Effects: Returns a const reference to the last Chris@16: //! element of the container. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: const_reference back() const BOOST_NOEXCEPT_OR_NOTHROW Chris@101: { Chris@101: BOOST_ASSERT(this->m_holder.m_size > 0); Chris@101: return this->m_holder.start()[this->m_holder.m_size - 1]; Chris@101: } Chris@16: Chris@16: //! Requires: size() > n. Chris@16: //! Chris@16: //! Effects: Returns a reference to the nth element Chris@16: //! from the beginning of the container. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: reference operator[](size_type n) BOOST_NOEXCEPT_OR_NOTHROW Chris@101: { Chris@101: BOOST_ASSERT(this->m_holder.m_size > n); Chris@101: return this->m_holder.start()[n]; Chris@101: } Chris@16: Chris@16: //! Requires: size() > n. Chris@16: //! Chris@16: //! Effects: Returns a const reference to the nth element Chris@16: //! from the beginning of the container. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: const_reference operator[](size_type n) const BOOST_NOEXCEPT_OR_NOTHROW Chris@101: { Chris@101: return this->m_holder.start()[n]; Chris@101: } Chris@101: Chris@101: //! Requires: size() >= n. Chris@101: //! Chris@101: //! Effects: Returns an iterator to the nth element Chris@101: //! from the beginning of the container. Returns end() Chris@101: //! if n == size(). Chris@101: //! Chris@101: //! Throws: Nothing. Chris@101: //! Chris@101: //! Complexity: Constant. Chris@101: //! Chris@101: //! Note: Non-standard extension Chris@101: iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW Chris@101: { Chris@101: BOOST_ASSERT(this->m_holder.m_size >= n); Chris@101: return iterator(this->m_holder.start()+n); Chris@101: } Chris@101: Chris@101: //! Requires: size() >= n. Chris@101: //! Chris@101: //! Effects: Returns a const_iterator to the nth element Chris@101: //! from the beginning of the container. Returns end() Chris@101: //! if n == size(). Chris@101: //! Chris@101: //! Throws: Nothing. Chris@101: //! Chris@101: //! Complexity: Constant. Chris@101: //! Chris@101: //! Note: Non-standard extension Chris@101: const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW Chris@101: { Chris@101: BOOST_ASSERT(this->m_holder.m_size >= n); Chris@101: return const_iterator(this->m_holder.start()+n); Chris@101: } Chris@101: Chris@101: //! Requires: size() >= n. Chris@101: //! Chris@101: //! Effects: Returns an iterator to the nth element Chris@101: //! from the beginning of the container. Returns end() Chris@101: //! if n == size(). Chris@101: //! Chris@101: //! Throws: Nothing. Chris@101: //! Chris@101: //! Complexity: Constant. Chris@101: //! Chris@101: //! Note: Non-standard extension Chris@101: size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW Chris@101: { return this->priv_index_of(vector_iterator_get_ptr(p)); } Chris@101: Chris@101: //! Requires: begin() <= p <= end(). Chris@101: //! Chris@101: //! Effects: Returns the index of the element pointed by p Chris@101: //! and size() if p == end(). Chris@101: //! Chris@101: //! Throws: Nothing. Chris@101: //! Chris@101: //! Complexity: Constant. Chris@101: //! Chris@101: //! Note: Non-standard extension Chris@101: size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW Chris@101: { return this->priv_index_of(vector_iterator_get_ptr(p)); } Chris@16: Chris@16: //! Requires: size() > n. Chris@16: //! Chris@16: //! Effects: Returns a reference to the nth element Chris@16: //! from the beginning of the container. Chris@16: //! Chris@16: //! Throws: std::range_error if n >= size() Chris@16: //! Chris@16: //! Complexity: Constant. Chris@16: reference at(size_type n) Chris@16: { this->priv_check_range(n); return this->m_holder.start()[n]; } Chris@16: Chris@16: //! Requires: size() > n. Chris@16: //! Chris@16: //! Effects: Returns a const reference to the nth element Chris@16: //! from the beginning of the container. Chris@16: //! Chris@16: //! Throws: std::range_error if n >= size() Chris@16: //! Chris@16: //! Complexity: Constant. Chris@16: const_reference at(size_type n) const Chris@16: { this->priv_check_range(n); return this->m_holder.start()[n]; } Chris@16: Chris@16: ////////////////////////////////////////////// Chris@16: // Chris@16: // data access Chris@16: // Chris@16: ////////////////////////////////////////////// Chris@16: Chris@101: //! Returns: A pointer such that [data(),data() + size()) is a valid range. Chris@16: //! For a non-empty vector, data() == &front(). Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: T* data() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return container_detail::to_raw_pointer(this->m_holder.start()); } Chris@16: Chris@101: //! Returns: A pointer such that [data(),data() + size()) is a valid range. Chris@16: //! For a non-empty vector, data() == &front(). Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: const T * data() const BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { return container_detail::to_raw_pointer(this->m_holder.start()); } Chris@16: Chris@16: ////////////////////////////////////////////// Chris@16: // Chris@16: // modifiers Chris@16: // Chris@16: ////////////////////////////////////////////// Chris@16: Chris@101: #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) Chris@16: //! Effects: Inserts an object of type T constructed with Chris@16: //! std::forward(args)... in the end of the vector. Chris@16: //! Chris@16: //! Throws: If memory allocation throws or the in-place constructor throws or Chris@101: //! T's copy/move constructor throws. Chris@16: //! Chris@16: //! Complexity: Amortized constant time. Chris@16: template Chris@101: void emplace_back(BOOST_FWD_REF(Args)...args) Chris@16: { Chris@101: if (BOOST_LIKELY(this->room_enough())){ Chris@16: //There is more memory, just construct a new object at the end Chris@101: allocator_traits_type::construct(this->m_holder.alloc(), this->back_raw(), ::boost::forward(args)...); Chris@16: ++this->m_holder.m_size; Chris@16: } Chris@16: else{ Chris@16: typedef container_detail::insert_emplace_proxy type; Chris@16: this->priv_forward_range_insert_no_capacity Chris@101: (this->back_ptr(), 1, type(::boost::forward(args)...), alloc_version()); Chris@16: } Chris@16: } Chris@16: Chris@101: //! Effects: Inserts an object of type T constructed with Chris@101: //! std::forward(args)... in the end of the vector. Chris@101: //! Chris@101: //! Throws: If the in-place constructor throws. Chris@101: //! Chris@101: //! Complexity: Constant time. Chris@101: //! Chris@101: //! Note: Non-standard extension. Chris@101: template Chris@101: bool stable_emplace_back(BOOST_FWD_REF(Args)...args) Chris@101: { Chris@101: const bool is_room_enough = this->room_enough() || (alloc_version::value == 2 && this->m_holder.try_expand_fwd(1u)); Chris@101: if (BOOST_LIKELY(is_room_enough)){ Chris@101: //There is more memory, just construct a new object at the end Chris@101: allocator_traits_type::construct(this->m_holder.alloc(), this->back_raw(), ::boost::forward(args)...); Chris@101: ++this->m_holder.m_size; Chris@101: } Chris@101: return is_room_enough; Chris@101: } Chris@101: Chris@16: //! Requires: position must be a valid iterator of *this. Chris@16: //! Chris@16: //! Effects: Inserts an object of type T constructed with Chris@16: //! std::forward(args)... before position Chris@16: //! Chris@16: //! Throws: If memory allocation throws or the in-place constructor throws or Chris@101: //! T's copy/move constructor/assignment throws. Chris@16: //! Chris@16: //! Complexity: If position is end(), amortized constant time Chris@16: //! Linear time otherwise. Chris@16: template Chris@101: iterator emplace(const_iterator position, BOOST_FWD_REF(Args) ...args) Chris@16: { Chris@16: //Just call more general insert(pos, size, value) and return iterator Chris@16: typedef container_detail::insert_emplace_proxy type; Chris@101: return this->priv_forward_range_insert( vector_iterator_get_ptr(position), 1 Chris@101: , type(::boost::forward(args)...)); Chris@16: } Chris@16: Chris@101: #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) Chris@16: Chris@101: #define BOOST_CONTAINER_VECTOR_EMPLACE_CODE(N) \ Chris@101: BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ Chris@101: void emplace_back(BOOST_MOVE_UREF##N)\ Chris@101: {\ Chris@101: if (BOOST_LIKELY(this->room_enough())){\ Chris@101: allocator_traits_type::construct (this->m_holder.alloc()\ Chris@101: , this->back_raw() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ Chris@101: ++this->m_holder.m_size;\ Chris@101: }\ Chris@101: else{\ Chris@101: typedef container_detail::insert_emplace_proxy_arg##N type;\ Chris@101: this->priv_forward_range_insert_no_capacity\ Chris@101: ( this->back_ptr(), 1, type(BOOST_MOVE_FWD##N), alloc_version());\ Chris@101: }\ Chris@101: }\ Chris@101: \ Chris@101: BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ Chris@101: bool stable_emplace_back(BOOST_MOVE_UREF##N)\ Chris@101: {\ Chris@101: const bool is_room_enough = this->room_enough() || (alloc_version::value == 2 && this->m_holder.try_expand_fwd(1u));\ Chris@101: if (BOOST_LIKELY(is_room_enough)){\ Chris@101: allocator_traits_type::construct (this->m_holder.alloc()\ Chris@101: , this->back_raw() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ Chris@101: ++this->m_holder.m_size;\ Chris@101: }\ Chris@101: return is_room_enough;\ Chris@101: }\ Chris@101: \ Chris@101: BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ Chris@101: iterator emplace(const_iterator pos BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ Chris@101: {\ Chris@101: typedef container_detail::insert_emplace_proxy_arg##N type;\ Chris@101: return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), 1, type(BOOST_MOVE_FWD##N));\ Chris@101: }\ Chris@101: // Chris@101: BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_VECTOR_EMPLACE_CODE) Chris@101: #undef BOOST_CONTAINER_VECTOR_EMPLACE_CODE Chris@16: Chris@101: #endif Chris@16: Chris@16: #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) Chris@16: //! Effects: Inserts a copy of x at the end of the vector. Chris@16: //! Chris@16: //! Throws: If memory allocation throws or Chris@16: //! T's copy/move constructor throws. Chris@16: //! Chris@16: //! Complexity: Amortized constant time. Chris@16: void push_back(const T &x); Chris@16: Chris@16: //! Effects: Constructs a new element in the end of the vector Chris@101: //! and moves the resources of x to this new element. Chris@16: //! Chris@16: //! Throws: If memory allocation throws or Chris@101: //! T's copy/move constructor throws. Chris@16: //! Chris@16: //! Complexity: Amortized constant time. Chris@16: void push_back(T &&x); Chris@16: #else Chris@16: BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) Chris@16: #endif Chris@101: Chris@16: #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) Chris@16: //! Requires: position must be a valid iterator of *this. Chris@16: //! Chris@16: //! Effects: Insert a copy of x before position. Chris@16: //! Chris@16: //! Throws: If memory allocation throws or T's copy/move constructor/assignment throws. Chris@16: //! Chris@16: //! Complexity: If position is end(), amortized constant time Chris@16: //! Linear time otherwise. Chris@16: iterator insert(const_iterator position, const T &x); Chris@16: Chris@16: //! Requires: position must be a valid iterator of *this. Chris@16: //! Chris@101: //! Effects: Insert a new element before position with x's resources. Chris@16: //! Chris@16: //! Throws: If memory allocation throws. Chris@16: //! Chris@16: //! Complexity: If position is end(), amortized constant time Chris@16: //! Linear time otherwise. Chris@16: iterator insert(const_iterator position, T &&x); Chris@16: #else Chris@16: BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator, const_iterator) Chris@16: #endif Chris@16: Chris@16: //! Requires: p must be a valid iterator of *this. Chris@16: //! Chris@16: //! Effects: Insert n copies of x before pos. Chris@16: //! Chris@16: //! Returns: an iterator to the first inserted element or p if n is 0. Chris@16: //! Chris@101: //! Throws: If memory allocation throws or T's copy/move constructor throws. Chris@16: //! Chris@16: //! Complexity: Linear to n. Chris@16: iterator insert(const_iterator p, size_type n, const T& x) Chris@16: { Chris@101: container_detail::insert_n_copies_proxy proxy(x); Chris@101: return this->priv_forward_range_insert(vector_iterator_get_ptr(p), n, proxy); Chris@16: } Chris@16: Chris@16: //! Requires: p must be a valid iterator of *this. Chris@16: //! Chris@16: //! Effects: Insert a copy of the [first, last) range before pos. Chris@16: //! Chris@16: //! Returns: an iterator to the first inserted element or pos if first == last. Chris@16: //! Chris@16: //! Throws: If memory allocation throws, T's constructor from a Chris@16: //! dereferenced InpIt throws or T's copy/move constructor/assignment throws. Chris@16: //! Chris@101: //! Complexity: Linear to boost::container::iterator_distance [first, last). Chris@16: template Chris@16: iterator insert(const_iterator pos, InIt first, InIt last Chris@101: BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename container_detail::enable_if_c Chris@101: < !container_detail::is_convertible::value Chris@16: && container_detail::is_input_iterator::value Chris@101: >::type * = 0) Chris@16: ) Chris@16: { Chris@16: const size_type n_pos = pos - this->cbegin(); Chris@16: iterator it(vector_iterator_get_ptr(pos)); Chris@16: for(;first != last; ++first){ Chris@16: it = this->emplace(it, *first); Chris@16: ++it; Chris@16: } Chris@16: return iterator(this->m_holder.start() + n_pos); Chris@16: } Chris@16: Chris@16: #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) Chris@16: template Chris@16: iterator insert(const_iterator pos, FwdIt first, FwdIt last Chris@16: , typename container_detail::enable_if_c Chris@16: < !container_detail::is_convertible::value Chris@16: && !container_detail::is_input_iterator::value Chris@16: >::type * = 0 Chris@16: ) Chris@16: { Chris@101: container_detail::insert_range_proxy proxy(first); Chris@101: return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), boost::container::iterator_distance(first, last), proxy); Chris@101: } Chris@101: #endif Chris@101: Chris@101: //! Requires: p must be a valid iterator of *this. num, must Chris@101: //! be equal to boost::container::iterator_distance(first, last) Chris@101: //! Chris@101: //! Effects: Insert a copy of the [first, last) range before pos. Chris@101: //! Chris@101: //! Returns: an iterator to the first inserted element or pos if first == last. Chris@101: //! Chris@101: //! Throws: If memory allocation throws, T's constructor from a Chris@101: //! dereferenced InpIt throws or T's copy/move constructor/assignment throws. Chris@101: //! Chris@101: //! Complexity: Linear to boost::container::iterator_distance [first, last). Chris@101: //! Chris@101: //! Note: This function avoids a linear operation to calculate boost::container::iterator_distance[first, last) Chris@101: //! for forward and bidirectional iterators, and a one by one insertion for input iterators. This is a Chris@101: //! a non-standard extension. Chris@101: #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) Chris@101: template Chris@101: iterator insert(const_iterator pos, size_type num, InIt first, InIt last) Chris@101: { Chris@101: BOOST_ASSERT(container_detail::is_input_iterator::value || Chris@101: num == static_cast(boost::container::iterator_distance(first, last))); Chris@101: (void)last; Chris@101: container_detail::insert_range_proxy proxy(first); Chris@101: return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), num, proxy); Chris@101: } Chris@101: #endif Chris@101: Chris@101: #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) Chris@101: //! Requires: position must be a valid iterator of *this. Chris@101: //! Chris@101: //! Effects: Insert a copy of the [il.begin(), il.end()) range before position. Chris@101: //! Chris@101: //! Returns: an iterator to the first inserted element or position if first == last. Chris@101: //! Chris@101: //! Complexity: Linear to the range [il.begin(), il.end()). Chris@101: iterator insert(const_iterator position, std::initializer_list il) Chris@101: { Chris@101: return this->insert(position, il.begin(), il.end()); Chris@16: } Chris@16: #endif Chris@16: Chris@16: //! Effects: Removes the last element from the vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant time. Chris@101: void pop_back() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { Chris@16: //Destroy last element Chris@101: this->priv_destroy_last(); Chris@16: } Chris@16: Chris@16: //! Effects: Erases the element at position pos. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Linear to the elements between pos and the Chris@16: //! last element. Constant if pos is the last element. Chris@16: iterator erase(const_iterator position) Chris@16: { Chris@101: const pointer p = vector_iterator_get_ptr(position); Chris@101: T *const pos_ptr = container_detail::to_raw_pointer(p); Chris@101: T *const beg_ptr = container_detail::to_raw_pointer(this->m_holder.start()); Chris@101: T *const new_end_ptr = ::boost::container::move(pos_ptr + 1, beg_ptr + this->m_holder.m_size, pos_ptr); Chris@16: //Move elements forward and destroy last Chris@101: this->priv_destroy_last(pos_ptr == new_end_ptr); Chris@101: return iterator(p); Chris@16: } Chris@16: Chris@16: //! Effects: Erases the elements pointed by [first, last). Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Linear to the distance between first and last Chris@16: //! plus linear to the elements between pos and the last element. Chris@16: iterator erase(const_iterator first, const_iterator last) Chris@16: { Chris@16: if (first != last){ Chris@101: T* const old_end_ptr = this->back_raw(); Chris@101: T* const first_ptr = container_detail::to_raw_pointer(vector_iterator_get_ptr(first)); Chris@101: T* const last_ptr = container_detail::to_raw_pointer(vector_iterator_get_ptr(last)); Chris@101: T* const ptr = container_detail::to_raw_pointer(boost::container::move(last_ptr, old_end_ptr, first_ptr)); Chris@101: this->priv_destroy_last_n(old_end_ptr - ptr, last_ptr == old_end_ptr); Chris@16: } Chris@16: return iterator(vector_iterator_get_ptr(first)); Chris@16: } Chris@16: Chris@16: //! Effects: Swaps the contents of *this and x. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Constant. Chris@101: void swap(vector& x) Chris@101: BOOST_NOEXCEPT_IF( ((allocator_traits_type::propagate_on_container_swap::value Chris@101: || allocator_traits_type::is_always_equal::value) && Chris@101: !container_detail::is_version::value)) Chris@16: { Chris@101: this->priv_swap(x, container_detail::bool_::value>()); Chris@16: } Chris@16: Chris@16: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@16: Chris@16: //! Effects: Swaps the contents of *this and x. Chris@16: //! Chris@101: //! Throws: Nothing. Chris@16: //! Chris@16: //! Complexity: Linear Chris@16: //! Chris@101: //! Note: Non-standard extension to support static_vector Chris@16: template Chris@101: void swap(vector & x Chris@101: , typename container_detail::enable_if_c Chris@101: < container_detail::is_version::value && Chris@101: !container_detail::is_same::value >::type * = 0 Chris@101: ) Chris@101: { this->m_holder.deep_swap(x.m_holder); } Chris@16: Chris@16: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@16: Chris@16: //! Effects: Erases all the elements of the vector. Chris@16: //! Chris@16: //! Throws: Nothing. Chris@16: //! Chris@101: //! Complexity: Linear to the number of elements in the container. Chris@101: void clear() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { this->priv_destroy_all(); } Chris@16: Chris@101: //! Effects: Returns true if x and y are equal Chris@101: //! Chris@101: //! Complexity: Linear to the number of elements in the container. Chris@101: friend bool operator==(const vector& x, const vector& y) Chris@101: { return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); } Chris@101: Chris@101: //! Effects: Returns true if x and y are unequal Chris@101: //! Chris@101: //! Complexity: Linear to the number of elements in the container. Chris@101: friend bool operator!=(const vector& x, const vector& y) Chris@101: { return !(x == y); } Chris@101: Chris@101: //! Effects: Returns true if x is less than y Chris@101: //! Chris@101: //! Complexity: Linear to the number of elements in the container. Chris@101: friend bool operator<(const vector& x, const vector& y) Chris@101: { Chris@101: const_iterator first1(x.cbegin()), first2(y.cbegin()); Chris@101: const const_iterator last1(x.cend()), last2(y.cend()); Chris@101: for ( ; (first1 != last1) && (first2 != last2); ++first1, ++first2 ) { Chris@101: if (*first1 < *first2) return true; Chris@101: if (*first2 < *first1) return false; Chris@101: } Chris@101: return (first1 == last1) && (first2 != last2); Chris@101: } Chris@101: Chris@101: //! Effects: Returns true if x is greater than y Chris@101: //! Chris@101: //! Complexity: Linear to the number of elements in the container. Chris@101: friend bool operator>(const vector& x, const vector& y) Chris@101: { return y < x; } Chris@101: Chris@101: //! Effects: Returns true if x is equal or less than y Chris@101: //! Chris@101: //! Complexity: Linear to the number of elements in the container. Chris@101: friend bool operator<=(const vector& x, const vector& y) Chris@101: { return !(y < x); } Chris@101: Chris@101: //! Effects: Returns true if x is equal or greater than y Chris@101: //! Chris@101: //! Complexity: Linear to the number of elements in the container. Chris@101: friend bool operator>=(const vector& x, const vector& y) Chris@101: { return !(x < y); } Chris@101: Chris@101: //! Effects: x.swap(y) Chris@101: //! Chris@101: //! Complexity: Constant. Chris@101: friend void swap(vector& x, vector& y) Chris@101: { x.swap(y); } Chris@101: Chris@101: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@101: //! Effects: If n is less than or equal to capacity(), this call has no Chris@101: //! effect. Otherwise, it is a request for allocation of additional memory Chris@101: //! (memory expansion) that will not invalidate iterators. Chris@101: //! If the request is successful, then capacity() is greater than or equal to Chris@101: //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. Chris@101: //! Chris@101: //! Throws: If memory allocation allocation throws or T's copy/move constructor throws. Chris@101: //! Chris@101: //! Note: Non-standard extension. Chris@101: bool stable_reserve(size_type new_cap) Chris@101: { Chris@101: const size_type cp = this->capacity(); Chris@101: return cp >= new_cap || (alloc_version::value == 2 && this->m_holder.try_expand_fwd(new_cap - cp)); Chris@101: } Chris@16: Chris@16: //Absolutely experimental. This function might change, disappear or simply crash! Chris@16: template Chris@101: void insert_ordered_at(const size_type element_count, BiDirPosConstIt last_position_it, BiDirValueIt last_value_it) Chris@16: { Chris@101: const size_type old_size_pos = this->size(); Chris@101: this->reserve(old_size_pos + element_count); Chris@101: T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.start()); Chris@101: size_type insertions_left = element_count; Chris@101: size_type next_pos = old_size_pos; Chris@101: size_type hole_size = element_count; Chris@16: Chris@101: //Exception rollback. If any copy throws before the hole is filled, values Chris@101: //already inserted/copied at the end of the buffer will be destroyed. Chris@101: typename value_traits::ArrayDestructor past_hole_values_destroyer Chris@101: (begin_ptr + old_size_pos + element_count, this->m_holder.alloc(), size_type(0u)); Chris@101: //Loop for each insertion backwards, first moving the elements after the insertion point, Chris@101: //then inserting the element. Chris@101: while(insertions_left){ Chris@101: size_type pos = static_cast(*(--last_position_it)); Chris@101: while(pos == size_type(-1)){ Chris@101: --last_value_it; Chris@101: pos = static_cast(*(--last_position_it)); Chris@101: } Chris@101: Chris@101: BOOST_ASSERT(pos != size_type(-1) && pos <= old_size_pos); Chris@101: //If needed shift the range after the insertion point and the previous insertion point. Chris@101: //Function will take care if the shift crosses the size() boundary, using copy/move Chris@101: //or uninitialized copy/move if necessary. Chris@101: size_type new_hole_size = (pos != next_pos) Chris@101: ? priv_insert_ordered_at_shift_range(pos, next_pos, this->size(), insertions_left) Chris@101: : hole_size Chris@101: ; Chris@101: if(new_hole_size > 0){ Chris@101: //The hole was reduced by priv_insert_ordered_at_shift_range so expand exception rollback range backwards Chris@101: past_hole_values_destroyer.increment_size_backwards(next_pos - pos); Chris@101: //Insert the new value in the hole Chris@101: allocator_traits_type::construct(this->m_holder.alloc(), begin_ptr + pos + insertions_left - 1, *(--last_value_it)); Chris@101: --new_hole_size; Chris@101: if(new_hole_size == 0){ Chris@101: //Hole was just filled, disable exception rollback and change vector size Chris@101: past_hole_values_destroyer.release(); Chris@101: this->m_holder.m_size += element_count; Chris@101: } Chris@101: else{ Chris@101: //The hole was reduced by the new insertion by one Chris@101: past_hole_values_destroyer.increment_size_backwards(size_type(1u)); Chris@101: } Chris@101: } Chris@101: else{ Chris@101: if(hole_size){ Chris@101: //Hole was just filled by priv_insert_ordered_at_shift_range, disable exception rollback and change vector size Chris@101: past_hole_values_destroyer.release(); Chris@101: this->m_holder.m_size += element_count; Chris@101: } Chris@101: //Insert the new value in the already constructed range Chris@101: begin_ptr[pos + insertions_left - 1] = *(--last_value_it); Chris@101: } Chris@101: --insertions_left; Chris@101: hole_size = new_hole_size; Chris@101: next_pos = pos; Chris@101: } Chris@16: } Chris@16: Chris@16: private: Chris@16: Chris@101: bool room_enough() const Chris@101: { return this->m_holder.m_size < this->m_holder.capacity(); } Chris@101: Chris@101: pointer back_ptr() const Chris@101: { return this->m_holder.start() + this->m_holder.m_size; } Chris@101: Chris@101: T* back_raw() const Chris@101: { return container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; } Chris@101: Chris@101: size_type priv_index_of(pointer p) const Chris@101: { Chris@101: BOOST_ASSERT(this->m_holder.start() <= p); Chris@101: BOOST_ASSERT(p <= (this->m_holder.start()+this->size())); Chris@101: return static_cast(p - this->m_holder.start()); Chris@101: } Chris@101: Chris@101: template Chris@16: void priv_move_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x Chris@16: , typename container_detail::enable_if_c Chris@101: < container_detail::is_version::value >::type * = 0) Chris@16: { Chris@101: if(!container_detail::is_same::value && Chris@101: this->capacity() < x.size()){ Chris@16: throw_bad_alloc(); Chris@16: } Chris@16: T* const this_start = container_detail::to_raw_pointer(m_holder.start()); Chris@16: T* const other_start = container_detail::to_raw_pointer(x.m_holder.start()); Chris@16: const size_type this_sz = m_holder.m_size; Chris@16: const size_type other_sz = static_cast(x.m_holder.m_size); Chris@16: boost::container::move_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz); Chris@16: this->m_holder.m_size = other_sz; Chris@16: } Chris@16: Chris@101: template Chris@101: void priv_move_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x Chris@16: , typename container_detail::enable_if_c Chris@101: < !container_detail::is_version::value && Chris@101: container_detail::is_same::value>::type * = 0) Chris@16: { Chris@16: //for move constructor, no aliasing (&x != this) is assummed. Chris@101: BOOST_ASSERT(this != &x); Chris@16: allocator_type &this_alloc = this->m_holder.alloc(); Chris@16: allocator_type &x_alloc = x.m_holder.alloc(); Chris@101: const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; Chris@101: Chris@101: const bool is_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc); Chris@101: const bool is_propagable_from_t = is_propagable_from(this_alloc, m_holder.start(), x_alloc, propagate_alloc); Chris@101: const bool are_both_propagable = is_propagable_from_x && is_propagable_from_t; Chris@101: Chris@101: //Resources can be transferred if both allocators are Chris@101: //going to be equal after this function (either propagated or already equal) Chris@101: if(are_both_propagable){ Chris@16: //Destroy objects but retain memory in case x reuses it in the future Chris@16: this->clear(); Chris@101: this->m_holder.swap_resources(x.m_holder); Chris@16: } Chris@101: else if(is_propagable_from_x){ Chris@101: this->clear(); Chris@101: this->m_holder.alloc().deallocate(this->m_holder.m_start, this->m_holder.m_capacity); Chris@101: this->m_holder.steal_resources(x.m_holder); Chris@101: } Chris@101: //Else do a one by one move Chris@16: else{ Chris@101: this->assign( boost::make_move_iterator(container_detail::iterator_to_raw_pointer(x.begin())) Chris@101: , boost::make_move_iterator(container_detail::iterator_to_raw_pointer(x.end() )) Chris@101: ); Chris@16: } Chris@101: //Move allocator if needed Chris@101: container_detail::move_alloc(this_alloc, x_alloc, container_detail::bool_()); Chris@16: } Chris@16: Chris@101: template Chris@101: void priv_copy_assign(const vector &x Chris@16: , typename container_detail::enable_if_c Chris@101: < container_detail::is_version::value >::type * = 0) Chris@16: { Chris@101: if(!container_detail::is_same::value && Chris@101: this->capacity() < x.size()){ Chris@101: throw_bad_alloc(); Chris@101: } Chris@16: T* const this_start = container_detail::to_raw_pointer(m_holder.start()); Chris@16: T* const other_start = container_detail::to_raw_pointer(x.m_holder.start()); Chris@16: const size_type this_sz = m_holder.m_size; Chris@16: const size_type other_sz = static_cast(x.m_holder.m_size); Chris@16: boost::container::copy_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz); Chris@16: this->m_holder.m_size = other_sz; Chris@16: } Chris@16: Chris@101: template Chris@101: void priv_copy_assign(const vector &x Chris@16: , typename container_detail::enable_if_c Chris@101: < !container_detail::is_version::value && Chris@101: container_detail::is_same::value >::type * = 0) Chris@16: { Chris@16: allocator_type &this_alloc = this->m_holder.alloc(); Chris@16: const allocator_type &x_alloc = x.m_holder.alloc(); Chris@16: container_detail::bool_ flag; Chris@16: if(flag && this_alloc != x_alloc){ Chris@16: this->clear(); Chris@16: this->shrink_to_fit(); Chris@16: } Chris@16: container_detail::assign_alloc(this_alloc, x_alloc, flag); Chris@16: this->assign( container_detail::to_raw_pointer(x.m_holder.start()) Chris@16: , container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size)); Chris@16: } Chris@16: Chris@101: template //Template it to avoid it in explicit instantiations Chris@101: void priv_swap(Vector &x, container_detail::true_type) //version_0 Chris@101: { this->m_holder.deep_swap(x.m_holder); } Chris@101: Chris@101: template //Template it to avoid it in explicit instantiations Chris@101: void priv_swap(Vector &x, container_detail::false_type) //version_N Chris@16: { Chris@101: const bool propagate_alloc = allocator_traits_type::propagate_on_container_swap::value; Chris@101: if(are_swap_propagable( this->get_stored_allocator(), this->m_holder.start() Chris@101: , x.get_stored_allocator(), this->m_holder.start(), propagate_alloc)){ Chris@101: //Just swap internals Chris@101: this->m_holder.swap_resources(x.m_holder); Chris@101: } Chris@101: else{ Chris@101: //Else swap element by element... Chris@101: bool const t_smaller = this->size() < x.size(); Chris@101: vector &sml = t_smaller ? *this : x; Chris@101: vector &big = t_smaller ? x : *this; Chris@101: Chris@101: size_type const common_elements = sml.size(); Chris@101: for(size_type i = 0; i != common_elements; ++i){ Chris@101: boost::adl_move_swap(sml[i], big[i]); Chris@101: } Chris@101: //... and move-insert the remaining range Chris@101: sml.insert( sml.cend() Chris@101: , boost::make_move_iterator(container_detail::iterator_to_raw_pointer(big.nth(common_elements))) Chris@101: , boost::make_move_iterator(container_detail::iterator_to_raw_pointer(big.end())) Chris@101: ); Chris@101: } Chris@101: //And now swap the allocator Chris@101: container_detail::swap_alloc(this->m_holder.alloc(), x.m_holder.alloc(), container_detail::bool_()); Chris@16: } Chris@16: Chris@101: void priv_reserve_no_capacity(size_type, version_0) Chris@101: { throw_bad_alloc(); } Chris@101: Chris@101: container_detail::insert_range_proxy, T*> priv_dummy_empty_proxy() Chris@101: { Chris@101: return container_detail::insert_range_proxy, T*> Chris@101: (::boost::make_move_iterator((T *)0)); Chris@101: } Chris@101: Chris@101: void priv_reserve_no_capacity(size_type new_cap, version_1) Chris@16: { Chris@16: //There is not enough memory, allocate a new buffer Chris@101: //Pass the hint so that allocators can take advantage of this. Chris@101: pointer const p = allocator_traits_type::allocate(this->m_holder.alloc(), new_cap, this->m_holder.m_start); Chris@101: //We will reuse insert code, so create a dummy input iterator Chris@101: this->priv_forward_range_insert_new_allocation Chris@101: ( container_detail::to_raw_pointer(p), new_cap, this->back_raw(), 0, this->priv_dummy_empty_proxy()); Chris@16: } Chris@16: Chris@101: void priv_reserve_no_capacity(size_type new_cap, version_2) Chris@16: { Chris@16: //There is not enough memory, allocate a new Chris@16: //buffer or expand the old one. Chris@16: bool same_buffer_start; Chris@16: size_type real_cap = 0; Chris@101: pointer reuse = 0; Chris@101: pointer const ret(this->m_holder.allocation_command(allocate_new | expand_fwd | expand_bwd, new_cap, real_cap = new_cap, reuse)); Chris@16: Chris@16: //Check for forward expansion Chris@101: same_buffer_start = reuse && this->m_holder.start() == ret; Chris@16: if(same_buffer_start){ Chris@16: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@16: ++this->num_expand_fwd; Chris@16: #endif Chris@16: this->m_holder.capacity(real_cap); Chris@16: } Chris@101: else{ //If there is no forward expansion, move objects, we will reuse insertion code Chris@101: T * const new_mem = container_detail::to_raw_pointer(ret); Chris@101: T * const ins_pos = this->back_raw(); Chris@101: if(reuse){ //Backwards (and possibly forward) expansion Chris@16: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@16: ++this->num_expand_bwd; Chris@16: #endif Chris@16: this->priv_forward_range_insert_expand_backwards Chris@101: ( new_mem , real_cap, ins_pos, 0, this->priv_dummy_empty_proxy()); Chris@16: } Chris@101: else{ //New buffer Chris@16: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@16: ++this->num_alloc; Chris@16: #endif Chris@101: this->priv_forward_range_insert_new_allocation Chris@101: ( new_mem, real_cap, ins_pos, 0, this->priv_dummy_empty_proxy()); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@101: void priv_destroy_last() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { Chris@101: if(!value_traits::trivial_dctr){ Chris@101: value_type* const p = this->back_raw() - 1; Chris@101: allocator_traits_type::destroy(this->get_stored_allocator(), p); Chris@101: } Chris@101: --this->m_holder.m_size; Chris@16: } Chris@16: Chris@101: void priv_destroy_last(const bool moved) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { Chris@101: (void)moved; Chris@101: if(!(value_traits::trivial_dctr || (value_traits::trivial_dctr_after_move && moved))){ Chris@101: value_type* const p = this->back_raw() - 1; Chris@16: allocator_traits_type::destroy(this->get_stored_allocator(), p); Chris@101: } Chris@101: --this->m_holder.m_size; Chris@16: } Chris@16: Chris@101: void priv_destroy_last_n(const size_type n) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { Chris@101: BOOST_ASSERT(n <= this->m_holder.m_size); Chris@101: if(!value_traits::trivial_dctr){ Chris@101: T* const destroy_pos = container_detail::to_raw_pointer(this->m_holder.start()) + (this->m_holder.m_size-n); Chris@101: boost::container::destroy_alloc_n(this->get_stored_allocator(), destroy_pos, n); Chris@101: } Chris@16: this->m_holder.m_size -= n; Chris@16: } Chris@16: Chris@101: void priv_destroy_last_n(const size_type n, const bool moved) BOOST_NOEXCEPT_OR_NOTHROW Chris@101: { Chris@101: BOOST_ASSERT(n <= this->m_holder.m_size); Chris@101: (void)moved; Chris@101: if(!(value_traits::trivial_dctr || (value_traits::trivial_dctr_after_move && moved))){ Chris@101: T* const destroy_pos = container_detail::to_raw_pointer(this->m_holder.start()) + (this->m_holder.m_size-n); Chris@101: boost::container::destroy_alloc_n(this->get_stored_allocator(), destroy_pos, n); Chris@101: } Chris@101: this->m_holder.m_size -= n; Chris@101: } Chris@101: Chris@101: template Chris@101: void priv_uninitialized_construct_at_end(InpIt first, InpIt last) Chris@101: { Chris@101: T* const old_end_pos = this->back_raw(); Chris@101: T* const new_end_pos = boost::container::uninitialized_copy_alloc(this->m_holder.alloc(), first, last, old_end_pos); Chris@101: this->m_holder.m_size += new_end_pos - old_end_pos; Chris@101: } Chris@101: Chris@101: void priv_destroy_all() BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { Chris@16: boost::container::destroy_alloc_n Chris@16: (this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size); Chris@16: this->m_holder.m_size = 0; Chris@16: } Chris@16: Chris@16: template Chris@16: iterator priv_insert(const const_iterator &p, BOOST_FWD_REF(U) x) Chris@16: { Chris@16: return this->priv_forward_range_insert Chris@101: ( vector_iterator_get_ptr(p), 1, container_detail::get_insert_value_proxy(::boost::forward(x))); Chris@16: } Chris@16: Chris@101: container_detail::insert_copy_proxy priv_single_insert_proxy(const T &x) Chris@101: { return container_detail::insert_copy_proxy (x); } Chris@101: Chris@101: container_detail::insert_move_proxy priv_single_insert_proxy(BOOST_RV_REF(T) x) Chris@101: { return container_detail::insert_move_proxy (x); } Chris@101: Chris@101: template Chris@101: void priv_push_back(BOOST_FWD_REF(U) u) Chris@16: { Chris@101: if (BOOST_LIKELY(this->room_enough())){ Chris@16: //There is more memory, just construct a new object at the end Chris@16: allocator_traits_type::construct Chris@16: ( this->m_holder.alloc() Chris@16: , container_detail::to_raw_pointer(this->m_holder.start() + this->m_holder.m_size) Chris@101: , ::boost::forward(u) ); Chris@16: ++this->m_holder.m_size; Chris@16: } Chris@16: else{ Chris@101: this->priv_forward_range_insert_no_capacity Chris@101: ( this->back_ptr(), 1 Chris@101: , this->priv_single_insert_proxy(::boost::forward(u)), alloc_version()); Chris@16: } Chris@16: } Chris@16: Chris@101: container_detail::insert_n_copies_proxy priv_resize_proxy(const T &x) Chris@101: { return container_detail::insert_n_copies_proxy(x); } Chris@101: Chris@101: container_detail::insert_default_initialized_n_proxy priv_resize_proxy(default_init_t) Chris@101: { return container_detail::insert_default_initialized_n_proxy(); } Chris@101: Chris@101: container_detail::insert_value_initialized_n_proxy priv_resize_proxy(value_init_t) Chris@101: { return container_detail::insert_value_initialized_n_proxy(); } Chris@101: Chris@101: template Chris@101: void priv_resize(size_type new_size, const U& u) Chris@16: { Chris@101: const size_type sz = this->size(); Chris@101: if (new_size < sz){ Chris@101: //Destroy last elements Chris@101: this->priv_destroy_last_n(sz - new_size); Chris@16: } Chris@16: else{ Chris@101: const size_type n = new_size - this->size(); Chris@101: this->priv_forward_range_insert_at_end(n, this->priv_resize_proxy(u), alloc_version()); Chris@16: } Chris@16: } Chris@16: Chris@101: void priv_shrink_to_fit(version_0) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: {} Chris@16: Chris@101: void priv_shrink_to_fit(version_1) Chris@16: { Chris@16: const size_type cp = this->m_holder.capacity(); Chris@16: if(cp){ Chris@16: const size_type sz = this->size(); Chris@16: if(!sz){ Chris@16: this->m_holder.alloc().deallocate(this->m_holder.m_start, cp); Chris@16: this->m_holder.m_start = pointer(); Chris@16: this->m_holder.m_capacity = 0; Chris@16: } Chris@16: else if(sz < cp){ Chris@16: //Allocate a new buffer. Chris@101: //Pass the hint so that allocators can take advantage of this. Chris@101: pointer const p = allocator_traits_type::allocate(this->m_holder.alloc(), sz, this->m_holder.m_start); Chris@16: Chris@16: //We will reuse insert code, so create a dummy input iterator Chris@16: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@16: ++this->num_alloc; Chris@16: #endif Chris@16: this->priv_forward_range_insert_new_allocation Chris@101: ( container_detail::to_raw_pointer(p), sz Chris@16: , container_detail::to_raw_pointer(this->m_holder.start()) Chris@101: , 0, this->priv_dummy_empty_proxy()); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@101: void priv_shrink_to_fit(version_2) BOOST_NOEXCEPT_OR_NOTHROW Chris@16: { Chris@16: const size_type cp = this->m_holder.capacity(); Chris@16: if(cp){ Chris@16: const size_type sz = this->size(); Chris@16: if(!sz){ Chris@16: this->m_holder.alloc().deallocate(this->m_holder.m_start, cp); Chris@16: this->m_holder.m_start = pointer(); Chris@16: this->m_holder.m_capacity = 0; Chris@16: } Chris@16: else{ Chris@101: size_type received_size = sz; Chris@101: pointer reuse(this->m_holder.start()); Chris@16: if(this->m_holder.allocation_command Chris@101: (shrink_in_place | nothrow_allocation, cp, received_size, reuse)){ Chris@16: this->m_holder.capacity(received_size); Chris@16: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@16: ++this->num_shrink; Chris@16: #endif Chris@16: } Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: iterator priv_forward_range_insert_no_capacity Chris@101: (const pointer &pos, const size_type, const InsertionProxy , version_0) Chris@16: { Chris@16: throw_bad_alloc(); Chris@16: return iterator(pos); Chris@16: } Chris@16: Chris@16: template Chris@16: iterator priv_forward_range_insert_no_capacity Chris@101: (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, version_1) Chris@16: { Chris@16: //Check if we have enough memory or try to expand current memory Chris@16: const size_type n_pos = pos - this->m_holder.start(); Chris@16: T *const raw_pos = container_detail::to_raw_pointer(pos); Chris@16: Chris@16: const size_type new_cap = this->m_holder.next_capacity(n); Chris@101: //Pass the hint so that allocators can take advantage of this. Chris@101: T * const new_buf = container_detail::to_raw_pointer(allocator_traits_type::allocate(this->m_holder.alloc(), new_cap, this->m_holder.m_start)); Chris@16: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@16: ++this->num_alloc; Chris@16: #endif Chris@16: this->priv_forward_range_insert_new_allocation Chris@16: ( new_buf, new_cap, raw_pos, n, insert_range_proxy); Chris@16: return iterator(this->m_holder.start() + n_pos); Chris@16: } Chris@16: Chris@16: template Chris@16: iterator priv_forward_range_insert_no_capacity Chris@101: (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, version_2) Chris@16: { Chris@16: //Check if we have enough memory or try to expand current memory Chris@16: T *const raw_pos = container_detail::to_raw_pointer(pos); Chris@16: const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start()); Chris@16: Chris@16: //There is not enough memory, allocate a new Chris@16: //buffer or expand the old one. Chris@101: size_type real_cap = this->m_holder.next_capacity(n); Chris@101: pointer reuse(this->m_holder.start()); Chris@101: pointer const ret (this->m_holder.allocation_command Chris@101: (allocate_new | expand_fwd | expand_bwd, this->m_holder.m_size + n, real_cap, reuse)); Chris@16: Chris@16: //Buffer reallocated Chris@101: if(reuse){ Chris@16: //Forward expansion, delay insertion Chris@101: if(this->m_holder.start() == ret){ Chris@16: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@16: ++this->num_expand_fwd; Chris@16: #endif Chris@16: this->m_holder.capacity(real_cap); Chris@16: //Expand forward Chris@16: this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy); Chris@16: } Chris@16: //Backwards (and possibly forward) expansion Chris@16: else{ Chris@16: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@16: ++this->num_expand_bwd; Chris@16: #endif Chris@16: this->priv_forward_range_insert_expand_backwards Chris@101: (container_detail::to_raw_pointer(ret), real_cap, raw_pos, n, insert_range_proxy); Chris@16: } Chris@16: } Chris@16: //New buffer Chris@16: else{ Chris@16: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@16: ++this->num_alloc; Chris@16: #endif Chris@16: this->priv_forward_range_insert_new_allocation Chris@101: ( container_detail::to_raw_pointer(ret), real_cap, raw_pos, n, insert_range_proxy); Chris@16: } Chris@16: Chris@16: return iterator(this->m_holder.start() + n_pos); Chris@16: } Chris@16: Chris@16: template Chris@16: iterator priv_forward_range_insert Chris@101: (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy) Chris@16: { Chris@101: BOOST_ASSERT(this->m_holder.capacity() >= this->m_holder.m_size); Chris@16: //Check if we have enough memory or try to expand current memory Chris@16: const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; Chris@16: Chris@16: bool same_buffer_start = n <= remaining; Chris@16: if (!same_buffer_start){ Chris@16: return priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version()); Chris@16: } Chris@16: else{ Chris@16: //Expand forward Chris@16: T *const raw_pos = container_detail::to_raw_pointer(pos); Chris@16: const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start()); Chris@16: this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy); Chris@16: return iterator(this->m_holder.start() + n_pos); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: iterator priv_forward_range_insert_at_end Chris@101: (const size_type n, const InsertionProxy insert_range_proxy, version_0) Chris@16: { Chris@16: //Check if we have enough memory or try to expand current memory Chris@16: const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; Chris@16: Chris@16: if (n > remaining){ Chris@16: //This will trigger an error Chris@16: throw_bad_alloc(); Chris@16: } Chris@16: this->priv_forward_range_insert_at_end_expand_forward(n, insert_range_proxy); Chris@16: return this->end(); Chris@16: } Chris@16: Chris@101: template Chris@16: iterator priv_forward_range_insert_at_end Chris@101: (const size_type n, const InsertionProxy insert_range_proxy, AllocVersion) Chris@16: { Chris@101: return this->priv_forward_range_insert(this->back_ptr(), n, insert_range_proxy); Chris@16: } Chris@16: Chris@16: //Absolutely experimental. This function might change, disappear or simply crash! Chris@16: template Chris@16: void priv_insert_ordered_at( size_type element_count, BiDirPosConstIt last_position_it Chris@16: , bool do_skip, BiDirSkipConstIt last_skip_it, BiDirValueIt last_value_it) Chris@16: { Chris@16: const size_type old_size_pos = this->size(); Chris@16: this->reserve(old_size_pos + element_count); Chris@16: T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.start()); Chris@16: size_type insertions_left = element_count; Chris@16: size_type next_pos = old_size_pos; Chris@16: size_type hole_size = element_count; Chris@16: Chris@16: //Exception rollback. If any copy throws before the hole is filled, values Chris@16: //already inserted/copied at the end of the buffer will be destroyed. Chris@16: typename value_traits::ArrayDestructor past_hole_values_destroyer Chris@16: (begin_ptr + old_size_pos + element_count, this->m_holder.alloc(), size_type(0u)); Chris@16: //Loop for each insertion backwards, first moving the elements after the insertion point, Chris@16: //then inserting the element. Chris@16: while(insertions_left){ Chris@16: if(do_skip){ Chris@16: size_type n = *(--last_skip_it); Chris@101: boost::container::iterator_advance(last_value_it, -difference_type(n)); Chris@16: } Chris@16: const size_type pos = static_cast(*(--last_position_it)); Chris@16: BOOST_ASSERT(pos <= old_size_pos); Chris@16: //If needed shift the range after the insertion point and the previous insertion point. Chris@16: //Function will take care if the shift crosses the size() boundary, using copy/move Chris@16: //or uninitialized copy/move if necessary. Chris@16: size_type new_hole_size = (pos != next_pos) Chris@16: ? priv_insert_ordered_at_shift_range(pos, next_pos, this->size(), insertions_left) Chris@16: : hole_size Chris@16: ; Chris@16: if(new_hole_size > 0){ Chris@16: //The hole was reduced by priv_insert_ordered_at_shift_range so expand exception rollback range backwards Chris@16: past_hole_values_destroyer.increment_size_backwards(next_pos - pos); Chris@16: //Insert the new value in the hole Chris@16: allocator_traits_type::construct(this->m_holder.alloc(), begin_ptr + pos + insertions_left - 1, *(--last_value_it)); Chris@16: --new_hole_size; Chris@16: if(new_hole_size == 0){ Chris@16: //Hole was just filled, disable exception rollback and change vector size Chris@16: past_hole_values_destroyer.release(); Chris@16: this->m_holder.m_size += element_count; Chris@16: } Chris@16: else{ Chris@16: //The hole was reduced by the new insertion by one Chris@16: past_hole_values_destroyer.increment_size_backwards(size_type(1u)); Chris@16: } Chris@16: } Chris@16: else{ Chris@16: if(hole_size){ Chris@16: //Hole was just filled by priv_insert_ordered_at_shift_range, disable exception rollback and change vector size Chris@16: past_hole_values_destroyer.release(); Chris@16: this->m_holder.m_size += element_count; Chris@16: } Chris@16: //Insert the new value in the already constructed range Chris@16: begin_ptr[pos + insertions_left - 1] = *(--last_value_it); Chris@16: } Chris@16: --insertions_left; Chris@16: hole_size = new_hole_size; Chris@16: next_pos = pos; Chris@16: } Chris@16: } Chris@16: Chris@16: //Takes the range pointed by [first_pos, last_pos) and shifts it to the right Chris@16: //by 'shift_count'. 'limit_pos' marks the end of constructed elements. Chris@16: // Chris@16: //Precondition: first_pos <= last_pos <= limit_pos Chris@16: // Chris@16: //The shift operation might cross limit_pos so elements to moved beyond limit_pos Chris@16: //are uninitialized_moved with an allocator. Other elements are moved. Chris@16: // Chris@16: //The shift operation might left uninitialized elements after limit_pos Chris@16: //and the number of uninitialized elements is returned by the function. Chris@16: // Chris@16: //Old situation: Chris@16: // first_pos last_pos old_limit Chris@101: // | | | Chris@16: // ____________V_______V__________________V_____________ Chris@16: //| prefix | range | suffix |raw_mem ~ Chris@16: //|____________|_______|__________________|_____________~ Chris@16: // Chris@101: //New situation in Case A (hole_size == 0): Chris@16: // range is moved through move assignments Chris@16: // Chris@16: // first_pos last_pos limit_pos Chris@101: // | | | Chris@16: // ____________V_______V__________________V_____________ Chris@16: //| prefix' | | | range |suffix'|raw_mem ~ Chris@16: //|________________+______|___^___|_______|_____________~ Chris@16: // | | Chris@101: // |_>_>_>_>_>^ Chris@16: // Chris@16: // Chris@16: //New situation in Case B (hole_size > 0): Chris@16: // range is moved through uninitialized moves Chris@16: // Chris@16: // first_pos last_pos limit_pos Chris@101: // | | | Chris@16: // ____________V_______V__________________V________________ Chris@16: //| prefix' | | | [hole] | range | Chris@16: //|_______________________________________|________|___^___| Chris@16: // | | Chris@16: // |_>_>_>_>_>_>_>_>_>_>_>_>_>_>_>_>_>_^ Chris@16: // Chris@16: //New situation in Case C (hole_size == 0): Chris@16: // range is moved through move assignments and uninitialized moves Chris@16: // Chris@16: // first_pos last_pos limit_pos Chris@101: // | | | Chris@16: // ____________V_______V__________________V___ Chris@16: //| prefix' | | | range | Chris@16: //|___________________________________|___^___| Chris@16: // | | Chris@16: // |_>_>_>_>_>_>_>_>_>_>_>^ Chris@16: size_type priv_insert_ordered_at_shift_range Chris@16: (size_type first_pos, size_type last_pos, size_type limit_pos, size_type shift_count) Chris@16: { Chris@16: BOOST_ASSERT(first_pos <= last_pos); Chris@16: BOOST_ASSERT(last_pos <= limit_pos); Chris@16: // Chris@16: T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.start()); Chris@16: T* const first_ptr = begin_ptr + first_pos; Chris@16: T* const last_ptr = begin_ptr + last_pos; Chris@16: Chris@16: size_type hole_size = 0; Chris@101: //Case A: Chris@16: if((last_pos + shift_count) <= limit_pos){ Chris@16: //All move assigned Chris@101: boost::container::move_backward(first_ptr, last_ptr, last_ptr + shift_count); Chris@16: } Chris@16: //Case B: Chris@16: else if((first_pos + shift_count) >= limit_pos){ Chris@16: //All uninitialized_moved Chris@16: ::boost::container::uninitialized_move_alloc Chris@16: (this->m_holder.alloc(), first_ptr, last_ptr, first_ptr + shift_count); Chris@16: hole_size = last_pos + shift_count - limit_pos; Chris@16: } Chris@16: //Case C: Chris@16: else{ Chris@16: //Some uninitialized_moved Chris@16: T* const limit_ptr = begin_ptr + limit_pos; Chris@16: T* const boundary_ptr = limit_ptr - shift_count; Chris@16: ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), boundary_ptr, last_ptr, limit_ptr); Chris@16: //The rest is move assigned Chris@101: boost::container::move_backward(first_ptr, boundary_ptr, limit_ptr); Chris@16: } Chris@16: return hole_size; Chris@16: } Chris@16: Chris@16: private: Chris@16: template Chris@16: void priv_forward_range_insert_at_end_expand_forward(const size_type n, InsertionProxy insert_range_proxy) Chris@16: { Chris@101: T* const old_finish = this->back_raw(); Chris@101: insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, n); Chris@16: this->m_holder.m_size += n; Chris@16: } Chris@16: Chris@16: template Chris@16: void priv_forward_range_insert_expand_forward(T* const pos, const size_type n, InsertionProxy insert_range_proxy) Chris@16: { Chris@16: //n can't be 0, because there is nothing to do in that case Chris@16: if(!n) return; Chris@16: //There is enough memory Chris@101: T* const old_finish = this->back_raw(); Chris@16: const size_type elems_after = old_finish - pos; Chris@16: Chris@16: if (!elems_after){ Chris@101: insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, n); Chris@16: this->m_holder.m_size += n; Chris@16: } Chris@16: else if (elems_after >= n){ Chris@16: //New elements can be just copied. Chris@16: //Move to uninitialized memory last objects Chris@16: ::boost::container::uninitialized_move_alloc Chris@16: (this->m_holder.alloc(), old_finish - n, old_finish, old_finish); Chris@16: this->m_holder.m_size += n; Chris@16: //Copy previous to last objects to the initialized end Chris@101: boost::container::move_backward(pos, old_finish - n, old_finish); Chris@16: //Insert new objects in the pos Chris@101: insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), pos, n); Chris@16: } Chris@16: else { Chris@16: //The new elements don't fit in the [pos, end()) range. Chris@16: Chris@16: //Copy old [pos, end()) elements to the uninitialized memory (a gap is created) Chris@16: ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), pos, old_finish, pos + n); Chris@16: BOOST_TRY{ Chris@16: //Copy first new elements in pos (gap is still there) Chris@101: insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), pos, elems_after); Chris@16: //Copy to the beginning of the unallocated zone the last new elements (the gap is closed). Chris@101: insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, n - elems_after); Chris@16: this->m_holder.m_size += n; Chris@16: } Chris@16: BOOST_CATCH(...){ Chris@16: boost::container::destroy_alloc_n(this->get_stored_allocator(), pos + n, elems_after); Chris@16: BOOST_RETHROW Chris@16: } Chris@16: BOOST_CATCH_END Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: void priv_forward_range_insert_new_allocation Chris@16: (T* const new_start, size_type new_cap, T* const pos, const size_type n, InsertionProxy insert_range_proxy) Chris@16: { Chris@16: //n can be zero, if we want to reallocate! Chris@16: T *new_finish = new_start; Chris@16: T *old_finish; Chris@16: //Anti-exception rollbacks Chris@101: typename value_traits::ArrayDeallocator new_buffer_deallocator(new_start, this->m_holder.alloc(), new_cap); Chris@101: typename value_traits::ArrayDestructor new_values_destroyer(new_start, this->m_holder.alloc(), 0u); Chris@16: Chris@16: //Initialize with [begin(), pos) old buffer Chris@16: //the start of the new buffer Chris@101: T * const old_buffer = container_detail::to_raw_pointer(this->m_holder.start()); Chris@16: if(old_buffer){ Chris@16: new_finish = ::boost::container::uninitialized_move_alloc Chris@16: (this->m_holder.alloc(), container_detail::to_raw_pointer(this->m_holder.start()), pos, old_finish = new_finish); Chris@101: new_values_destroyer.increment_size(new_finish - old_finish); Chris@16: } Chris@16: //Initialize new objects, starting from previous point Chris@101: old_finish = new_finish; Chris@101: insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, n); Chris@16: new_finish += n; Chris@101: new_values_destroyer.increment_size(new_finish - old_finish); Chris@16: //Initialize from the rest of the old buffer, Chris@16: //starting from previous point Chris@16: if(old_buffer){ Chris@16: new_finish = ::boost::container::uninitialized_move_alloc Chris@16: (this->m_holder.alloc(), pos, old_buffer + this->m_holder.m_size, new_finish); Chris@16: //Destroy and deallocate old elements Chris@16: //If there is allocated memory, destroy and deallocate Chris@16: if(!value_traits::trivial_dctr_after_move) Chris@16: boost::container::destroy_alloc_n(this->get_stored_allocator(), old_buffer, this->m_holder.m_size); Chris@16: this->m_holder.alloc().deallocate(this->m_holder.start(), this->m_holder.capacity()); Chris@16: } Chris@16: this->m_holder.start(new_start); Chris@16: this->m_holder.m_size = new_finish - new_start; Chris@16: this->m_holder.capacity(new_cap); Chris@16: //All construction successful, disable rollbacks Chris@101: new_values_destroyer.release(); Chris@101: new_buffer_deallocator.release(); Chris@16: } Chris@16: Chris@16: template Chris@16: void priv_forward_range_insert_expand_backwards Chris@16: (T* const new_start, const size_type new_capacity, Chris@16: T* const pos, const size_type n, InsertionProxy insert_range_proxy) Chris@16: { Chris@16: //n can be zero to just expand capacity Chris@16: //Backup old data Chris@16: T* const old_start = container_detail::to_raw_pointer(this->m_holder.start()); Chris@16: const size_type old_size = this->m_holder.m_size; Chris@101: T* const old_finish = old_start + old_size; Chris@16: Chris@16: //We can have 8 possibilities: Chris@16: const size_type elemsbefore = static_cast(pos - old_start); Chris@16: const size_type s_before = static_cast(old_start - new_start); Chris@16: const size_type before_plus_new = elemsbefore + n; Chris@16: Chris@16: //Update the vector buffer information to a safe state Chris@16: this->m_holder.start(new_start); Chris@16: this->m_holder.capacity(new_capacity); Chris@16: this->m_holder.m_size = 0; Chris@16: Chris@16: //If anything goes wrong, this object will destroy Chris@16: //all the old objects to fulfill previous vector state Chris@101: typename value_traits::ArrayDestructor old_values_destroyer(old_start, this->m_holder.alloc(), old_size); Chris@16: //Check if s_before is big enough to hold the beginning of old data + new data Chris@16: if(s_before >= before_plus_new){ Chris@16: //Copy first old values before pos, after that the new objects Chris@101: T *const new_elem_pos = Chris@101: ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), old_start, pos, new_start); Chris@16: this->m_holder.m_size = elemsbefore; Chris@101: insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), new_elem_pos, n); Chris@101: this->m_holder.m_size = before_plus_new; Chris@101: const size_type new_size = old_size + n; Chris@16: //Check if s_before is so big that even copying the old data + new data Chris@16: //there is a gap between the new data and the old data Chris@16: if(s_before >= new_size){ Chris@16: //Old situation: Chris@16: // _________________________________________________________ Chris@16: //| raw_mem | old_begin | old_end | Chris@16: //| __________________________________|___________|_________| Chris@16: // Chris@16: //New situation: Chris@16: // _________________________________________________________ Chris@16: //| old_begin | new | old_end | raw_mem | Chris@16: //|___________|__________|_________|________________________| Chris@16: // Chris@16: //Now initialize the rest of memory with the last old values Chris@101: if(before_plus_new != new_size){ //Special case to avoid operations in back insertion Chris@101: ::boost::container::uninitialized_move_alloc Chris@101: (this->m_holder.alloc(), pos, old_finish, new_start + before_plus_new); Chris@101: //All new elements correctly constructed, avoid new element destruction Chris@101: this->m_holder.m_size = new_size; Chris@101: } Chris@16: //Old values destroyed automatically with "old_values_destroyer" Chris@16: //when "old_values_destroyer" goes out of scope unless the have trivial Chris@16: //destructor after move. Chris@16: if(value_traits::trivial_dctr_after_move) Chris@16: old_values_destroyer.release(); Chris@16: } Chris@16: //s_before is so big that divides old_end Chris@16: else{ Chris@16: //Old situation: Chris@16: // __________________________________________________ Chris@16: //| raw_mem | old_begin | old_end | Chris@16: //| ___________________________|___________|_________| Chris@16: // Chris@16: //New situation: Chris@16: // __________________________________________________ Chris@16: //| old_begin | new | old_end | raw_mem | Chris@16: //|___________|__________|_________|_________________| Chris@16: // Chris@16: //Now initialize the rest of memory with the last old values Chris@16: //All new elements correctly constructed, avoid new element destruction Chris@16: const size_type raw_gap = s_before - before_plus_new; Chris@101: if(!value_traits::trivial_dctr){ Chris@101: //Now initialize the rest of s_before memory with the Chris@101: //first of elements after new values Chris@101: ::boost::container::uninitialized_move_alloc_n Chris@101: (this->m_holder.alloc(), pos, raw_gap, new_start + before_plus_new); Chris@101: //Now we have a contiguous buffer so program trailing element destruction Chris@101: //and update size to the final size. Chris@101: old_values_destroyer.shrink_forward(new_size-s_before); Chris@101: this->m_holder.m_size = new_size; Chris@101: //Now move remaining last objects in the old buffer begin Chris@101: ::boost::container::move(pos + raw_gap, old_finish, old_start); Chris@101: //Once moved, avoid calling the destructors if trivial after move Chris@101: if(value_traits::trivial_dctr_after_move){ Chris@101: old_values_destroyer.release(); Chris@101: } Chris@101: } Chris@101: else{ //If trivial destructor, we can uninitialized copy + copy in a single uninitialized copy Chris@101: ::boost::container::uninitialized_move_alloc_n Chris@101: (this->m_holder.alloc(), pos, old_finish - pos, new_start + before_plus_new); Chris@101: this->m_holder.m_size = new_size; Chris@101: old_values_destroyer.release(); Chris@101: } Chris@16: } Chris@16: } Chris@16: else{ Chris@16: //Check if we have to do the insertion in two phases Chris@16: //since maybe s_before is not big enough and Chris@16: //the buffer was expanded both sides Chris@16: // Chris@16: //Old situation: Chris@16: // _________________________________________________ Chris@16: //| raw_mem | old_begin + old_end | raw_mem | Chris@16: //|_________|_____________________|_________________| Chris@16: // Chris@16: //New situation with do_after: Chris@16: // _________________________________________________ Chris@16: //| old_begin + new + old_end | raw_mem | Chris@16: //|___________________________________|_____________| Chris@16: // Chris@16: //New without do_after: Chris@16: // _________________________________________________ Chris@16: //| old_begin + new + old_end | raw_mem | Chris@16: //|____________________________|____________________| Chris@16: // Chris@16: const bool do_after = n > s_before; Chris@16: Chris@16: //Now we can have two situations: the raw_mem of the Chris@16: //beginning divides the old_begin, or the new elements: Chris@16: if (s_before <= elemsbefore) { Chris@16: //The raw memory divides the old_begin group: Chris@16: // Chris@16: //If we need two phase construction (do_after) Chris@16: //new group is divided in new = new_beg + new_end groups Chris@16: //In this phase only new_beg will be inserted Chris@16: // Chris@16: //Old situation: Chris@16: // _________________________________________________ Chris@16: //| raw_mem | old_begin | old_end | raw_mem | Chris@16: //|_________|___________|_________|_________________| Chris@16: // Chris@16: //New situation with do_after(1): Chris@16: //This is not definitive situation, the second phase Chris@16: //will include Chris@16: // _________________________________________________ Chris@16: //| old_begin | new_beg | old_end | raw_mem | Chris@16: //|___________|_________|_________|_________________| Chris@16: // Chris@16: //New situation without do_after: Chris@16: // _________________________________________________ Chris@16: //| old_begin | new | old_end | raw_mem | Chris@16: //|___________|_____|_________|_____________________| Chris@16: // Chris@16: //Copy the first part of old_begin to raw_mem Chris@16: ::boost::container::uninitialized_move_alloc_n Chris@16: (this->m_holder.alloc(), old_start, s_before, new_start); Chris@16: //The buffer is all constructed until old_end, Chris@101: //so program trailing destruction and assign final size Chris@101: //if !do_after, s_before+n otherwise. Chris@101: size_type new_1st_range; Chris@16: if(do_after){ Chris@101: new_1st_range = s_before; Chris@101: //release destroyer and update size Chris@101: old_values_destroyer.release(); Chris@16: } Chris@16: else{ Chris@101: new_1st_range = n; Chris@101: if(value_traits::trivial_dctr_after_move) Chris@101: old_values_destroyer.release(); Chris@101: else{ Chris@101: old_values_destroyer.shrink_forward(old_size - (s_before - n)); Chris@101: } Chris@101: } Chris@101: this->m_holder.m_size = old_size + new_1st_range; Chris@101: //Now copy the second part of old_begin overwriting itself Chris@101: T *const next = ::boost::container::move(old_start + s_before, pos, old_start); Chris@101: //Now copy the new_beg elements Chris@101: insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), next, new_1st_range); Chris@101: Chris@101: //If there is no after work and the last old part needs to be moved to front, do it Chris@101: if(!do_after && (n != s_before)){ Chris@16: //Now displace old_end elements Chris@101: ::boost::container::move(pos, old_finish, next + new_1st_range); Chris@16: } Chris@16: } Chris@16: else { Chris@16: //If we have to expand both sides, Chris@16: //we will play if the first new values so Chris@16: //calculate the upper bound of new values Chris@16: Chris@16: //The raw memory divides the new elements Chris@16: // Chris@16: //If we need two phase construction (do_after) Chris@16: //new group is divided in new = new_beg + new_end groups Chris@16: //In this phase only new_beg will be inserted Chris@16: // Chris@16: //Old situation: Chris@16: // _______________________________________________________ Chris@16: //| raw_mem | old_begin | old_end | raw_mem | Chris@16: //|_______________|___________|_________|_________________| Chris@16: // Chris@16: //New situation with do_after(): Chris@16: // ____________________________________________________ Chris@16: //| old_begin | new_beg | old_end | raw_mem | Chris@16: //|___________|_______________|_________|______________| Chris@16: // Chris@16: //New situation without do_after: Chris@16: // ______________________________________________________ Chris@16: //| old_begin | new | old_end | raw_mem | Chris@16: //|___________|_____|_________|__________________________| Chris@16: // Chris@16: //First copy whole old_begin and part of new to raw_mem Chris@16: T * const new_pos = ::boost::container::uninitialized_move_alloc Chris@16: (this->m_holder.alloc(), old_start, pos, new_start); Chris@16: this->m_holder.m_size = elemsbefore; Chris@16: const size_type mid_n = s_before - elemsbefore; Chris@101: insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), new_pos, mid_n); Chris@16: //The buffer is all constructed until old_end, Chris@16: //release destroyer Chris@16: this->m_holder.m_size = old_size + s_before; Chris@16: old_values_destroyer.release(); Chris@16: Chris@16: if(do_after){ Chris@16: //Copy new_beg part Chris@101: insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), old_start, elemsbefore); Chris@16: } Chris@16: else{ Chris@16: //Copy all new elements Chris@16: const size_type rest_new = n - mid_n; Chris@101: insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), old_start, rest_new); Chris@101: T* const move_start = old_start + rest_new; Chris@16: //Displace old_end Chris@101: T* const move_end = ::boost::container::move(pos, old_finish, move_start); Chris@16: //Destroy remaining moved elements from old_end except if they Chris@16: //have trivial destructor after being moved Chris@16: size_type n_destroy = s_before - n; Chris@16: if(!value_traits::trivial_dctr_after_move) Chris@16: boost::container::destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy); Chris@16: this->m_holder.m_size -= n_destroy; Chris@16: } Chris@16: } Chris@16: Chris@16: //This is only executed if two phase construction is needed Chris@16: if(do_after){ Chris@16: //The raw memory divides the new elements Chris@16: // Chris@16: //Old situation: Chris@16: // ______________________________________________________ Chris@16: //| raw_mem | old_begin | old_end | raw_mem | Chris@16: //|______________|___________|____________|______________| Chris@16: // Chris@16: //New situation with do_after(1): Chris@16: // _______________________________________________________ Chris@16: //| old_begin + new_beg | new_end |old_end | raw_mem | Chris@16: //|__________________________|_________|________|_________| Chris@16: // Chris@16: //New situation with do_after(2): Chris@16: // ______________________________________________________ Chris@16: //| old_begin + new | old_end |raw | Chris@16: //|_______________________________________|_________|____| Chris@16: // Chris@16: const size_type n_after = n - s_before; Chris@16: const size_type elemsafter = old_size - elemsbefore; Chris@16: Chris@16: //We can have two situations: Chris@16: if (elemsafter >= n_after){ Chris@16: //The raw_mem from end will divide displaced old_end Chris@16: // Chris@16: //Old situation: Chris@16: // ______________________________________________________ Chris@16: //| raw_mem | old_begin | old_end | raw_mem | Chris@16: //|______________|___________|____________|______________| Chris@16: // Chris@16: //New situation with do_after(1): Chris@16: // _______________________________________________________ Chris@16: //| old_begin + new_beg | new_end |old_end | raw_mem | Chris@16: //|__________________________|_________|________|_________| Chris@16: // Chris@16: //First copy the part of old_end raw_mem Chris@16: T* finish_n = old_finish - n_after; Chris@16: ::boost::container::uninitialized_move_alloc Chris@16: (this->m_holder.alloc(), finish_n, old_finish, old_finish); Chris@16: this->m_holder.m_size += n_after; Chris@16: //Displace the rest of old_end to the new position Chris@101: boost::container::move_backward(pos, finish_n, old_finish); Chris@16: //Now overwrite with new_end Chris@16: //The new_end part is [first + (n - n_after), last) Chris@101: insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), pos, n_after); Chris@16: } Chris@16: else { Chris@16: //The raw_mem from end will divide new_end part Chris@16: // Chris@16: //Old situation: Chris@16: // _____________________________________________________________ Chris@16: //| raw_mem | old_begin | old_end | raw_mem | Chris@16: //|______________|___________|____________|_____________________| Chris@16: // Chris@16: //New situation with do_after(2): Chris@16: // _____________________________________________________________ Chris@16: //| old_begin + new_beg | new_end |old_end | raw_mem | Chris@16: //|__________________________|_______________|________|_________| Chris@16: // Chris@16: Chris@16: const size_type mid_last_dist = n_after - elemsafter; Chris@16: //First initialize data in raw memory Chris@16: Chris@16: //Copy to the old_end part to the uninitialized zone leaving a gap. Chris@16: ::boost::container::uninitialized_move_alloc Chris@16: (this->m_holder.alloc(), pos, old_finish, old_finish + mid_last_dist); Chris@16: Chris@101: typename value_traits::ArrayDestructor old_end_destroyer Chris@101: (old_finish + mid_last_dist, this->m_holder.alloc(), old_finish - pos); Chris@16: Chris@101: //Copy the first part to the already constructed old_end zone Chris@101: insert_range_proxy.copy_n_and_update(this->m_holder.alloc(), pos, elemsafter); Chris@101: //Copy the rest to the uninitialized zone filling the gap Chris@101: insert_range_proxy.uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, mid_last_dist); Chris@101: this->m_holder.m_size += n_after; Chris@101: old_end_destroyer.release(); Chris@16: } Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: void priv_check_range(size_type n) const Chris@16: { Chris@16: //If n is out of range, throw an out_of_range exception Chris@16: if (n >= this->size()){ Chris@16: throw_out_of_range("vector::at out of range"); Chris@16: } Chris@16: } Chris@16: Chris@16: #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS Chris@16: public: Chris@16: unsigned int num_expand_fwd; Chris@16: unsigned int num_expand_bwd; Chris@16: unsigned int num_shrink; Chris@16: unsigned int num_alloc; Chris@16: void reset_alloc_stats() Chris@16: { num_expand_fwd = num_expand_bwd = num_alloc = 0, num_shrink = 0; } Chris@16: #endif Chris@101: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@16: }; Chris@16: Chris@101: }} //namespace boost::container Chris@16: Chris@101: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: //!has_trivial_destructor_after_move<> == true_type Chris@16: //!specialization for optimizations Chris@16: template Chris@16: struct has_trivial_destructor_after_move > Chris@101: { Chris@101: typedef typename ::boost::container::allocator_traits::pointer pointer; Chris@101: static const bool value = ::boost::has_trivial_destructor_after_move::value && Chris@101: ::boost::has_trivial_destructor_after_move::value; Chris@101: }; Chris@16: Chris@16: } Chris@16: Chris@101: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // #ifndef BOOST_CONTAINER_CONTAINER_VECTOR_HPP