| ////////////////////////////////////////////////////////////////////////////// |
| // |
| // (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost |
| // Software License, Version 1.0. (See accompanying file |
| // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| // |
| // See http://www.boost.org/libs/container for documentation. |
| // |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| #ifndef BOOST_CONTAINERS_CONTAINERS_VECTOR_HPP |
| #define BOOST_CONTAINERS_CONTAINERS_VECTOR_HPP |
| |
| #if (defined _MSC_VER) && (_MSC_VER >= 1200) |
| # pragma once |
| #endif |
| |
| #include "detail/config_begin.hpp" |
| #include INCLUDE_BOOST_CONTAINER_DETAIL_WORKAROUND_HPP |
| #include INCLUDE_BOOST_CONTAINER_CONTAINER_FWD_HPP |
| |
| #include <cstddef> |
| #include <memory> |
| #include <algorithm> |
| #include <stdexcept> |
| #include <iterator> |
| #include <utility> |
| #include <boost/detail/no_exceptions_support.hpp> |
| #include <boost/type_traits/has_trivial_destructor.hpp> |
| #include <boost/type_traits/has_trivial_copy.hpp> |
| #include <boost/type_traits/has_trivial_assign.hpp> |
| #include <boost/type_traits/has_nothrow_copy.hpp> |
| #include <boost/type_traits/has_nothrow_assign.hpp> |
| #include INCLUDE_BOOST_CONTAINER_DETAIL_VERSION_TYPE_HPP |
| #include INCLUDE_BOOST_CONTAINER_DETAIL_ALLOCATION_TYPE_HPP |
| #include INCLUDE_BOOST_CONTAINER_DETAIL_UTILITIES_HPP |
| #include INCLUDE_BOOST_CONTAINER_DETAIL_ITERATORS_HPP |
| #include INCLUDE_BOOST_CONTAINER_DETAIL_ALGORITHMS_HPP |
| #include INCLUDE_BOOST_CONTAINER_DETAIL_DESTROYERS_HPP |
| #include INCLUDE_BOOST_CONTAINER_CONTAINER_FWD_HPP |
| #include INCLUDE_BOOST_CONTAINER_MOVE_HPP |
| #include <boost/pointer_to_other.hpp> |
| #include INCLUDE_BOOST_CONTAINER_DETAIL_MPL_HPP |
| #include INCLUDE_BOOST_CONTAINER_DETAIL_ADVANCED_INSERT_INT_HPP |
| |
| namespace boost { |
| namespace container { |
| |
| /// @cond |
| |
| namespace containers_detail { |
| |
| //! Const vector_iterator used to iterate through a vector. |
| template <class Pointer> |
| class vector_const_iterator |
| : public std::iterator<std::random_access_iterator_tag |
| ,const typename std::iterator_traits<Pointer>::value_type |
| ,typename std::iterator_traits<Pointer>::difference_type |
| ,typename boost::pointer_to_other |
| <Pointer |
| ,const typename std::iterator_traits<Pointer>::value_type |
| >::type |
| ,const typename std::iterator_traits<Pointer>::value_type &> |
| { |
| public: |
| typedef typename std::iterator_traits<Pointer>::value_type value_type; |
| typedef typename std::iterator_traits<Pointer>::difference_type difference_type; |
| typedef typename boost::pointer_to_other<Pointer, value_type>::type pointer; |
| typedef const value_type& reference; |
| |
| /// @cond |
| protected: |
| Pointer m_ptr; |
| |
| public: |
| Pointer get_ptr() const { return m_ptr; } |
| explicit vector_const_iterator(Pointer ptr) : m_ptr(ptr){} |
| /// @endcond |
| |
| public: |
| |
| //Constructors |
| vector_const_iterator() : m_ptr(0){} |
| |
| //Pointer like operators |
| reference operator*() const |
| { return *m_ptr; } |
| |
| const value_type * operator->() const |
| { return containers_detail::get_pointer(m_ptr); } |
| |
| reference operator[](difference_type off) const |
| { return m_ptr[off]; } |
| |
| //Increment / Decrement |
| vector_const_iterator& operator++() |
| { ++m_ptr; return *this; } |
| |
| vector_const_iterator operator++(int) |
| { Pointer tmp = m_ptr; ++*this; return vector_const_iterator(tmp); } |
| |
| vector_const_iterator& operator--() |
| { --m_ptr; return *this; } |
| |
| vector_const_iterator operator--(int) |
| { Pointer tmp = m_ptr; --*this; return vector_const_iterator(tmp); } |
| |
| //Arithmetic |
| vector_const_iterator& operator+=(difference_type off) |
| { m_ptr += off; return *this; } |
| |
| vector_const_iterator operator+(difference_type off) const |
| { return vector_const_iterator(m_ptr+off); } |
| |
| friend vector_const_iterator operator+(difference_type off, const vector_const_iterator& right) |
| { return vector_const_iterator(off + right.m_ptr); } |
| |
| vector_const_iterator& operator-=(difference_type off) |
| { m_ptr -= off; return *this; } |
| |
| vector_const_iterator operator-(difference_type off) const |
| { return vector_const_iterator(m_ptr-off); } |
| |
| difference_type operator-(const vector_const_iterator& right) const |
| { return m_ptr - right.m_ptr; } |
| |
| //Comparison operators |
| bool operator== (const vector_const_iterator& r) const |
| { return m_ptr == r.m_ptr; } |
| |
| bool operator!= (const vector_const_iterator& r) const |
| { return m_ptr != r.m_ptr; } |
| |
| bool operator< (const vector_const_iterator& r) const |
| { return m_ptr < r.m_ptr; } |
| |
| bool operator<= (const vector_const_iterator& r) const |
| { return m_ptr <= r.m_ptr; } |
| |
| bool operator> (const vector_const_iterator& r) const |
| { return m_ptr > r.m_ptr; } |
| |
| bool operator>= (const vector_const_iterator& r) const |
| { return m_ptr >= r.m_ptr; } |
| }; |
| |
| //! Iterator used to iterate through a vector |
| template <class Pointer> |
| class vector_iterator |
| : public vector_const_iterator<Pointer> |
| { |
| public: |
| explicit vector_iterator(Pointer ptr) |
| : vector_const_iterator<Pointer>(ptr) |
| {} |
| |
| public: |
| typedef typename std::iterator_traits<Pointer>::value_type value_type; |
| typedef typename vector_const_iterator<Pointer>::difference_type difference_type; |
| typedef Pointer pointer; |
| typedef value_type& reference; |
| |
| //Constructors |
| vector_iterator() |
| {} |
| |
| //Pointer like operators |
| reference operator*() const |
| { return *this->m_ptr; } |
| |
| value_type* operator->() const |
| { return containers_detail::get_pointer(this->m_ptr); } |
| |
| reference operator[](difference_type off) const |
| { return this->m_ptr[off]; } |
| |
| //Increment / Decrement |
| vector_iterator& operator++() |
| { ++this->m_ptr; return *this; } |
| |
| vector_iterator operator++(int) |
| { pointer tmp = this->m_ptr; ++*this; return vector_iterator(tmp); } |
| |
| vector_iterator& operator--() |
| { --this->m_ptr; return *this; } |
| |
| vector_iterator operator--(int) |
| { vector_iterator tmp = *this; --*this; return vector_iterator(tmp); } |
| |
| // Arithmetic |
| vector_iterator& operator+=(difference_type off) |
| { this->m_ptr += off; return *this; } |
| |
| vector_iterator operator+(difference_type off) const |
| { return vector_iterator(this->m_ptr+off); } |
| |
| friend vector_iterator operator+(difference_type off, const vector_iterator& right) |
| { return vector_iterator(off + right.m_ptr); } |
| |
| vector_iterator& operator-=(difference_type off) |
| { this->m_ptr -= off; return *this; } |
| |
| vector_iterator operator-(difference_type off) const |
| { return vector_iterator(this->m_ptr-off); } |
| |
| difference_type operator-(const vector_const_iterator<Pointer>& right) const |
| { return static_cast<const vector_const_iterator<Pointer>&>(*this) - right; } |
| }; |
| |
| template <class T, class A> |
| struct vector_value_traits |
| { |
| typedef T value_type; |
| typedef A allocator_type; |
| static const bool trivial_dctr = boost::has_trivial_destructor<value_type>::value; |
| static const bool trivial_dctr_after_move = false; |
| //::boost::has_trivial_destructor_after_move<value_type>::value || trivial_dctr; |
| static const bool trivial_copy = has_trivial_copy<value_type>::value; |
| static const bool nothrow_copy = has_nothrow_copy<value_type>::value; |
| static const bool trivial_assign = has_trivial_assign<value_type>::value; |
| static const bool nothrow_assign = has_nothrow_assign<value_type>::value; |
| |
| //This is the anti-exception array destructor |
| //to deallocate values already constructed |
| typedef typename containers_detail::if_c |
| <trivial_dctr |
| ,containers_detail::null_scoped_destructor_n<allocator_type> |
| ,containers_detail::scoped_destructor_n<allocator_type> |
| >::type OldArrayDestructor; |
| //This is the anti-exception array destructor |
| //to destroy objects created with copy construction |
| typedef typename containers_detail::if_c |
| <nothrow_copy |
| ,containers_detail::null_scoped_destructor_n<allocator_type> |
| ,containers_detail::scoped_destructor_n<allocator_type> |
| >::type UCopiedArrayDestructor; |
| //This is the anti-exception array deallocator |
| typedef typename containers_detail::if_c |
| <nothrow_copy |
| ,containers_detail::null_scoped_array_deallocator<allocator_type> |
| ,containers_detail::scoped_array_deallocator<allocator_type> |
| >::type UCopiedArrayDeallocator; |
| }; |
| |
| //!This struct deallocates and allocated memory |
| template <class A> |
| struct vector_alloc_holder |
| { |
| typedef typename A::pointer pointer; |
| typedef typename A::size_type size_type; |
| typedef typename A::value_type value_type; |
| typedef vector_value_traits<value_type, A> value_traits; |
| |
| //Constructor, does not throw |
| vector_alloc_holder(const A &a) |
| : members_(a) |
| {} |
| |
| //Destructor |
| ~vector_alloc_holder() |
| { |
| this->prot_destroy_all(); |
| this->prot_deallocate(); |
| } |
| |
| typedef containers_detail::integral_constant<unsigned, 1> allocator_v1; |
| typedef containers_detail::integral_constant<unsigned, 2> allocator_v2; |
| typedef containers_detail::integral_constant<unsigned, |
| boost::container::containers_detail::version<A>::value> alloc_version; |
| std::pair<pointer, bool> |
| allocation_command(allocation_type command, |
| size_type limit_size, |
| size_type preferred_size, |
| size_type &received_size, const pointer &reuse = 0) |
| { |
| return allocation_command(command, limit_size, preferred_size, |
| received_size, reuse, alloc_version()); |
| } |
| |
| std::pair<pointer, bool> |
| allocation_command(allocation_type command, |
| size_type limit_size, |
| size_type preferred_size, |
| size_type &received_size, |
| const pointer &reuse, |
| allocator_v1) |
| { |
| (void)limit_size; |
| (void)reuse; |
| if(!(command & allocate_new)) |
| return std::pair<pointer, bool>(pointer(0), false); |
| received_size = preferred_size; |
| return std::make_pair(this->alloc().allocate(received_size), false); |
| } |
| |
| std::pair<pointer, bool> |
| allocation_command(allocation_type command, |
| size_type limit_size, |
| size_type preferred_size, |
| size_type &received_size, |
| const pointer &reuse, |
| allocator_v2) |
| { |
| return this->alloc().allocation_command |
| (command, limit_size, preferred_size, received_size, reuse); |
| } |
| |
| size_type next_capacity(size_type additional_objects) const |
| { return get_next_capacity(this->alloc().max_size(), this->members_.m_capacity, additional_objects); } |
| |
| struct members_holder |
| : public A |
| { |
| private: |
| members_holder(const members_holder&); |
| |
| public: |
| members_holder(const A &alloc) |
| : A(alloc), m_start(0), m_size(0), m_capacity(0) |
| {} |
| |
| pointer m_start; |
| size_type m_size; |
| size_type m_capacity; |
| } members_; |
| |
| A &alloc() |
| { return members_; } |
| |
| const A &alloc() const |
| { return members_; } |
| |
| protected: |
| void prot_deallocate() |
| { |
| if(!this->members_.m_capacity) return; |
| this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); |
| this->members_.m_start = 0; |
| this->members_.m_size = 0; |
| this->members_.m_capacity = 0; |
| } |
| |
| void destroy(value_type* p) |
| { |
| if(!value_traits::trivial_dctr) |
| containers_detail::get_pointer(p)->~value_type(); |
| } |
| |
| void destroy_n(value_type* p, size_type n) |
| { |
| if(!value_traits::trivial_dctr) |
| for(; n--; ++p) p->~value_type(); |
| } |
| |
| void prot_destroy_all() |
| { |
| this->destroy_n(containers_detail::get_pointer(this->members_.m_start), this->members_.m_size); |
| this->members_.m_size = 0; |
| } |
| }; |
| |
| } //namespace containers_detail { |
| /// @endcond |
| |
| //! \class vector |
| //! A vector is a sequence that supports random access to elements, constant |
| //! time insertion and removal of elements at the end, and linear time insertion |
| //! and removal of elements at the beginning or in the middle. The number of |
| //! elements in a vector may vary dynamically; memory management is automatic. |
| //! boost::container::vector is similar to std::vector but it's compatible |
| //! with shared memory and memory mapped files. |
| template <class T, class A> |
| class vector : private containers_detail::vector_alloc_holder<A> |
| { |
| /// @cond |
| typedef vector<T, A> self_t; |
| typedef containers_detail::vector_alloc_holder<A> base_t; |
| typedef typename containers_detail:: |
| move_const_ref_type<T>::type insert_const_ref_type; |
| /// @endcond |
| public: |
| //! The type of object, T, stored in the vector |
| typedef T value_type; |
| //! Pointer to T |
| typedef typename A::pointer pointer; |
| //! Const pointer to T |
| typedef typename A::const_pointer const_pointer; |
| //! Reference to T |
| typedef typename A::reference reference; |
| //! Const reference to T |
| typedef typename A::const_reference const_reference; |
| //! An unsigned integral type |
| typedef typename A::size_type size_type; |
| //! A signed integral type |
| typedef typename A::difference_type difference_type; |
| //! The allocator type |
| typedef A allocator_type; |
| //! The random access iterator |
| typedef containers_detail::vector_iterator<pointer> iterator; |
| //! The random access const_iterator |
| typedef containers_detail::vector_const_iterator<pointer> const_iterator; |
| |
| //! Iterator used to iterate backwards through a vector. |
| typedef std::reverse_iterator<iterator> |
| reverse_iterator; |
| //! Const iterator used to iterate backwards through a vector. |
| typedef std::reverse_iterator<const_iterator> |
| const_reverse_iterator; |
| //! The stored allocator type |
| typedef allocator_type stored_allocator_type; |
| |
| /// @cond |
| private: |
| BOOST_MOVE_MACRO_COPYABLE_AND_MOVABLE(vector) |
| typedef containers_detail::advanced_insert_aux_int<T, T*> advanced_insert_aux_int_t; |
| typedef containers_detail::vector_value_traits<value_type, A> value_traits; |
| |
| typedef typename base_t::allocator_v1 allocator_v1; |
| typedef typename base_t::allocator_v2 allocator_v2; |
| typedef typename base_t::alloc_version alloc_version; |
| |
| typedef constant_iterator<T, difference_type> cvalue_iterator; |
| typedef repeat_iterator<T, difference_type> repeat_it; |
| typedef BOOST_CONTAINER_MOVE_NAMESPACE::move_iterator<repeat_it> repeat_move_it; |
| /// @endcond |
| |
| public: |
| |
| //! <b>Effects</b>: Constructs a vector taking the allocator as parameter. |
| //! |
| //! <b>Throws</b>: If allocator_type's copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Constant. |
| explicit vector(const A& a = A()) |
| : base_t(a) |
| {} |
| |
| //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a |
| //! and inserts n default contructed values. |
| //! |
| //! <b>Throws</b>: If allocator_type's default constructor or copy constructor |
| //! throws or T's default or copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Linear to n. |
| explicit vector(size_type n) |
| : base_t(allocator_type()) |
| { this->resize(n); } |
| |
| //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a |
| //! and inserts n copies of value. |
| //! |
| //! <b>Throws</b>: If allocator_type's default constructor or copy constructor |
| //! throws or T's default or copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Linear to n. |
| vector(size_type n, const T& value, const allocator_type& a = allocator_type()) |
| : base_t(a) |
| { this->insert(this->cend(), n, value); } |
| |
| //! <b>Effects</b>: Copy constructs a vector. |
| //! |
| //! <b>Postcondition</b>: x == *this. |
| //! |
| //! <b>Complexity</b>: Linear to the elements x contains. |
| vector(const vector<T, A>& x) |
| : base_t(static_cast<const base_t&>(x).alloc()) |
| { *this = x; } |
| |
| //! <b>Effects</b>: Move constructor. Moves mx's resources to *this. |
| //! |
| //! <b>Throws</b>: If allocator_type's copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Constant. |
| vector(BOOST_MOVE_MACRO_RV_REF(vector) mx) |
| : base_t(static_cast<base_t&>(mx).alloc()) |
| { this->swap(mx); } |
| |
| //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a |
| //! and inserts a copy of the range [first, last) in the vector. |
| //! |
| //! <b>Throws</b>: If allocator_type's default constructor or copy constructor |
| //! throws or T's constructor taking an dereferenced InIt throws. |
| //! |
| //! <b>Complexity</b>: Linear to the range [first, last). |
| template <class InIt> |
| vector(InIt first, InIt last, const allocator_type& a = allocator_type()) |
| : base_t(a) |
| { this->assign(first, last); } |
| |
| //! <b>Effects</b>: Destroys the vector. All stored values are destroyed |
| //! and used memory is deallocated. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Linear to the number of elements. |
| ~vector() |
| {} //vector_alloc_holder clears the data |
| |
| //! <b>Effects</b>: Returns an iterator to the first element contained in the vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| iterator begin() |
| { return iterator(this->members_.m_start); } |
| |
| //! <b>Effects</b>: Returns a const_iterator to the first element contained in the vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| const_iterator begin() const |
| { return const_iterator(this->members_.m_start); } |
| |
| //! <b>Effects</b>: Returns an iterator to the end of the vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| iterator end() |
| { return iterator(this->members_.m_start + this->members_.m_size); } |
| |
| //! <b>Effects</b>: Returns a const_iterator to the end of the vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| const_iterator end() const |
| { return this->cend(); } |
| |
| //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning |
| //! of the reversed vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| reverse_iterator rbegin() |
| { return reverse_iterator(this->end()); } |
| |
| //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning |
| //! of the reversed vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| const_reverse_iterator rbegin()const |
| { return this->crbegin(); } |
| |
| //! <b>Effects</b>: Returns a reverse_iterator pointing to the end |
| //! of the reversed vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| reverse_iterator rend() |
| { return reverse_iterator(this->begin()); } |
| |
| //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end |
| //! of the reversed vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| const_reverse_iterator rend() const |
| { return this->crend(); } |
| |
| //! <b>Effects</b>: Returns a const_iterator to the first element contained in the vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| const_iterator cbegin() const |
| { return const_iterator(this->members_.m_start); } |
| |
| //! <b>Effects</b>: Returns a const_iterator to the end of the vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| const_iterator cend() const |
| { return const_iterator(this->members_.m_start + this->members_.m_size); } |
| |
| //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning |
| //! of the reversed vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| const_reverse_iterator crbegin()const |
| { return const_reverse_iterator(this->end());} |
| |
| //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end |
| //! of the reversed vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| const_reverse_iterator crend() const |
| { return const_reverse_iterator(this->begin()); } |
| |
| //! <b>Requires</b>: !empty() |
| //! |
| //! <b>Effects</b>: Returns a reference to the first element |
| //! from the beginning of the container. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| reference front() |
| { return *this->members_.m_start; } |
| |
| //! <b>Requires</b>: !empty() |
| //! |
| //! <b>Effects</b>: Returns a const reference to the first element |
| //! from the beginning of the container. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| const_reference front() const |
| { return *this->members_.m_start; } |
| |
| //! <b>Requires</b>: !empty() |
| //! |
| //! <b>Effects</b>: Returns a reference to the first element |
| //! from the beginning of the container. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| reference back() |
| { return this->members_.m_start[this->members_.m_size - 1]; } |
| |
| //! <b>Effects</b>: Returns a const reference to the first element |
| //! from the beginning of the container. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| const_reference back() const |
| { return this->members_.m_start[this->members_.m_size - 1]; } |
| |
| //! <b>Returns</b>: A pointer such that [data(),data() + size()) is a valid range. |
| //! For a non-empty vector, data() == &front(). |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| pointer data() |
| { return this->members_.m_start; } |
| |
| //! <b>Returns</b>: A pointer such that [data(),data() + size()) is a valid range. |
| //! For a non-empty vector, data() == &front(). |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| const_pointer data() const |
| { return this->members_.m_start; } |
| |
| //! <b>Effects</b>: Returns the number of the elements contained in the vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| size_type size() const |
| { return this->members_.m_size; } |
| |
| //! <b>Effects</b>: Returns the largest possible size of the vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| size_type max_size() const |
| { return this->alloc().max_size(); } |
| |
| //! <b>Effects</b>: Number of elements for which memory has been allocated. |
| //! capacity() is always greater than or equal to size(). |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| size_type capacity() const |
| { return this->members_.m_capacity; } |
| |
| //! <b>Effects</b>: Returns true if the vector contains no elements. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| bool empty() const |
| { return !this->members_.m_size; } |
| |
| //! <b>Requires</b>: size() < n. |
| //! |
| //! <b>Effects</b>: Returns a reference to the nth element |
| //! from the beginning of the container. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| reference operator[](size_type n) |
| { return this->members_.m_start[n]; } |
| |
| //! <b>Requires</b>: size() < n. |
| //! |
| //! <b>Effects</b>: Returns a const reference to the nth element |
| //! from the beginning of the container. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| const_reference operator[](size_type n) const |
| { return this->members_.m_start[n]; } |
| |
| //! <b>Requires</b>: size() < n. |
| //! |
| //! <b>Effects</b>: Returns a reference to the nth element |
| //! from the beginning of the container. |
| //! |
| //! <b>Throws</b>: std::range_error if n >= size() |
| //! |
| //! <b>Complexity</b>: Constant. |
| reference at(size_type n) |
| { this->priv_check_range(n); return this->members_.m_start[n]; } |
| |
| //! <b>Requires</b>: size() < n. |
| //! |
| //! <b>Effects</b>: Returns a const reference to the nth element |
| //! from the beginning of the container. |
| //! |
| //! <b>Throws</b>: std::range_error if n >= size() |
| //! |
| //! <b>Complexity</b>: Constant. |
| const_reference at(size_type n) const |
| { this->priv_check_range(n); return this->members_.m_start[n]; } |
| |
| //! <b>Effects</b>: Returns a copy of the internal allocator. |
| //! |
| //! <b>Throws</b>: If allocator's copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Constant. |
| allocator_type get_allocator() const |
| { return this->alloc(); } |
| |
| const stored_allocator_type &get_stored_allocator() const |
| { return this->alloc(); } |
| |
| stored_allocator_type &get_stored_allocator() |
| { return this->alloc(); } |
| |
| //! <b>Effects</b>: If n is less than or equal to capacity(), this call has no |
| //! effect. Otherwise, it is a request for allocation of additional memory. |
| //! If the request is successful, then capacity() is greater than or equal to |
| //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. |
| //! |
| //! <b>Throws</b>: If memory allocation allocation throws or T's copy constructor throws. |
| void reserve(size_type new_cap) |
| { |
| if (this->capacity() < new_cap){ |
| //There is not enough memory, allocate a new |
| //buffer or expand the old one. |
| bool same_buffer_start; |
| size_type real_cap = 0; |
| std::pair<pointer, bool> ret = |
| this->allocation_command |
| (allocate_new | expand_fwd | expand_bwd, |
| new_cap, new_cap, real_cap, this->members_.m_start); |
| |
| //Check for forward expansion |
| same_buffer_start = ret.second && this->members_.m_start == ret.first; |
| if(same_buffer_start){ |
| #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS |
| ++this->num_expand_fwd; |
| #endif |
| this->members_.m_capacity = real_cap; |
| } |
| |
| //If there is no forward expansion, move objects |
| else{ |
| //We will reuse insert code, so create a dummy input iterator |
| T *dummy_it(containers_detail::get_pointer(this->members_.m_start)); |
| containers_detail::advanced_insert_aux_proxy<T, BOOST_CONTAINER_MOVE_NAMESPACE::move_iterator<T*>, T*> |
| proxy(::BOOST_CONTAINER_MOVE_NAMESPACE::make_move_iterator(dummy_it), ::BOOST_CONTAINER_MOVE_NAMESPACE::make_move_iterator(dummy_it)); |
| //Backwards (and possibly forward) expansion |
| if(ret.second){ |
| #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS |
| ++this->num_expand_bwd; |
| #endif |
| this->priv_range_insert_expand_backwards |
| ( containers_detail::get_pointer(ret.first) |
| , real_cap |
| , containers_detail::get_pointer(this->members_.m_start) |
| , 0 |
| , proxy); |
| } |
| //New buffer |
| else{ |
| #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS |
| ++this->num_alloc; |
| #endif |
| this->priv_range_insert_new_allocation |
| ( containers_detail::get_pointer(ret.first) |
| , real_cap |
| , containers_detail::get_pointer(this->members_.m_start) |
| , 0 |
| , proxy); |
| } |
| } |
| } |
| } |
| |
| //! <b>Effects</b>: Makes *this contain the same elements as x. |
| //! |
| //! <b>Postcondition</b>: this->size() == x.size(). *this contains a copy |
| //! of each of x's elements. |
| //! |
| //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Linear to the number of elements in x. |
| vector& operator=(BOOST_MOVE_MACRO_COPY_ASSIGN_REF(vector) x) |
| { |
| if (&x != this){ |
| this->assign(x.members_.m_start, x.members_.m_start + x.members_.m_size); |
| } |
| return *this; |
| } |
| |
| //! <b>Effects</b>: Move assignment. All mx's values are transferred to *this. |
| //! |
| //! <b>Postcondition</b>: x.empty(). *this contains a the elements x had |
| //! before the function. |
| //! |
| //! <b>Throws</b>: If allocator_type's copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Linear. |
| vector& operator=(BOOST_MOVE_MACRO_RV_REF(vector) x) |
| { |
| if (&x != this){ |
| this->swap(x); |
| x.clear(); |
| } |
| return *this; |
| } |
| |
| //! <b>Effects</b>: Assigns the n copies of val to *this. |
| //! |
| //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Linear to n. |
| void assign(size_type n, const value_type& val) |
| { this->assign(cvalue_iterator(val, n), cvalue_iterator()); } |
| |
| //! <b>Effects</b>: Assigns the the range [first, last) to *this. |
| //! |
| //! <b>Throws</b>: If memory allocation throws or |
| //! T's constructor from dereferencing InpIt throws. |
| //! |
| //! <b>Complexity</b>: Linear to n. |
| template <class InIt> |
| void assign(InIt first, InIt last) |
| { |
| //Dispatch depending on integer/iterator |
| const bool aux_boolean = containers_detail::is_convertible<InIt, std::size_t>::value; |
| typedef containers_detail::bool_<aux_boolean> Result; |
| this->priv_assign_dispatch(first, last, Result()); |
| } |
| |
| //! <b>Effects</b>: Inserts a copy of x at the end of the vector. |
| //! |
| //! <b>Throws</b>: If memory allocation throws or |
| //! T's copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Amortized constant time. |
| void push_back(insert_const_ref_type x) |
| { return priv_push_back(x); } |
| |
| #if defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_MOVE_DOXYGEN_INVOKED) |
| void push_back(T &x) { push_back(const_cast<const T &>(x)); } |
| |
| template<class U> |
| void push_back(const U &u, typename containers_detail::enable_if_c |
| <containers_detail::is_same<T, U>::value && |
| !::BOOST_CONTAINER_MOVE_NAMESPACE::is_movable<U>::value |
| >::type* =0) |
| { return priv_push_back(u); } |
| #endif |
| |
| //! <b>Effects</b>: Constructs a new element in the end of the vector |
| //! and moves the resources of mx to this new element. |
| //! |
| //! <b>Throws</b>: If memory allocation throws. |
| //! |
| //! <b>Complexity</b>: Amortized constant time. |
| void push_back(BOOST_MOVE_MACRO_RV_REF(T) x) |
| { |
| if (this->members_.m_size < this->members_.m_capacity){ |
| //There is more memory, just construct a new object at the end |
| new((void*)containers_detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(BOOST_CONTAINER_MOVE_NAMESPACE::move(x)); |
| ++this->members_.m_size; |
| } |
| else{ |
| this->insert(this->cend(), BOOST_CONTAINER_MOVE_NAMESPACE::move(x)); |
| } |
| } |
| |
| #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
| |
| //! <b>Effects</b>: Inserts an object of type T constructed with |
| //! std::forward<Args>(args)... in the end of the vector. |
| //! |
| //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws. |
| //! |
| //! <b>Complexity</b>: Amortized constant time. |
| template<class ...Args> |
| void emplace_back(Args &&...args) |
| { |
| T* back_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; |
| if (this->members_.m_size < this->members_.m_capacity){ |
| //There is more memory, just construct a new object at the end |
| new((void*)(back_pos))value_type(BOOST_CONTAINER_MOVE_NAMESPACE::forward<Args>(args)...); |
| ++this->members_.m_size; |
| } |
| else{ |
| typedef containers_detail::advanced_insert_aux_emplace<T, T*, Args...> type; |
| type &&proxy = type(BOOST_CONTAINER_MOVE_NAMESPACE::forward<Args>(args)...); |
| priv_range_insert(back_pos, 1, proxy); |
| } |
| } |
| |
| //! <b>Requires</b>: position must be a valid iterator of *this. |
| //! |
| //! <b>Effects</b>: Inserts an object of type T constructed with |
| //! std::forward<Args>(args)... before position |
| //! |
| //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws. |
| //! |
| //! <b>Complexity</b>: If position is end(), amortized constant time |
| //! Linear time otherwise. |
| template<class ...Args> |
| iterator emplace(const_iterator position, Args && ...args) |
| { |
| //Just call more general insert(pos, size, value) and return iterator |
| size_type pos_n = position - cbegin(); |
| typedef containers_detail::advanced_insert_aux_emplace<T, T*, Args...> type; |
| type &&proxy = type(BOOST_CONTAINER_MOVE_NAMESPACE::forward<Args>(args)...); |
| priv_range_insert(position.get_ptr(), 1, proxy); |
| return iterator(this->members_.m_start + pos_n); |
| } |
| |
| #else |
| |
| void emplace_back() |
| { |
| T* back_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; |
| if (this->members_.m_size < this->members_.m_capacity){ |
| //There is more memory, just construct a new object at the end |
| new((void*)(back_pos))value_type(); |
| ++this->members_.m_size; |
| } |
| else{ |
| containers_detail::advanced_insert_aux_emplace<value_type, T*> proxy; |
| priv_range_insert(back_pos, 1, proxy); |
| } |
| } |
| |
| iterator emplace(const_iterator position) |
| { |
| size_type pos_n = position - cbegin(); |
| containers_detail::advanced_insert_aux_emplace<value_type, T*> proxy; |
| priv_range_insert(containers_detail::get_pointer(position.get_ptr()), 1, proxy); |
| return iterator(this->members_.m_start + pos_n); |
| } |
| |
| #define BOOST_PP_LOCAL_MACRO(n) \ |
| template<BOOST_PP_ENUM_PARAMS(n, class P)> \ |
| void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ |
| { \ |
| T* back_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; \ |
| if (this->members_.m_size < this->members_.m_capacity){ \ |
| new((void*)(back_pos))value_type \ |
| (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ |
| ++this->members_.m_size; \ |
| } \ |
| else{ \ |
| containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ |
| <value_type, T*, BOOST_PP_ENUM_PARAMS(n, P)> \ |
| proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ |
| priv_range_insert(back_pos, 1, proxy); \ |
| } \ |
| } \ |
| \ |
| template<BOOST_PP_ENUM_PARAMS(n, class P)> \ |
| iterator emplace(const_iterator pos, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ |
| { \ |
| size_type pos_n = pos - cbegin(); \ |
| containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ |
| <value_type, T*, BOOST_PP_ENUM_PARAMS(n, P)> \ |
| proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ |
| priv_range_insert(containers_detail::get_pointer(pos.get_ptr()), 1, proxy); \ |
| return iterator(this->members_.m_start + pos_n); \ |
| } \ |
| //! |
| #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) |
| #include BOOST_PP_LOCAL_ITERATE() |
| |
| #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING |
| |
| //! <b>Effects</b>: Swaps the contents of *this and x. |
| //! If this->allocator_type() != x.allocator_type() |
| //! allocators are also swapped. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant. |
| void swap(vector& x) |
| { |
| allocator_type &this_al = this->alloc(), &other_al = x.alloc(); |
| //Just swap internals |
| containers_detail::do_swap(this->members_.m_start, x.members_.m_start); |
| containers_detail::do_swap(this->members_.m_size, x.members_.m_size); |
| containers_detail::do_swap(this->members_.m_capacity, x.members_.m_capacity); |
| |
| if (this_al != other_al){ |
| containers_detail::do_swap(this_al, other_al); |
| } |
| } |
| |
| //! <b>Requires</b>: position must be a valid iterator of *this. |
| //! |
| //! <b>Effects</b>: Insert a copy of x before position. |
| //! |
| //! <b>Throws</b>: If memory allocation throws or x's copy constructor throws. |
| //! |
| //! <b>Complexity</b>: If position is end(), amortized constant time |
| //! Linear time otherwise. |
| iterator insert(const_iterator position, insert_const_ref_type x) |
| { return this->priv_insert(position, x); } |
| |
| #if defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_MOVE_DOXYGEN_INVOKED) |
| iterator insert(const_iterator position, T &x) { return this->insert(position, const_cast<const T &>(x)); } |
| |
| template<class U> |
| iterator insert(const_iterator position, const U &u, typename containers_detail::enable_if_c<containers_detail::is_same<T, U>::value && !::BOOST_CONTAINER_MOVE_NAMESPACE::is_movable<U>::value >::type* =0) |
| { return this->priv_insert(position, u); } |
| #endif |
| |
| //! <b>Requires</b>: position must be a valid iterator of *this. |
| //! |
| //! <b>Effects</b>: Insert a new element before position with mx's resources. |
| //! |
| //! <b>Throws</b>: If memory allocation throws. |
| //! |
| //! <b>Complexity</b>: If position is end(), amortized constant time |
| //! Linear time otherwise. |
| iterator insert(const_iterator position, BOOST_MOVE_MACRO_RV_REF(T) x) |
| { |
| //Just call more general insert(pos, size, value) and return iterator |
| size_type pos_n = position - cbegin(); |
| this->insert(position |
| ,repeat_move_it(repeat_it(x, 1)) |
| ,repeat_move_it(repeat_it())); |
| return iterator(this->members_.m_start + pos_n); |
| } |
| |
| //! <b>Requires</b>: pos must be a valid iterator of *this. |
| //! |
| //! <b>Effects</b>: Insert a copy of the [first, last) range before pos. |
| //! |
| //! <b>Throws</b>: If memory allocation throws, T's constructor from a |
| //! dereferenced InpIt throws or T's copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Linear to std::distance [first, last). |
| template <class InIt> |
| void insert(const_iterator pos, InIt first, InIt last) |
| { |
| //Dispatch depending on integer/iterator |
| const bool aux_boolean = containers_detail::is_convertible<InIt, std::size_t>::value; |
| typedef containers_detail::bool_<aux_boolean> Result; |
| this->priv_insert_dispatch(pos, first, last, Result()); |
| } |
| |
| //! <b>Requires</b>: pos must be a valid iterator of *this. |
| //! |
| //! <b>Effects</b>: Insert n copies of x before pos. |
| //! |
| //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Linear to n. |
| void insert(const_iterator p, size_type n, const T& x) |
| { this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); } |
| |
| //! <b>Effects</b>: Removes the last element from the vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Constant time. |
| void pop_back() |
| { |
| //Destroy last element |
| --this->members_.m_size; |
| this->destroy(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size); |
| } |
| |
| //! <b>Effects</b>: Erases the element at position pos. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Linear to the elements between pos and the |
| //! last element. Constant if pos is the first or the last element. |
| iterator erase(const_iterator position) |
| { |
| T *pos = containers_detail::get_pointer(position.get_ptr()); |
| T *beg = containers_detail::get_pointer(this->members_.m_start); |
| BOOST_CONTAINER_MOVE_NAMESPACE::move(pos + 1, beg + this->members_.m_size, pos); |
| --this->members_.m_size; |
| //Destroy last element |
| base_t::destroy(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size); |
| return iterator(position.get_ptr()); |
| } |
| |
| //! <b>Effects</b>: Erases the elements pointed by [first, last). |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Linear to the distance between first and last. |
| iterator erase(const_iterator first, const_iterator last) |
| { |
| if (first != last){ // worth doing, copy down over hole |
| T* end_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; |
| T* ptr = containers_detail::get_pointer(BOOST_CONTAINER_MOVE_NAMESPACE::move |
| (containers_detail::get_pointer(last.get_ptr()) |
| ,end_pos |
| ,containers_detail::get_pointer(first.get_ptr()) |
| )); |
| size_type destroyed = (end_pos - ptr); |
| this->destroy_n(ptr, destroyed); |
| this->members_.m_size -= destroyed; |
| } |
| return iterator(first.get_ptr()); |
| } |
| |
| //! <b>Effects</b>: Inserts or erases elements at the end such that |
| //! the size becomes n. New elements are copy constructed from x. |
| //! |
| //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Linear to the difference between size() and new_size. |
| void resize(size_type new_size, const T& x) |
| { |
| pointer finish = this->members_.m_start + this->members_.m_size; |
| if (new_size < size()){ |
| //Destroy last elements |
| this->erase(const_iterator(this->members_.m_start + new_size), this->end()); |
| } |
| else{ |
| //Insert new elements at the end |
| this->insert(const_iterator(finish), new_size - this->size(), x); |
| } |
| } |
| |
| //! <b>Effects</b>: Inserts or erases elements at the end such that |
| //! the size becomes n. New elements are default constructed. |
| //! |
| //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Linear to the difference between size() and new_size. |
| void resize(size_type new_size) |
| { |
| if (new_size < this->size()){ |
| //Destroy last elements |
| this->erase(const_iterator(this->members_.m_start + new_size), this->end()); |
| } |
| else{ |
| size_type n = new_size - this->size(); |
| this->reserve(new_size); |
| containers_detail::default_construct_aux_proxy<T, T*, size_type> proxy(n); |
| priv_range_insert(this->cend().get_ptr(), n, proxy); |
| } |
| } |
| |
| //! <b>Effects</b>: Erases all the elements of the vector. |
| //! |
| //! <b>Throws</b>: Nothing. |
| //! |
| //! <b>Complexity</b>: Linear to the number of elements in the vector. |
| void clear() |
| { this->prot_destroy_all(); } |
| |
| //! <b>Effects</b>: Tries to deallocate the excess of memory created |
| //! with previous allocations. The size of the vector is unchanged |
| //! |
| //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws. |
| //! |
| //! <b>Complexity</b>: Linear to size(). |
| void shrink_to_fit() |
| { priv_shrink_to_fit(alloc_version()); } |
| |
| /// @cond |
| |
| private: |
| iterator priv_insert(const_iterator position, const T &x) |
| { |
| //Just call more general insert(pos, size, value) and return iterator |
| size_type pos_n = position - cbegin(); |
| this->insert(position, (size_type)1, x); |
| return iterator(this->members_.m_start + pos_n); |
| } |
| |
| void priv_push_back(const T &x) |
| { |
| if (this->members_.m_size < this->members_.m_capacity){ |
| //There is more memory, just construct a new object at the end |
| new((void*)(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size))value_type(x); |
| ++this->members_.m_size; |
| } |
| else{ |
| this->insert(this->cend(), x); |
| } |
| } |
| |
| void priv_shrink_to_fit(allocator_v1) |
| { |
| if(this->members_.m_capacity){ |
| if(!size()){ |
| this->prot_deallocate(); |
| } |
| else{ |
| //This would not work with stateful allocators |
| vector<T, A>(*this).swap(*this); |
| } |
| } |
| } |
| |
| void priv_shrink_to_fit(allocator_v2) |
| { |
| if(this->members_.m_capacity){ |
| if(!size()){ |
| this->prot_deallocate(); |
| } |
| else{ |
| size_type received_size; |
| if(this->alloc().allocation_command |
| ( shrink_in_place | nothrow_allocation |
| , this->capacity(), this->size() |
| , received_size, this->members_.m_start).first){ |
| this->members_.m_capacity = received_size; |
| #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS |
| ++this->num_shrink; |
| #endif |
| } |
| } |
| } |
| } |
| |
| template <class FwdIt> |
| void priv_range_insert(pointer pos, FwdIt first, FwdIt last, std::forward_iterator_tag) |
| { |
| if(first != last){ |
| const size_type n = std::distance(first, last); |
| containers_detail::advanced_insert_aux_proxy<T, FwdIt, T*> proxy(first, last); |
| priv_range_insert(pos, n, proxy); |
| } |
| } |
| |
| void priv_range_insert(pointer pos, const size_type n, advanced_insert_aux_int_t &interf) |
| { |
| //Check if we have enough memory or try to expand current memory |
| size_type remaining = this->members_.m_capacity - this->members_.m_size; |
| bool same_buffer_start; |
| std::pair<pointer, bool> ret; |
| size_type real_cap = this->members_.m_capacity; |
| |
| //Check if we already have room |
| if (n <= remaining){ |
| same_buffer_start = true; |
| } |
| else{ |
| //There is not enough memory, allocate a new |
| //buffer or expand the old one. |
| size_type new_cap = this->next_capacity(n); |
| ret = this->allocation_command |
| (allocate_new | expand_fwd | expand_bwd, |
| this->members_.m_size + n, new_cap, real_cap, this->members_.m_start); |
| |
| //Check for forward expansion |
| same_buffer_start = ret.second && this->members_.m_start == ret.first; |
| if(same_buffer_start){ |
| this->members_.m_capacity = real_cap; |
| } |
| } |
| |
| //If we had room or we have expanded forward |
| if (same_buffer_start){ |
| #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS |
| ++this->num_expand_fwd; |
| #endif |
| this->priv_range_insert_expand_forward |
| (containers_detail::get_pointer(pos), n, interf); |
| } |
| //Backwards (and possibly forward) expansion |
| else if(ret.second){ |
| #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS |
| ++this->num_expand_bwd; |
| #endif |
| this->priv_range_insert_expand_backwards |
| ( containers_detail::get_pointer(ret.first) |
| , real_cap |
| , containers_detail::get_pointer(pos) |
| , n |
| , interf); |
| } |
| //New buffer |
| else{ |
| #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS |
| ++this->num_alloc; |
| #endif |
| this->priv_range_insert_new_allocation |
| ( containers_detail::get_pointer(ret.first) |
| , real_cap |
| , containers_detail::get_pointer(pos) |
| , n |
| , interf); |
| } |
| } |
| |
| void priv_range_insert_expand_forward(T* pos, size_type n, advanced_insert_aux_int_t &interf) |
| { |
| //n can't be 0, because there is nothing to do in that case |
| if(!n) return; |
| //There is enough memory |
| T* old_finish = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; |
| const size_type elems_after = old_finish - pos; |
| |
| if (elems_after > n){ |
| //New elements can be just copied. |
| //Move to uninitialized memory last objects |
| ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_move(old_finish - n, old_finish, old_finish); |
| this->members_.m_size += n; |
| //Copy previous to last objects to the initialized end |
| BOOST_CONTAINER_MOVE_NAMESPACE::move_backward(pos, old_finish - n, old_finish); |
| //Insert new objects in the pos |
| interf.copy_all_to(pos); |
| } |
| else { |
| //The new elements don't fit in the [pos, end()) range. Copy |
| //to the beginning of the unallocated zone the last new elements. |
| interf.uninitialized_copy_some_and_update(old_finish, elems_after, false); |
| this->members_.m_size += n - elems_after; |
| //Copy old [pos, end()) elements to the uninitialized memory |
| ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_move |
| ( pos, old_finish, containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size); |
| this->members_.m_size += elems_after; |
| //Copy first new elements in pos |
| interf.copy_all_to(pos); |
| } |
| } |
| |
| void priv_range_insert_new_allocation |
| (T* new_start, size_type new_cap, T* pos, size_type n, advanced_insert_aux_int_t &interf) |
| { |
| //n can be zero, if we want to reallocate! |
| T *new_finish = new_start; |
| T *old_finish; |
| //Anti-exception rollbacks |
| typename value_traits::UCopiedArrayDeallocator scoped_alloc(new_start, this->alloc(), new_cap); |
| typename value_traits::UCopiedArrayDestructor constructed_values_destroyer(new_start, 0u); |
| |
| //Initialize with [begin(), pos) old buffer |
| //the start of the new buffer |
| T *old_buffer = containers_detail::get_pointer(this->members_.m_start); |
| if(old_buffer){ |
| new_finish = ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_move |
| (containers_detail::get_pointer(this->members_.m_start), pos, old_finish = new_finish); |
| constructed_values_destroyer.increment_size(new_finish - old_finish); |
| } |
| //Initialize new objects, starting from previous point |
| interf.uninitialized_copy_all_to(old_finish = new_finish); |
| new_finish += n; |
| constructed_values_destroyer.increment_size(new_finish - old_finish); |
| //Initialize from the rest of the old buffer, |
| //starting from previous point |
| if(old_buffer){ |
| new_finish = ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_move |
| (pos, old_buffer + this->members_.m_size, new_finish); |
| //Destroy and deallocate old elements |
| //If there is allocated memory, destroy and deallocate |
| if(!value_traits::trivial_dctr_after_move) |
| this->destroy_n(old_buffer, this->members_.m_size); |
| this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); |
| } |
| this->members_.m_start = new_start; |
| this->members_.m_size = new_finish - new_start; |
| this->members_.m_capacity = new_cap; |
| //All construction successful, disable rollbacks |
| constructed_values_destroyer.release(); |
| scoped_alloc.release(); |
| } |
| |
| void priv_range_insert_expand_backwards |
| (T* new_start, size_type new_capacity, |
| T* pos, const size_type n, advanced_insert_aux_int_t &interf) |
| { |
| //n can be zero to just expand capacity |
| //Backup old data |
| T* old_start = containers_detail::get_pointer(this->members_.m_start); |
| T* old_finish = old_start + this->members_.m_size; |
| size_type old_size = this->members_.m_size; |
| |
| //We can have 8 possibilities: |
| const size_type elemsbefore = (size_type)(pos - old_start); |
| const size_type s_before = (size_type)(old_start - new_start); |
| |
| //Update the vector buffer information to a safe state |
| this->members_.m_start = new_start; |
| this->members_.m_capacity = new_capacity; |
| this->members_.m_size = 0; |
| |
| //If anything goes wrong, this object will destroy |
| //all the old objects to fulfill previous vector state |
| typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size); |
| //Check if s_before is big enough to hold the beginning of old data + new data |
| if(difference_type(s_before) >= difference_type(elemsbefore + n)){ |
| //Copy first old values before pos, after that the new objects |
| ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_move(old_start, pos, new_start); |
| this->members_.m_size = elemsbefore; |
| interf.uninitialized_copy_all_to(new_start + elemsbefore); |
| this->members_.m_size += n; |
| //Check if s_before is so big that even copying the old data + new data |
| //there is a gap between the new data and the old data |
| if(s_before >= (old_size + n)){ |
| //Old situation: |
| // _________________________________________________________ |
| //| raw_mem | old_begin | old_end | |
| //| __________________________________|___________|_________| |
| // |
| //New situation: |
| // _________________________________________________________ |
| //| old_begin | new | old_end | raw_mem | |
| //|___________|__________|_________|________________________| |
| // |
| //Now initialize the rest of memory with the last old values |
| ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_move |
| (pos, old_finish, new_start + elemsbefore + n); |
| //All new elements correctly constructed, avoid new element destruction |
| this->members_.m_size = old_size + n; |
| //Old values destroyed automatically with "old_values_destroyer" |
| //when "old_values_destroyer" goes out of scope unless the have trivial |
| //destructor after move. |
| if(value_traits::trivial_dctr_after_move) |
| old_values_destroyer.release(); |
| } |
| //s_before is so big that divides old_end |
| else{ |
| //Old situation: |
| // __________________________________________________ |
| //| raw_mem | old_begin | old_end | |
| //| ___________________________|___________|_________| |
| // |
| //New situation: |
| // __________________________________________________ |
| //| old_begin | new | old_end | raw_mem | |
| //|___________|__________|_________|_________________| |
| // |
| //Now initialize the rest of memory with the last old values |
| //All new elements correctly constructed, avoid new element destruction |
| size_type raw_gap = s_before - (elemsbefore + n); |
| //Now initialize the rest of s_before memory with the |
| //first of elements after new values |
| ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_move(pos, pos + raw_gap, new_start + elemsbefore + n); |
| //Update size since we have a contiguous buffer |
| this->members_.m_size = old_size + s_before; |
| //All new elements correctly constructed, avoid old element destruction |
| old_values_destroyer.release(); |
| //Now copy remaining last objects in the old buffer begin |
| T *to_destroy = BOOST_CONTAINER_MOVE_NAMESPACE::move(pos + raw_gap, old_finish, old_start); |
| //Now destroy redundant elements except if they were moved and |
| //they have trivial destructor after move |
| size_type n_destroy = old_finish - to_destroy; |
| if(!value_traits::trivial_dctr_after_move) |
| this->destroy_n(to_destroy, n_destroy); |
| this->members_.m_size -= n_destroy; |
| } |
| } |
| else{ |
| //Check if we have to do the insertion in two phases |
| //since maybe s_before is not big enough and |
| //the buffer was expanded both sides |
| // |
| //Old situation: |
| // _________________________________________________ |
| //| raw_mem | old_begin + old_end | raw_mem | |
| //|_________|_____________________|_________________| |
| // |
| //New situation with do_after: |
| // _________________________________________________ |
| //| old_begin + new + old_end | raw_mem | |
| //|___________________________________|_____________| |
| // |
| //New without do_after: |
| // _________________________________________________ |
| //| old_begin + new + old_end | raw_mem | |
| //|____________________________|____________________| |
| // |
| bool do_after = n > s_before; |
| |
| //Now we can have two situations: the raw_mem of the |
| //beginning divides the old_begin, or the new elements: |
| if (s_before <= elemsbefore) { |
| //The raw memory divides the old_begin group: |
| // |
| //If we need two phase construction (do_after) |
| //new group is divided in new = new_beg + new_end groups |
| //In this phase only new_beg will be inserted |
| // |
| //Old situation: |
| // _________________________________________________ |
| //| raw_mem | old_begin | old_end | raw_mem | |
| //|_________|___________|_________|_________________| |
| // |
| //New situation with do_after(1): |
| //This is not definitive situation, the second phase |
| //will include |
| // _________________________________________________ |
| //| old_begin | new_beg | old_end | raw_mem | |
| //|___________|_________|_________|_________________| |
| // |
| //New situation without do_after: |
| // _________________________________________________ |
| //| old_begin | new | old_end | raw_mem | |
| //|___________|_____|_________|_____________________| |
| // |
| //Copy the first part of old_begin to raw_mem |
| T *start_n = old_start + difference_type(s_before); |
| ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_move(old_start, start_n, new_start); |
| //The buffer is all constructed until old_end, |
| //release destroyer and update size |
| old_values_destroyer.release(); |
| this->members_.m_size = old_size + s_before; |
| //Now copy the second part of old_begin overwriting himself |
| T* next = BOOST_CONTAINER_MOVE_NAMESPACE::move(start_n, pos, old_start); |
| if(do_after){ |
| //Now copy the new_beg elements |
| interf.copy_some_and_update(next, s_before, true); |
| } |
| else{ |
| //Now copy the all the new elements |
| interf.copy_all_to(next); |
| T* move_start = next + n; |
| //Now displace old_end elements |
| T* move_end = BOOST_CONTAINER_MOVE_NAMESPACE::move(pos, old_finish, move_start); |
| //Destroy remaining moved elements from old_end except if |
| //they have trivial destructor after being moved |
| difference_type n_destroy = s_before - n; |
| if(!value_traits::trivial_dctr_after_move) |
| this->destroy_n(move_end, n_destroy); |
| this->members_.m_size -= n_destroy; |
| } |
| } |
| else { |
| //If we have to expand both sides, |
| //we will play if the first new values so |
| //calculate the upper bound of new values |
| |
| //The raw memory divides the new elements |
| // |
| //If we need two phase construction (do_after) |
| //new group is divided in new = new_beg + new_end groups |
| //In this phase only new_beg will be inserted |
| // |
| //Old situation: |
| // _______________________________________________________ |
| //| raw_mem | old_begin | old_end | raw_mem | |
| //|_______________|___________|_________|_________________| |
| // |
| //New situation with do_after(): |
| // ____________________________________________________ |
| //| old_begin | new_beg | old_end | raw_mem | |
| //|___________|_______________|_________|______________| |
| // |
| //New situation without do_after: |
| // ______________________________________________________ |
| //| old_begin | new | old_end | raw_mem | |
| //|___________|_____|_________|__________________________| |
| // |
| //First copy whole old_begin and part of new to raw_mem |
| ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_move(old_start, pos, new_start); |
| this->members_.m_size = elemsbefore; |
| |
| const size_type mid_n = difference_type(s_before) - elemsbefore; |
| interf.uninitialized_copy_some_and_update(new_start + elemsbefore, mid_n, true); |
| this->members_.m_size = old_size + s_before; |
| //The buffer is all constructed until old_end, |
| //release destroyer and update size |
| old_values_destroyer.release(); |
| |
| if(do_after){ |
| //Copy new_beg part |
| interf.copy_some_and_update(old_start, s_before - mid_n, true); |
| } |
| else{ |
| //Copy all new elements |
| interf.copy_all_to(old_start); |
| T* move_start = old_start + (n-mid_n); |
| //Displace old_end |
| T* move_end = BOOST_CONTAINER_MOVE_NAMESPACE::move(pos, old_finish, move_start); |
| //Destroy remaining moved elements from old_end except if they |
| //have trivial destructor after being moved |
| difference_type n_destroy = s_before - n; |
| if(!value_traits::trivial_dctr_after_move) |
| this->destroy_n(move_end, n_destroy); |
| this->members_.m_size -= n_destroy; |
| } |
| } |
| |
| //This is only executed if two phase construction is needed |
| //This can be executed without exception handling since we |
| //have to just copy and append in raw memory and |
| //old_values_destroyer has been released in phase 1. |
| if(do_after){ |
| //The raw memory divides the new elements |
| // |
| //Old situation: |
| // ______________________________________________________ |
| //| raw_mem | old_begin | old_end | raw_mem | |
| //|______________|___________|____________|______________| |
| // |
| //New situation with do_after(1): |
| // _______________________________________________________ |
| //| old_begin + new_beg | new_end |old_end | raw_mem | |
| //|__________________________|_________|________|_________| |
| // |
| //New situation with do_after(2): |
| // ______________________________________________________ |
| //| old_begin + new | old_end |raw | |
| //|_______________________________________|_________|____| |
| // |
| const size_type n_after = n - s_before; |
| const difference_type elemsafter = old_size - elemsbefore; |
| |
| //We can have two situations: |
| if (elemsafter > difference_type(n_after)){ |
| //The raw_mem from end will divide displaced old_end |
| // |
| //Old situation: |
| // ______________________________________________________ |
| //| raw_mem | old_begin | old_end | raw_mem | |
| //|______________|___________|____________|______________| |
| // |
| //New situation with do_after(1): |
| // _______________________________________________________ |
| //| old_begin + new_beg | new_end |old_end | raw_mem | |
| //|__________________________|_________|________|_________| |
| // |
| //First copy the part of old_end raw_mem |
| T* finish_n = old_finish - difference_type(n_after); |
| ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_move(finish_n, old_finish, old_finish); |
| this->members_.m_size += n_after; |
| //Displace the rest of old_end to the new position |
| BOOST_CONTAINER_MOVE_NAMESPACE::move_backward(pos, finish_n, old_finish); |
| //Now overwrite with new_end |
| //The new_end part is [first + (n - n_after), last) |
| interf.copy_all_to(pos); |
| } |
| else { |
| //The raw_mem from end will divide new_end part |
| // |
| //Old situation: |
| // _____________________________________________________________ |
| //| raw_mem | old_begin | old_end | raw_mem | |
| //|______________|___________|____________|_____________________| |
| // |
| //New situation with do_after(2): |
| // _____________________________________________________________ |
| //| old_begin + new_beg | new_end |old_end | raw_mem | |
| //|__________________________|_______________|________|_________| |
| // |
| size_type mid_last_dist = n_after - elemsafter; |
| //First initialize data in raw memory |
| //The new_end part is [first + (n - n_after), last) |
| interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false); |
| this->members_.m_size += mid_last_dist; |
| ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_move(pos, old_finish, old_finish + mid_last_dist); |
| this->members_.m_size += n_after - mid_last_dist; |
| //Now copy the part of new_end over constructed elements |
| interf.copy_all_to(pos); |
| } |
| } |
| } |
| } |
| |
| template <class InIt> |
| void priv_range_insert(const_iterator pos, InIt first, InIt last, std::input_iterator_tag) |
| { |
| for(;first != last; ++first){ |
| this->insert(pos, BOOST_CONTAINER_MOVE_NAMESPACE::move(value_type(*first))); |
| } |
| } |
| |
| template <class InIt> |
| void priv_assign_aux(InIt first, InIt last, std::input_iterator_tag) |
| { |
| //Overwrite all elements we can from [first, last) |
| iterator cur = begin(); |
| for ( ; first != last && cur != end(); ++cur, ++first){ |
| *cur = *first; |
| } |
| |
| if (first == last){ |
| //There are no more elements in the sequence, erase remaining |
| this->erase(cur, cend()); |
| } |
| else{ |
| //There are more elements in the range, insert the remaining ones |
| this->insert(this->cend(), first, last); |
| } |
| } |
| |
| template <class FwdIt> |
| void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag) |
| { |
| size_type n = std::distance(first, last); |
| if(!n){ |
| this->prot_destroy_all(); |
| return; |
| } |
| //Check if we have enough memory or try to expand current memory |
| size_type remaining = this->members_.m_capacity - this->members_.m_size; |
| bool same_buffer_start; |
| std::pair<pointer, bool> ret; |
| size_type real_cap = this->members_.m_capacity; |
| |
| if (n <= remaining){ |
| same_buffer_start = true; |
| } |
| else{ |
| //There is not enough memory, allocate a new buffer |
| size_type new_cap = this->next_capacity(n); |
| ret = this->allocation_command |
| (allocate_new | expand_fwd | expand_bwd, |
| this->size() + n, new_cap, real_cap, this->members_.m_start); |
| same_buffer_start = ret.second && this->members_.m_start == ret.first; |
| if(same_buffer_start){ |
| this->members_.m_capacity = real_cap; |
| } |
| } |
| |
| if(same_buffer_start){ |
| T *start = containers_detail::get_pointer(this->members_.m_start); |
| if (this->size() >= n){ |
| //There is memory, but there are more old elements than new ones |
| //Overwrite old elements with new ones |
| std::copy(first, last, start); |
| //Destroy remaining old elements |
| this->destroy_n(start + n, this->members_.m_size - n); |
| this->members_.m_size = n; |
| } |
| else{ |
| //There is memory, but there are less old elements than new ones |
| //First overwrite some old elements with new ones |
| FwdIt mid = first; |
| std::advance(mid, this->size()); |
| // iG T *end = std::copy(first, mid, start); |
| T *end = std::copy(first, mid, start); |
| //Initialize the remaining new elements in the uninitialized memory |
| // iG std::uninitialized_copy(mid, last, end); |
| ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_copy_or_move(mid, last, end); |
| this->members_.m_size = n; |
| } |
| } |
| else if(!ret.second){ |
| typename value_traits::UCopiedArrayDeallocator scoped_alloc(ret.first, this->alloc(), real_cap); |
| // iG std::uninitialized_copy(first, last, containers_detail::get_pointer(ret.first)); |
| ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_copy_or_move(first, last, containers_detail::get_pointer(ret.first)); |
| scoped_alloc.release(); |
| //Destroy and deallocate old buffer |
| if(this->members_.m_start != 0){ |
| this->destroy_n(containers_detail::get_pointer(this->members_.m_start), this->members_.m_size); |
| this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); |
| } |
| this->members_.m_start = ret.first; |
| this->members_.m_size = n; |
| this->members_.m_capacity = real_cap; |
| } |
| else{ |
| //Backwards expansion |
| //If anything goes wrong, this object will destroy old objects |
| T *old_start = containers_detail::get_pointer(this->members_.m_start); |
| size_type old_size = this->members_.m_size; |
| typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size); |
| //If something goes wrong size will be 0 |
| //but holding the whole buffer |
| this->members_.m_size = 0; |
| this->members_.m_start = ret.first; |
| this->members_.m_capacity = real_cap; |
| |
| //Backup old buffer data |
| size_type old_offset = old_start - containers_detail::get_pointer(ret.first); |
| size_type first_count = containers_detail::min_value(n, old_offset); |
| |
| FwdIt mid = first; |
| std::advance(mid, first_count); |
| // iG std::uninitialized_copy(first, mid, containers_detail::get_pointer(ret.first)); |
| ::BOOST_CONTAINER_MOVE_NAMESPACE::uninitialized_copy_or_move(first, mid, containers_detail::get_pointer(ret.first)); |
| |
| if(old_offset > n){ |
| //All old elements will be destroyed by "old_values_destroyer" |
| this->members_.m_size = n; |
| } |
| else{ |
| //We have constructed objects from the new begin until |
| //the old end so release the rollback destruction |
| old_values_destroyer.release(); |
| this->members_.m_start = ret.first; |
| this->members_.m_size = first_count + old_size; |
| //Now overwrite the old values |
| size_type second_count = containers_detail::min_value(old_size, n - first_count); |
| FwdIt mid2 = mid; |
| std::advance(mid2, second_count); |
| // iG std::copy(mid, mid2, old_start); |
| std::copy(mid, mid2, old_start); |
| |
| //Check if we still have to append elements in the |
| //uninitialized end |
| if(second_count == old_size){ |
| // iG std::copy(mid2, last, old_start + old_size); |
| std::copy(mid2, last, old_start + old_size); |
| } |
| else{ |
| //We have to destroy some old values |
| this->destroy_n |
| (old_start + second_count, old_size - second_count); |
| this->members_.m_size = n; |
| } |
| this->members_.m_size = n; |
| } |
| } |
| } |
| |
| template <class Integer> |
| void priv_assign_dispatch(Integer n, Integer val, containers_detail::true_) |
| { this->assign((size_type) n, (value_type)val); } |
| |
| template <class InIt> |
| void priv_assign_dispatch(InIt first, InIt last, containers_detail::false_) |
| { |
| //Dispatch depending on integer/iterator |
| typedef typename std::iterator_traits<InIt>::iterator_category ItCat; |
| this->priv_assign_aux(first, last, ItCat()); |
| } |
| |
| template <class Integer> |
| void priv_insert_dispatch(const_iterator pos, Integer n, Integer val, containers_detail::true_) |
| { this->insert(pos, (size_type)n, (T)val); } |
| |
| template <class InIt> |
| void priv_insert_dispatch(const_iterator pos, InIt first, |
| InIt last, containers_detail::false_) |
| { |
| //Dispatch depending on integer/iterator |
| typedef typename std::iterator_traits<InIt>::iterator_category ItCat; |
| this->priv_range_insert(pos.get_ptr(), first, last, ItCat()); |
| } |
| |
| void priv_check_range(size_type n) const |
| { |
| //If n is out of range, throw an out_of_range exception |
| if (n >= size()) |
| throw std::out_of_range("vector::at"); |
| } |
| |
| #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS |
| public: |
| unsigned int num_expand_fwd; |
| unsigned int num_expand_bwd; |
| unsigned int num_shrink; |
| unsigned int num_alloc; |
| void reset_alloc_stats() |
| { num_expand_fwd = num_expand_bwd = num_alloc = 0, num_shrink = 0; } |
| #endif |
| /// @endcond |
| }; |
| |
| template <class T, class A> |
| inline bool |
| operator==(const vector<T, A>& x, const vector<T, A>& y) |
| { |
| //Check first size and each element if needed |
| return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); |
| } |
| |
| template <class T, class A> |
| inline bool |
| operator!=(const vector<T, A>& x, const vector<T, A>& y) |
| { |
| //Check first size and each element if needed |
| return x.size() != y.size() || !std::equal(x.begin(), x.end(), y.begin()); |
| } |
| |
| template <class T, class A> |
| inline bool |
| operator<(const vector<T, A>& x, const vector<T, A>& y) |
| { |
| return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); |
| } |
| |
| template <class T, class A> |
| inline void swap(vector<T, A>& x, vector<T, A>& y) |
| { x.swap(y); } |
| |
| }} |
| |
| /// @cond |
| |
| namespace boost { |
| |
| /* |
| |
| //!has_trivial_destructor_after_move<> == true_type |
| //!specialization for optimizations |
| template <class T, class A> |
| struct has_trivial_destructor_after_move<boost::container::vector<T, A> > |
| { |
| static const bool value = has_trivial_destructor<A>::value; |
| }; |
| |
| */ |
| |
| } |
| |
| /// @endcond |
| |
| #include INCLUDE_BOOST_CONTAINER_DETAIL_CONFIG_END_HPP |
| |
| #endif // #ifndef BOOST_CONTAINERS_CONTAINERS_VECTOR_HPP |
| |