diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index a9095bd..58865b4 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -27,6 +27,8 @@ doxygen autodoc MACRO_EXPANSION=YES "PREDEFINED=\"insert_const_ref_type= const T&\" \\ \"BOOST_CONTAINER_DOXYGEN_INVOKED\" \\ + \"BOOST_CONTAINER_IMPDEF(T)=implementation_defined\" \\ + \"BOOST_CONTAINER_SEEDOC(T)=see_documentation\" \\ \"BOOST_RV_REF(T)=T &&\" \\ \"BOOST_RV_REF_BEG=\" \\ \"BOOST_RV_REF_END=&&\" \\ diff --git a/doc/container.qbk b/doc/container.qbk index 65d4e90..8b71c43 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -38,7 +38,7 @@ In short, what does [*Boost.Container] offer? * The library offers new useful containers: * [classref boost::container::flat_map flat_map], [classref boost::container::flat_set flat_set], - [classref boost::container::flat_multiset flat_multiset] and + [classref boost::container::flat_multimap flat_multimap] and [classref boost::container::flat_multiset flat_multiset]: drop-in replacements for standard associative containers but more memory friendly and with faster searches. @@ -614,6 +614,21 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes Release Notes] +[section:release_notes_boost_1_52_00 Boost 1.52 Release] + +* Improved `stable_vector`'s template code bloat and type safety. +* Changed typedefs and reordered functions of sequence containers to improve doxygen documentation. +* Fixed bugs + [@https://svn.boost.org/trac/boost/ticket/6615 #6615], + [@https://svn.boost.org/trac/boost/ticket/7139 #7139], + [@https://svn.boost.org/trac/boost/ticket/7215 #7215], + [@https://svn.boost.org/trac/boost/ticket/7232 #7232], + [@https://svn.boost.org/trac/boost/ticket/7269 #7269]. +* Implemented LWG Issue #149 (range insertion now returns an iterator) & cleaned up insertion code in most containers +* Corrected aliasing errors. + +[endsect] + [section:release_notes_boost_1_51_00 Boost 1.51 Release] * Fixed bugs @@ -623,7 +638,6 @@ use [*Boost.Container]? There are several reasons for that: [@https://svn.boost.org/trac/boost/ticket/7103 #7103]. [@https://svn.boost.org/trac/boost/ticket/7123 #7123], - [endsect] [section:release_notes_boost_1_50_00 Boost 1.50 Release] @@ -631,12 +645,11 @@ use [*Boost.Container]? There are several reasons for that: * Added Scoped Allocator Model support. * Fixed bugs + [@https://svn.boost.org/trac/boost/ticket/6606 #6606], [@https://svn.boost.org/trac/boost/ticket/6533 #6533], [@https://svn.boost.org/trac/boost/ticket/6536 #6536], [@https://svn.boost.org/trac/boost/ticket/6566 #6566], [@https://svn.boost.org/trac/boost/ticket/6575 #6575], - [@https://svn.boost.org/trac/boost/ticket/6606 #6606], - [@https://svn.boost.org/trac/boost/ticket/6615 #6615], [endsect] diff --git a/include/boost/container/allocator_traits.hpp b/include/boost/container/allocator_traits.hpp index 8e537cc..11d948b 100644 --- a/include/boost/container/allocator_traits.hpp +++ b/include/boost/container/allocator_traits.hpp @@ -70,41 +70,41 @@ struct allocator_traits typedef unspecified pointer; //! Alloc::const_pointer if such a type exists ; otherwise, pointer_traits::rebind::rebind. //! - typedef unspecified void_pointer; + typedef see_documentation void_pointer; //! Alloc::const_void_pointer if such a type exists ; otherwis e, pointer_traits::rebind::difference_type. //! - typedef unspecified difference_type; + typedef see_documentation difference_type; //! Alloc::size_type if such a type exists ; otherwise, make_unsigned::type //! - typedef unspecified size_type; + typedef see_documentation size_type; //! Alloc::propagate_on_container_copy_assignment if such a type exists, otherwise an integral_constant //! type with internal constant static member `value` == false. - typedef unspecified propagate_on_container_copy_assignment; + typedef see_documentation propagate_on_container_copy_assignment; //! Alloc::propagate_on_container_move_assignment if such a type exists, otherwise an integral_constant //! type with internal constant static member `value` == false. - typedef unspecified propagate_on_container_move_assignment; + typedef see_documentation propagate_on_container_move_assignment; //! Alloc::propagate_on_container_swap if such a type exists, otherwise an integral_constant //! type with internal constant static member `value` == false. - typedef unspecified propagate_on_container_swap; + typedef see_documentation propagate_on_container_swap; //! Defines an allocator: Alloc::rebind::other if such a type exists; otherwise, Alloc //! if Alloc is a class template instantiation of the form Alloc, where Args is zero or //! more type arguments ; otherwise, the instantiation of rebind_alloc is ill-formed. //! //! In C++03 compilers `rebind_alloc` is a struct derived from an allocator //! deduced by previously detailed rules. - template using rebind_alloc = unspecified; + template using rebind_alloc = see_documentation; //! In C++03 compilers `rebind_traits` is a struct derived from //! `allocator_traits`, where `OtherAlloc` is @@ -115,7 +115,7 @@ struct allocator_traits //! `type` is an allocator related to Alloc deduced deduced by rules explained in `rebind_alloc`. template struct portable_rebind_alloc - { typedef unspecified_type type; }; + { typedef see_documentation type; }; #else //pointer typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Alloc, diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index 6a85ae9..52b3b68 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -101,17 +101,17 @@ class deque_base { BOOST_COPYABLE_AND_MOVABLE(deque_base) public: - typedef allocator_traits val_alloc_traits_type; - typedef typename val_alloc_traits_type::value_type val_alloc_val; - typedef typename val_alloc_traits_type::pointer val_alloc_ptr; - typedef typename val_alloc_traits_type::const_pointer val_alloc_cptr; - typedef typename val_alloc_traits_type::reference val_alloc_ref; - typedef typename val_alloc_traits_type::const_reference val_alloc_cref; - typedef typename val_alloc_traits_type::difference_type val_alloc_diff; - typedef typename val_alloc_traits_type::size_type val_alloc_size; + typedef allocator_traits val_alloc_traits_type; + typedef typename val_alloc_traits_type::value_type val_alloc_val; + typedef typename val_alloc_traits_type::pointer val_alloc_ptr; + typedef typename val_alloc_traits_type::const_pointer val_alloc_cptr; + typedef typename val_alloc_traits_type::reference val_alloc_ref; + typedef typename val_alloc_traits_type::const_reference val_alloc_cref; + typedef typename val_alloc_traits_type::difference_type val_alloc_diff; + typedef typename val_alloc_traits_type::size_type val_alloc_size; typedef typename val_alloc_traits_type::template - portable_rebind_alloc::type ptr_alloc_t; - typedef allocator_traits ptr_alloc_traits_type; + portable_rebind_alloc::type ptr_alloc_t; + typedef allocator_traits ptr_alloc_traits_type; typedef typename ptr_alloc_traits_type::value_type ptr_alloc_val; typedef typename ptr_alloc_traits_type::pointer ptr_alloc_ptr; typedef typename ptr_alloc_traits_type::const_pointer ptr_alloc_cptr; @@ -534,46 +534,35 @@ class deque : protected deque_base /// @cond private: typedef deque_base Base; - typedef typename Base::val_alloc_val val_alloc_val; - typedef typename Base::val_alloc_ptr val_alloc_ptr; - typedef typename Base::val_alloc_cptr val_alloc_cptr; - typedef typename Base::val_alloc_ref val_alloc_ref; - typedef typename Base::val_alloc_cref val_alloc_cref; - typedef typename Base::val_alloc_size val_alloc_size; - typedef typename Base::val_alloc_diff val_alloc_diff; - - typedef typename Base::ptr_alloc_t ptr_alloc_t; - typedef typename Base::ptr_alloc_val ptr_alloc_val; - typedef typename Base::ptr_alloc_ptr ptr_alloc_ptr; - typedef typename Base::ptr_alloc_cptr ptr_alloc_cptr; - typedef typename Base::ptr_alloc_ref ptr_alloc_ref; - typedef typename Base::ptr_alloc_cref ptr_alloc_cref; /// @endcond - public: // Basic types - typedef T value_type; - typedef val_alloc_ptr pointer; - typedef val_alloc_cptr const_pointer; - typedef val_alloc_ref reference; - typedef val_alloc_cref const_reference; - typedef val_alloc_size size_type; - typedef val_alloc_diff difference_type; - typedef typename Base::allocator_type allocator_type; + public: - public: // Iterators - typedef typename Base::iterator iterator; - typedef typename Base::const_iterator const_iterator; + ////////////////////////////////////////////// + // + // types + // + ////////////////////////////////////////////// - typedef std::reverse_iterator const_reverse_iterator; - typedef std::reverse_iterator reverse_iterator; - - typedef allocator_type stored_allocator_type; + typedef T value_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + typedef typename ::boost::container::allocator_traits::const_pointer const_pointer; + typedef typename ::boost::container::allocator_traits::reference reference; + typedef typename ::boost::container::allocator_traits::const_reference const_reference; + typedef typename ::boost::container::allocator_traits::size_type size_type; + typedef typename ::boost::container::allocator_traits::difference_type difference_type; + typedef A allocator_type; + typedef BOOST_CONTAINER_IMPDEF(allocator_type) stored_allocator_type; + typedef BOOST_CONTAINER_IMPDEF(typename Base::iterator) iterator; + typedef BOOST_CONTAINER_IMPDEF(typename Base::const_iterator) const_iterator; + typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator) reverse_iterator; + typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator) const_reverse_iterator; /// @cond private: // Internal typedefs BOOST_COPYABLE_AND_MOVABLE(deque) - typedef ptr_alloc_ptr index_pointer; + typedef typename Base::ptr_alloc_ptr index_pointer; static size_type s_buffer_size() { return Base::s_buffer_size(); } typedef container_detail::advanced_insert_aux_int advanced_insert_aux_int_t; @@ -584,248 +573,11 @@ class deque : protected deque_base /// @endcond public: - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: Constant. - allocator_type get_allocator() const BOOST_CONTAINER_NOEXCEPT - { return Base::alloc(); } - - //! Effects: Returns a reference to the internal allocator. - //! - //! Throws: Nothing - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension. - const stored_allocator_type &get_stored_allocator() const BOOST_CONTAINER_NOEXCEPT - { return Base::alloc(); } - - //! Effects: Returns a reference to the internal allocator. - //! - //! Throws: Nothing - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension. - stored_allocator_type &get_stored_allocator() BOOST_CONTAINER_NOEXCEPT - { return Base::alloc(); } - - //! Effects: Returns an iterator to the first element contained in the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start; } - - //! Effects: Returns an iterator to the end of the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_finish; } - - //! Effects: Returns a const_iterator to the first element contained in the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start; } - - //! Effects: Returns a const_iterator to the end of the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_finish; } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() BOOST_CONTAINER_NOEXCEPT - { return reverse_iterator(this->members_.m_finish); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() BOOST_CONTAINER_NOEXCEPT - { return reverse_iterator(this->members_.m_start); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const BOOST_CONTAINER_NOEXCEPT - { return const_reverse_iterator(this->members_.m_finish); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const BOOST_CONTAINER_NOEXCEPT - { return const_reverse_iterator(this->members_.m_start); } - - //! Effects: Returns a const_iterator to the first element contained in the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start; } - - //! Effects: Returns a const_iterator to the end of the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_finish; } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const BOOST_CONTAINER_NOEXCEPT - { return const_reverse_iterator(this->members_.m_finish); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const BOOST_CONTAINER_NOEXCEPT - { return const_reverse_iterator(this->members_.m_start); } - - //! Requires: size() > n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference operator[](size_type n) BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start[difference_type(n)]; } - - //! Requires: size() > n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference operator[](size_type n) const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start[difference_type(n)]; } - - //! Requires: size() > n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - reference at(size_type n) - { this->priv_range_check(n); return (*this)[n]; } - - //! Requires: size() > n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - const_reference at(size_type n) const - { this->priv_range_check(n); return (*this)[n]; } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first - //! element of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference front() BOOST_CONTAINER_NOEXCEPT - { return *this->members_.m_start; } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference front() const BOOST_CONTAINER_NOEXCEPT - { return *this->members_.m_start; } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the last - //! element of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference back() BOOST_CONTAINER_NOEXCEPT - { return *(end()-1); } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the last - //! element of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference back() const BOOST_CONTAINER_NOEXCEPT - { return *(cend()-1); } - - //! Effects: Returns the number of the elements contained in the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_finish - this->members_.m_start; } - - //! Effects: Returns the largest possible size of the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const BOOST_CONTAINER_NOEXCEPT - { return allocator_traits_type::max_size(this->alloc()); } - - //! Effects: Returns true if the deque contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_finish == this->members_.m_start; } + ////////////////////////////////////////////// + // + // construct/copy/destroy + // + ////////////////////////////////////////////// //! Effects: Default constructors a deque. //! @@ -872,6 +624,27 @@ class deque : protected deque_base : Base(n, a) { this->priv_fill_initialize(value); } + //! Effects: Constructs a deque that will use a copy of allocator a + //! and inserts a copy of the range [first, last) in the deque. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's constructor taking an dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + deque(InIt first, InIt last, const allocator_type& a = allocator_type() + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + >::type * = 0 + #endif + ) + : Base(a) + { + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_range_initialize(first, last, ItCat()); + } + //! Effects: Copy constructs a deque. //! //! Postcondition: x == *this. @@ -936,23 +709,6 @@ class deque : protected deque_base } } - //! Effects: Constructs a deque that will use a copy of allocator a - //! and inserts a copy of the range [first, last) in the deque. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's constructor taking an dereferenced InIt throws. - //! - //! Complexity: Linear to the range [first, last). - template - deque(InpIt first, InpIt last, const allocator_type& a = allocator_type()) - : Base(a) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_initialize_dispatch(first, last, Result()); - } - //! Effects: Destroys the deque. All stored values are destroyed //! and used memory is deallocated. //! @@ -1024,195 +780,385 @@ class deque : protected deque_base return *this; } - //! Effects: Swaps the contents of *this and x. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - void swap(deque &x) - { - this->swap_members(x); - container_detail::bool_ flag; - container_detail::swap_alloc(this->alloc(), x.alloc(), flag); - container_detail::swap_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); - } - //! Effects: Assigns the n copies of val to *this. //! //! Throws: If memory allocation throws or T's copy constructor throws. //! //! Complexity: Linear to n. void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } + { + typedef constant_iterator c_it; + this->assign(c_it(val, n), c_it()); + } //! Effects: Assigns the the range [first, last) to *this. //! //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InpIt throws. + //! T's constructor from dereferencing InIt throws. //! //! Complexity: Linear to n. - template - void assign(InpIt first, InpIt last) + template + void assign(InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } - - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //! Effects: Inserts a copy of x at the end of the deque. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_back(const T &x); - - //! Effects: Constructs a new element in the end of the deque - //! and moves the resources of mx to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - void push_back(T &&x); - #else - BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) - #endif - - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //! Effects: Inserts a copy of x at the front of the deque. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_front(const T &x); - - //! Effects: Constructs a new element in the front of the deque - //! and moves the resources of mx to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - void push_front(T &&x); - #else - BOOST_MOVE_CONVERSION_AWARE_CATCH(push_front, T, void, priv_push_front) - #endif - - //! Effects: Removes the last element from the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant time. - void pop_back() BOOST_CONTAINER_NOEXCEPT - { - if (this->members_.m_finish.m_cur != this->members_.m_finish.m_first) { - --this->members_.m_finish.m_cur; - allocator_traits_type::destroy - ( this->alloc() - , container_detail::to_raw_pointer(this->members_.m_finish.m_cur) - ); + iterator cur = this->begin(); + for ( ; first != last && cur != end(); ++cur, ++first){ + *cur = *first; } - else - this->priv_pop_back_aux(); - } - - //! Effects: Removes the first element from the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant time. - void pop_front() BOOST_CONTAINER_NOEXCEPT - { - if (this->members_.m_start.m_cur != this->members_.m_start.m_last - 1) { - allocator_traits_type::destroy - ( this->alloc() - , container_detail::to_raw_pointer(this->members_.m_start.m_cur) - ); - ++this->members_.m_start.m_cur; - } - else - this->priv_pop_front_aux(); - } - - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before position. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: If position is end(), amortized constant time - //! Linear time otherwise. - iterator insert(const_iterator position, const T &x); - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Insert a new element before position with mx's resources. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: If position is end(), amortized constant time - //! Linear time otherwise. - iterator insert(const_iterator position, T &&x); - #else - BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator) - #endif - - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert n copies of x before pos. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void insert(const_iterator pos, size_type n, const value_type& x) - { this->priv_fill_insert(pos, n, x); } - - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before pos. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws or T's copy constructor throws. - //! - //! Complexity: Linear to std::distance [first, last). - template - void insert(const_iterator pos, InpIt first, InpIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_insert_dispatch(pos, first, last, Result()); - } - - #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the end of the deque. - //! - //! Throws: If memory allocation throws or the in-place constructor throws. - //! - //! Complexity: Amortized constant time - template - void emplace_back(Args&&... args) - { - if(this->priv_push_back_simple_available()){ - allocator_traits_type::construct - ( this->alloc() - , this->priv_push_back_simple_pos() - , boost::forward(args)...); - this->priv_push_back_simple_commit(); + if (first == last){ + this->erase(cur, this->cend()); } else{ - typedef container_detail::advanced_insert_aux_non_movable_emplace type; - type &&proxy = type(this->alloc(), boost::forward(args)...); - this->priv_insert_back_aux_impl(1, proxy); + this->insert(this->cend(), first, last); } } + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + void assign(FwdIt first, FwdIt last + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !container_detail::is_input_iterator::value + >::type * = 0 + ) + { + const size_type len = std::distance(first, last); + if (len > size()) { + FwdIt mid = first; + std::advance(mid, this->size()); + boost::copy_or_move(first, mid, begin()); + this->insert(this->cend(), mid, last); + } + else{ + this->erase(boost::copy_or_move(first, last, this->begin()), cend()); + } + } + #endif + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + allocator_type get_allocator() const BOOST_CONTAINER_NOEXCEPT + { return Base::alloc(); } + + //! Effects: Returns a reference to the internal allocator. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. + const stored_allocator_type &get_stored_allocator() const BOOST_CONTAINER_NOEXCEPT + { return Base::alloc(); } + + ////////////////////////////////////////////// + // + // iterators + // + ////////////////////////////////////////////// + + //! Effects: Returns a reference to the internal allocator. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. + stored_allocator_type &get_stored_allocator() BOOST_CONTAINER_NOEXCEPT + { return Base::alloc(); } + + //! Effects: Returns an iterator to the first element contained in the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() BOOST_CONTAINER_NOEXCEPT + { return this->members_.m_start; } + + //! Effects: Returns a const_iterator to the first element contained in the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const BOOST_CONTAINER_NOEXCEPT + { return this->members_.m_start; } + + //! Effects: Returns an iterator to the end of the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() BOOST_CONTAINER_NOEXCEPT + { return this->members_.m_finish; } + + //! Effects: Returns a const_iterator to the end of the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const BOOST_CONTAINER_NOEXCEPT + { return this->members_.m_finish; } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() BOOST_CONTAINER_NOEXCEPT + { return reverse_iterator(this->members_.m_finish); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const BOOST_CONTAINER_NOEXCEPT + { return const_reverse_iterator(this->members_.m_finish); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() BOOST_CONTAINER_NOEXCEPT + { return reverse_iterator(this->members_.m_start); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const BOOST_CONTAINER_NOEXCEPT + { return const_reverse_iterator(this->members_.m_start); } + + //! Effects: Returns a const_iterator to the first element contained in the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const BOOST_CONTAINER_NOEXCEPT + { return this->members_.m_start; } + + //! Effects: Returns a const_iterator to the end of the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const BOOST_CONTAINER_NOEXCEPT + { return this->members_.m_finish; } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const BOOST_CONTAINER_NOEXCEPT + { return const_reverse_iterator(this->members_.m_finish); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const BOOST_CONTAINER_NOEXCEPT + { return const_reverse_iterator(this->members_.m_start); } + + ////////////////////////////////////////////// + // + // capacity + // + ////////////////////////////////////////////// + + //! Effects: Returns true if the deque contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const BOOST_CONTAINER_NOEXCEPT + { return this->members_.m_finish == this->members_.m_start; } + + //! Effects: Returns the number of the elements contained in the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const BOOST_CONTAINER_NOEXCEPT + { return this->members_.m_finish - this->members_.m_start; } + + //! Effects: Returns the largest possible size of the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const BOOST_CONTAINER_NOEXCEPT + { return allocator_traits_type::max_size(this->alloc()); } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size) + { + const size_type len = size(); + if (new_size < len) + this->priv_erase_last_n(len - new_size); + else{ + const size_type n = new_size - this->size(); + container_detail::default_construct_aux_proxy proxy(this->alloc(), n); + priv_insert_back_aux_impl(n, proxy); + } + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size, const value_type& x) + { + const size_type len = size(); + if (new_size < len) + this->erase(this->members_.m_start + new_size, this->members_.m_finish); + else + this->insert(this->members_.m_finish, new_size - len, x); + } + + //! Effects: Tries to deallocate the excess of memory created + //! with previous allocations. The size of the deque is unchanged + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Constant. + void shrink_to_fit() + { + //This deque implementation already + //deallocates excess nodes when erasing + //so there is nothing to do except for + //empty deque + if(this->empty()){ + this->priv_clear_map(); + } + } + + ////////////////////////////////////////////// + // + // element access + // + ////////////////////////////////////////////// + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first + //! element of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() BOOST_CONTAINER_NOEXCEPT + { return *this->members_.m_start; } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const BOOST_CONTAINER_NOEXCEPT + { return *this->members_.m_start; } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the last + //! element of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference back() BOOST_CONTAINER_NOEXCEPT + { return *(end()-1); } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the last + //! element of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference back() const BOOST_CONTAINER_NOEXCEPT + { return *(cend()-1); } + + //! Requires: size() > n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference operator[](size_type n) BOOST_CONTAINER_NOEXCEPT + { return this->members_.m_start[difference_type(n)]; } + + //! Requires: size() > n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference operator[](size_type n) const BOOST_CONTAINER_NOEXCEPT + { return this->members_.m_start[difference_type(n)]; } + + //! Requires: size() > n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + reference at(size_type n) + { this->priv_range_check(n); return (*this)[n]; } + + //! Requires: size() > n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + const_reference at(size_type n) const + { this->priv_range_check(n); return (*this)[n]; } + + ////////////////////////////////////////////// + // + // modifiers + // + ////////////////////////////////////////////// + + #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: Inserts an object of type T constructed with //! std::forward(args)... in the beginning of the deque. //! @@ -1236,6 +1182,29 @@ class deque : protected deque_base } } + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the deque. + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: Amortized constant time + template + void emplace_back(Args&&... args) + { + if(this->priv_push_back_simple_available()){ + allocator_traits_type::construct + ( this->alloc() + , this->priv_push_back_simple_pos() + , boost::forward(args)...); + this->priv_push_back_simple_commit(); + } + else{ + typedef container_detail::advanced_insert_aux_non_movable_emplace type; + type &&proxy = type(this->alloc(), boost::forward(args)...); + this->priv_insert_back_aux_impl(1, proxy); + } + } + //! Requires: position must be a valid iterator of *this. //! //! Effects: Inserts an object of type T constructed with @@ -1257,11 +1226,9 @@ class deque : protected deque_base return (this->end()-1); } else{ - size_type n = p - this->cbegin(); typedef container_detail::advanced_insert_aux_emplace type; type &&proxy = type(this->alloc(), boost::forward(args)...); - this->priv_insert_aux_impl(p, 1, proxy); - return iterator(this->begin() + n); + return this->priv_insert_aux_impl(p, 1, proxy); } } @@ -1269,25 +1236,6 @@ class deque : protected deque_base //advanced_insert_int.hpp includes all necessary preprocessor machinery... #define BOOST_PP_LOCAL_MACRO(n) \ - BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ - void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ - { \ - if(priv_push_back_simple_available()){ \ - allocator_traits_type::construct \ - ( this->alloc() \ - , this->priv_push_back_simple_pos() \ - BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ - priv_push_back_simple_commit(); \ - } \ - else{ \ - container_detail::BOOST_PP_CAT(BOOST_PP_CAT( \ - advanced_insert_aux_non_movable_emplace, n), arg) \ - proxy \ - (this->alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ - priv_insert_back_aux_impl(1, proxy); \ - } \ - } \ - \ BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, > ) \ void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ @@ -1308,6 +1256,25 @@ class deque : protected deque_base } \ \ BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + if(priv_push_back_simple_available()){ \ + allocator_traits_type::construct \ + ( this->alloc() \ + , this->priv_push_back_simple_pos() \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ + priv_push_back_simple_commit(); \ + } \ + else{ \ + container_detail::BOOST_PP_CAT(BOOST_PP_CAT( \ + advanced_insert_aux_non_movable_emplace, n), arg) \ + proxy \ + (this->alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ + priv_insert_back_aux_impl(1, proxy); \ + } \ + } \ + \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ iterator emplace(const_iterator p \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ @@ -1320,12 +1287,10 @@ class deque : protected deque_base return (this->end()-1); \ } \ else{ \ - size_type pos_num = p - this->cbegin(); \ container_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ proxy \ (this->alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ - this->priv_insert_aux_impl(p, 1, proxy); \ - return iterator(this->begin() + pos_num); \ + return this->priv_insert_aux_impl(p, 1, proxy); \ } \ } \ //! @@ -1334,37 +1299,170 @@ class deque : protected deque_base #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: Inserts a copy of x at the front of the deque. //! - //! Throws: If memory allocation throws, or T's copy constructor throws. + //! Throws: If memory allocation throws or + //! T's copy constructor throws. //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size, const value_type& x) + //! Complexity: Amortized constant time. + void push_front(const T &x); + + //! Effects: Constructs a new element in the front of the deque + //! and moves the resources of mx to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_front(T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_front, T, void, priv_push_front) + #endif + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: Inserts a copy of x at the end of the deque. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_back(const T &x); + + //! Effects: Constructs a new element in the end of the deque + //! and moves the resources of mx to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_back(T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) + #endif + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before position. + //! + //! Returns: an iterator to the inserted element. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + iterator insert(const_iterator position, const T &x); + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Insert a new element before position with mx's resources. + //! + //! Returns: an iterator to the inserted element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + iterator insert(const_iterator position, T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator) + #endif + + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert n copies of x before pos. + //! + //! Returns: an iterator to the first inserted element or pos if n is 0. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + iterator insert(const_iterator pos, size_type n, const value_type& x) { - const size_type len = size(); - if (new_size < len) - this->erase(this->members_.m_start + new_size, this->members_.m_finish); - else - this->insert(this->members_.m_finish, new_size - len, x); + typedef constant_iterator c_it; + return this->insert(pos, c_it(x, n), c_it()); } - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. + //! Requires: pos must be a valid iterator of *this. //! - //! Throws: If memory allocation throws, or T's copy constructor throws. + //! Effects: Insert a copy of the [first, last) range before pos. //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size) + //! Returns: an iterator to the first inserted element or pos if first == last. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InIt throws or T's copy constructor throws. + //! + //! Complexity: Linear to std::distance [first, last). + template + iterator insert(const_iterator pos, InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { - const size_type len = size(); - if (new_size < len) - this->priv_erase_last_n(len - new_size); - else{ - size_type n = new_size - this->size(); - container_detail::default_construct_aux_proxy proxy(this->alloc(), n); - priv_insert_back_aux_impl(n, proxy); + size_type n = 0; + iterator it(pos); + for(;first != last; ++first, ++n){ + it = this->emplace(it, *first); + ++it; } + it -= n; + return it; + } + + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator insert(const_iterator p, FwdIt first, FwdIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) + { + container_detail::advanced_insert_aux_proxy proxy(this->alloc(), first, last); + return priv_insert_aux_impl(p, (size_type)std::distance(first, last), proxy); + } + #endif + + //! Effects: Removes the first element from the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + void pop_front() BOOST_CONTAINER_NOEXCEPT + { + if (this->members_.m_start.m_cur != this->members_.m_start.m_last - 1) { + allocator_traits_type::destroy + ( this->alloc() + , container_detail::to_raw_pointer(this->members_.m_start.m_cur) + ); + ++this->members_.m_start.m_cur; + } + else + this->priv_pop_front_aux(); + } + + //! Effects: Removes the last element from the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + void pop_back() BOOST_CONTAINER_NOEXCEPT + { + if (this->members_.m_finish.m_cur != this->members_.m_finish.m_first) { + --this->members_.m_finish.m_cur; + allocator_traits_type::destroy + ( this->alloc() + , container_detail::to_raw_pointer(this->members_.m_finish.m_cur) + ); + } + else + this->priv_pop_back_aux(); } //! Effects: Erases the element at position pos. @@ -1428,18 +1526,17 @@ class deque : protected deque_base } } - void priv_erase_last_n(size_type n) + //! Effects: Swaps the contents of *this and x. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(deque &x) { - if(n == this->size()) { - this->clear(); - } - else { - iterator new_finish = this->members_.m_finish - n; - if(!Base::traits_t::trivial_dctr_after_move) - this->priv_destroy_range(new_finish, this->members_.m_finish); - this->priv_destroy_nodes(new_finish.m_node + 1, this->members_.m_finish.m_node + 1); - this->members_.m_finish = new_finish; - } + this->swap_members(x); + container_detail::bool_ flag; + container_detail::swap_alloc(this->alloc(), x.alloc(), flag); + container_detail::swap_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); } //! Effects: Erases all the elements of the deque. @@ -1467,25 +1564,23 @@ class deque : protected deque_base this->members_.m_finish = this->members_.m_start; } - //! Effects: Tries to deallocate the excess of memory created - //! with previous allocations. The size of the deque is unchanged - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Constant. - void shrink_to_fit() + /// @cond + private: + + void priv_erase_last_n(size_type n) { - //This deque implementation already - //deallocates excess nodes when erasing - //so there is nothing to do except for - //empty deque - if(this->empty()){ - this->priv_clear_map(); + if(n == this->size()) { + this->clear(); + } + else { + iterator new_finish = this->members_.m_finish - n; + if(!Base::traits_t::trivial_dctr_after_move) + this->priv_destroy_range(new_finish, this->members_.m_finish); + this->priv_destroy_nodes(new_finish.m_node + 1, this->members_.m_finish.m_node + 1); + this->members_.m_finish = new_finish; } } - /// @cond - private: void priv_range_check(size_type n) const { if (n >= this->size()) BOOST_RETHROW std::out_of_range("deque"); } @@ -1500,9 +1595,7 @@ class deque : protected deque_base return (end()-1); } else { - size_type n = position - cbegin(); - this->priv_insert_aux(position, size_type(1), x); - return iterator(this->begin() + n); + return this->insert(position, size_type(1), x); } } @@ -1517,10 +1610,7 @@ class deque : protected deque_base return(end()-1); } else { - //Just call more general insert(pos, size, value) and return iterator - size_type n = position - begin(); - this->priv_insert_aux(position, move_it(r_iterator(mx, 1)), move_it(r_iterator())); - return iterator(this->begin() + n); + return this->insert(position, move_it(r_iterator(mx, 1)), move_it(r_iterator())); } } @@ -1532,7 +1622,7 @@ class deque : protected deque_base this->priv_push_front_simple_commit(); } else{ - this->priv_insert_aux(cbegin(), size_type(1), t); + this->insert(cbegin(), size_type(1), t); } } @@ -1544,7 +1634,7 @@ class deque : protected deque_base this->priv_push_front_simple_commit(); } else{ - this->priv_insert_aux(cbegin(), move_it(r_iterator(t, 1)), move_it(r_iterator())); + this->insert(cbegin(), move_it(r_iterator(t, 1)), move_it(r_iterator())); } } @@ -1556,7 +1646,7 @@ class deque : protected deque_base this->priv_push_back_simple_commit(); } else{ - this->priv_insert_aux(cend(), size_type(1), t); + this->insert(cend(), size_type(1), t); } } @@ -1568,7 +1658,7 @@ class deque : protected deque_base this->priv_push_back_simple_commit(); } else{ - this->priv_insert_aux(cend(), move_it(r_iterator(t, 1)), move_it(r_iterator())); + this->insert(cend(), move_it(r_iterator(t, 1)), move_it(r_iterator())); } } @@ -1600,48 +1690,6 @@ class deque : protected deque_base void priv_push_front_simple_commit() { --this->members_.m_start.m_cur; } - template - void priv_insert_aux(const_iterator pos, InpIt first, InpIt last, std::input_iterator_tag) - { - for(;first != last; ++first){ - this->insert(pos, boost::move(value_type(*first))); - } - } - - template - void priv_insert_aux(const_iterator pos, FwdIt first, FwdIt last, std::forward_iterator_tag) - { this->priv_insert_aux(pos, first, last); } - - // assign(), a generalized assignment member function. Two - // versions: one that takes a count, and one that takes a range. - // The range version is a member template, so we dispatch on whether - // or not the type is an integer. - void priv_fill_assign(size_type n, const T& val) - { - if (n > size()) { - std::fill(begin(), end(), val); - this->insert(cend(), n - size(), val); - } - else { - this->erase(cbegin() + n, cend()); - std::fill(begin(), end(), val); - } - } - - template - void priv_initialize_dispatch(Integer n, Integer x, container_detail::true_) - { - this->priv_initialize_map(n); - this->priv_fill_initialize(x); - } - - template - void priv_initialize_dispatch(InpIt first, InpIt last, container_detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_range_initialize(first, last, ItCat()); - } - void priv_destroy_range(iterator p, iterator p2) { for(;p != p2; ++p){ @@ -1662,71 +1710,10 @@ class deque : protected deque_base } } - template - void priv_assign_dispatch(Integer n, Integer val, container_detail::true_) - { this->priv_fill_assign((size_type) n, (value_type)val); } - - template - void priv_assign_dispatch(InpIt first, InpIt last, container_detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_assign_aux(first, last, ItCat()); - } - - template - void priv_assign_aux(InpIt first, InpIt last, std::input_iterator_tag) - { - iterator cur = begin(); - for ( ; first != last && cur != end(); ++cur, ++first) - *cur = *first; - if (first == last) - this->erase(cur, cend()); - else - this->insert(cend(), first, last); - } - - template - void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag) - { - size_type len = std::distance(first, last); - if (len > size()) { - FwdIt mid = first; - std::advance(mid, size()); - boost::copy_or_move(first, mid, begin()); - this->insert(cend(), mid, last); - } - else - this->erase(boost::copy_or_move(first, last, begin()), cend()); - } - - template - void priv_insert_dispatch(const_iterator pos, Integer n, Integer x, container_detail::true_) - { this->priv_fill_insert(pos, (size_type) n, (value_type)x); } - - template - void priv_insert_dispatch(const_iterator pos,InpIt first, InpIt last, container_detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_insert_aux(pos, first, last, ItCat()); - } - - void priv_insert_aux(const_iterator pos, size_type n, const value_type& x) - { - typedef constant_iterator c_it; - this->priv_insert_aux(pos, c_it(x, n), c_it()); - } - - //Just forward all operations to priv_insert_aux_impl - template - void priv_insert_aux(const_iterator p, FwdIt first, FwdIt last) - { - container_detail::advanced_insert_aux_proxy proxy(this->alloc(), first, last); - priv_insert_aux_impl(p, (size_type)std::distance(first, last), proxy); - } - - void priv_insert_aux_impl(const_iterator p, size_type n, advanced_insert_aux_int_t &interf) + iterator priv_insert_aux_impl(const_iterator p, size_type n, advanced_insert_aux_int_t &interf) { iterator pos(p); + const size_type pos_n = p - this->cbegin(); if(!this->members_.m_map){ this->priv_initialize_map(0); pos = this->begin(); @@ -1780,9 +1767,10 @@ class deque : protected deque_base interf.copy_remaining_to(pos); } } + return this->begin() + pos_n; } - void priv_insert_back_aux_impl(size_type n, advanced_insert_aux_int_t &interf) + iterator priv_insert_back_aux_impl(size_type n, advanced_insert_aux_int_t &interf) { if(!this->members_.m_map){ this->priv_initialize_map(0); @@ -1792,9 +1780,10 @@ class deque : protected deque_base iterator old_finish = this->members_.m_finish; interf.uninitialized_copy_some_and_update(old_finish, n, true); this->members_.m_finish = new_finish; + return iterator(this->members_.m_finish - n); } - void priv_insert_front_aux_impl(size_type n, advanced_insert_aux_int_t &interf) + iterator priv_insert_front_aux_impl(size_type n, advanced_insert_aux_int_t &interf) { if(!this->members_.m_map){ this->priv_initialize_map(0); @@ -1803,13 +1792,13 @@ class deque : protected deque_base iterator new_start = this->priv_reserve_elements_at_front(n); interf.uninitialized_copy_some_and_update(new_start, difference_type(n), true); this->members_.m_start = new_start; + return new_start; } - - void priv_fill_insert(const_iterator pos, size_type n, const value_type& x) + iterator priv_fill_insert(const_iterator pos, size_type n, const value_type& x) { typedef constant_iterator c_it; - this->insert(pos, c_it(x, n), c_it()); + return this->insert(pos, c_it(x, n), c_it()); } // Precondition: this->members_.m_start and this->members_.m_finish have already been initialized, @@ -1832,13 +1821,13 @@ class deque : protected deque_base BOOST_CATCH_END } - template - void priv_range_initialize(InpIt first, InpIt last, std::input_iterator_tag) + template + void priv_range_initialize(InIt first, InIt last, std::input_iterator_tag) { this->priv_initialize_map(0); BOOST_TRY { for ( ; first != last; ++first) - this->push_back(*first); + this->emplace_back(*first); } BOOST_CATCH(...){ this->clear(); @@ -1990,39 +1979,32 @@ class deque : protected deque_base // Nonmember functions. template -inline bool operator==(const deque& x, - const deque& y) +inline bool operator==(const deque& x, const deque& y) { return x.size() == y.size() && equal(x.begin(), x.end(), y.begin()); } template -inline bool operator<(const deque& x, - const deque& y) +inline bool operator<(const deque& x, const deque& y) { return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } template -inline bool operator!=(const deque& x, - const deque& y) +inline bool operator!=(const deque& x, const deque& y) { return !(x == y); } template -inline bool operator>(const deque& x, - const deque& y) +inline bool operator>(const deque& x, const deque& y) { return y < x; } template -inline bool operator<=(const deque& x, - const deque& y) - { return !(y < x); } - -template -inline bool operator>=(const deque& x, - const deque& y) +inline bool operator>=(const deque& x, const deque& y) { return !(x < y); } +template +inline bool operator<=(const deque& x, const deque& y) + { return !(y < x); } template inline void swap(deque& x, deque& y) diff --git a/include/boost/container/detail/adaptive_node_pool_impl.hpp b/include/boost/container/detail/adaptive_node_pool_impl.hpp index afba6b5..39b9942 100644 --- a/include/boost/container/detail/adaptive_node_pool_impl.hpp +++ b/include/boost/container/detail/adaptive_node_pool_impl.hpp @@ -348,8 +348,7 @@ class private_adaptive_node_pool_impl { block_iterator block_it(m_block_multiset.end()); while(n--){ - void *pElem = container_detail::to_raw_pointer(chain.front()); - chain.pop_front(); + void *pElem = container_detail::to_raw_pointer(chain.pop_front()); priv_invariants(); block_info_t *block_info = this->priv_block_from_node(pElem); BOOST_ASSERT(block_info->free_nodes.size() < m_real_num_node); diff --git a/include/boost/container/detail/advanced_insert_int.hpp b/include/boost/container/detail/advanced_insert_int.hpp index a97af28..e7adcd2 100644 --- a/include/boost/container/detail/advanced_insert_int.hpp +++ b/include/boost/container/detail/advanced_insert_int.hpp @@ -173,7 +173,6 @@ struct default_construct_aux_proxy #ifdef BOOST_CONTAINER_PERFECT_FORWARDING #include -#include #include #include //#include //For debugging purposes @@ -227,8 +226,7 @@ struct advanced_insert_aux_non_movable_emplace if(!this->used_){ alloc_traits::construct( this->a_ , container_detail::to_raw_pointer(&*p) - , ::boost::container::container_detail:: - stored_ref::forward(get(this->args_))... + , ::boost::forward(get(this->args_))... ); this->used_ = true; } @@ -241,8 +239,7 @@ struct advanced_insert_aux_non_movable_emplace if(!this->used_){ alloc_traits::construct( this->a_ , container_detail::to_raw_pointer(&*p) - , ::boost::container::container_detail:: - stored_ref::forward(get(this->args_))... + , ::boost::forward(get(this->args_))... ); this->used_ = true; } @@ -288,7 +285,7 @@ struct advanced_insert_aux_emplace aligned_storage::value> v; value_type *vp = static_cast(static_cast(&v)); alloc_traits::construct(this->a_, vp, - ::boost::container::container_detail::stored_ref::forward(get(this->args_))...); + ::boost::forward(get(this->args_))...); scoped_destructor d(this->a_, vp); *p = ::boost::move(*vp); d.release(); @@ -305,7 +302,7 @@ struct advanced_insert_aux_emplace aligned_storage::value> v; value_type *vp = static_cast(static_cast(&v)); alloc_traits::construct(this->a_, vp, - ::boost::container::container_detail::stored_ref::forward(get(this->args_))...); + ::boost::forward(get(this->args_))...); try { *p = ::boost::move(*vp); } catch (...) { @@ -413,7 +410,7 @@ struct BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) alloc_traits::construct(this->a_, vp \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_MEMBER_FORWARD, _)); \ scoped_destructor d(this->a_, vp); \ - *p = ::boost::move(*vp); \ + *p = ::boost::move(*vp); \ d.release(); \ this->used_ = true; \ } \ @@ -430,7 +427,7 @@ struct BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) alloc_traits::construct(this->a_, vp \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_MEMBER_FORWARD, _)); \ scoped_destructor d(this->a_, vp); \ - *p = ::boost::move(*vp); \ + *p = ::boost::move(*vp); \ d.release(); \ this->used_ = true; \ } \ diff --git a/include/boost/container/detail/algorithms.hpp b/include/boost/container/detail/algorithms.hpp index dc09575..824e44b 100644 --- a/include/boost/container/detail/algorithms.hpp +++ b/include/boost/container/detail/algorithms.hpp @@ -34,6 +34,30 @@ namespace boost { namespace container { +template +struct is_default_construct_iterator +{ + static const bool value = false; +}; + +template +struct is_default_construct_iterator > +{ + static const bool value = true; +}; + +template +struct is_emplace_iterator +{ + static const bool value = false; +}; + +template +struct is_emplace_iterator > +{ + static const bool value = true; +}; + template inline void construct_in_place(A &a, T* dest, InpIt source) { boost::container::allocator_traits::construct(a, dest, *source); } diff --git a/include/boost/container/detail/destroyers.hpp b/include/boost/container/detail/destroyers.hpp index d1b118c..befae3f 100644 --- a/include/boost/container/detail/destroyers.hpp +++ b/include/boost/container/detail/destroyers.hpp @@ -27,6 +27,68 @@ namespace boost { namespace container { namespace container_detail { +//!A deleter for scoped_ptr that deallocates the memory +//!allocated for an object using a STL allocator. +template +struct scoped_deallocator +{ + typedef allocator_traits allocator_traits_type; + typedef typename allocator_traits_type::pointer pointer; + typedef container_detail::integral_constant::value> alloc_version; + typedef container_detail::integral_constant allocator_v1; + typedef container_detail::integral_constant allocator_v2; + + private: + void priv_deallocate(allocator_v1) + { m_alloc.deallocate(m_ptr, 1); } + + void priv_deallocate(allocator_v2) + { m_alloc.deallocate_one(m_ptr); } + + BOOST_MOVABLE_BUT_NOT_COPYABLE(scoped_deallocator) + + public: + + pointer m_ptr; + A& m_alloc; + + scoped_deallocator(pointer p, A& a) + : m_ptr(p), m_alloc(a) + {} + + ~scoped_deallocator() + { if (m_ptr)priv_deallocate(alloc_version()); } + + scoped_deallocator(BOOST_RV_REF(scoped_deallocator) o) + : m_ptr(o.m_ptr), m_alloc(o.m_alloc) + { o.release(); } + + pointer get() const + { return m_ptr; } + + void release() + { m_ptr = 0; } +}; + +template +struct null_scoped_deallocator +{ + typedef boost::container::allocator_traits AllocTraits; + typedef typename AllocTraits::pointer pointer; + typedef typename AllocTraits::size_type size_type; + + null_scoped_deallocator(pointer, Allocator&, size_type) + {} + + void release() + {} + + pointer get() const + { return pointer(); } +}; + //!A deleter for scoped_ptr that deallocates the memory //!allocated for an array of objects using a STL allocator. template @@ -239,10 +301,57 @@ class allocator_destroyer void operator()(const pointer &p) { AllocTraits::destroy(a_, container_detail::to_raw_pointer(p)); - priv_deallocate(p, alloc_version()); + this->priv_deallocate(p, alloc_version()); } }; +template +class allocator_destroyer_and_chain_builder +{ + typedef allocator_traits allocator_traits_type; + typedef typename allocator_traits_type::value_type value_type; + typedef typename A::multiallocation_chain multiallocation_chain; + + A & a_; + multiallocation_chain &c_; + + public: + allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c) + : a_(a), c_(c) + {} + + void operator()(const typename A::pointer &p) + { + allocator_traits::destroy(a_, container_detail::to_raw_pointer(p)); + c_.push_front(p); + } +}; + +template +class allocator_multialloc_chain_node_deallocator +{ + typedef allocator_traits allocator_traits_type; + typedef typename allocator_traits_type::value_type value_type; + typedef typename A::multiallocation_chain multiallocation_chain; + typedef allocator_destroyer_and_chain_builder chain_builder; + + A & a_; + multiallocation_chain c_; + + public: + allocator_multialloc_chain_node_deallocator(A &a) + : a_(a), c_() + {} + + chain_builder get_chain_builder() + { return chain_builder(a_, c_); } + + ~allocator_multialloc_chain_node_deallocator() + { + if(!c_.empty()) + a_.deallocate_individual(boost::move(c_)); + } +}; } //namespace container_detail { } //namespace container { diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 23be0bf..55fac62 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -214,6 +214,21 @@ class flat_tree : m_data(comp, a) { this->m_data.m_vect.insert(this->m_data.m_vect.end(), first, last); } + template + flat_tree( bool unique_insertion + , InputIterator first, InputIterator last + , const Compare& comp = Compare() + , const allocator_type& a = allocator_type()) + : m_data(comp, a) + { + if(unique_insertion){ + this->insert_unique(first, last); + } + else{ + this->insert_equal(first, last); + } + } + ~flat_tree() { } @@ -290,9 +305,9 @@ class flat_tree std::pair insert_unique(const value_type& val) { insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(val, data); + std::pair ret = this->priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, val); + ret.first = this->priv_insert_commit(data, val); } return ret; } @@ -300,9 +315,9 @@ class flat_tree std::pair insert_unique(BOOST_RV_REF(value_type) val) { insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(val, data); + std::pair ret = this->priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, boost::move(val)); + ret.first = this->priv_insert_commit(data, boost::move(val)); } return ret; } @@ -324,9 +339,9 @@ class flat_tree iterator insert_unique(const_iterator pos, const value_type& val) { insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(pos, val, data); + std::pair ret = this->priv_insert_unique_prepare(pos, val, data); if(ret.second){ - ret.first = priv_insert_commit(data, val); + ret.first = this->priv_insert_commit(data, val); } return ret.first; } @@ -334,9 +349,9 @@ class flat_tree iterator insert_unique(const_iterator pos, BOOST_RV_REF(value_type) mval) { insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(pos, mval, data); + std::pair ret = this->priv_insert_unique_prepare(pos, mval, data); if(ret.second){ - ret.first = priv_insert_commit(data, boost::move(mval)); + ret.first = this->priv_insert_commit(data, boost::move(mval)); } return ret.first; } @@ -345,45 +360,164 @@ class flat_tree { insert_commit_data data; this->priv_insert_equal_prepare(pos, val, data); - return priv_insert_commit(data, val); + return this->priv_insert_commit(data, val); } iterator insert_equal(const_iterator pos, BOOST_RV_REF(value_type) mval) { insert_commit_data data; this->priv_insert_equal_prepare(pos, mval, data); - return priv_insert_commit(data, boost::move(mval)); + return this->priv_insert_commit(data, boost::move(mval)); } template void insert_unique(InIt first, InIt last) + { this->priv_insert_unique_loop(first, last); } + + template + void insert_equal(InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) + { this->priv_insert_equal_loop(first, last); } + + template + void insert_equal(InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { - for ( ; first != last; ++first) - this->insert_unique(*first); + const size_type len = static_cast(std::distance(first, last)); + this->reserve(this->size()+len); + this->priv_insert_equal_loop(first, last); + } + + //Ordered + + template + void insert_equal(ordered_range_t, InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) + { this->priv_insert_equal_loop_ordered(first, last); } + + template + void insert_equal(ordered_range_t, FwdIt first, FwdIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_forward_iterator::value + >::type * = 0 + #endif + ) + { + const size_type len = static_cast(std::distance(first, last)); + this->reserve(this->size()+len); + this->priv_insert_equal_loop_ordered(first, last); + } + + template + void insert_equal(ordered_range_t, BidirIt first, BidirIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_input_iterator::value && + !container_detail::is_forward_iterator::value + >::type * = 0 + #endif + ) + { + size_type len = static_cast(std::distance(first, last)); + const size_type BurstSize = 16; + size_type positions[BurstSize]; + + //Prereserve all memory so that iterators are not invalidated + this->reserve(this->size()+len); + const const_iterator beg(this->cbegin()); + const_iterator pos(beg); + //Loop in burst sizes + while(len){ + const size_type burst = len < BurstSize ? len : BurstSize; + const const_iterator cend(this->cend()); + len -= burst; + for(size_type i = 0; i != burst; ++i){ + //Get the insertion position for each key + pos = const_cast(*this).priv_upper_bound(pos, cend, KeyOfValue()(*first)); + positions[i] = static_cast(pos - beg); + ++first; + } + //Insert all in a single step in the precalculated positions + this->m_data.m_vect.insert_ordered_at(burst, positions + burst, first); + //Next search position updated + pos += burst; + } } template - void insert_equal(InIt first, InIt last) - { - typedef typename - std::iterator_traits::iterator_category ItCat; - this->priv_insert_equal(first, last, ItCat()); - } + void insert_unique(ordered_unique_range_t, InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator::value || + container_detail::is_forward_iterator::value + >::type * = 0 + #endif + ) + { this->priv_insert_unique_loop_hint(first, last); } - template - void insert_equal(ordered_range_t, InIt first, InIt last) + template + void insert_unique(ordered_unique_range_t, BidirIt first, BidirIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !(container_detail::is_input_iterator::value || + container_detail::is_forward_iterator::value) + >::type * = 0 + #endif + ) { - typedef typename - std::iterator_traits::iterator_category ItCat; - this->priv_insert_equal(ordered_range_t(), first, last, ItCat()); - } + size_type len = static_cast(std::distance(first, last)); + const size_type BurstSize = 16; + size_type positions[BurstSize]; + size_type skips[BurstSize]; - template - void insert_unique(ordered_unique_range_t, InIt first, InIt last) - { - typedef typename - std::iterator_traits::iterator_category ItCat; - this->priv_insert_unique(ordered_unique_range_t(), first, last, ItCat()); + //Prereserve all memory so that iterators are not invalidated + this->reserve(this->size()+len); + const const_iterator beg(this->cbegin()); + const_iterator pos(beg); + const value_compare &value_comp = this->m_data; + //Loop in burst sizes + while(len){ + skips[0u] = 0u; + const size_type burst = len < BurstSize ? len : BurstSize; + size_type unique_burst = 0u; + const const_iterator cend(this->cend()); + while(unique_burst < burst && len > 0){ + //Get the insertion position for each key + const value_type & val = *first++; + --len; + pos = const_cast(*this).priv_lower_bound(pos, cend, KeyOfValue()(val)); + //Check if already present + if(pos != cend && !value_comp(*pos, val)){ + ++skips[unique_burst]; + continue; + } + + //If not present, calculate position + positions[unique_burst] = static_cast(pos - beg); + if(++unique_burst < burst) + skips[unique_burst] = 0u; + } + //Insert all in a single step in the precalculated positions + this->m_data.m_vect.insert_ordered_at(unique_burst, positions + unique_burst, skips + unique_burst, first); + //Next search position updated + pos += unique_burst; + } } #ifdef BOOST_CONTAINER_PERFECT_FORWARDING @@ -398,9 +532,9 @@ class flat_tree value_destructor d(a, val); insert_commit_data data; std::pair ret = - priv_insert_unique_prepare(val, data); + this->priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, boost::move(val)); + ret.first = this->priv_insert_commit(data, boost::move(val)); } return ret; } @@ -414,9 +548,9 @@ class flat_tree stored_allocator_traits::construct(a, &val, ::boost::forward(args)... ); value_destructor d(a, val); insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(hint, val, data); + std::pair ret = this->priv_insert_unique_prepare(hint, val, data); if(ret.second){ - ret.first = priv_insert_commit(data, boost::move(val)); + ret.first = this->priv_insert_commit(data, boost::move(val)); } return ret.first; } @@ -444,7 +578,7 @@ class flat_tree value_destructor d(a, val); insert_commit_data data; this->priv_insert_equal_prepare(hint, val, data); - iterator i = priv_insert_commit(data, boost::move(val)); + iterator i = this->priv_insert_commit(data, boost::move(val)); return i; } @@ -462,9 +596,9 @@ class flat_tree BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ value_destructor d(a, val); \ insert_commit_data data; \ - std::pair ret = priv_insert_unique_prepare(val, data); \ + std::pair ret = this->priv_insert_unique_prepare(val, data); \ if(ret.second){ \ - ret.first = priv_insert_commit(data, boost::move(val)); \ + ret.first = this->priv_insert_commit(data, boost::move(val)); \ } \ return ret; \ } \ @@ -480,9 +614,9 @@ class flat_tree BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ value_destructor d(a, val); \ insert_commit_data data; \ - std::pair ret = priv_insert_unique_prepare(hint, val, data); \ + std::pair ret = this->priv_insert_unique_prepare(hint, val, data); \ if(ret.second){ \ - ret.first = priv_insert_commit(data, boost::move(val)); \ + ret.first = this->priv_insert_commit(data, boost::move(val)); \ } \ return ret.first; \ } \ @@ -513,7 +647,7 @@ class flat_tree value_destructor d(a, val); \ insert_commit_data data; \ this->priv_insert_equal_prepare(hint, val, data); \ - iterator i = priv_insert_commit(data, boost::move(val)); \ + iterator i = this->priv_insert_commit(data, boost::move(val)); \ return i; \ } \ @@ -653,7 +787,7 @@ class flat_tree std::pair priv_insert_unique_prepare (const value_type& val, insert_commit_data &commit_data) - { return priv_insert_unique_prepare(this->begin(), this->end(), val, commit_data); } + { return this->priv_insert_unique_prepare(this->begin(), this->end(), val, commit_data); } std::pair priv_insert_unique_prepare (const_iterator pos, const value_type& val, insert_commit_data &commit_data) @@ -794,102 +928,38 @@ class flat_tree return std::pair(first, first); } - template - void priv_insert_equal(ordered_range_t, BidirIt first, BidirIt last, std::bidirectional_iterator_tag) + template + void priv_insert_equal_loop(InIt first, InIt last) { - size_type len = static_cast(std::distance(first, last)); - const size_type BurstSize = 16; - size_type positions[BurstSize]; - - //Prereserve all memory so that iterators are not invalidated - this->reserve(this->size()+len); - const const_iterator beg(this->cbegin()); - const_iterator pos(beg); - //Loop in burst sizes - while(len){ - const size_type burst = len < BurstSize ? len : BurstSize; - const const_iterator cend(this->cend()); - len -= burst; - for(size_type i = 0; i != burst; ++i){ - //Get the insertion position for each key - pos = const_cast(*this).priv_upper_bound(pos, cend, KeyOfValue()(*first)); - positions[i] = static_cast(pos - beg); - ++first; - } - //Insert all in a single step in the precalculated positions - this->m_data.m_vect.insert_ordered_at(burst, positions + burst, first); - //Next search position updated - pos += burst; - } - } - - template - void priv_insert_unique(ordered_unique_range_t, BidirIt first, BidirIt last, std::bidirectional_iterator_tag) - { - size_type len = static_cast(std::distance(first, last)); - const size_type BurstSize = 16; - size_type positions[BurstSize]; - size_type skips[BurstSize]; - - //Prereserve all memory so that iterators are not invalidated - this->reserve(this->size()+len); - const const_iterator beg(this->cbegin()); - const_iterator pos(beg); - const value_compare &value_comp = this->m_data; - //Loop in burst sizes - while(len){ - skips[0u] = 0u; - const size_type burst = len < BurstSize ? len : BurstSize; - size_type unique_burst = 0u; - const const_iterator cend(this->cend()); - while(unique_burst < burst && len > 0){ - //Get the insertion position for each key - const value_type & val = *first++; - --len; - pos = const_cast(*this).priv_lower_bound(pos, cend, KeyOfValue()(val)); - //Check if already present - if(pos != cend && !value_comp(*pos, val)){ - ++skips[unique_burst]; - continue; - } - - //If not present, calculate position - positions[unique_burst] = static_cast(pos - beg); - if(++unique_burst < burst) - skips[unique_burst] = 0u; - } - //Insert all in a single step in the precalculated positions - this->m_data.m_vect.insert_ordered_at(unique_burst, positions + unique_burst, skips + unique_burst, first); - //Next search position updated - pos += unique_burst; - } - } -/* - template - void priv_insert_equal_forward(ordered_range_t, FwdIt first, FwdIt last, std::forward_iterator_tag) - { this->priv_insert_equal(first, last, std::forward_iterator_tag()); } -*/ - template - void priv_insert_equal(ordered_range_t, InIt first, InIt last, std::input_iterator_tag) - { this->priv_insert_equal(first, last, std::input_iterator_tag()); } - - template - void priv_insert_unique(ordered_unique_range_t, InIt first, InIt last, std::input_iterator_tag) - { this->priv_insert_unique(first, last, std::input_iterator_tag()); } -/* - template - void priv_insert_equal_forward(FwdIt first, FwdIt last, std::forward_iterator_tag) - { - const size_type len = static_cast(std::distance(first, last)); - this->reserve(this->size()+len); - this->priv_insert_equal(first, last, std::input_iterator_tag()); - } -*/ - template - void priv_insert_equal(InIt first, InIt last, std::input_iterator_tag) - { - for ( ; first != last; ++first) + for ( ; first != last; ++first){ this->insert_equal(*first); + } + } + + template + void priv_insert_equal_loop_ordered(InIt first, InIt last) + { + const_iterator pos(this->cend()); + for ( ; first != last; ++first){ + pos = this->insert_equal(pos, *first); + } + } + + template + void priv_insert_unique_loop(InIt first, InIt last) + { + for ( ; first != last; ++first){ + this->insert_unique(*first); + } + } + + template + void priv_insert_unique_loop_ordered(InIt first, InIt last) + { + const_iterator pos(this->cend()); + for ( ; first != last; ++first){ + pos = this->insert_unique(pos, *first); + } } }; diff --git a/include/boost/container/detail/iterators.hpp b/include/boost/container/detail/iterators.hpp index 374b55c..3e77931 100644 --- a/include/boost/container/detail/iterators.hpp +++ b/include/boost/container/detail/iterators.hpp @@ -22,10 +22,10 @@ #include #include #include +#include #ifdef BOOST_CONTAINER_PERFECT_FORWARDING #include -#include #else #include #endif @@ -222,14 +222,12 @@ class default_construct_iterator default_construct_iterator operator-(Difference off) const { return *this + (-off); } - const T& operator*() const - { return dereference(); } - - const T* operator->() const - { return &(dereference()); } - - const T& operator[] (Difference n) const - { return dereference(); } + //This pseudo-iterator's dereference operations have no sense since value is not + //constructed until ::boost::container::construct_in_place is called. + //So comment them to catch bad uses + //const T& operator*() const; + //const T& operator[](difference_type) const; + //const T* operator->() const; private: Difference m_num; @@ -445,14 +443,12 @@ class emplace_iterator this_type operator-(difference_type off) const { return *this + (-off); } - const T& operator*() const - { return dereference(); } - - const T& operator[](difference_type) const - { return dereference(); } - - const T* operator->() const - { return &(dereference()); } + //This pseudo-iterator's dereference operations have no sense since value is not + //constructed until ::boost::container::construct_in_place is called. + //So comment them to catch bad uses + //const T& operator*() const; + //const T& operator[](difference_type) const; + //const T* operator->() const; template void construct_in_place(A &a, T* ptr) @@ -506,8 +502,7 @@ struct emplace_functor void inplace_impl(A &a, T* ptr, const container_detail::index_tuple&) { allocator_traits::construct - (a, ptr, container_detail::stored_ref::forward - (container_detail::get(args_))...); + (a, ptr, ::boost::forward(container_detail::get(args_))...); } container_detail::tuple args_; @@ -539,10 +534,78 @@ struct emplace_functor #endif +namespace container_detail { + +template +struct has_iterator_category +{ + template + static char test(int, typename X::iterator_category*); + + template + static int test(int, ...); + + static const bool value = (1 == sizeof(test(0, 0))); +}; + + +template::value > +struct is_input_iterator +{ + static const bool value = is_same::value; +}; + +template +struct is_input_iterator +{ + static const bool value = false; +}; + +template::value > +struct is_forward_iterator +{ + static const bool value = is_same::value; +}; + +template +struct is_forward_iterator +{ + static const bool value = false; +}; + +template::value > +struct is_bidirectional_iterator +{ + static const bool value = is_same::value; +}; + +template +struct is_bidirectional_iterator +{ + static const bool value = false; +}; + +template +struct iiterator_types +{ + typedef typename std::iterator_traits::pointer it_pointer; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename ::boost::intrusive::pointer_traits:: + template rebind_pointer::type pointer; + typedef typename ::boost::intrusive::pointer_traits:: + template rebind_pointer::type const_pointer; + typedef typename ::boost::intrusive:: + pointer_traits::reference reference; + typedef typename ::boost::intrusive:: + pointer_traits::reference const_reference; +}; + + +} //namespace container_detail { + } //namespace container { } //namespace boost { #include #endif //#ifndef BOOST_CONTAINER_DETAIL_ITERATORS_HPP - diff --git a/include/boost/container/detail/multiallocation_chain.hpp b/include/boost/container/detail/multiallocation_chain.hpp index c995253..98d0924 100644 --- a/include/boost/container/detail/multiallocation_chain.hpp +++ b/include/boost/container/detail/multiallocation_chain.hpp @@ -45,14 +45,30 @@ class basic_multiallocation_chain > slist_impl_t; slist_impl_t slist_impl_; - static node & to_node(VoidPointer p) - { return *static_cast(static_cast(container_detail::to_raw_pointer(p))); } + typedef typename boost::intrusive::pointer_traits + ::template rebind_pointer::type node_ptr; + typedef typename boost::intrusive:: + pointer_traits node_ptr_traits; + + static node & build_node(const VoidPointer &p) + { + return *::new (static_cast(static_cast(container_detail::to_raw_pointer(p)))) node; + } + + static VoidPointer destroy_node(node &n) + { + VoidPointer retptr = node_ptr_traits::pointer_to(n); + n.~node(); + return retptr; + } + + static node_ptr to_node_ptr(VoidPointer p) + { return node_ptr_traits::static_cast_from(p); } BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_multiallocation_chain) public: - typedef VoidPointer void_pointer; typedef typename slist_impl_t::iterator iterator; typedef typename slist_impl_t::size_type size_type; @@ -94,19 +110,21 @@ class basic_multiallocation_chain { slist_impl_.clear(); } iterator insert_after(iterator it, void_pointer m) - { return slist_impl_.insert_after(it, to_node(m)); } + { return slist_impl_.insert_after(it, build_node(m)); } void push_front(void_pointer m) - { return slist_impl_.push_front(to_node(m)); } + { return slist_impl_.push_front(build_node(m)); } void push_back(void_pointer m) - { return slist_impl_.push_back(to_node(m)); } + { return slist_impl_.push_back(build_node(m)); } - void pop_front() - { return slist_impl_.pop_front(); } - - void *front() - { return &*slist_impl_.begin(); } + void_pointer pop_front() + { + node & n = slist_impl_.front(); + void_pointer ret = destroy_node(n); + slist_impl_.pop_front(); + return ret; + } void splice_after(iterator after_this, basic_multiallocation_chain &x, iterator before_begin, iterator before_end) { slist_impl_.splice_after(after_this, x.slist_impl_, before_begin, before_end); } @@ -118,10 +136,12 @@ class basic_multiallocation_chain { slist_impl_.splice_after(after_this, x.slist_impl_); } void incorporate_after(iterator after_this, void_pointer begin , iterator before_end) - { slist_impl_.incorporate_after(after_this, &to_node(begin), &to_node(before_end)); } + { + slist_impl_.incorporate_after(after_this, to_node_ptr(begin), to_node_ptr(before_end)); + } void incorporate_after(iterator after_this, void_pointer begin, void_pointer before_end, size_type n) - { slist_impl_.incorporate_after(after_this, &to_node(begin), &to_node(before_end), n); } + { slist_impl_.incorporate_after(after_this, to_node_ptr(begin), to_node_ptr(before_end), n); } void swap(basic_multiallocation_chain &x) { slist_impl_.swap(x.slist_impl_); } @@ -157,18 +177,20 @@ class transform_multiallocation_chain MultiallocationChain holder_; typedef typename MultiallocationChain::void_pointer void_pointer; typedef typename boost::intrusive::pointer_traits - ::template rebind_pointer::type pointer; + void_pointer_traits; + typedef typename void_pointer_traits::template + rebind_pointer::type pointer; + typedef typename boost::intrusive::pointer_traits + pointer_traits; - static pointer cast(void_pointer p) - { - return pointer(static_cast(container_detail::to_raw_pointer(p))); - } + static pointer cast(const void_pointer &p) + { return pointer_traits::static_cast_from(p); } public: typedef transform_iterator < typename MultiallocationChain::iterator - , container_detail::cast_functor > iterator; - typedef typename MultiallocationChain::size_type size_type; + , container_detail::cast_functor > iterator; + typedef typename MultiallocationChain::size_type size_type; transform_multiallocation_chain() : holder_() @@ -198,14 +220,11 @@ class transform_multiallocation_chain void splice_after(iterator after_this, transform_multiallocation_chain &x, iterator before_begin, iterator before_end, size_type n) { holder_.splice_after(after_this.base(), x.holder_, before_begin.base(), before_end.base(), n); } - void incorporate_after(iterator after_this, void_pointer begin, void_pointer before_end, size_type n) + void incorporate_after(iterator after_this, pointer begin, pointer before_end, size_type n) { holder_.incorporate_after(after_this.base(), begin, before_end, n); } - void pop_front() - { holder_.pop_front(); } - - pointer front() - { return cast(holder_.front()); } + pointer pop_front() + { return cast(holder_.pop_front()); } bool empty() const { return holder_.empty(); } @@ -234,8 +253,11 @@ class transform_multiallocation_chain static iterator iterator_to(pointer p) { return iterator(MultiallocationChain::iterator_to(p)); } - std::pair extract_data() - { return holder_.extract_data(); } + std::pair extract_data() + { + std::pair data(holder_.extract_data()); + return std::pair(cast(data.first), cast(data.second)); + } MultiallocationChain extract_multiallocation_chain() { diff --git a/include/boost/container/detail/node_alloc_holder.hpp b/include/boost/container/detail/node_alloc_holder.hpp index 9797f1f..68048bc 100644 --- a/include/boost/container/detail/node_alloc_holder.hpp +++ b/include/boost/container/detail/node_alloc_holder.hpp @@ -43,99 +43,6 @@ namespace boost { namespace container { namespace container_detail { -//!A deleter for scoped_ptr that deallocates the memory -//!allocated for an object using a STL allocator. -template -struct scoped_deallocator -{ - typedef allocator_traits allocator_traits_type; - typedef typename allocator_traits_type::pointer pointer; - typedef container_detail::integral_constant::value> alloc_version; - typedef container_detail::integral_constant allocator_v1; - typedef container_detail::integral_constant allocator_v2; - - private: - void priv_deallocate(allocator_v1) - { m_alloc.deallocate(m_ptr, 1); } - - void priv_deallocate(allocator_v2) - { m_alloc.deallocate_one(m_ptr); } - - BOOST_MOVABLE_BUT_NOT_COPYABLE(scoped_deallocator) - - public: - - pointer m_ptr; - A& m_alloc; - - scoped_deallocator(pointer p, A& a) - : m_ptr(p), m_alloc(a) - {} - - ~scoped_deallocator() - { if (m_ptr)priv_deallocate(alloc_version()); } - - scoped_deallocator(BOOST_RV_REF(scoped_deallocator) o) - : m_ptr(o.m_ptr), m_alloc(o.m_alloc) - { o.release(); } - - pointer get() const - { return m_ptr; } - - void release() - { m_ptr = 0; } -}; - -template -class allocator_destroyer_and_chain_builder -{ - typedef allocator_traits allocator_traits_type; - typedef typename allocator_traits_type::value_type value_type; - typedef typename A::multiallocation_chain multiallocation_chain; - - A & a_; - multiallocation_chain &c_; - - public: - allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c) - : a_(a), c_(c) - {} - - void operator()(const typename A::pointer &p) - { - allocator_traits::destroy(a_, container_detail::to_raw_pointer(p)); - c_.push_front(p); - } -}; - -template -class allocator_multialloc_chain_node_deallocator -{ - typedef allocator_traits allocator_traits_type; - typedef typename allocator_traits_type::value_type value_type; - typedef typename A::multiallocation_chain multiallocation_chain; - typedef allocator_destroyer_and_chain_builder chain_builder; - - A & a_; - multiallocation_chain c_; - - public: - allocator_multialloc_chain_node_deallocator(A &a) - : a_(a), c_() - {} - - chain_builder get_chain_builder() - { return chain_builder(a_, c_); } - - ~allocator_multialloc_chain_node_deallocator() - { - if(!c_.empty()) - a_.deallocate_individual(boost::move(c_)); - } -}; - template struct node_compare : private ValueCompare @@ -340,8 +247,7 @@ struct node_alloc_holder Node *p = 0; BOOST_TRY{ for(difference_type i = 0; i < n; ++i, ++beg, --constructed){ - p = container_detail::to_raw_pointer(mem.front()); - mem.pop_front(); + p = container_detail::to_raw_pointer(mem.pop_front()); //This can throw constructed = 0; boost::container::construct_in_place(this->node_alloc(), container_detail::addressof(p->m_data), beg); diff --git a/include/boost/container/detail/preprocessor.hpp b/include/boost/container/detail/preprocessor.hpp index 1818094..5129ea1 100644 --- a/include/boost/container/detail/preprocessor.hpp +++ b/include/boost/container/detail/preprocessor.hpp @@ -16,11 +16,6 @@ #endif #include - -#ifndef BOOST_NO_RVALUE_REFERENCES -#include -#endif //#ifndef BOOST_NO_RVALUE_REFERENCES - #include #ifdef BOOST_CONTAINER_PERFECT_FORWARDING @@ -78,19 +73,10 @@ const BOOST_PP_CAT(Q, n) & BOOST_PP_CAT(q, n) \ #ifndef BOOST_NO_RVALUE_REFERENCES - #if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) - - #define BOOST_CONTAINER_PP_PARAM_INIT(z, n, data) \ - BOOST_PP_CAT(m_p, n) (static_cast( BOOST_PP_CAT(p, n) )) \ - - #else //#if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) - #define BOOST_CONTAINER_PP_PARAM_INIT(z, n, data) \ BOOST_PP_CAT(m_p, n) (::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) )) \ //! - #endif //BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - #else //BOOST_NO_RVALUE_REFERENCES #define BOOST_CONTAINER_PP_PARAM_INIT(z, n, data) \ @@ -102,8 +88,68 @@ const BOOST_PP_CAT(Q, n) & BOOST_PP_CAT(q, n) \ #if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) + namespace boost { + namespace container { + namespace container_detail { + template + struct ref_holder; + + template + struct ref_holder + { + ref_holder(T &t) + : t_(t) + {} + T &t_; + T & get() { return t_; } + }; + + template + struct ref_holder + { + ref_holder(const T &t) + : t_(t) + {} + const T &t_; + const T & get() { return t_; } + }; + + template + struct ref_holder + { + ref_holder(const T &t) + : t_(t) + {} + const T &t_; + const T & get() { return t_; } + }; + + template + struct ref_holder + { + ref_holder(T &&t) + : t_(t) + {} + T &t_; + T && get() { return ::boost::move(t_); } + }; + + template + struct ref_holder + { + ref_holder(T &&t) + : t(t) + {} + T &t; + T && get() { return ::boost::move(t_); } + }; + + } //namespace container_detail { + } //namespace container { + } //namespace boost { + #define BOOST_CONTAINER_PP_PARAM_DEFINE(z, n, data) \ - BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \ + ::boost::container::container_detail::ref_holder BOOST_PP_CAT(m_p, n); \ //! #else //BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG @@ -123,8 +169,7 @@ const BOOST_PP_CAT(Q, n) & BOOST_PP_CAT(q, n) \ #if !defined(BOOST_NO_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) - #define BOOST_CONTAINER_PP_MEMBER_FORWARD(z, n, data) \ - ::boost::container::container_detail::stored_ref< BOOST_PP_CAT(P, n) >::forward( BOOST_PP_CAT(this->m_p, n) ) \ + #define BOOST_CONTAINER_PP_MEMBER_FORWARD(z, n, data) BOOST_PP_CAT(this->m_p, n).get() \ //! #else //!defined(BOOST_NO_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) diff --git a/include/boost/container/detail/stored_ref.hpp b/include/boost/container/detail/stored_ref.hpp deleted file mode 100644 index 80fda89..0000000 --- a/include/boost/container/detail/stored_ref.hpp +++ /dev/null @@ -1,92 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost -// Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// See http://www.boost.org/libs/container for documentation. -// -////////////////////////////////////////////////////////////////////////////// - -#ifndef BOOST_CONTAINER_DETAIL_STORED_REF_HPP -#define BOOST_CONTAINER_DETAIL_STORED_REF_HPP - -#include "config_begin.hpp" -#include - -#ifndef BOOST_NO_RVALUE_REFERENCES - -namespace boost{ -namespace container{ -namespace container_detail{ - -template -struct stored_ref -{ - - static T && forward(T &t) - #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - { return t; } - #else - { return boost::move(t); } - #endif -}; - -template -struct stored_ref -{ - static const T && forward(const T &t) - #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - { return t; } - #else - { return static_cast(t); } - #endif -}; - -template -struct stored_ref -{ - static T && forward(T &t) - #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - { return t; } - #else - { return boost::move(t); } - #endif -}; - -template -struct stored_ref -{ - static const T && forward(const T &t) - #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - { return t; } - #else - { return static_cast(t); } - #endif -}; - -template -struct stored_ref -{ - static const T & forward(const T &t) - { return t; } -}; - -template -struct stored_ref -{ - static T & forward(T &t) - { return t; } -}; - -} //namespace container_detail{ -} //namespace container{ -} //namespace boost{ - -#else -#error "This header can be included only for compiler with rvalue references" -#endif //BOOST_NO_RVALUE_REFERENCES - -#include - -#endif //BOOST_CONTAINER_DETAIL_STORED_REF_HPP diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index 3ab1536..96db26f 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -476,21 +476,77 @@ class rbtree {} template - rbtree(InputIterator first, InputIterator last, const key_compare& comp, - const allocator_type& a, bool unique_insertion) + rbtree(bool unique_insertion, InputIterator first, InputIterator last, const key_compare& comp, + const allocator_type& a + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator::value + || container_detail::is_same::value + >::type * = 0 + #endif + ) : AllocHolder(a, comp) { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_nodes(first, last, unique_insertion, alloc_version(), ItCat()); + if(unique_insertion){ + this->insert_unique(first, last); + } + else{ + this->insert_equal(first, last); + } + } + + template + rbtree(bool unique_insertion, InputIterator first, InputIterator last, const key_compare& comp, + const allocator_type& a + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !(container_detail::is_input_iterator::value + || container_detail::is_same::value) + >::type * = 0 + #endif + ) + : AllocHolder(a, comp) + { + if(unique_insertion){ + this->insert_unique(first, last); + } + else{ + //Optimized allocation and construction + this->allocate_many_and_construct + (first, std::distance(first, last), insert_equal_end_hint_functor(this->icont())); + } } template rbtree( ordered_range_t, InputIterator first, InputIterator last - , const key_compare& comp = key_compare(), const allocator_type& a = allocator_type()) + , const key_compare& comp = key_compare(), const allocator_type& a = allocator_type() + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator::value + || container_detail::is_same::value + >::type * = 0 + #endif + ) : AllocHolder(a, comp) { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_ordered_nodes(first, last, alloc_version(), ItCat()); + this->insert_equal(first, last); + } + + template + rbtree( ordered_range_t, InputIterator first, InputIterator last + , const key_compare& comp = key_compare(), const allocator_type& a = allocator_type() + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !(container_detail::is_input_iterator::value + || container_detail::is_same::value) + >::type * = 0 + #endif + ) + : AllocHolder(a, comp) + { + //Optimized allocation and construction + this->allocate_many_and_construct + (first, std::distance(first, last), push_back_functor(this->icont())); } rbtree(const rbtree& x) @@ -943,14 +999,14 @@ class rbtree { return const_iterator(this->non_const_icont().upper_bound(k, KeyNodeCompare(value_comp()))); } std::pair equal_range(const key_type& k) - { + { std::pair ret = this->icont().equal_range(k, KeyNodeCompare(value_comp())); return std::pair(iterator(ret.first), iterator(ret.second)); } std::pair equal_range(const key_type& k) const - { + { std::pair ret = this->non_const_icont().equal_range(k, KeyNodeCompare(value_comp())); return std::pair @@ -958,108 +1014,39 @@ class rbtree } private: - //Iterator range version - template - void priv_create_and_insert_nodes - (InpIterator beg, InpIterator end, bool unique, allocator_v1, std::input_iterator_tag) - { - if(unique){ - for (; beg != end; ++beg){ - this->insert_unique(*beg); - } - } - else{ - for (; beg != end; ++beg){ - this->insert_equal(*beg); - } - } - } - template - void priv_create_and_insert_nodes - (InpIterator beg, InpIterator end, bool unique, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_nodes(beg, end, unique, allocator_v1(), std::input_iterator_tag()); - } + class insert_equal_end_hint_functor; + friend class insert_equal_end_hint_functor; - class insertion_functor; - friend class insertion_functor; - - class insertion_functor + class insert_equal_end_hint_functor { Icont &icont_; + const iconst_iterator cend_; public: - insertion_functor(Icont &icont) - : icont_(icont) + insert_equal_end_hint_functor(Icont &icont) + : icont_(icont), cend_(this->icont_.cend()) {} void operator()(Node &n) - { this->icont_.insert_equal(this->icont_.cend(), n); } + { this->icont_.insert_equal(cend_, n); } }; + class push_back_functor; + friend class push_back_functor; - template - void priv_create_and_insert_nodes - (FwdIterator beg, FwdIterator end, bool unique, allocator_v2, std::forward_iterator_tag) - { - if(beg != end){ - if(unique){ - priv_create_and_insert_nodes(beg, end, unique, allocator_v2(), std::input_iterator_tag()); - } - else{ - //Optimized allocation and construction - this->allocate_many_and_construct - (beg, std::distance(beg, end), insertion_functor(this->icont())); - } - } - } - - //Iterator range version - template - void priv_create_and_insert_ordered_nodes - (InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) - { - const_iterator cend_n(this->cend()); - for (; beg != end; ++beg){ - this->insert_before(cend_n, *beg); - } - } - - template - void priv_create_and_insert_ordered_nodes - (InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_ordered_nodes(beg, end, allocator_v1(), std::input_iterator_tag()); - } - - class back_insertion_functor; - friend class back_insertion_functor; - - class back_insertion_functor + class push_back_functor { Icont &icont_; public: - back_insertion_functor(Icont &icont) + push_back_functor(Icont &icont) : icont_(icont) {} void operator()(Node &n) { this->icont_.push_back(n); } }; - - - template - void priv_create_and_insert_ordered_nodes - (FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) - { - if(beg != end){ - //Optimized allocation and construction - this->allocate_many_and_construct - (beg, std::distance(beg, end), back_insertion_functor(this->icont())); - } - } }; template #endif //#ifndef BOOST_CONTAINER_DETAIL_WORKAROUND_HPP diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index 0142500..27f1074 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -39,11 +39,7 @@ namespace container { /// @cond // Forward declarations of operators == and <, needed for friend declarations. -#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template >, class A = std::allocator > -#else template -#endif class flat_map; template @@ -94,7 +90,7 @@ static D force_copy(S s) //! Erasing an element of a flat_map invalidates iterators and references //! pointing to elements that come after (their keys are bigger) the erased element. #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template >, class A = std::allocator > +template , class A = std::allocator< std::pair< Key, T> > > #else template #endif @@ -194,8 +190,8 @@ class flat_map template flat_map(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_flat_tree(comp, container_detail::force(a)) - { m_flat_tree.insert_unique(first, last); } + : m_flat_tree(true, first, last, comp, container_detail::force(a)) + {} //! Effects: Constructs an empty flat_map using the specified comparison object and //! allocator, and inserts elements from the ordered unique range [first ,last). This function @@ -870,11 +866,7 @@ struct has_trivial_destructor_after_move namespace container { // Forward declaration of operators < and ==, needed for friend declaration. -#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template >, class A = std::allocator > -#else template -#endif class flat_multimap; template @@ -901,7 +893,7 @@ inline bool operator<(const flat_multimap& x, //! A is the allocator to allocate the value_types //! (e.g. allocator< std::pair >). #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template >, class A = std::allocator > +template , class A = std::allocator< std::pair< Key, T> > > #else template #endif @@ -996,8 +988,8 @@ class flat_multimap flat_multimap(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_flat_tree(comp, container_detail::force(a)) - { m_flat_tree.insert_equal(first, last); } + : m_flat_tree(false, first, last, comp, container_detail::force(a)) + {} //! Effects: Constructs an empty flat_multimap using the specified comparison object and //! allocator, and inserts elements from the ordered range [first ,last). This function diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 09c95eb..513d487 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -125,8 +125,8 @@ class flat_set flat_set(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) - { m_flat_tree.insert_unique(first, last); } + : m_flat_tree(true, first, last, comp, a) + {} //! Effects: Constructs an empty flat_set using the specified comparison object and //! allocator, and inserts elements from the ordered unique range [first ,last). This function @@ -777,8 +777,8 @@ class flat_multiset flat_multiset(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) - { m_flat_tree.insert_equal(first, last); } + : m_flat_tree(false, first, last, comp, a) + {} //! Effects: Constructs an empty flat_multiset using the specified comparison object and //! allocator, and inserts elements from the ordered range [first ,last ). This function diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index c3e3562..8f196d1 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -94,6 +94,111 @@ struct intrusive_list_type typedef container_type type ; }; +template +class list_const_iterator + : public std::iterator< std::bidirectional_iterator_tag, T + , typename iiterator_types::difference_type + , typename iiterator_types::const_pointer + , typename iiterator_types::const_reference> +{ + protected: + + IIterator m_it; + + public: + typedef typename iiterator_types::const_pointer const_pointer; + typedef typename iiterator_types::const_reference const_reference; + + //Constructors + list_const_iterator() + : m_it() + {} + + explicit list_const_iterator(const IIterator &it) + : m_it(it) + {} + + //Pointer like operators + const_reference operator*() const + { return this->m_it->m_data; } + + const_pointer operator->() const + { return ::boost::intrusive::pointer_traits::to_pointer(this->m_it->m_data); } + + //Increment / Decrement + list_const_iterator& operator++() + { ++this->m_it; return *this; } + + list_const_iterator operator++(int) + { IIterator tmp = this->m_it; ++*this; return list_const_iterator(tmp); } + + list_const_iterator& operator--() + { --this->m_it; return *this; } + + list_const_iterator operator--(int) + { IIterator tmp = this->m_it; --*this; return list_const_iterator(tmp); } + + //Comparison operators + friend bool operator== (const list_const_iterator& l, const list_const_iterator& r) + { return l.m_it == r.m_it; } + + friend bool operator!= (const list_const_iterator& l, const list_const_iterator& r) + { return l.m_it != r.m_it; } + + IIterator &get() + { return this->m_it; } + + const IIterator &get() const + { return this->m_it; } +}; + +template +class list_iterator + : public list_const_iterator +{ + private: + typedef list_const_iterator const_iterator; + + public: + typedef typename iiterator_types::pointer pointer; + typedef typename iiterator_types::reference reference; + + //Constructors + list_iterator() + : const_iterator() + {} + + explicit list_iterator(const IIterator &it) + : const_iterator(it) + {} + + //Pointer like operators + reference operator*() const + { return this->m_it->m_data; } + + pointer operator->() const + { return ::boost::intrusive::pointer_traits::pointer_to(this->m_it->m_data); } + + //Increment / Decrement + list_iterator& operator++() + { ++this->m_it; return *this; } + + list_iterator operator++(int) + { IIterator tmp = this->m_it; ++*this; return list_iterator(tmp); } + + list_iterator& operator--() + { --this->m_it; return *this; } + + list_iterator operator--(int) + { IIterator tmp = this->m_it; --*this; return list_iterator(tmp); } + + IIterator &get() + { return this->m_it; } + + const IIterator &get() const + { return this->m_it; } +}; + } //namespace container_detail { /// @endcond @@ -119,7 +224,6 @@ class list /// @cond typedef typename container_detail::intrusive_list_type::type Icont; - typedef list ThisType; typedef container_detail::node_alloc_holder AllocHolder; typedef typename AllocHolder::NodePtr NodePtr; typedef typename AllocHolder::NodeAlloc NodeAlloc; @@ -159,141 +263,39 @@ class list bool operator()(const Node &a) const { return static_cast(*this)(a.m_data); } }; - /// @endcond - public: - //! The type of object, T, stored in the list - typedef T value_type; - //! Pointer to T - typedef typename allocator_traits_type::pointer pointer; - //! Const pointer to T - typedef typename allocator_traits_type::const_pointer const_pointer; - //! Reference to T - typedef typename allocator_traits_type::reference reference; - //! Const reference to T - typedef typename allocator_traits_type::const_reference const_reference; - //! An unsigned integral type - typedef typename allocator_traits_type::size_type size_type; - //! A signed integral type - typedef typename allocator_traits_type::difference_type difference_type; - //! The allocator type - typedef A allocator_type; - //! Non-standard extension: the stored allocator type - typedef NodeAlloc stored_allocator_type; - - /// @cond - private: BOOST_COPYABLE_AND_MOVABLE(list) - typedef difference_type list_difference_type; - typedef pointer list_pointer; - typedef const_pointer list_const_pointer; - typedef reference list_reference; - typedef const_reference list_const_reference; + + typedef container_detail::list_iterator iterator_impl; + typedef container_detail::list_const_iteratorconst_iterator_impl; /// @endcond public: - //! Const iterator used to iterate through a list. - class const_iterator - /// @cond - : public std::iterator - { + ////////////////////////////////////////////// + // + // types + // + ////////////////////////////////////////////// - protected: - typename Icont::iterator m_it; - explicit const_iterator(typename Icont::iterator it) : m_it(it){} - void prot_incr() { ++m_it; } - void prot_decr() { --m_it; } + typedef T value_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + typedef typename ::boost::container::allocator_traits::const_pointer const_pointer; + typedef typename ::boost::container::allocator_traits::reference reference; + typedef typename ::boost::container::allocator_traits::const_reference const_reference; + typedef typename ::boost::container::allocator_traits::size_type size_type; + typedef typename ::boost::container::allocator_traits::difference_type difference_type; + typedef A allocator_type; + typedef BOOST_CONTAINER_IMPDEF(NodeAlloc) stored_allocator_type; + typedef BOOST_CONTAINER_IMPDEF(iterator_impl) iterator; + typedef BOOST_CONTAINER_IMPDEF(const_iterator_impl) const_iterator; + typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator) reverse_iterator; + typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator) const_reverse_iterator; - private: - typename Icont::iterator get() - { return this->m_it; } - - public: - friend class list; - typedef list_difference_type difference_type; - - //Constructors - const_iterator() - : m_it() - {} - - //Pointer like operators - const_reference operator*() const - { return m_it->m_data; } - - const_pointer operator->() const - { return const_pointer(&m_it->m_data); } - - //Increment / Decrement - const_iterator& operator++() - { prot_incr(); return *this; } - - const_iterator operator++(int) - { typename Icont::iterator tmp = m_it; ++*this; return const_iterator(tmp); } - - const_iterator& operator--() - { prot_decr(); return *this; } - - const_iterator operator--(int) - { typename Icont::iterator tmp = m_it; --*this; return const_iterator(tmp); } - - //Comparison operators - bool operator== (const const_iterator& r) const - { return m_it == r.m_it; } - - bool operator!= (const const_iterator& r) const - { return m_it != r.m_it; } - } - /// @endcond - ; - - //! Iterator used to iterate through a list - class iterator - /// @cond - : public const_iterator - { - - private: - explicit iterator(typename Icont::iterator it) - : const_iterator(it) - {} - - typename Icont::iterator get() - { return this->m_it; } - - public: - friend class list; - typedef list_pointer pointer; - typedef list_reference reference; - - //Constructors - iterator(){} - - //Pointer like operators - reference operator*() const { return this->m_it->m_data; } - pointer operator->() const { return pointer(&this->m_it->m_data); } - - //Increment / Decrement - iterator& operator++() - { this->prot_incr(); return *this; } - - iterator operator++(int) - { typename Icont::iterator tmp = this->m_it; ++*this; return iterator(tmp); } - - iterator& operator--() - { this->prot_decr(); return *this; } - - iterator operator--(int) - { iterator tmp = *this; --*this; return tmp; } - }; - /// @endcond - - //! Iterator used to iterate backwards through a list. - typedef std::reverse_iterator reverse_iterator; - //! Const iterator used to iterate backwards through a list. - typedef std::reverse_iterator const_reverse_iterator; + ////////////////////////////////////////////// + // + // construct/copy/destroy + // + ////////////////////////////////////////////// //! Effects: Default constructs a list. //! @@ -404,6 +406,98 @@ class list ~list() {} //AllocHolder clears the list + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + list& operator=(BOOST_COPY_ASSIGN_REF(list) x) + { + if (&x != this){ + NodeAlloc &this_alloc = this->node_alloc(); + const NodeAlloc &x_alloc = x.node_alloc(); + container_detail::bool_ flag; + if(flag && this_alloc != x_alloc){ + this->clear(); + } + this->AllocHolder::copy_assign_alloc(x); + this->assign(x.begin(), x.end()); + } + return *this; + } + + //! Effects: Move assignment. All mx's values are transferred to *this. + //! + //! Postcondition: x.empty(). *this contains a the elements x had + //! before the function. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + list& operator=(BOOST_RV_REF(list) x) + { + if (&x != this){ + NodeAlloc &this_alloc = this->node_alloc(); + NodeAlloc &x_alloc = x.node_alloc(); + //If allocators are equal we can just swap pointers + if(this_alloc == x_alloc){ + //Destroy and swap pointers + this->clear(); + this->icont() = boost::move(x.icont()); + //Move allocator if needed + this->AllocHolder::move_assign_alloc(x); + } + //If unequal allocators, then do a one by one move + else{ + typedef typename std::iterator_traits::iterator_category ItCat; + this->assign( boost::make_move_iterator(x.begin()) + , boost::make_move_iterator(x.end())); + } + } + return *this; + } + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void assign(size_type n, const T& val) + { + typedef constant_iterator cvalue_iterator; + return this->assign(cvalue_iterator(val, n), cvalue_iterator()); + } + + //! Effects: Assigns the the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing InpIt throws. + //! + //! Complexity: Linear to n. + template + void assign(InpIt first, InpIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + >::type * = 0 + #endif + ) + { + iterator first1 = this->begin(); + const iterator last1 = this->end(); + for ( ; first1 != last1 && first != last; ++first1, ++first) + *first1 = *first; + if (first == last) + this->erase(first1, last1); + else{ + this->insert(last1, first, last); + } + } + //! Effects: Returns a copy of the internal allocator. //! //! Throws: If allocator's copy constructor throws. @@ -412,19 +506,27 @@ class list allocator_type get_allocator() const { return allocator_type(this->node_alloc()); } + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. const stored_allocator_type &get_stored_allocator() const { return this->node_alloc(); } + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. stored_allocator_type &get_stored_allocator() { return this->node_alloc(); } - //! Effects: Erases all the elements of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements in the list. - void clear() - { AllocHolder::clear(alloc_version()); } + ////////////////////////////////////////////// + // + // iterators + // + ////////////////////////////////////////////// //! Effects: Returns an iterator to the first element contained in the list. //! @@ -528,6 +630,12 @@ class list const_reverse_iterator crend() const { return const_reverse_iterator(this->cbegin()); } + ////////////////////////////////////////////// + // + // capacity + // + ////////////////////////////////////////////// + //! Effects: Returns true if the list contains no elements. //! //! Throws: Nothing. @@ -552,61 +660,38 @@ class list size_type max_size() const { return AllocHolder::max_size(); } - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //! Effects: Inserts a copy of x at the beginning of the list. + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. + //! Throws: If memory allocation throws, or T's copy constructor throws. //! - //! Complexity: Amortized constant time. - void push_front(const T &x); + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size) + { + if(!priv_try_shrink(new_size)){ + typedef default_construct_iterator default_iterator; + this->insert(this->cend(), default_iterator(new_size - this->size()), default_iterator()); + } + } - //! Effects: Constructs a new element in the beginning of the list - //! and moves the resources of mx to this new element. + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. //! - //! Throws: If memory allocation throws. + //! Throws: If memory allocation throws, or T's copy constructor throws. //! - //! Complexity: Amortized constant time. - void push_front(T &&x); - #else - BOOST_MOVE_CONVERSION_AWARE_CATCH(push_front, T, void, priv_push_front) - #endif + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size, const T& x) + { + if(!priv_try_shrink(new_size)){ + this->insert(this->cend(), new_size - this->size(), x); + } + } - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //! Effects: Inserts a copy of x at the end of the list. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_back(const T &x); - - //! Effects: Constructs a new element in the end of the list - //! and moves the resources of mx to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - void push_back(T &&x); - #else - BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) - #endif - - //! Effects: Removes the first element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void pop_front() - { this->erase(this->cbegin()); } - - //! Effects: Removes the last element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void pop_back() - { const_iterator tmp = this->cend(); this->erase(--tmp); } + ////////////////////////////////////////////// + // + // element access + // + ////////////////////////////////////////////// //! Requires: !empty() //! @@ -652,173 +737,11 @@ class list const_reference back() const { return *(--this->end()); } - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size, const T& x) - { - const_iterator iend = this->cend(); - size_type len = this->size(); - - if(len > new_size){ - size_type to_erase = len - new_size; - while(to_erase--){ - --iend; - } - this->erase(iend, this->cend()); - } - else{ - this->priv_create_and_insert_nodes(iend, new_size - len, x); - } - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size) - { - const_iterator iend = this->end(); - size_type len = this->size(); - - if(len > new_size){ - size_type to_erase = len - new_size; - const_iterator ifirst; - if(to_erase < len/2u){ - ifirst = iend; - while(to_erase--){ - --ifirst; - } - } - else{ - ifirst = this->begin(); - size_type to_skip = len - to_erase; - while(to_skip--){ - ++ifirst; - } - } - this->erase(ifirst, iend); - } - else{ - this->priv_create_and_insert_nodes(this->cend(), new_size - len); - } - } - - //! Effects: Swaps the contents of *this and x. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - void swap(ThisType& x) - { AllocHolder::swap(x); } - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - ThisType& operator=(BOOST_COPY_ASSIGN_REF(ThisType) x) - { - if (&x != this){ - NodeAlloc &this_alloc = this->node_alloc(); - const NodeAlloc &x_alloc = x.node_alloc(); - container_detail::bool_ flag; - if(flag && this_alloc != x_alloc){ - this->clear(); - } - this->AllocHolder::copy_assign_alloc(x); - this->assign(x.begin(), x.end()); - } - return *this; - } - - //! Effects: Move assignment. All mx's values are transferred to *this. - //! - //! Postcondition: x.empty(). *this contains a the elements x had - //! before the function. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - ThisType& operator=(BOOST_RV_REF(ThisType) x) - { - if (&x != this){ - NodeAlloc &this_alloc = this->node_alloc(); - NodeAlloc &x_alloc = x.node_alloc(); - //If allocators are equal we can just swap pointers - if(this_alloc == x_alloc){ - //Destroy and swap pointers - this->clear(); - this->icont() = boost::move(x.icont()); - //Move allocator if needed - this->AllocHolder::move_assign_alloc(x); - } - //If unequal allocators, then do a one by one move - else{ - typedef typename std::iterator_traits::iterator_category ItCat; - this->assign( boost::make_move_iterator(x.begin()) - , boost::make_move_iterator(x.end())); - } - } - return *this; - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Inserts n copies of x before p. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void insert(const_iterator p, size_type n, const T& x) - { this->priv_create_and_insert_nodes(p, n, x); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before p. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws. - //! - //! Complexity: Linear to std::distance [first, last). - template - void insert(const_iterator p, InpIt first, InpIt last) - { - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_insert_dispatch(p, first, last, Result()); - } - - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before position. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: Amortized constant time. - iterator insert(const_iterator position, const T &x); - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Insert a new element before position with mx's resources. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - iterator insert(const_iterator position, T &&x); - #else - BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator) - #endif + ////////////////////////////////////////////// + // + // modifiers + // + ////////////////////////////////////////////// #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -831,9 +754,7 @@ class list //! Complexity: Constant template void emplace_back(Args&&... args) - { - this->emplace(this->cend(), boost::forward(args)...); - } + { this->emplace(this->cend(), boost::forward(args)...); } //! Effects: Inserts an object of type T constructed with //! std::forward(args)... in the beginning of the list. @@ -844,9 +765,7 @@ class list //! Complexity: Constant template void emplace_front(Args&&... args) - { - this->emplace(this->cbegin(), boost::forward(args)...); - } + { this->emplace(this->cbegin(), boost::forward(args)...); } //! Effects: Inserts an object of type T constructed with //! std::forward(args)... before p. @@ -893,6 +812,155 @@ class list #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: Inserts a copy of x at the beginning of the list. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_front(const T &x); + + //! Effects: Constructs a new element in the beginning of the list + //! and moves the resources of mx to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_front(T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_front, T, void, priv_push_front) + #endif + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: Inserts a copy of x at the end of the list. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_back(const T &x); + + //! Effects: Constructs a new element in the end of the list + //! and moves the resources of mx to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_back(T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) + #endif + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before position. + //! + //! Returns: an iterator to the inserted element. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: Amortized constant time. + iterator insert(const_iterator position, const T &x); + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Insert a new element before position with mx's resources. + //! + //! Returns: an iterator to the inserted element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + iterator insert(const_iterator position, T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator) + #endif + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts n copies of x before p. + //! + //! Returns: an iterator to the first inserted element or p if n is 0. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + iterator insert(const_iterator p, size_type n, const T& x) + { + typedef constant_iterator cvalue_iterator; + return this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before p. + //! + //! Returns: an iterator to the first inserted element or p if first == last. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws. + //! + //! Complexity: Linear to std::distance [first, last). + template + iterator insert(const_iterator p, InpIt first, InpIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && (container_detail::is_input_iterator::value + || container_detail::is_same::value + ) + >::type * = 0 + #endif + ) + { + const typename Icont::iterator ipos(p.get()); + iterator ret_it(ipos); + if(first != last){ + ret_it = iterator(this->icont().insert(ipos, *this->create_node_from_it(first))); + ++first; + } + for (; first != last; ++first){ + this->icont().insert(ipos, *this->create_node_from_it(first)); + } + return ret_it; + } + + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator insert(const_iterator p, FwdIt first, FwdIt last + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !(container_detail::is_input_iterator::value + || container_detail::is_same::value + ) + >::type * = 0 + ) + { + //Optimized allocation and construction + insertion_functor func(this->icont(), p.get()); + this->allocate_many_and_construct(first, std::distance(first, last), func); + return iterator(func.inserted_first()); + } + #endif + + //! Effects: Removes the first element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void pop_front() + { this->erase(this->cbegin()); } + + //! Effects: Removes the last element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void pop_back() + { const_iterator tmp = this->cend(); this->erase(--tmp); } + //! Requires: p must be a valid iterator of *this. //! //! Effects: Erases the element at p p. @@ -913,26 +981,46 @@ class list iterator erase(const_iterator first, const_iterator last) { return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); } - //! Effects: Assigns the n copies of val to *this. + //! Effects: Swaps the contents of *this and x. //! - //! Throws: If memory allocation throws or T's copy constructor throws. + //! Throws: Nothing. //! - //! Complexity: Linear to n. - void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } + //! Complexity: Constant. + void swap(list& x) + { AllocHolder::swap(x); } - //! Effects: Assigns the the range [first, last) to *this. + //! Effects: Erases all the elements of the list. //! - //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InpIt throws. + //! Throws: Nothing. //! - //! Complexity: Linear to n. - template - void assign(InpIt first, InpIt last) + //! Complexity: Linear to the number of elements in the list. + void clear() + { AllocHolder::clear(alloc_version()); } + + ////////////////////////////////////////////// + // + // slist operations + // + ////////////////////////////////////////////// + + //! Requires: p must point to an element contained + //! by the list. x != *this + //! + //! Effects: Transfers all the elements of list x to this list, before the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of + //! this list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, list& x) BOOST_CONTAINER_NOEXCEPT { - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); + BOOST_ASSERT(*this != x); + BOOST_ASSERT(this->node_alloc() == x.node_alloc()); + this->icont().splice(p.get(), x.icont()); } //! Requires: p must point to an element contained @@ -948,10 +1036,28 @@ class list //! //! Note: Iterators of values obtained from list x now point to elements of //! this list. Iterators of this list and all the references are not invalidated. - void splice(const_iterator p, ThisType& x) BOOST_CONTAINER_NOEXCEPT + void splice(const_iterator p, BOOST_RV_REF(list) x) BOOST_CONTAINER_NOEXCEPT + { this->splice(p, static_cast(x)); } + + //! Requires: p must point to an element contained + //! by this list. i must point to an element contained in list x. + //! + //! Effects: Transfers the value pointed by i, from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! If p == i or p == ++i, this function is a null operation. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, list &x, const_iterator i) BOOST_CONTAINER_NOEXCEPT { - BOOST_ASSERT((NodeAlloc&)*this == (NodeAlloc&)x); - this->icont().splice(p.get(), x.icont()); + BOOST_ASSERT(*this != x); + BOOST_ASSERT(this->node_alloc() == x.node_alloc()); + this->icont().splice(p.get(), x.icont(), i.get()); } //! Requires: p must point to an element contained @@ -968,10 +1074,27 @@ class list //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice(const_iterator p, ThisType &x, const_iterator i) BOOST_CONTAINER_NOEXCEPT + void splice(const_iterator p, BOOST_RV_REF(list) x, const_iterator i) BOOST_CONTAINER_NOEXCEPT + { this->splice(p, static_cast(x), i); } + + //! Requires: p must point to an element contained + //! by this list. first and last must point to elements contained in list x. + //! + //! Effects: Transfers the range pointed by first and last from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear to the number of elements transferred. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, list &x, const_iterator first, const_iterator last) BOOST_CONTAINER_NOEXCEPT { - BOOST_ASSERT((NodeAlloc&)*this == (NodeAlloc&)x); - this->icont().splice(p.get(), x.icont(), i.get()); + BOOST_ASSERT(*this != x); + BOOST_ASSERT(this->node_alloc() == x.node_alloc()); + this->icont().splice(p.get(), x.icont(), first.get(), last.get()); } //! Requires: p must point to an element contained @@ -987,10 +1110,30 @@ class list //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last) BOOST_CONTAINER_NOEXCEPT + void splice(const_iterator p, BOOST_RV_REF(list) x, const_iterator first, const_iterator last) BOOST_CONTAINER_NOEXCEPT + { this->splice(p, static_cast(x), first, last); } + + //! Requires: p must point to an element contained + //! by this list. first and last must point to elements contained in list x. + //! n == std::distance(first, last) + //! + //! Effects: Transfers the range pointed by first and last from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + //! + //! Note: Non-standard extension + void splice(const_iterator p, list &x, const_iterator first, const_iterator last, size_type n) BOOST_CONTAINER_NOEXCEPT { - BOOST_ASSERT((NodeAlloc&)*this == (NodeAlloc&)x); - this->icont().splice(p.get(), x.icont(), first.get(), last.get()); + BOOST_ASSERT(*this != x); + BOOST_ASSERT(this->node_alloc() == x.node_alloc()); + this->icont().splice(p.get(), x.icont(), first.get(), last.get(), n); } //! Requires: p must point to an element contained @@ -1007,21 +1150,10 @@ class list //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last, size_type n) BOOST_CONTAINER_NOEXCEPT - { - BOOST_ASSERT((NodeAlloc&)*this == (NodeAlloc&)x); - this->icont().splice(p.get(), x.icont(), first.get(), last.get(), n); - } - - //! Effects: Reverses the order of elements in the list. //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time. - //! - //! Note: Iterators and references are not invalidated - void reverse() - { this->icont().reverse(); } + //! Note: Non-standard extension + void splice(const_iterator p, BOOST_RV_REF(list) x, const_iterator first, const_iterator last, size_type n) BOOST_CONTAINER_NOEXCEPT + { this->splice(p, static_cast(x), first, last, n); } //! Effects: Removes all the elements that compare equal to value. //! @@ -1032,7 +1164,7 @@ class list //! Note: The relative order of elements that are not removed is unchanged, //! and iterators to elements that are not removed remain valid. void remove(const T& value) - { remove_if(equal_to_value(value)); } + { this->remove_if(equal_to_value(value)); } //! Effects: Removes all the elements for which a specified //! predicate is satisfied. @@ -1089,9 +1221,23 @@ class list //! //! Complexity: This function is linear time: it performs at most //! size() + x.size() - 1 comparisons. - void merge(list& x) + void merge(list &x) { this->merge(x, value_less()); } + //! Requires: The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this according to std::less. The merge is stable; + //! that is, if an element from *this is equivalent to one from x, then the element + //! from *this will precede the one from x. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + void merge(BOOST_RV_REF(list) x) + { this->merge(static_cast(x)); } + //! Requires: p must be a comparison function that induces a strict weak //! ordering and both *this and x must be sorted according to that ordering //! The lists x and *this must be distinct. @@ -1118,6 +1264,24 @@ class list } } + //! Requires: p must be a comparison function that induces a strict weak + //! ordering and both *this and x must be sorted according to that ordering + //! The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this. The merge is stable; that is, if an element from *this is + //! equivalent to one from x, then the element from *this will precede the one from x. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references to *this are not invalidated. + template + void merge(BOOST_RV_REF(list) x, StrictWeakOrdering comp) + { this->merge(static_cast(x), comp); } + //! Effects: This function sorts the list *this according to std::less. //! The sort is stable, that is, the relative order of equivalent elements is preserved. //! @@ -1148,9 +1312,47 @@ class list this->icont().sort(ValueCompareToNodeCompare(comp)); } + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time. + //! + //! Note: Iterators and references are not invalidated + void reverse() + { this->icont().reverse(); } + /// @cond private: + bool priv_try_shrink(size_type new_size) + { + const size_type len = this->size(); + if(len > new_size){ + const const_iterator iend = this->cend(); + size_type to_erase = len - new_size; + const_iterator ifirst; + if(to_erase < len/2u){ + ifirst = iend; + while(to_erase--){ + --ifirst; + } + } + else{ + ifirst = this->cbegin(); + size_type to_skip = len - to_erase; + while(to_skip--){ + ++ifirst; + } + } + this->erase(ifirst, iend); + return true; + } + else{ + return false; + } + } + iterator priv_insert(const_iterator p, const T &x) { NodePtr tmp = AllocHolder::create_node(x); @@ -1175,117 +1377,39 @@ class list void priv_push_front (BOOST_RV_REF(T) x) { this->insert(this->cbegin(), boost::move(x)); } - //Iterator range version - template - void priv_create_and_insert_nodes - (const_iterator pos, InpIterator beg, InpIterator end) - { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_nodes(pos, beg, end, alloc_version(), ItCat()); - } - - template - void priv_create_and_insert_nodes - (const_iterator pos, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) - { - for (; beg != end; ++beg){ - this->icont().insert(pos.get(), *this->create_node_from_it(beg)); - } - } - - template - void priv_create_and_insert_nodes - (const_iterator pos, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_nodes(pos, beg, end, allocator_v1(), std::input_iterator_tag()); - } - class insertion_functor; friend class insertion_functor; class insertion_functor { Icont &icont_; - typename Icont::const_iterator pos_; + typedef typename Icont::iterator iiterator; + typedef typename Icont::const_iterator iconst_iterator; + + const iconst_iterator pos_; + iiterator ret_; + bool first_; public: insertion_functor(Icont &icont, typename Icont::const_iterator pos) - : icont_(icont), pos_(pos) + : icont_(icont), pos_(pos), ret_(pos.unconst()), first_(true) {} void operator()(Node &n) - { this->icont_.insert(pos_, n); } + { + if(first_){ + ret_ = this->icont_.insert(pos_, n); + first_ = false; + } + else{ + this->icont_.insert(pos_, n); + } + } + + iiterator inserted_first() const + { return ret_; } }; - - template - void priv_create_and_insert_nodes - (const_iterator pos, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) - { - if(beg != end){ - //Optimized allocation and construction - this->allocate_many_and_construct - (beg, std::distance(beg, end), insertion_functor(this->icont(), pos.get())); - } - } - - //Default constructed version - void priv_create_and_insert_nodes(const_iterator pos, size_type n) - { - typedef default_construct_iterator default_iterator; - this->priv_create_and_insert_nodes(pos, default_iterator(n), default_iterator()); - } - - //Copy constructed version - void priv_create_and_insert_nodes(const_iterator pos, size_type n, const T& x) - { - typedef constant_iterator cvalue_iterator; - this->priv_create_and_insert_nodes(pos, cvalue_iterator(x, n), cvalue_iterator()); - } - - //Dispatch to detect iterator range or integer overloads - template - void priv_insert_dispatch(const_iterator p, - InputIter first, InputIter last, - container_detail::false_) - { this->priv_create_and_insert_nodes(p, first, last); } - - template - void priv_insert_dispatch(const_iterator p, Integer n, Integer x, container_detail::true_) - { this->insert(p, (size_type)n, x); } - - void priv_fill_assign(size_type n, const T& val) - { - iterator i = this->begin(), iend = this->end(); - - for ( ; i != iend && n > 0; ++i, --n) - *i = val; - if (n > 0){ - this->priv_create_and_insert_nodes(this->cend(), n, val); - } - else{ - this->erase(i, cend()); - } - } - - template - void priv_assign_dispatch(Integer n, Integer val, container_detail::true_) - { this->priv_fill_assign((size_type) n, (T) val); } - - template - void priv_assign_dispatch(InputIter first2, InputIter last2, container_detail::false_) - { - iterator first1 = this->begin(); - iterator last1 = this->end(); - for ( ; first1 != last1 && first2 != last2; ++first1, ++first2) - *first1 = *first2; - if (first2 == last2) - this->erase(first1, last1); - else{ - this->priv_create_and_insert_nodes(last1, first2, last2); - } - } - //Functors for member algorithm defaults struct value_less { diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index 91cbd35..d31122c 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -68,7 +68,7 @@ inline bool operator<(const map& x, //! A is the allocator to allocate the value_types //! (e.g. allocator< std::pair > ). #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template >, class A = std::allocator > +template , class A = std::allocator< std::pair< const Key, T> > > #else template #endif @@ -155,7 +155,7 @@ class map template map(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, true) + : m_tree(true, first, last, comp, a) { //Allocator type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename A::value_type>::value)); @@ -814,7 +814,7 @@ namespace container { //! A is the allocator to allocate the value_types //!(e.g. allocator< std::pair<const Key, T> >). #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template >, class A = std::allocator > +template , class A = std::allocator< std::pair< const Key, T> > > #else template #endif @@ -902,7 +902,7 @@ class multimap multimap(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, false) + : m_tree(false, first, last, comp, a) { //Allocator type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename A::value_type>::value)); diff --git a/include/boost/container/set.hpp b/include/boost/container/set.hpp index 09ada20..44a854c 100644 --- a/include/boost/container/set.hpp +++ b/include/boost/container/set.hpp @@ -118,7 +118,7 @@ class set template set(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, true) + : m_tree(true, first, last, comp, a) {} //! Effects: Constructs an empty set using the specified comparison object and @@ -705,7 +705,7 @@ class multiset multiset(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, false) + : m_tree(false, first, last, comp, a) {} //! Effects: Constructs an empty multiset using the specified comparison object and diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index 5771935..c5ca7fa 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -20,9 +20,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -52,6 +54,9 @@ namespace container { /// @cond +template +class slist; + namespace container_detail { template @@ -95,6 +100,99 @@ struct intrusive_slist_type typedef container_type type ; }; +template +class slist_const_iterator + : public std::iterator< std::forward_iterator_tag, T + , typename iiterator_types::difference_type + , typename iiterator_types::const_pointer + , typename iiterator_types::const_reference> +{ + protected: + + IIterator m_it; + + public: + typedef typename iiterator_types::const_pointer const_pointer; + typedef typename iiterator_types::const_reference const_reference; + + //Constructors + slist_const_iterator() + : m_it() + {} + + explicit slist_const_iterator(const IIterator &it) + : m_it(it) + {} + + //Pointer like operators + const_reference operator*() const + { return this->m_it->m_data; } + + const_pointer operator->() const + { return ::boost::intrusive::pointer_traits::pointer_to(this->m_it->m_data); } + + //Increment / Decrement + slist_const_iterator& operator++() + { ++this->m_it; return *this; } + + slist_const_iterator operator++(int) + { IIterator tmp = this->m_it; ++*this; return slist_const_iterator(tmp); } + + //Comparison operators + friend bool operator== (const slist_const_iterator& l, const slist_const_iterator& r) + { return l.m_it == r.m_it; } + + friend bool operator!= (const slist_const_iterator& l, const slist_const_iterator& r) + { return l.m_it != r.m_it; } + + IIterator &get() + { return this->m_it; } + + const IIterator &get() const + { return this->m_it; } +}; + +template +class slist_iterator + : public slist_const_iterator +{ + private: + typedef slist_const_iterator const_iterator; + + public: + typedef typename iiterator_types::pointer pointer; + typedef typename iiterator_types::reference reference; + + //Constructors + slist_iterator() + : const_iterator() + {} + + explicit slist_iterator(const IIterator &it) + : const_iterator(it) + {} + + //Pointer like operators + reference operator*() const + { return this->m_it->m_data; } + + pointer operator->() const + { return ::boost::intrusive::pointer_traits::to_pointer(this->m_it->m_data); } + + //Increment / Decrement + slist_iterator& operator++() + { ++this->m_it; return *this; } + + slist_iterator operator++(int) + { IIterator tmp = this->m_it; ++*this; return slist_iterator(tmp); } + + IIterator &get() + { return this->m_it; } + + const IIterator &get() const + { return this->m_it; } +}; + } //namespace container_detail { /// @endcond @@ -141,13 +239,10 @@ class slist ::type> { /// @cond - typedef typename container_detail:: - move_const_ref_type::type insert_const_ref_type; typedef typename container_detail::intrusive_slist_type::type Icont; typedef container_detail::node_alloc_holder AllocHolder; typedef typename AllocHolder::NodePtr NodePtr; - typedef slist ThisType; typedef typename AllocHolder::NodeAlloc NodeAlloc; typedef typename AllocHolder::ValAlloc ValAlloc; typedef typename AllocHolder::Node Node; @@ -185,126 +280,39 @@ class slist bool operator()(const Node &a) const { return static_cast(*this)(a.m_data); } }; - /// @endcond - public: - //! The type of object, T, stored in the list - typedef T value_type; - //! Pointer to T - typedef typename allocator_traits_type::pointer pointer; - //! Const pointer to T - typedef typename allocator_traits_type::const_pointer const_pointer; - //! Reference to T - typedef typename allocator_traits_type::reference reference; - //! Const reference to T - typedef typename allocator_traits_type::const_reference const_reference; - //! An unsigned integral type - typedef typename allocator_traits_type::size_type size_type; - //! A signed integral type - typedef typename allocator_traits_type::difference_type difference_type; - //! The allocator type - typedef A allocator_type; - //! Non-standard extension: the stored allocator type - typedef NodeAlloc stored_allocator_type; - /// @cond - private: BOOST_COPYABLE_AND_MOVABLE(slist) - typedef difference_type list_difference_type; - typedef pointer list_pointer; - typedef const_pointer list_const_pointer; - typedef reference list_reference; - typedef const_reference list_const_reference; + typedef container_detail::slist_iterator iterator_impl; + typedef container_detail::slist_const_iteratorconst_iterator_impl; /// @endcond public: + ////////////////////////////////////////////// + // + // types + // + ////////////////////////////////////////////// - //! Const iterator used to iterate through a list. - class const_iterator - /// @cond - : public std::iterator - { - - protected: - typename Icont::iterator m_it; - explicit const_iterator(typename Icont::iterator it) : m_it(it){} - void prot_incr(){ ++m_it; } - - private: - typename Icont::iterator get() - { return this->m_it; } - - public: - friend class slist; - typedef list_difference_type difference_type; - - //Constructors - const_iterator() - : m_it() - {} - - //Pointer like operators - const_reference operator*() const - { return m_it->m_data; } - - const_pointer operator->() const - { return const_pointer(&m_it->m_data); } - - //Increment / Decrement - const_iterator& operator++() - { prot_incr(); return *this; } - - const_iterator operator++(int) - { typename Icont::iterator tmp = m_it; ++*this; return const_iterator(tmp); } - - //Comparison operators - bool operator== (const const_iterator& r) const - { return m_it == r.m_it; } - - bool operator!= (const const_iterator& r) const - { return m_it != r.m_it; } - } - /// @endcond - ; - - //! Iterator used to iterate through a list - class iterator - /// @cond - : public const_iterator - { - - private: - explicit iterator(typename Icont::iterator it) - : const_iterator(it) - {} - - typename Icont::iterator get() - { return this->m_it; } - - public: - friend class slist; - typedef list_pointer pointer; - typedef list_reference reference; - - //Constructors - iterator(){} - - //Pointer like operators - reference operator*() const { return this->m_it->m_data; } - pointer operator->() const { return pointer(&this->m_it->m_data); } - - //Increment / Decrement - iterator& operator++() - { this->prot_incr(); return *this; } - - iterator operator++(int) - { typename Icont::iterator tmp = this->m_it; ++*this; return iterator(tmp); } - } - /// @endcond - ; + typedef T value_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + typedef typename ::boost::container::allocator_traits::const_pointer const_pointer; + typedef typename ::boost::container::allocator_traits::reference reference; + typedef typename ::boost::container::allocator_traits::const_reference const_reference; + typedef typename ::boost::container::allocator_traits::size_type size_type; + typedef typename ::boost::container::allocator_traits::difference_type difference_type; + typedef A allocator_type; + typedef BOOST_CONTAINER_IMPDEF(NodeAlloc) stored_allocator_type; + typedef BOOST_CONTAINER_IMPDEF(iterator_impl) iterator; + typedef BOOST_CONTAINER_IMPDEF(const_iterator_impl) const_iterator; public: + + ////////////////////////////////////////////// + // + // construct/copy/destroy + // + ////////////////////////////////////////////// + //! Effects: Constructs a list taking the allocator as parameter. //! //! Throws: If allocator_type's copy constructor throws. @@ -336,7 +344,7 @@ class slist //! Complexity: Linear to n. explicit slist(size_type n, const value_type& x, const allocator_type& a = allocator_type()) : AllocHolder(a) - { this->priv_create_and_insert_nodes(this->before_begin(), n, x); } + { this->insert_after(this->cbefore_begin(), n, x); } //! Effects: Constructs a list that will use a copy of allocator a //! and inserts a copy of the range [first, last) in the list. @@ -346,10 +354,9 @@ class slist //! //! Complexity: Linear to the range [first, last). template - slist(InpIt first, InpIt last, - const allocator_type& a = allocator_type()) + slist(InpIt first, InpIt last, const allocator_type& a = allocator_type()) : AllocHolder(a) - { this->insert_after(this->before_begin(), first, last); } + { this->insert_after(this->cbefore_begin(), first, last); } //! Effects: Copy constructs a list. //! @@ -360,7 +367,7 @@ class slist //! Complexity: Linear to the elements x contains. slist(const slist& x) : AllocHolder(x) - { this->insert_after(this->before_begin(), x.begin(), x.end()); } + { this->insert_after(this->cbefore_begin(), x.begin(), x.end()); } //! Effects: Move constructor. Moves mx's resources to *this. //! @@ -380,7 +387,7 @@ class slist //! Complexity: Linear to the elements x contains. slist(const slist& x, const allocator_type &a) : AllocHolder(a) - { this->insert_after(this->before_begin(), x.begin(), x.end()); } + { this->insert_after(this->cbefore_begin(), x.begin(), x.end()); } //! Effects: Move constructor using the specified allocator. //! Moves x's resources to *this. @@ -399,6 +406,15 @@ class slist } } + //! Effects: Destroys the list. All stored values are destroyed + //! and used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements. + ~slist() + {} //AllocHolder clears the slist + //! Effects: Makes *this contain the same elements as x. //! //! Postcondition: this->size() == x.size(). *this contains a copy @@ -454,14 +470,46 @@ class slist return *this; } - //! Effects: Destroys the list. All stored values are destroyed - //! and used memory is deallocated. + //! Effects: Assigns the n copies of val to *this. //! - //! Throws: Nothing. + //! Throws: If memory allocation throws or T's copy constructor throws. //! - //! Complexity: Linear to the number of elements. - ~slist() - {} //AllocHolder clears the slist + //! Complexity: Linear to n. + void assign(size_type n, const T& val) + { + typedef constant_iterator cvalue_iterator; + return this->assign(cvalue_iterator(val, n), cvalue_iterator()); + } + + //! Effects: Assigns the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing InpIt throws. + //! + //! Complexity: Linear to n. + template + void assign(InpIt first, InpIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + >::type * = 0 + #endif + ) + { + iterator end_n(this->end()); + iterator prev(this->before_begin()); + iterator node(this->begin()); + while (node != end_n && first != last){ + *node = *first; + prev = node; + ++node; + ++first; + } + if (first != last) + this->insert_after(prev, first, last); + else + this->erase_after(prev, end_n); + } //! Effects: Returns a copy of the internal allocator. //! @@ -471,35 +519,49 @@ class slist allocator_type get_allocator() const { return allocator_type(this->node_alloc()); } + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. const stored_allocator_type &get_stored_allocator() const { return this->node_alloc(); } + //! Effects: Returns a reference to the internal allocator. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. stored_allocator_type &get_stored_allocator() { return this->node_alloc(); } - public: + ////////////////////////////////////////////// + // + // iterators + // + ////////////////////////////////////////////// - //! Effects: Assigns the n copies of val to *this. + //! Effects: Returns a non-dereferenceable iterator that, + //! when incremented, yields begin(). This iterator may be used + //! as the argument to insert_after, erase_after, etc. //! - //! Throws: If memory allocation throws or T's copy constructor throws. + //! Throws: Nothing. //! - //! Complexity: Linear to n. - void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } + //! Complexity: Constant. + iterator before_begin() + { return iterator(end()); } - //! Effects: Assigns the range [first, last) to *this. + //! Effects: Returns a non-dereferenceable const_iterator + //! that, when incremented, yields begin(). This iterator may be used + //! as the argument to insert_after, erase_after, etc. //! - //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InpIt throws. + //! Throws: Nothing. //! - //! Complexity: Linear to n. - template - void assign(InpIt first, InpIt last) - { - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } + //! Complexity: Constant. + const_iterator before_begin() const + { return this->cbefore_begin(); } //! Effects: Returns an iterator to the first element contained in the list. //! @@ -533,25 +595,15 @@ class slist const_iterator end() const { return this->cend(); } - //! Effects: Returns a non-dereferenceable iterator that, - //! when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator before_begin() - { return iterator(end()); } - //! Effects: Returns a non-dereferenceable const_iterator //! that, when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. + //! as the argument to insert_after, erase_after, etc. //! //! Throws: Nothing. //! //! Complexity: Constant. - const_iterator before_begin() const - { return this->cbefore_begin(); } + const_iterator cbefore_begin() const + { return const_iterator(end()); } //! Effects: Returns a const_iterator to the first element contained in the list. //! @@ -569,15 +621,43 @@ class slist const_iterator cend() const { return const_iterator(this->non_const_icont().end()); } - //! Effects: Returns a non-dereferenceable const_iterator - //! that, when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. + //! Returns: The iterator to the element before i in the sequence. + //! Returns the end-iterator, if either i is the begin-iterator or the + //! sequence is empty. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + //! + //! Note: Non-standard extension. + iterator previous(iterator p) + { return iterator(this->icont().previous(p.get())); } + + //! Returns: The const_iterator to the element before i in the sequence. + //! Returns the end-const_iterator, if either i is the begin-const_iterator or + //! the sequence is empty. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + //! + //! Note: Non-standard extension. + const_iterator previous(const_iterator p) + { return const_iterator(this->icont().previous(p.get())); } + + ////////////////////////////////////////////// + // + // capacity + // + ////////////////////////////////////////////// + + //! Effects: Returns true if the list contains no elements. //! //! Throws: Nothing. //! //! Complexity: Constant. - const_iterator cbefore_begin() const - { return const_iterator(end()); } + bool empty() const + { return !this->size(); } //! Effects: Returns the number of the elements contained in the list. //! @@ -595,21 +675,40 @@ class slist size_type max_size() const { return AllocHolder::max_size(); } - //! Effects: Returns true if the list contains no elements. + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. //! - //! Throws: Nothing. + //! Throws: If memory allocation throws, or T's copy constructor throws. //! - //! Complexity: Constant. - bool empty() const - { return !this->size(); } + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size) + { + const_iterator last_pos; + if(!priv_try_shrink(new_size, last_pos)){ + typedef default_construct_iterator default_iterator; + this->insert_after(last_pos, default_iterator(new_size - this->size()), default_iterator()); + } + } - //! Effects: Swaps the contents of *this and x. + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. //! - //! Throws: Nothing. + //! Throws: If memory allocation throws, or T's copy constructor throws. //! - //! Complexity: Linear to the number of elements on *this and x. - void swap(slist& x) - { AllocHolder::swap(x); } + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size, const T& x) + { + const_iterator last_pos; + if(!priv_try_shrink(new_size, last_pos)){ + this->insert_after(last_pos, new_size, x); + } + } + + ////////////////////////////////////////////// + // + // element access + // + ////////////////////////////////////////////// //! Requires: !empty() //! @@ -633,188 +732,11 @@ class slist const_reference front() const { return *this->begin(); } - //! Effects: Inserts a copy of t in the beginning of the list. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_front(insert_const_ref_type x) - { return priv_push_front(x); } - - #if defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - void push_front(T &x) { push_front(const_cast(x)); } - - template - void push_front(const U &u - , typename container_detail::enable_if_c::value && !::boost::has_move_emulation_enabled::value >::type* =0) - { return priv_push_front(u); } - #endif - - //! Effects: Constructs a new element in the beginning of the list - //! and moves the resources of t to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - void push_front(BOOST_RV_REF(T) x) - { this->icont().push_front(*this->create_node(boost::move(x))); } - - //! Effects: Removes the first element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void pop_front() - { this->icont().pop_front_and_dispose(Destroyer(this->node_alloc())); } - - //! Returns: The iterator to the element before i in the sequence. - //! Returns the end-iterator, if either i is the begin-iterator or the - //! sequence is empty. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements before i. - iterator previous(iterator p) - { return iterator(this->icont().previous(p.get())); } - - //! Returns: The const_iterator to the element before i in the sequence. - //! Returns the end-const_iterator, if either i is the begin-const_iterator or - //! the sequence is empty. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements before i. - const_iterator previous(const_iterator p) - { return const_iterator(this->icont().previous(p.get())); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Inserts a copy of the value after the p pointed - //! by prev_p. - //! - //! Returns: An iterator to the inserted element. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - iterator insert_after(const_iterator prev_pos, insert_const_ref_type x) - { return this->priv_insert_after(prev_pos, x); } - - #if defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - iterator insert_after(const_iterator position, T &x) - { return this->insert_after(position, const_cast(x)); } - - template - iterator insert_after( const_iterator position, const U &u - , typename container_detail::enable_if_c::value && !::boost::has_move_emulation_enabled::value >::type* =0) - { return this->priv_insert_after(position, u); } - #endif - - //! Requires: prev_pos must be a valid iterator of *this. - //! - //! Effects: Inserts a move constructed copy object from the value after the - //! p pointed by prev_pos. - //! - //! Returns: An iterator to the inserted element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - iterator insert_after(const_iterator prev_pos, BOOST_RV_REF(value_type) x) - { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(boost::move(x)))); } - - //! Requires: prev_pos must be a valid iterator of *this. - //! - //! Effects: Inserts n copies of x after prev_pos. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - void insert_after(const_iterator prev_pos, size_type n, const value_type& x) - { this->priv_create_and_insert_nodes(prev_pos, n, x); } - - //! Requires: prev_pos must be a valid iterator of *this. - //! - //! Effects: Inserts the range pointed by [first, last) - //! after the p prev_pos. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws. - //! - //! Complexity: Linear to the number of elements inserted. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - template - void insert_after(const_iterator prev_pos, InIter first, InIter last) - { - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_insert_after_range_dispatch(prev_pos, first, last, Result()); - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before p. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: Linear to the elements before p. - iterator insert(const_iterator position, insert_const_ref_type x) - { return this->priv_insert(position, x); } - - #if defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - iterator insert(const_iterator position, T &x) - { return this->insert(position, const_cast(x)); } - - template - iterator insert( const_iterator position, const U &u - , typename container_detail::enable_if_c::value && !::boost::has_move_emulation_enabled::value >::type* =0) - { return this->priv_insert(position, u); } - #endif - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a new element before p with mx's resources. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Linear to the elements before p. - iterator insert(const_iterator p, BOOST_RV_REF(value_type) x) - { return this->insert_after(previous(p), boost::move(x)); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Inserts n copies of x before p. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n plus linear to the elements before p. - void insert(const_iterator p, size_type n, const value_type& x) - { return this->insert_after(previous(p), n, x); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before p. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws. - //! - //! Complexity: Linear to std::distance [first, last) plus - //! linear to the elements before p. - template - void insert(const_iterator p, InIter first, InIter last) - { return this->insert_after(previous(p), first, last); } + ////////////////////////////////////////////// + // + // modifiers + // + ////////////////////////////////////////////// #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -829,17 +751,6 @@ class slist void emplace_front(Args&&... args) { this->emplace_after(this->cbefore_begin(), boost::forward(args)...); } - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... before p - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Linear to the elements before p - template - iterator emplace(const_iterator p, Args&&... args) - { return this->emplace_after(this->previous(p), boost::forward(args)...); } - //! Effects: Inserts an object of type T constructed with //! std::forward(args)... after prev //! @@ -865,15 +776,6 @@ class slist } \ \ BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ - iterator emplace (const_iterator p \ - BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ - { \ - return this->emplace_after \ - (this->previous(p) \ - BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ - } \ - \ - BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ iterator emplace_after(const_iterator prev \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ { \ @@ -887,6 +789,139 @@ class slist #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: Inserts a copy of x at the beginning of the list. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_front(const T &x); + + //! Effects: Constructs a new element in the beginning of the list + //! and moves the resources of mx to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_front(T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_front, T, void, priv_push_front) + #endif + + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts a copy of the value after the position pointed + //! by prev_p. + //! + //! Returns: An iterator to the inserted element. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + iterator insert_after(const_iterator prev_pos, const T &x); + + //! Requires: prev_pos must be a valid iterator of *this. + //! + //! Effects: Inserts a move constructed copy object from the value after the + //! p pointed by prev_pos. + //! + //! Returns: An iterator to the inserted element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + iterator insert_after(const_iterator prev_pos, T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert_after, T, iterator, priv_insert_after, const_iterator) + #endif + + //! Requires: prev_pos must be a valid iterator of *this. + //! + //! Effects: Inserts n copies of x after prev_pos. + //! + //! Returns: an iterator to the last inserted element or prev_pos if n is 0. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! + //! Complexity: Linear to n. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + iterator insert_after(const_iterator prev_pos, size_type n, const value_type& x) + { + typedef constant_iterator cvalue_iterator; + return this->insert_after(prev_pos, cvalue_iterator(x, n), cvalue_iterator()); + } + + //! Requires: prev_pos must be a valid iterator of *this. + //! + //! Effects: Inserts the range pointed by [first, last) + //! after the position prev_pos. + //! + //! Returns: an iterator to the last inserted element or prev_pos if first == last. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws. + //! + //! Complexity: Linear to the number of elements inserted. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + template + iterator insert_after(const_iterator prev_pos, InpIt first, InpIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && (container_detail::is_input_iterator::value + || container_detail::is_same::value + ) + >::type * = 0 + #endif + ) + { + iterator ret_it(prev_pos.get()); + for (; first != last; ++first){ + ret_it = iterator(this->icont().insert_after(ret_it.get(), *this->create_node_from_it(first))); + } + return ret_it; + } + + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator insert_after(const_iterator prev, FwdIt first, FwdIt last + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !(container_detail::is_input_iterator::value + || container_detail::is_same::value + ) + >::type * = 0 + ) + { + //Optimized allocation and construction + insertion_functor func(this->icont(), prev.get()); + this->allocate_many_and_construct(first, std::distance(first, last), func); + return iterator(func.inserted_first()); + } + #endif + + //! Effects: Removes the first element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void pop_front() + { this->icont().pop_front_and_dispose(Destroyer(this->node_alloc())); } + //! Effects: Erases the element after the element pointed by prev_pos //! of the list. //! @@ -919,69 +954,13 @@ class slist return iterator(this->icont().erase_after_and_dispose(before_first.get(), last.get(), Destroyer(this->node_alloc()))); } - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Erases the element at p p. + //! Effects: Swaps the contents of *this and x. //! //! Throws: Nothing. //! - //! Complexity: Linear to the number of elements before p. - iterator erase(const_iterator p) - { return iterator(this->erase_after(previous(p))); } - - //! Requires: first and last must be valid iterator to elements in *this. - //! - //! Effects: Erases the elements pointed by [first, last). - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the distance between first and last plus - //! linear to the elements before first. - iterator erase(const_iterator first, const_iterator last) - { return iterator(this->erase_after(previous(first), last)); } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size, const T& x) - { - typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; - while (++(cur_next = cur) != end_n && new_size > 0){ - --new_size; - cur = cur_next; - } - if (cur_next != end_n) - this->erase_after(const_iterator(cur), const_iterator(end_n)); - else - this->insert_after(const_iterator(cur), new_size, x); - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size) - { - typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; - size_type len = this->size(); - size_type left = new_size; - - while (++(cur_next = cur) != end_n && left > 0){ - --left; - cur = cur_next; - } - if (cur_next != end_n){ - this->erase_after(const_iterator(cur), const_iterator(end_n)); - } - else{ - this->priv_create_and_insert_nodes(const_iterator(cur), new_size - len); - } - } + //! Complexity: Linear to the number of elements on *this and x. + void swap(slist& x) + { AllocHolder::swap(x); } //! Effects: Erases all the elements of the list. //! @@ -991,6 +970,12 @@ class slist void clear() { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); } + ////////////////////////////////////////////// + // + // slist operations + // + ////////////////////////////////////////////// + //! Requires: p must point to an element contained //! by the list. x != *this //! @@ -1006,14 +991,27 @@ class slist //! this list. Iterators of this list and all the references are not invalidated. void splice_after(const_iterator prev_pos, slist& x) { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice_after(prev_pos.get(), x.icont()); - } - else{ - throw std::runtime_error("slist::splice called with unequal allocators"); - } + BOOST_ASSERT(*this != x); + BOOST_ASSERT(this->node_alloc() == x.node_alloc()); + this->icont().splice_after(prev_pos.get(), x.icont()); } + //! Requires: p must point to an element contained + //! by the list. x != *this + //! + //! Effects: Transfers all the elements of list x to this list, after the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear to the elements in x. + //! + //! Note: Iterators of values obtained from list x now point to elements of + //! this list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, BOOST_RV_REF(slist) x) + { this->splice_after(prev_pos, static_cast(x)); } + //! Requires: prev_pos must be a valid iterator of this. //! i must point to an element contained in list x. //! @@ -1030,14 +1028,28 @@ class slist //! list. Iterators of this list and all the references are not invalidated. void splice_after(const_iterator prev_pos, slist& x, const_iterator prev) { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice_after(prev_pos.get(), x.icont(), prev.get()); - } - else{ - throw std::runtime_error("slist::splice called with unequal allocators"); - } + BOOST_ASSERT(*this != x); + BOOST_ASSERT(this->node_alloc() == x.node_alloc()); + this->icont().splice_after(prev_pos.get(), x.icont(), prev.get()); } + //! Requires: prev_pos must be a valid iterator of this. + //! i must point to an element contained in list x. + //! + //! Effects: Transfers the value pointed by i, from list x to this list, + //! after the element pointed by prev_pos. + //! If prev_pos == prev or prev_pos == ++prev, this function is a null operation. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, BOOST_RV_REF(slist) x, const_iterator prev) + { this->splice_after(prev_pos, static_cast(x), prev); } + //! Requires: prev_pos must be a valid iterator of this. //! before_first and before_last must be valid iterators of x. //! prev_pos must not be contained in [before_first, before_last) range. @@ -1055,15 +1067,30 @@ class slist void splice_after(const_iterator prev_pos, slist& x, const_iterator before_first, const_iterator before_last) { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice_after - (prev_pos.get(), x.icont(), before_first.get(), before_last.get()); - } - else{ - throw std::runtime_error("slist::splice called with unequal allocators"); - } + BOOST_ASSERT(*this != x); + BOOST_ASSERT(this->node_alloc() == x.node_alloc()); + this->icont().splice_after + (prev_pos.get(), x.icont(), before_first.get(), before_last.get()); } + //! Requires: prev_pos must be a valid iterator of this. + //! before_first and before_last must be valid iterators of x. + //! prev_pos must not be contained in [before_first, before_last) range. + //! + //! Effects: Transfers the range [before_first + 1, before_last + 1) + //! from list x to this list, after the element pointed by prev_pos. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear to the number of transferred elements. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, BOOST_RV_REF(slist) x, + const_iterator before_first, const_iterator before_last) + { this->splice_after(prev_pos, static_cast(x), before_first, before_last); } + //! Requires: prev_pos must be a valid iterator of this. //! before_first and before_last must be valid iterators of x. //! prev_pos must not be contained in [before_first, before_last) range. @@ -1083,74 +1110,31 @@ class slist const_iterator before_first, const_iterator before_last, size_type n) { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice_after - (prev_pos.get(), x.icont(), before_first.get(), before_last.get(), n); - } - else{ - throw std::runtime_error("slist::splice called with unequal allocators"); - } + BOOST_ASSERT(*this != x); + BOOST_ASSERT(this->node_alloc() == x.node_alloc()); + this->icont().splice_after + (prev_pos.get(), x.icont(), before_first.get(), before_last.get(), n); } - //! Requires: p must point to an element contained - //! by the list. x != *this + //! Requires: prev_pos must be a valid iterator of this. + //! before_first and before_last must be valid iterators of x. + //! prev_pos must not be contained in [before_first, before_last) range. + //! n == std::distance(before_first, before_last) //! - //! Effects: Transfers all the elements of list x to this list, before the - //! the element pointed by p. No destructors or copy constructors are called. + //! Effects: Transfers the range [before_first + 1, before_last + 1) + //! from list x to this list, after the element pointed by prev_pos. //! //! Throws: std::runtime_error if this' allocator and x's allocator //! are not equal. //! - //! Complexity: Linear in distance(begin(), p), and linear in x.size(). - //! - //! Note: Iterators of values obtained from list x now point to elements of - //! this list. Iterators of this list and all the references are not invalidated. - void splice(const_iterator p, ThisType& x) - { this->splice_after(this->previous(p), x); } - - //! Requires: p must point to an element contained - //! by this list. i must point to an element contained in list x. - //! - //! Effects: Transfers the value pointed by i, from list x to this list, - //! before the the element pointed by p. No destructors or copy constructors are called. - //! If p == i or p == ++i, this function is a null operation. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear in distance(begin(), p), and in distance(x.begin(), i). + //! Complexity: Constant. //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice(const_iterator p, slist& x, const_iterator i) - { this->splice_after(previous(p), x, i); } - - //! Requires: p must point to an element contained - //! by this list. first and last must point to elements contained in list x. - //! - //! Effects: Transfers the range pointed by first and last from list x to this list, - //! before the the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear in distance(begin(), p), in distance(x.begin(), first), - //! and in distance(first, last). - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - void splice(const_iterator p, slist& x, const_iterator first, const_iterator last) - { this->splice_after(previous(p), x, previous(first), previous(last)); } - - //! Effects: Reverses the order of elements in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time. - //! - //! Note: Iterators and references are not invalidated - void reverse() - { this->icont().reverse(); } + void splice_after(const_iterator prev_pos, BOOST_RV_REF(slist) x, + const_iterator before_first, const_iterator before_last, + size_type n) + { this->splice_after(prev_pos, static_cast(x), before_first, before_last, n); } //! Effects: Removes all the elements that compare equal to value. //! @@ -1161,7 +1145,7 @@ class slist //! Note: The relative order of elements that are not removed is unchanged, //! and iterators to elements that are not removed remain valid. void remove(const T& value) - { remove_if(equal_to_value(value)); } + { this->remove_if(equal_to_value(value)); } //! Effects: Removes all the elements for which a specified //! predicate is satisfied. @@ -1221,6 +1205,20 @@ class slist void merge(slist & x) { this->merge(x, value_less()); } + //! Requires: The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this according to std::less. The merge is stable; + //! that is, if an element from *this is equivalent to one from x, then the element + //! from *this will precede the one from x. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + void merge(BOOST_RV_REF(slist) x) + { this->merge(static_cast(x)); } + //! Requires: p must be a comparison function that induces a strict weak //! ordering and both *this and x must be sorted according to that ordering //! The lists x and *this must be distinct. @@ -1247,6 +1245,24 @@ class slist } } + //! Requires: p must be a comparison function that induces a strict weak + //! ordering and both *this and x must be sorted according to that ordering + //! The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this. The merge is stable; that is, if an element from *this is + //! equivalent to one from x, then the element from *this will precede the one from x. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references to *this are not invalidated. + template + void merge(BOOST_RV_REF(slist) x, StrictWeakOrdering comp) + { this->merge(static_cast(x), comp); } + //! Effects: This function sorts the list *this according to std::less. //! The sort is stable, that is, the relative order of equivalent elements is preserved. //! @@ -1277,42 +1293,266 @@ class slist this->icont().sort(ValueCompareToNodeCompare(comp)); } - /// @cond - private: - iterator priv_insert(const_iterator p, const value_type& x) - { return this->insert_after(previous(p), x); } + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time. + //! + //! Note: Iterators and references are not invalidated + void reverse() + { this->icont().reverse(); } - iterator priv_insert_after(const_iterator prev_pos, const value_type& x) - { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(x))); } + ////////////////////////////////////////////// + // + // list compatibility interface + // + ////////////////////////////////////////////// - void priv_push_front(const value_type &x) - { this->icont().push_front(*this->create_node(x)); } + #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //Iterator range version - template - void priv_create_and_insert_nodes - (const_iterator prev, InpIterator beg, InpIterator end) + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before p + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Linear to the elements before p + template + iterator emplace(const_iterator p, Args&&... args) + { return this->emplace_after(this->previous(p), boost::forward(args)...); } + + #else //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + + #define BOOST_PP_LOCAL_MACRO(n) \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + iterator emplace (const_iterator p \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + return this->emplace_after \ + (this->previous(p) \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before p. + //! + //! Returns: an iterator to the inserted element. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: Linear to the elements before p. + iterator insert(const_iterator position, const T &x); + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a new element before p with mx's resources. + //! + //! Returns: an iterator to the inserted element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Linear to the elements before p. + iterator insert(const_iterator prev_pos, T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator) + #endif + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts n copies of x before p. + //! + //! Returns: an iterator to the first inserted element or p if n == 0. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n plus linear to the elements before p. + iterator insert(const_iterator p, size_type n, const value_type& x) { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_nodes(prev, beg, end, alloc_version(), ItCat()); + const_iterator prev(this->previous(p)); + this->insert_after(prev, n, x); + return ++iterator(prev.get()); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before p. + //! + //! Returns: an iterator to the first inserted element or p if first == last. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws. + //! + //! Complexity: Linear to std::distance [first, last) plus + //! linear to the elements before p. + template + iterator insert(const_iterator p, InIter first, InIter last) + { + const_iterator prev(this->previous(p)); + this->insert_after(prev, first, last); + return ++iterator(prev.get()); } - template - void priv_create_and_insert_nodes - (const_iterator prev, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Erases the element at p p. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before p. + iterator erase(const_iterator p) + { return iterator(this->erase_after(previous(p))); } + + //! Requires: first and last must be valid iterator to elements in *this. + //! + //! Effects: Erases the elements pointed by [first, last). + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the distance between first and last plus + //! linear to the elements before first. + iterator erase(const_iterator first, const_iterator last) + { return iterator(this->erase_after(previous(first), last)); } + + //! Requires: p must point to an element contained + //! by the list. x != *this + //! + //! Effects: Transfers all the elements of list x to this list, before the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), and linear in x.size(). + //! + //! Note: Iterators of values obtained from list x now point to elements of + //! this list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, slist& x) + { this->splice_after(this->previous(p), x); } + + //! Requires: p must point to an element contained + //! by the list. x != *this + //! + //! Effects: Transfers all the elements of list x to this list, before the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), and linear in x.size(). + //! + //! Note: Iterators of values obtained from list x now point to elements of + //! this list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, BOOST_RV_REF(slist) x) + { this->splice(p, static_cast(x)); } + + //! Requires: p must point to an element contained + //! by this list. i must point to an element contained in list x. + //! + //! Effects: Transfers the value pointed by i, from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! If p == i or p == ++i, this function is a null operation. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), and in distance(x.begin(), i). + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, slist& x, const_iterator i) + { this->splice_after(this->previous(p), x, this->previous(i)); } + + //! Requires: p must point to an element contained + //! by this list. i must point to an element contained in list x. + //! + //! Effects: Transfers the value pointed by i, from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! If p == i or p == ++i, this function is a null operation. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), and in distance(x.begin(), i). + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, BOOST_RV_REF(slist) x, const_iterator i) + { this->splice(p, static_cast(x), i); } + + //! Requires: p must point to an element contained + //! by this list. first and last must point to elements contained in list x. + //! + //! Effects: Transfers the range pointed by first and last from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), in distance(x.begin(), first), + //! and in distance(first, last). + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, slist& x, const_iterator first, const_iterator last) + { this->splice_after(this->previous(p), x, this->previous(first), this->previous(last)); } + + //! Requires: p must point to an element contained + //! by this list. first and last must point to elements contained in list x. + //! + //! Effects: Transfers the range pointed by first and last from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), in distance(x.begin(), first), + //! and in distance(first, last). + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, BOOST_RV_REF(slist) x, const_iterator first, const_iterator last) + { this->splice(p, static_cast(x), first, last); } + + /// @cond + private: + + void priv_push_front (const T &x) + { this->insert(this->cbegin(), x); } + + void priv_push_front (BOOST_RV_REF(T) x) + { this->insert(this->cbegin(), ::boost::move(x)); } + + bool priv_try_shrink(size_type new_size, const_iterator &last_pos) { - for (; beg != end; ++beg){ - this->icont().insert_after(prev.get(), *this->create_node_from_it(beg)); - ++prev; + typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; + while (++(cur_next = cur) != end_n && new_size > 0){ + --new_size; + cur = cur_next; + } + last_pos = const_iterator(cur); + if (cur_next != end_n){ + this->erase_after(last_pos, const_iterator(end_n)); + return true; + } + else{ + return false; } } - template - void priv_create_and_insert_nodes - (const_iterator prev, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_nodes(prev, beg, end, allocator_v1(), std::input_iterator_tag()); - } + template + iterator priv_insert(const_iterator p, BOOST_FWD_REF(U) x) + { return this->insert_after(previous(p), ::boost::forward(x)); } + + template + iterator priv_insert_after(const_iterator prev_pos, BOOST_FWD_REF(U) x) + { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(::boost::forward(x)))); } class insertion_functor; friend class insertion_functor; @@ -1320,97 +1560,25 @@ class slist class insertion_functor { Icont &icont_; - typename Icont::const_iterator prev_; + typedef typename Icont::iterator iiterator; + typedef typename Icont::const_iterator iconst_iterator; + const iconst_iterator prev_; + iiterator ret_; public: insertion_functor(Icont &icont, typename Icont::const_iterator prev) - : icont_(icont), prev_(prev) + : icont_(icont), prev_(prev), ret_(prev.unconst()) {} void operator()(Node &n) - { prev_ = this->icont_.insert_after(prev_, n); } + { + ret_ = this->icont_.insert_after(prev_, n); + } + + iiterator inserted_first() const + { return ret_; } }; - template - void priv_create_and_insert_nodes - (const_iterator prev, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) - { - //Optimized allocation and construction - this->allocate_many_and_construct - (beg, std::distance(beg, end), insertion_functor(this->icont(), prev.get())); - } - - //Default constructed version - void priv_create_and_insert_nodes(const_iterator prev, size_type n) - { - typedef default_construct_iterator default_iterator; - this->priv_create_and_insert_nodes(prev, default_iterator(n), default_iterator()); - } - - //Copy constructed version - void priv_create_and_insert_nodes(const_iterator prev, size_type n, const T& x) - { - typedef constant_iterator cvalue_iterator; - this->priv_create_and_insert_nodes(prev, cvalue_iterator(x, n), cvalue_iterator()); - } - - //Dispatch to detect iterator range or integer overloads - template - void priv_insert_dispatch(const_iterator prev, - InputIter first, InputIter last, - container_detail::false_) - { this->priv_create_and_insert_nodes(prev, first, last); } - - template - void priv_insert_dispatch(const_iterator prev, Integer n, Integer x, container_detail::true_) - { this->priv_create_and_insert_nodes(prev, (size_type)n, x); } - - void priv_fill_assign(size_type n, const T& val) - { - iterator end_n(this->end()); - iterator prev(this->before_begin()); - iterator node(this->begin()); - for ( ; node != end_n && n > 0 ; --n){ - *node = val; - prev = node; - ++node; - } - if (n > 0) - this->priv_create_and_insert_nodes(prev, n, val); - else - this->erase_after(prev, end_n); - } - - template - void priv_assign_dispatch(Int n, Int val, container_detail::true_) - { this->priv_fill_assign((size_type) n, (T)val); } - - template - void priv_assign_dispatch(InpIt first, InpIt last, container_detail::false_) - { - iterator end_n(this->end()); - iterator prev(this->before_begin()); - iterator node(this->begin()); - while (node != end_n && first != last){ - *node = *first; - prev = node; - ++node; - ++first; - } - if (first != last) - this->priv_create_and_insert_nodes(prev, first, last); - else - this->erase_after(prev, end_n); - } - - template - void priv_insert_after_range_dispatch(const_iterator prev_pos, Int n, Int x, container_detail::true_) - { this->priv_create_and_insert_nodes(prev_pos, (size_type)n, x); } - - template - void priv_insert_after_range_dispatch(const_iterator prev_pos, InIter first, InIter last, container_detail::false_) - { this->priv_create_and_insert_nodes(prev_pos, first, last); } - //Functors for member algorithm defaults struct value_less { diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index d91eccd..3e45e7e 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -36,10 +37,11 @@ #include #include #include - -#include +#include +#include //max #include #include +#include //placement new ///@cond @@ -47,10 +49,6 @@ //#define STABLE_VECTOR_ENABLE_INVARIANT_CHECKING -#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) -#include -#endif - ///@endcond namespace boost { @@ -60,24 +58,6 @@ namespace container { namespace stable_vector_detail{ -template -struct smart_ptr_type -{ - typedef typename SmartPtr::value_type value_type; - typedef value_type *pointer; - static pointer get (const SmartPtr &smartptr) - { return smartptr.get();} -}; - -template -struct smart_ptr_type -{ - typedef T value_type; - typedef value_type *pointer; - static pointer get (pointer ptr) - { return ptr;} -}; - template class clear_on_destroy { @@ -93,7 +73,7 @@ class clear_on_destroy { if(do_clear_){ c_.clear(); - c_.clear_pool(); + c_.priv_clear_pool(); } } @@ -104,23 +84,40 @@ class clear_on_destroy bool do_clear_; }; -template -struct node_type_base -{ - node_type_base() - {} - void set_pointer(const VoidPtr &p) - { up = p; } +template +struct node; - VoidPtr up; +template +struct node_base +{ + private: + typedef typename boost::intrusive:: + pointer_traits void_ptr_traits; + typedef typename void_ptr_traits:: + template rebind_pointer + ::type node_base_ptr; + typedef typename void_ptr_traits:: + template rebind_pointer + ::type node_base_ptr_ptr; + + public: + node_base(const node_base_ptr_ptr &n) + : up(n) + {} + + node_base() + : up() + {} + + node_base_ptr_ptr up; }; template -struct node_type - : public node_type_base +struct node + : public node_base { private: - node_type(); + node(); public: T value; @@ -135,87 +132,78 @@ class iterator , Pointer , Reference> { - typedef typename boost::intrusive:: - pointer_traits::template - rebind_pointer::type void_ptr; - typedef typename boost::intrusive:: - pointer_traits::template - rebind_pointer::type const_void_ptr; - typedef node_type node_type_t; - typedef typename boost::intrusive:: - pointer_traits::template - rebind_pointer::type node_type_ptr_t; - typedef typename boost::intrusive:: - pointer_traits::template - rebind_pointer::type const_node_type_ptr_t; - typedef typename boost::intrusive:: - pointer_traits::template - rebind_pointer::type void_ptr_ptr; + typedef boost::intrusive:: + pointer_traits ptr_traits; + typedef typename ptr_traits::template + rebind_pointer::type void_ptr; + typedef node node_type; + typedef node_base node_base_type; + typedef typename ptr_traits::template + rebind_pointer::type node_ptr; + typedef boost::intrusive:: + pointer_traits node_ptr_traits; + typedef typename ptr_traits::template + rebind_pointer::type node_base_ptr; + typedef typename ptr_traits::template + rebind_pointer::type node_base_ptr_ptr; + typedef typename ptr_traits::template + rebind_pointer::type friend_iterator_pointer; - friend class iterator::template rebind_pointer::type>; + friend class iterator; public: typedef std::random_access_iterator_tag iterator_category; typedef T value_type; - typedef typename boost::intrusive:: - pointer_traits::difference_type difference_type; + typedef typename ptr_traits::difference_type difference_type; typedef Pointer pointer; typedef Reference reference; iterator() {} - explicit iterator(node_type_ptr_t pn) - : pn(pn) + explicit iterator(node_ptr p) + : pn(p) {} - iterator(const iterator::template rebind_pointer::type>& x) + iterator(const iterator& x) : pn(x.pn) {} - - private: - static node_type_ptr_t node_ptr_cast(const void_ptr &p) - { - return node_type_ptr_t(static_cast(container_detail::to_raw_pointer(p))); - } - static const_node_type_ptr_t node_ptr_cast(const const_void_ptr &p) - { - return const_node_type_ptr_t(static_cast(container_detail::to_raw_pointer(p))); - } + node_ptr &node_pointer() + { return pn; } - static void_ptr_ptr void_ptr_ptr_cast(const void_ptr &p) - { - return void_ptr_ptr(static_cast(container_detail::to_raw_pointer(p))); - } - - reference dereference() const - { return pn->value; } - bool equal(const iterator& x) const - { return pn==x.pn; } - void increment() - { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+1)); } - void decrement() - { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)-1)); } - void advance(difference_type n) - { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+n)); } - difference_type distance_to(const iterator& x)const - { return void_ptr_ptr_cast(x.pn->up) - void_ptr_ptr_cast(pn->up); } + const node_ptr &node_pointer() const + { return pn; } public: //Pointer like operators - reference operator*() const { return this->dereference(); } - pointer operator->() const { return pointer(&this->dereference()); } + reference operator*() const + { return pn->value; } + + pointer operator->() const + { return ptr_traits::pointer_to(this->operator*()); } //Increment / Decrement - iterator& operator++() - { this->increment(); return *this; } + iterator& operator++() + { + if(node_base_ptr_ptr p = this->pn->up){ + ++p; + this->pn = node_ptr_traits::static_cast_from(*p); + } + return *this; + } iterator operator++(int) { iterator tmp(*this); ++*this; return iterator(tmp); } iterator& operator--() - { this->decrement(); return *this; } + { + if(node_base_ptr_ptr p = this->pn->up){ + --p; + this->pn = node_ptr_traits::static_cast_from(*p); + } + return *this; + } iterator operator--(int) { iterator tmp(*this); --*this; return iterator(tmp); } @@ -229,7 +217,10 @@ class iterator iterator& operator+=(difference_type off) { - pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+off)); + if(node_base_ptr_ptr p = this->pn->up){ + p += off; + this->pn = node_ptr_traits::static_cast_from(*p); + } return *this; } @@ -259,7 +250,7 @@ class iterator friend difference_type operator-(const iterator& left, const iterator& right) { - return void_ptr_ptr_cast(left.pn->up) - void_ptr_ptr_cast(right.pn->up); + return left.pn->up - right.pn->up; } //Comparison operators @@ -270,18 +261,18 @@ class iterator { return l.pn != r.pn; } friend bool operator< (const iterator& l, const iterator& r) - { return void_ptr_ptr_cast(l.pn->up) < void_ptr_ptr_cast(r.pn->up); } + { return l.pn->up < r.pn->up; } friend bool operator<= (const iterator& l, const iterator& r) - { return void_ptr_ptr_cast(l.pn->up) <= void_ptr_ptr_cast(r.pn->up); } + { return l.pn->up <= r.pn->up; } friend bool operator> (const iterator& l, const iterator& r) - { return void_ptr_ptr_cast(l.pn->up) > void_ptr_ptr_cast(r.pn->up); } + { return l.pn->up > r.pn->up; } friend bool operator>= (const iterator& l, const iterator& r) - { return void_ptr_ptr_cast(l.pn->up) >= void_ptr_ptr_cast(r.pn->up); } + { return l.pn->up >= r.pn->up; } - node_type_ptr_t pn; + node_ptr pn; }; template @@ -304,39 +295,131 @@ struct select_multiallocation_chain , typename allocator_traits::value_type> type; }; +template +struct index_traits +{ + typedef boost::intrusive:: + pointer_traits + void_ptr_traits; + typedef stable_vector_detail:: + node_base node_base_type; + typedef typename void_ptr_traits::template + rebind_pointer::type node_base_ptr; + typedef typename void_ptr_traits::template + rebind_pointer::type node_base_ptr_ptr; + typedef boost::intrusive:: + pointer_traits node_base_ptr_traits; + typedef boost::intrusive:: + pointer_traits node_base_ptr_ptr_traits; + typedef typename allocator_traits:: + template portable_rebind_alloc + ::type node_base_ptr_allocator; + typedef ::boost::container::vector + index_type; + typedef typename index_type::iterator index_iterator; + typedef typename index_type::const_iterator const_index_iterator; + typedef typename index_type::size_type size_type; + + static const size_type ExtraPointers = 3; + //Stable vector stores metadata at the end of the index (node_base_ptr vector) with additional 3 pointers: + // back() is this->index.back() - ExtraPointers; + // end node index is *(this->index.end() -3) + // Node cache first is *(this->index.end() - 2); + // Node cache last is this->index.back(); + + static node_base_ptr_ptr ptr_to_node_base_ptr(node_base_ptr &n) + { return node_base_ptr_ptr_traits::pointer_to(n); } + + static void fix_up_pointers(index_iterator first, index_iterator last) + { + while(first != last){ + typedef typename index_type::reference node_base_ptr_ref; + node_base_ptr_ref nbp = *first; + nbp->up = index_traits::ptr_to_node_base_ptr(nbp); + ++first; + } + } + + static index_iterator get_fix_up_end(index_type &index) + { return index.end() - (ExtraPointers - 1); } + + static void fix_up_pointers_from(index_type & index, index_iterator first) + { index_traits::fix_up_pointers(first, index_traits::get_fix_up_end(index)); } + + static void readjust_end_node(index_type &index, node_base_type &end_node) + { + if(!index.empty()){ + node_base_ptr &end_node_idx_ref = *(--index_traits::get_fix_up_end(index)); + end_node_idx_ref = node_base_ptr_traits::pointer_to(end_node); + end_node.up = node_base_ptr_ptr_traits::pointer_to(end_node_idx_ref); + } + else{ + end_node.up = node_base_ptr_ptr(); + } + } + + static void initialize_end_node(index_type &index, node_base_type &end_node, const size_type index_capacity_if_empty) + { + if(index.empty()){ + index.reserve(index_capacity_if_empty + ExtraPointers); + index.resize(ExtraPointers); + node_base_ptr &end_node_ref = *index.data(); + end_node_ref = node_base_ptr_traits::pointer_to(end_node); + end_node.up = index_traits::ptr_to_node_base_ptr(end_node_ref); + } + } + + + #ifdef STABLE_VECTOR_ENABLE_INVARIANT_CHECKING + static bool invariants(index_type &index) + { + for( index_iterator it = index.begin() + , it_end = index_traits::get_fix_up_end(index) + ; it != it_end + ; ++it){ + if((*it)->up != index_traits::ptr_to_node_base_ptr(*it)){ + return false; + } + } + return true; + } + #endif //STABLE_VECTOR_ENABLE_INVARIANT_CHECKING +}; + } //namespace stable_vector_detail #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) -#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) + #if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) -#define STABLE_VECTOR_CHECK_INVARIANT \ -invariant_checker BOOST_JOIN(check_invariant_,__LINE__)(*this); \ -BOOST_JOIN(check_invariant_,__LINE__).touch(); -#else + #define STABLE_VECTOR_CHECK_INVARIANT \ + invariant_checker BOOST_JOIN(check_invariant_,__LINE__)(*this); \ + BOOST_JOIN(check_invariant_,__LINE__).touch(); -#define STABLE_VECTOR_CHECK_INVARIANT + #else //STABLE_VECTOR_ENABLE_INVARIANT_CHECKING -#endif //#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) + #define STABLE_VECTOR_CHECK_INVARIANT + + #endif //#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) #endif //#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) /// @endcond -//! Originally developed by Joaquin M. Lopez Munoz, stable_vector is std::vector +//! Originally developed by Joaquin M. Lopez Munoz, stable_vector is a std::vector //! drop-in replacement implemented as a node container, offering iterator and reference //! stability. //! -//! More details taken the author's blog: +//! Here are the details taken from the author's blog //! ( -//! Introducing stable_vector) +//! Introducing stable_vector): //! //! We present stable_vector, a fully STL-compliant stable container that provides //! most of the features of std::vector except element contiguity. //! //! General properties: stable_vector satisfies all the requirements of a container, //! a reversible container and a sequence and provides all the optional operations -//! present in std::vector. Like std::vector, iterators are random access. +//! present in std::vector. Like std::vector, iterators are random access. //! stable_vector does not provide element contiguity; in exchange for this absence, //! the container is stable, i.e. references and iterators to an element of a stable_vector //! remain valid as long as the element is not erased, and an iterator that has been @@ -353,7 +436,7 @@ BOOST_JOIN(check_invariant_,__LINE__).touch(); //! additional allocation per element. //! //! Exception safety: As stable_vector does not internally copy elements around, some -//! operations provide stronger exception safety guarantees than in std::vector: +//! operations provide stronger exception safety guarantees than in std::vector. #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED template > #else @@ -363,36 +446,40 @@ class stable_vector { ///@cond typedef allocator_traits allocator_traits_type; - typedef typename container_detail:: - move_const_ref_type::type insert_const_ref_type; typedef typename boost::intrusive::pointer_traits :: template rebind_pointer::type void_ptr; - typedef typename boost::intrusive::pointer_traits - ::template - rebind_pointer::type const_void_ptr; - typedef typename boost::intrusive::pointer_traits - ::template - rebind_pointer::type void_ptr_ptr; - typedef typename boost::intrusive::pointer_traits - ::template - rebind_pointer::type const_void_ptr_ptr; - typedef stable_vector_detail::node_type - node_type_t; - typedef typename boost::intrusive::pointer_traits - ::template - rebind_pointer::type node_type_ptr_t; - typedef stable_vector_detail::node_type_base - node_type_base_t; - typedef typename boost::intrusive::pointer_traits - ::template - rebind_pointer::type node_type_base_ptr_t; - typedef ::boost::container::vector::type> impl_type; - typedef typename impl_type::iterator impl_iterator; - typedef typename impl_type::const_iterator const_impl_iterator; + typedef typename allocator_traits_type:: + template portable_rebind_alloc + ::type void_allocator_type; + typedef stable_vector_detail::index_traits + index_traits_type; + typedef typename index_traits_type::node_base_type node_base_type; + typedef typename index_traits_type::node_base_ptr node_base_ptr; + typedef typename index_traits_type:: + node_base_ptr_ptr node_base_ptr_ptr; + typedef typename index_traits_type:: + node_base_ptr_traits node_base_ptr_traits; + typedef typename index_traits_type:: + node_base_ptr_ptr_traits node_base_ptr_ptr_traits; + typedef typename index_traits_type::index_type index_type; + typedef typename index_traits_type::index_iterator index_iterator; + typedef typename index_traits_type:: + const_index_iterator const_index_iterator; + typedef boost::intrusive:: + pointer_traits + ptr_traits; + typedef stable_vector_detail::node node_type; + typedef typename ptr_traits::template + rebind_pointer::type node_ptr; + typedef boost::intrusive:: + pointer_traits node_ptr_traits; + typedef typename ptr_traits::template + rebind_pointer::type const_node_ptr; + typedef boost::intrusive:: + pointer_traits const_node_ptr_traits; + typedef typename node_ptr_traits::reference node_reference; + typedef typename const_node_ptr_traits::reference const_node_reference; typedef ::boost::container::container_detail:: integral_constant allocator_v1; @@ -403,90 +490,170 @@ class stable_vector version::value> alloc_version; typedef typename allocator_traits_type:: template portable_rebind_alloc - ::type node_allocator_type; - - node_type_ptr_t allocate_one() - { return this->allocate_one(alloc_version()); } - - template - node_type_ptr_t allocate_one(AllocatorVersion, - typename boost::container::container_detail::enable_if_c - - ::value>::type * = 0) - { return node_alloc().allocate(1); } - - template - node_type_ptr_t allocate_one(AllocatorVersion, - typename boost::container::container_detail::enable_if_c - - ::value>::type * = 0) - { return node_alloc().allocate_one(); } - - void deallocate_one(node_type_ptr_t p) - { return this->deallocate_one(p, alloc_version()); } - - template - void deallocate_one(node_type_ptr_t p, AllocatorVersion, - typename boost::container::container_detail::enable_if_c - - ::value>::type * = 0) - { node_alloc().deallocate(p, 1); } - - template - void deallocate_one(node_type_ptr_t p, AllocatorVersion, - typename boost::container::container_detail::enable_if_c - - ::value>::type * = 0) - { node_alloc().deallocate_one(p); } - - friend class stable_vector_detail::clear_on_destroy; - ///@endcond - public: - - - // types: - - typedef typename allocator_traits_type::reference reference; - typedef typename allocator_traits_type::const_reference const_reference; - typedef typename allocator_traits_type::pointer pointer; - typedef typename allocator_traits_type::const_pointer const_pointer; - typedef stable_vector_detail::iterator - iterator; - typedef stable_vector_detail::iterator - const_iterator; - typedef typename impl_type::size_type size_type; - typedef typename iterator::difference_type difference_type; - typedef T value_type; - typedef A allocator_type; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - typedef node_allocator_type stored_allocator_type; - - ///@cond - private: - BOOST_COPYABLE_AND_MOVABLE(stable_vector) - static const size_type ExtraPointers = 3; - //This container stores metadata at the end of the void_ptr vector with additional 3 pointers: - // back() is impl.back() - ExtraPointers; - // end node index is impl.end()[-3] - // Node cache first is impl.end()[-2]; - // Node cache last is *impl.back(); - + ::type node_allocator_type; typedef typename stable_vector_detail:: select_multiallocation_chain < node_allocator_type , alloc_version::value >::type multiallocation_chain; + + node_ptr allocate_one() + { return this->allocate_one(alloc_version()); } + + template + node_ptr allocate_one(AllocatorVersion, + typename boost::container::container_detail::enable_if_c + + ::value>::type * = 0) + { return this->priv_node_alloc().allocate(1); } + + template + node_ptr allocate_one(AllocatorVersion, + typename boost::container::container_detail::enable_if_c + + ::value>::type * = 0) + { return this->priv_node_alloc().allocate_one(); } + + void deallocate_one(node_ptr p) + { return this->deallocate_one(p, alloc_version()); } + + template + void deallocate_one(node_ptr p, AllocatorVersion, + typename boost::container::container_detail::enable_if_c + + ::value>::type * = 0) + { this->priv_node_alloc().deallocate(p, 1); } + + template + void deallocate_one(node_ptr p, AllocatorVersion, + typename boost::container::container_detail::enable_if_c + + ::value>::type * = 0) + { this->priv_node_alloc().deallocate_one(p); } + + multiallocation_chain allocate_individual(typename allocator_traits_type::size_type n) + { return this->allocate_individual(n, alloc_version()); } + + struct allocate_individual_rollback + { + allocate_individual_rollback(stable_vector &sv, multiallocation_chain &chain) + : mr_sv(sv), mr_chain(chain) + {} + + ~allocate_individual_rollback() + { + if(!mr_chain.empty()){ + mr_sv.deallocate_individual(mr_chain); + } + } + + stable_vector &mr_sv; + multiallocation_chain &mr_chain; + }; + + template + multiallocation_chain allocate_individual + (typename allocator_traits_type::size_type n, AllocatorVersion, + typename boost::container::container_detail::enable_if_c + + ::value>::type * = 0) + { + multiallocation_chain m; + multiallocation_chain m_ret; + allocate_individual_rollback rollback(*this, m); + while(n--){ + m.push_front(this->allocate_one()); + } + m.swap(m_ret); + return ::boost::move(m_ret); + } + + template + multiallocation_chain allocate_individual + (typename allocator_traits_type::size_type n, AllocatorVersion, + typename boost::container::container_detail::enable_if_c + + ::value>::type * = 0) + { return this->priv_node_alloc().allocate_individual(n); } + + void deallocate_individual(multiallocation_chain &holder) + { this->deallocate_individual(holder, alloc_version()); } + + template + void deallocate_individual(multiallocation_chain & holder, AllocatorVersion, + typename boost::container::container_detail::enable_if_c + + ::value>::type * = 0) + { + while(!holder.empty()){ + this->deallocate_one(holder.pop_front()); + } + } + + template + void deallocate_individual(multiallocation_chain & holder, AllocatorVersion, + typename boost::container::container_detail::enable_if_c + + ::value>::type * = 0) + { this->priv_node_alloc().deallocate_individual(boost::move(holder)); } + + friend class stable_vector_detail::clear_on_destroy; + typedef stable_vector_detail::iterator + < T + , typename allocator_traits::reference + , typename allocator_traits::pointer> iterator_impl; + typedef stable_vector_detail::iterator + < T + , typename allocator_traits::const_reference + , typename allocator_traits::const_pointer> const_iterator_impl; ///@endcond public: + ////////////////////////////////////////////// + // + // types + // + ////////////////////////////////////////////// + typedef T value_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + typedef typename ::boost::container::allocator_traits::const_pointer const_pointer; + typedef typename ::boost::container::allocator_traits::reference reference; + typedef typename ::boost::container::allocator_traits::const_reference const_reference; + typedef typename ::boost::container::allocator_traits::size_type size_type; + typedef typename ::boost::container::allocator_traits::difference_type difference_type; + typedef A allocator_type; + typedef node_allocator_type stored_allocator_type; + typedef BOOST_CONTAINER_IMPDEF(iterator_impl) iterator; + typedef BOOST_CONTAINER_IMPDEF(const_iterator_impl) const_iterator; + typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator) reverse_iterator; + typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator) const_reverse_iterator; + + ///@cond + private: + BOOST_COPYABLE_AND_MOVABLE(stable_vector) + static const size_type ExtraPointers = index_traits_type::ExtraPointers; + + class insert_rollback; + friend class insert_rollback; + + class push_back_rollback; + friend class push_back_rollback; + ///@endcond + + public: + ////////////////////////////////////////////// + // + // construct/copy/destroy + // + ////////////////////////////////////////////// + //! Effects: Default constructs a stable_vector. //! //! Throws: If allocator_type's default constructor throws. //! //! Complexity: Constant. stable_vector() - : internal_data(), impl() + : internal_data(), index() { STABLE_VECTOR_CHECK_INVARIANT; } @@ -497,7 +664,7 @@ class stable_vector //! //! Complexity: Constant. explicit stable_vector(const allocator_type& al) - : internal_data(al),impl(al) + : internal_data(al), index(al) { STABLE_VECTOR_CHECK_INVARIANT; } @@ -510,7 +677,7 @@ class stable_vector //! //! Complexity: Linear to n. explicit stable_vector(size_type n) - : internal_data(),impl() + : internal_data(), index() { stable_vector_detail::clear_on_destroy cod(*this); this->resize(n); @@ -526,10 +693,10 @@ class stable_vector //! //! Complexity: Linear to n. stable_vector(size_type n, const T& t, const allocator_type& al = allocator_type()) - : internal_data(al),impl(al) + : internal_data(al), index(al) { stable_vector_detail::clear_on_destroy cod(*this); - this->insert(this->cbegin(), n, t); + this->insert(this->cend(), n, t); STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -543,10 +710,10 @@ class stable_vector //! Complexity: Linear to the range [first, last). template stable_vector(InputIterator first,InputIterator last, const allocator_type& al = allocator_type()) - : internal_data(al),impl(al) + : internal_data(al), index(al) { stable_vector_detail::clear_on_destroy cod(*this); - this->insert(this->cbegin(), first, last); + this->insert(this->cend(), first, last); STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -558,12 +725,12 @@ class stable_vector //! Complexity: Linear to the elements x contains. stable_vector(const stable_vector& x) : internal_data(allocator_traits:: - select_on_container_copy_construction(x.node_alloc())) - , impl(allocator_traits:: - select_on_container_copy_construction(x.impl.get_stored_allocator())) + select_on_container_copy_construction(x.priv_node_alloc())) + , index(allocator_traits:: + select_on_container_copy_construction(x.index.get_stored_allocator())) { stable_vector_detail::clear_on_destroy cod(*this); - this->insert(this->cbegin(), x.begin(), x.end()); + this->insert(this->cend(), x.begin(), x.end()); STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -574,7 +741,7 @@ class stable_vector //! //! Complexity: Constant. stable_vector(BOOST_RV_REF(stable_vector) x) - : internal_data(boost::move(x.node_alloc())), impl(boost::move(x.impl)) + : internal_data(boost::move(x.priv_node_alloc())), index(boost::move(x.index)) { this->priv_swap_members(x); } @@ -585,10 +752,10 @@ class stable_vector //! //! Complexity: Linear to the elements x contains. stable_vector(const stable_vector& x, const allocator_type &a) - : internal_data(a), impl(a) + : internal_data(a), index(a) { stable_vector_detail::clear_on_destroy cod(*this); - this->insert(this->cbegin(), x.begin(), x.end()); + this->insert(this->cend(), x.begin(), x.end()); STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -600,14 +767,14 @@ class stable_vector //! //! Complexity: Constant if a == x.get_allocator(), linear otherwise stable_vector(BOOST_RV_REF(stable_vector) x, const allocator_type &a) - : internal_data(a), impl(a) + : internal_data(a), index(a) { - if(this->node_alloc() == x.node_alloc()){ + if(this->priv_node_alloc() == x.priv_node_alloc()){ this->priv_swap_members(x); } else{ stable_vector_detail::clear_on_destroy cod(*this); - this->insert(this->cbegin(), x.begin(), x.end()); + this->insert(this->cend(), x.begin(), x.end()); STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -622,7 +789,7 @@ class stable_vector ~stable_vector() { this->clear(); - clear_pool(); + this->priv_clear_pool(); } //! Effects: Makes *this contain the same elements as x. @@ -637,16 +804,16 @@ class stable_vector { STABLE_VECTOR_CHECK_INVARIANT; if (&x != this){ - node_allocator_type &this_alloc = this->node_alloc(); - const node_allocator_type &x_alloc = x.node_alloc(); + node_allocator_type &this_alloc = this->priv_node_alloc(); + const node_allocator_type &x_alloc = x.priv_node_alloc(); container_detail::bool_ flag; if(flag && this_alloc != x_alloc){ this->clear(); this->shrink_to_fit(); } - container_detail::assign_alloc(this->node_alloc(), x.node_alloc(), flag); - container_detail::assign_alloc(this->impl.get_stored_allocator(), x.impl.get_stored_allocator(), flag); + container_detail::assign_alloc(this->priv_node_alloc(), x.priv_node_alloc(), flag); + container_detail::assign_alloc(this->index.get_stored_allocator(), x.index.get_stored_allocator(), flag); this->assign(x.begin(), x.end()); } return *this; @@ -663,22 +830,21 @@ class stable_vector stable_vector& operator=(BOOST_RV_REF(stable_vector) x) { if (&x != this){ - node_allocator_type &this_alloc = this->node_alloc(); - node_allocator_type &x_alloc = x.node_alloc(); + node_allocator_type &this_alloc = this->priv_node_alloc(); + node_allocator_type &x_alloc = x.priv_node_alloc(); //If allocators are equal we can just swap pointers if(this_alloc == x_alloc){ //Destroy objects but retain memory this->clear(); - this->impl = boost::move(x.impl); + this->index = boost::move(x.index); this->priv_swap_members(x); //Move allocator if needed container_detail::bool_ flag; - container_detail::move_alloc(this->node_alloc(), x.node_alloc(), flag); + container_detail::move_alloc(this->priv_node_alloc(), x.priv_node_alloc(), flag); } //If unequal allocators, then do a one by one move else{ - typedef typename std::iterator_traits::iterator_category ItCat; this->assign( boost::make_move_iterator(x.begin()) , boost::make_move_iterator(x.end())); } @@ -686,6 +852,18 @@ class stable_vector return *this; } + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void assign(size_type n, const T& t) + { + typedef constant_iterator cvalue_iterator; + this->assign(cvalue_iterator(t, n), cvalue_iterator()); + } + //! Effects: Assigns the the range [first, last) to *this. //! //! Throws: If memory allocation throws or @@ -693,21 +871,25 @@ class stable_vector //! //! Complexity: Linear to n. template - void assign(InputIterator first,InputIterator last) + void assign(InputIterator first,InputIterator last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + >::type * = 0 + #endif + ) { - assign_dispatch(first, last, boost::is_integral()); - } - - - //! Effects: Assigns the n copies of val to *this. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void assign(size_type n,const T& t) - { - typedef constant_iterator cvalue_iterator; - return assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_()); + STABLE_VECTOR_CHECK_INVARIANT; + iterator first1 = this->begin(); + iterator last1 = this->end(); + for ( ; first1 != last1 && first != last; ++first1, ++first) + *first1 = *first; + if (first == last){ + this->erase(first1, last1); + } + else{ + this->insert(last1, first, last); + } } //! Effects: Returns a copy of the internal allocator. @@ -715,7 +897,8 @@ class stable_vector //! Throws: If allocator's copy constructor throws. //! //! Complexity: Constant. - allocator_type get_allocator()const {return this->node_alloc();} + allocator_type get_allocator() const + { return this->priv_node_alloc(); } //! Effects: Returns a reference to the internal allocator. //! @@ -725,7 +908,7 @@ class stable_vector //! //! Note: Non-standard extension. const stored_allocator_type &get_stored_allocator() const BOOST_CONTAINER_NOEXCEPT - { return node_alloc(); } + { return this->priv_node_alloc(); } //! Effects: Returns a reference to the internal allocator. //! @@ -735,8 +918,13 @@ class stable_vector //! //! Note: Non-standard extension. stored_allocator_type &get_stored_allocator() BOOST_CONTAINER_NOEXCEPT - { return node_alloc(); } + { return this->priv_node_alloc(); } + ////////////////////////////////////////////// + // + // iterators + // + ////////////////////////////////////////////// //! Effects: Returns an iterator to the first element contained in the stable_vector. //! @@ -744,7 +932,7 @@ class stable_vector //! //! Complexity: Constant. iterator begin() - { return (impl.empty()) ? end(): iterator(node_ptr_cast(impl.front())) ; } + { return (this->index.empty()) ? this->end(): iterator(node_ptr_traits::static_cast_from(this->index.front())); } //! Effects: Returns a const_iterator to the first element contained in the stable_vector. //! @@ -752,21 +940,23 @@ class stable_vector //! //! Complexity: Constant. const_iterator begin()const - { return (impl.empty()) ? cend() : const_iterator(node_ptr_cast(impl.front())) ; } + { return (this->index.empty()) ? this->cend() : const_iterator(node_ptr_traits::static_cast_from(this->index.front())) ; } //! Effects: Returns an iterator to the end of the stable_vector. //! //! Throws: Nothing. //! //! Complexity: Constant. - iterator end() {return iterator(get_end_node());} + iterator end() + { return iterator(this->priv_get_end_node()); } //! Effects: Returns a const_iterator to the end of the stable_vector. //! //! Throws: Nothing. //! //! Complexity: Constant. - const_iterator end()const {return const_iterator(get_end_node());} + const_iterator end() const + { return const_iterator(this->priv_get_end_node()); } //! Effects: Returns a reverse_iterator pointing to the beginning //! of the reversed stable_vector. @@ -774,7 +964,8 @@ class stable_vector //! Throws: Nothing. //! //! Complexity: Constant. - reverse_iterator rbegin() {return reverse_iterator(this->end());} + reverse_iterator rbegin() + { return reverse_iterator(this->end()); } //! Effects: Returns a const_reverse_iterator pointing to the beginning //! of the reversed stable_vector. @@ -782,7 +973,8 @@ class stable_vector //! Throws: Nothing. //! //! Complexity: Constant. - const_reverse_iterator rbegin()const {return const_reverse_iterator(this->end());} + const_reverse_iterator rbegin() const + { return const_reverse_iterator(this->end()); } //! Effects: Returns a reverse_iterator pointing to the end //! of the reversed stable_vector. @@ -790,7 +982,8 @@ class stable_vector //! Throws: Nothing. //! //! Complexity: Constant. - reverse_iterator rend() {return reverse_iterator(this->begin());} + reverse_iterator rend() + { return reverse_iterator(this->begin()); } //! Effects: Returns a const_reverse_iterator pointing to the end //! of the reversed stable_vector. @@ -798,21 +991,24 @@ class stable_vector //! Throws: Nothing. //! //! Complexity: Constant. - const_reverse_iterator rend()const {return const_reverse_iterator(this->begin());} + const_reverse_iterator rend()const + { return const_reverse_iterator(this->begin()); } //! Effects: Returns a const_iterator to the first element contained in the stable_vector. //! //! Throws: Nothing. //! //! Complexity: Constant. - const_iterator cbegin()const {return this->begin();} + const_iterator cbegin() const + { return this->begin(); } //! Effects: Returns a const_iterator to the end of the stable_vector. //! //! Throws: Nothing. //! //! Complexity: Constant. - const_iterator cend()const {return this->end();} + const_iterator cend()const + { return this->end(); } //! Effects: Returns a const_reverse_iterator pointing to the beginning //! of the reversed stable_vector. @@ -820,7 +1016,8 @@ class stable_vector //! Throws: Nothing. //! //! Complexity: Constant. - const_reverse_iterator crbegin()const{return this->rbegin();} + const_reverse_iterator crbegin() const + { return this->rbegin(); } //! Effects: Returns a const_reverse_iterator pointing to the end //! of the reversed stable_vector. @@ -828,41 +1025,14 @@ class stable_vector //! Throws: Nothing. //! //! Complexity: Constant. - const_reverse_iterator crend()const {return this->rend();} + const_reverse_iterator crend()const + { return this->rend(); } - //! Effects: Returns the number of the elements contained in the stable_vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return impl.empty() ? 0 : (impl.size() - ExtraPointers); } - - //! Effects: Returns the largest possible size of the stable_vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return impl.max_size() - ExtraPointers; } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { - if(!impl.capacity()){ - return 0; - } - else{ - const size_type num_nodes = this->impl.size() + this->internal_data.pool_size; - const size_type num_buck = this->impl.capacity(); - return (num_nodes < num_buck) ? num_nodes : num_buck; - } - } + ////////////////////////////////////////////// + // + // capacity + // + ////////////////////////////////////////////// //! Effects: Returns true if the stable_vector contains no elements. //! @@ -870,23 +1040,27 @@ class stable_vector //! //! Complexity: Constant. bool empty() const - { return impl.empty() || impl.size() == ExtraPointers; } + { return this->index.size() <= ExtraPointers; } - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. + //! Effects: Returns the number of the elements contained in the stable_vector. //! - //! Throws: If memory allocation throws, or T's copy constructor throws. + //! Throws: Nothing. //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type n, const T& t) + //! Complexity: Constant. + size_type size() const { - STABLE_VECTOR_CHECK_INVARIANT; - if(n > size()) - this->insert(this->cend(), n - this->size(), t); - else if(n < this->size()) - this->erase(this->cbegin() + n, this->cend()); + const size_type index_size = this->index.size(); + return index_size ? (index_size - ExtraPointers) : 0; } + //! Effects: Returns the largest possible size of the stable_vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return this->index.max_size() - ExtraPointers; } + //! Effects: Inserts or erases elements at the end such that //! the size becomes n. New elements are default constructed. //! @@ -897,12 +1071,44 @@ class stable_vector { typedef default_construct_iterator default_iterator; STABLE_VECTOR_CHECK_INVARIANT; - if(n > size()) + if(n > this->size()) this->insert(this->cend(), default_iterator(n - this->size()), default_iterator()); else if(n < this->size()) this->erase(this->cbegin() + n, this->cend()); } + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type n, const T& t) + { + STABLE_VECTOR_CHECK_INVARIANT; + if(n > this->size()) + this->insert(this->cend(), n - this->size(), t); + else if(n < this->size()) + this->erase(this->cbegin() + n, this->cend()); + } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { + const size_type index_size = this->index.size(); + BOOST_ASSERT(!index_size || index_size >= ExtraPointers); + const size_type bucket_extra_capacity = this->index.capacity()- index_size; + const size_type node_extra_capacity = this->internal_data.pool_size; + const size_type extra_capacity = (bucket_extra_capacity < node_extra_capacity) + ? bucket_extra_capacity : node_extra_capacity; + return (index_size ? (index_size - ExtraPointers + extra_capacity) : index_size); + } + //! Effects: If n is less than or equal to capacity(), this call has no //! effect. Otherwise, it is a request for allocation of additional memory. //! If the request is successful, then capacity() is greater than or equal to @@ -915,24 +1121,104 @@ class stable_vector if(n > this->max_size()) throw std::bad_alloc(); - size_type size = this->size(); + size_type size = this->size(); size_type old_capacity = this->capacity(); if(n > old_capacity){ - this->initialize_end_node(n); - const void * old_ptr = &impl[0]; - impl.reserve(n + ExtraPointers); - bool realloced = &impl[0] != old_ptr; + index_traits_type::initialize_end_node(this->index, this->internal_data.end_node, n); + const void * old_ptr = &index[0]; + this->index.reserve(n + ExtraPointers); + bool realloced = &index[0] != old_ptr; //Fix the pointers for the newly allocated buffer if(realloced){ - this->align_nodes(impl.begin(), impl.begin()+size+1); + index_traits_type::fix_up_pointers_from(this->index, this->index.begin()); } //Now fill pool if data is not enough if((n - size) > this->internal_data.pool_size){ - this->add_to_pool((n - size) - this->internal_data.pool_size); + this->priv_increase_pool((n - size) - this->internal_data.pool_size); } } } + //! Effects: Tries to deallocate the excess of memory created + //! with previous allocations. The size of the stable_vector is unchanged + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { + if(this->capacity()){ + //First empty allocated node pool + this->priv_clear_pool(); + //If empty completely destroy the index, let's recover default-constructed state + if(this->empty()){ + this->index.clear(); + this->index.shrink_to_fit(); + this->internal_data.end_node.up = node_base_ptr_ptr(); + } + //Otherwise, try to shrink-to-fit the index and readjust pointers if necessary + else{ + const void* old_ptr = &index[0]; + this->index.shrink_to_fit(); + bool realloced = &index[0] != old_ptr; + //Fix the pointers for the newly allocated buffer + if(realloced){ + index_traits_type::fix_up_pointers_from(this->index, this->index.begin()); + } + } + } + } + + ////////////////////////////////////////////// + // + // element access + // + ////////////////////////////////////////////// + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first + //! element of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() + { return static_cast(*this->index.front()).value; } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first + //! element of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const + { return static_cast(*this->index.front()).value; } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the last + //! element of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference back() + { return static_cast(*this->index[this->size() - ExtraPointers]).value; } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the last + //! element of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference back()const + { return static_cast(*this->index[this->size() - ExtraPointers]).value; } + //! Requires: size() > n. //! //! Effects: Returns a reference to the nth element @@ -941,7 +1227,8 @@ class stable_vector //! Throws: Nothing. //! //! Complexity: Constant. - reference operator[](size_type n){return value(impl[n]);} + reference operator[](size_type n) + { return static_cast(*this->index[n]).value; } //! Requires: size() > n. //! @@ -951,7 +1238,8 @@ class stable_vector //! Throws: Nothing. //! //! Complexity: Constant. - const_reference operator[](size_type n)const{return value(impl[n]);} + const_reference operator[](size_type n)const + { return static_cast(*this->index[n]).value; } //! Requires: size() > n. //! @@ -963,7 +1251,7 @@ class stable_vector //! Complexity: Constant. reference at(size_type n) { - if(n>=size()) + if(n>=this->size()) throw std::out_of_range("invalid subscript at stable_vector::at"); return operator[](n); } @@ -978,158 +1266,16 @@ class stable_vector //! Complexity: Constant. const_reference at(size_type n)const { - if(n>=size()) + if(n>=this->size()) throw std::out_of_range("invalid subscript at stable_vector::at"); return operator[](n); } - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first - //! element of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference front() - { return value(impl.front()); } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first - //! element of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference front()const - { return value(impl.front()); } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the last - //! element of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference back() - { return value(*(&impl.back() - ExtraPointers)); } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the last - //! element of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference back()const - { return value(*(&impl.back() - ExtraPointers)); } - - //! Effects: Inserts a copy of x at the end of the stable_vector. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_back(insert_const_ref_type x) - { return priv_push_back(x); } - - #if defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - void push_back(T &x) { push_back(const_cast(x)); } - - template - void push_back(const U &u, typename container_detail::enable_if_c - ::value && !::boost::has_move_emulation_enabled::value >::type* =0) - { return priv_push_back(u); } - #endif - - //! Effects: Constructs a new element in the end of the stable_vector - //! and moves the resources of mx to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - void push_back(BOOST_RV_REF(T) t) - { this->insert(end(), boost::move(t)); } - - //! Effects: Removes the last element from the stable_vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant time. - void pop_back() - { this->erase(this->end()-1); } - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before position. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: 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_CONTAINER_DOXYGEN_INVOKED) - iterator insert(const_iterator position, T &x) { return this->insert(position, const_cast(x)); } - - template - iterator insert(const_iterator position, const U &u, typename container_detail::enable_if_c - ::value && !::boost::has_move_emulation_enabled::value >::type* =0) - { return this->priv_insert(position, u); } - #endif - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Insert a new element before position with mx's resources. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: If position is end(), amortized constant time - //! Linear time otherwise. - iterator insert(const_iterator position, BOOST_RV_REF(T) x) - { - typedef repeat_iterator repeat_it; - typedef boost::move_iterator repeat_move_it; - //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->begin() + pos_n); - } - - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert n copies of x before pos. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void insert(const_iterator position, size_type n, const T& t) - { - STABLE_VECTOR_CHECK_INVARIANT; - this->insert_not_iter(position, n, t); - } - - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before pos. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws or T's copy constructor throws. - //! - //! Complexity: Linear to std::distance [first, last). - template - void insert(const_iterator position,InputIterator first, InputIterator last) - { - STABLE_VECTOR_CHECK_INVARIANT; - this->insert_iter(position,first,last, - boost::mpl::not_ >()); - } + ////////////////////////////////////////////// + // + // modifiers + // + ////////////////////////////////////////////// #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -1206,6 +1352,147 @@ class stable_vector #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: Inserts a copy of x at the end of the stable_vector. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_back(const T &x); + + //! Effects: Constructs a new element in the end of the stable_vector + //! and moves the resources of mx to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_back(T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) + #endif + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before position. + //! + //! Returns: An iterator to the inserted element. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + iterator insert(const_iterator position, const T &x); + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Insert a new element before position with mx's resources. + //! + //! Returns: an iterator to the inserted element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + iterator insert(const_iterator position, T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator) + #endif + + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert n copies of x before position. + //! + //! Returns: an iterator to the first inserted element or position if n is 0. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + iterator insert(const_iterator position, size_type n, const T& t) + { + STABLE_VECTOR_CHECK_INVARIANT; + typedef constant_iterator cvalue_iterator; + return this->insert(position, cvalue_iterator(t, n), cvalue_iterator()); + } + + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before pos. + //! + //! Returns: an iterator to the first inserted element or position if first == last. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws or T's copy constructor throws. + //! + //! Complexity: Linear to std::distance [first, last). + template + iterator insert(const_iterator position,InputIterator first, InputIterator last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) + { + STABLE_VECTOR_CHECK_INVARIANT; + const size_type pos_n = position - this->cbegin(); + for(; first != last; ++first){ + this->emplace(position, *first); + } + return this->begin() + pos_n; + } + + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator insert(const_iterator position, FwdIt first, FwdIt last + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !container_detail::is_input_iterator::value + >::type * = 0 + ) + { + const size_type num_new = (size_type)std::distance(first,last); + const size_type pos = static_cast(position - this->cbegin()); + if(num_new){ + //Fills the node pool and inserts num_new null pointers in pos. + //If a new buffer was needed fixes up pointers up to pos so + //past-new nodes are not aligned until the end of this function + //or in a rollback in case of exception + index_iterator it_past_newly_constructed(this->priv_insert_forward_non_templated(pos, num_new)); + const index_iterator it_past_new(it_past_newly_constructed + num_new); + { + //Prepare rollback + insert_rollback rollback(*this, it_past_newly_constructed, it_past_new); + while(first != last){ + const node_ptr p = this->priv_get_from_pool(); + BOOST_ASSERT(!!p); + //Put it in the index so rollback can return it in pool if construct_in_place throws + *it_past_newly_constructed = p; + //Constructs and fixes up pointers This can throw + this->priv_build_node_from_it(p, it_past_newly_constructed, first); + ++first; + ++it_past_newly_constructed; + } + //rollback.~insert_rollback() called in case of exception + } + //Fix up pointers for past-new nodes (new nodes were fixed during construction) and + //nodes before insertion position in priv_insert_forward_non_templated(...) + index_traits_type::fix_up_pointers_from(this->index, it_past_newly_constructed); + } + return this->begin() + pos; + } + #endif + + //! Effects: Removes the last element from the stable_vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + void pop_back() + { this->erase(--this->cend()); } + //! Effects: Erases the element at position pos. //! //! Throws: Nothing. @@ -1216,10 +1503,10 @@ class stable_vector { STABLE_VECTOR_CHECK_INVARIANT; difference_type d = position - this->cbegin(); - impl_iterator it = impl.begin() + d; - this->delete_node(*it); - it = impl.erase(it); - this->align_nodes(it, get_last_align()); + index_iterator it = this->index.begin() + d; + this->priv_delete_node(position.node_pointer()); + it = this->index.erase(it); + index_traits_type::fix_up_pointers_from(this->index, it); return this->begin()+d; } @@ -1230,7 +1517,19 @@ class stable_vector //! Complexity: Linear to the distance between first and last //! plus linear to the elements between pos and the last element. iterator erase(const_iterator first, const_iterator last) - { return priv_erase(first, last, alloc_version()); } + { + STABLE_VECTOR_CHECK_INVARIANT; + difference_type d1 = first - this->cbegin(), d2 = last - this->cbegin(); + if(d1 != d2){ + index_iterator it1(this->index.begin() + d1), it2(it1 + (d2 - d1)); + for(index_iterator it = it1; it != it2; ++it){ + this->priv_delete_node(node_ptr_traits::static_cast_from(*it)); + } + const index_iterator e = this->index.erase(it1, it2); + index_traits_type::fix_up_pointers_from(this->index, e); + } + return iterator(this->begin() + d1); + } //! Effects: Swaps the contents of *this and x. //! @@ -1241,9 +1540,9 @@ class stable_vector { STABLE_VECTOR_CHECK_INVARIANT; container_detail::bool_ flag; - container_detail::swap_alloc(this->node_alloc(), x.node_alloc(), flag); + container_detail::swap_alloc(this->priv_node_alloc(), x.priv_node_alloc(), flag); //vector's allocator is swapped here - this->impl.swap(x.impl); + this->index.swap(x.index); this->priv_swap_members(x); } @@ -1255,456 +1554,269 @@ class stable_vector void clear() { this->erase(this->cbegin(),this->cend()); } - //! Effects: Tries to deallocate the excess of memory created - //! with previous allocations. The size of the stable_vector is unchanged - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() + /// @cond + + private: + + class insert_rollback { - if(this->capacity()){ - //First empty allocated node pool - this->clear_pool(); - //If empty completely destroy the index, let's recover default-constructed state - if(this->empty()){ - this->impl.clear(); - this->impl.shrink_to_fit(); - this->internal_data.set_end_pointer_to_default_constructed(); - } - //Otherwise, try to shrink-to-fit the index and readjust pointers if necessary - else{ - const size_type size = this->size(); - const void* old_ptr = &impl[0]; - this->impl.shrink_to_fit(); - bool realloced = &impl[0] != old_ptr; - //Fix the pointers for the newly allocated buffer - if(realloced){ - this->align_nodes(impl.begin(), impl.begin()+size+1); - } + public: + + insert_rollback(stable_vector &sv, index_iterator &it_past_constructed, const index_iterator &it_past_new) + : m_sv(sv), m_it_past_constructed(it_past_constructed), m_it_past_new(it_past_new) + {} + + ~insert_rollback() + { + if(m_it_past_constructed != m_it_past_new){ + m_sv.priv_put_in_pool(node_ptr_traits::static_cast_from(*m_it_past_constructed)); + index_iterator e = m_sv.index.erase(m_it_past_constructed, m_it_past_new); + index_traits_type::fix_up_pointers_from(m_sv.index, e); } } + + private: + stable_vector &m_sv; + index_iterator &m_it_past_constructed; + const index_iterator &m_it_past_new; + }; + + class push_back_rollback + { + public: + push_back_rollback(stable_vector &sv, const node_ptr &p) + : m_sv(sv), m_p(p) + {} + + ~push_back_rollback() + { + if(m_p){ + m_sv.priv_put_in_pool(m_p); + } + } + + void release() + { m_p = node_ptr(); } + + private: + stable_vector &m_sv; + node_ptr m_p; + }; + + index_iterator priv_insert_forward_non_templated(size_type pos, size_type num_new) + { + index_traits_type::initialize_end_node(this->index, this->internal_data.end_node, num_new); + + //Now try to fill the pool with new data + if(this->internal_data.pool_size < num_new){ + this->priv_increase_pool(num_new - this->internal_data.pool_size); + } + + //Now try to make room in the vector + const node_base_ptr_ptr old_buffer = this->index.data(); + this->index.insert(this->index.begin() + pos, num_new, node_ptr()); + bool new_buffer = this->index.data() != old_buffer; + + //Fix the pointers for the newly allocated buffer + const index_iterator index_beg = this->index.begin(); + if(new_buffer){ + index_traits_type::fix_up_pointers(index_beg, index_beg + pos); + } + return index_beg + pos; } - /// @cond + bool priv_capacity_bigger_than_size() const + { + return this->index.capacity() > this->index.size() && + this->internal_data.pool_size > 0; + } + + template + void priv_push_back(BOOST_MOVE_CATCH_FWD(U) x) + { + if(this->priv_capacity_bigger_than_size()){ + //Enough memory in the pool and in the index + const node_ptr p = this->priv_get_from_pool(); + BOOST_ASSERT(!!p); + { + push_back_rollback rollback(*this, p); + //This might throw + this->priv_build_node_from_convertible(p, ::boost::forward(x)); + rollback.release(); + } + //This can't throw as there is room for a new elements in the index + index_iterator new_index = this->index.insert(this->index.end() - ExtraPointers, p); + index_traits_type::fix_up_pointers_from(this->index, new_index); + } + else{ + this->insert(this->cend(), ::boost::forward(x)); + } + } iterator priv_insert(const_iterator position, const value_type &t) { typedef constant_iterator cvalue_iterator; - return this->insert_iter(position, cvalue_iterator(t, 1), cvalue_iterator(), std::forward_iterator_tag()); + return this->insert(position, cvalue_iterator(t, 1), cvalue_iterator()); } - void priv_push_back(const value_type &t) - { this->insert(end(), t); } - - template - void clear_pool(AllocatorVersion, - typename boost::container::container_detail::enable_if_c - - ::value>::type * = 0) + iterator priv_insert(const_iterator position, BOOST_RV_REF(T) x) { - if(!impl.empty() && impl.back()){ - void_ptr &pool_first_ref = impl.end()[-2]; - void_ptr &pool_last_ref = impl.back(); + typedef repeat_iterator repeat_it; + typedef boost::move_iterator repeat_move_it; + //Just call more general insert(pos, size, value) and return iterator + return this->insert(position, repeat_move_it(repeat_it(x, 1)), repeat_move_it(repeat_it())); + } + + void priv_clear_pool() + { + if(!this->index.empty() && this->index.back()){ + node_base_ptr &pool_first_ref = *(this->index.end() - 2); + node_base_ptr &pool_last_ref = this->index.back(); multiallocation_chain holder; - holder.incorporate_after(holder.before_begin(), pool_first_ref, pool_last_ref, this->internal_data.pool_size); - while(!holder.empty()){ - node_type_ptr_t n = holder.front(); - holder.pop_front(); - this->deallocate_one(n); - } + holder.incorporate_after( holder.before_begin() + , node_ptr_traits::static_cast_from(pool_first_ref) + , node_ptr_traits::static_cast_from(pool_last_ref) + , internal_data.pool_size); + this->deallocate_individual(holder); pool_first_ref = pool_last_ref = 0; this->internal_data.pool_size = 0; } } - template - void clear_pool(AllocatorVersion, - typename boost::container::container_detail::enable_if_c - - ::value>::type * = 0) + void priv_increase_pool(size_type n) { - if(!impl.empty() && impl.back()){ - void_ptr &pool_first_ref = impl.end()[-2]; - void_ptr &pool_last_ref = impl.back(); - multiallocation_chain holder; - holder.incorporate_after(holder.before_begin(), pool_first_ref, pool_last_ref, internal_data.pool_size); - node_alloc().deallocate_individual(boost::move(holder)); - pool_first_ref = pool_last_ref = 0; - this->internal_data.pool_size = 0; - } - } - - void clear_pool() - { - this->clear_pool(alloc_version()); - } - - void add_to_pool(size_type n) - { - this->add_to_pool(n, alloc_version()); - } - - template - void add_to_pool(size_type n, AllocatorVersion, - typename boost::container::container_detail::enable_if_c - - ::value>::type * = 0) - { - size_type remaining = n; - while(remaining--){ - this->put_in_pool(this->allocate_one()); - } - } - - template - void add_to_pool(size_type n, AllocatorVersion, - typename boost::container::container_detail::enable_if_c - - ::value>::type * = 0) - { - void_ptr &pool_first_ref = impl.end()[-2]; - void_ptr &pool_last_ref = impl.back(); + node_base_ptr &pool_first_ref = *(this->index.end() - 2); + node_base_ptr &pool_last_ref = this->index.back(); multiallocation_chain holder; - holder.incorporate_after(holder.before_begin(), pool_first_ref, pool_last_ref, internal_data.pool_size); - //BOOST_STATIC_ASSERT((::boost::has_move_emulation_enabled::value == true)); - multiallocation_chain m (node_alloc().allocate_individual(n)); + holder.incorporate_after( holder.before_begin() + , node_ptr_traits::static_cast_from(pool_first_ref) + , node_ptr_traits::static_cast_from(pool_last_ref) + , internal_data.pool_size); + multiallocation_chain m (this->allocate_individual(n)); holder.splice_after(holder.before_begin(), m, m.before_begin(), m.last(), n); this->internal_data.pool_size += n; - std::pair data(holder.extract_data()); + std::pair data(holder.extract_data()); pool_first_ref = data.first; pool_last_ref = data.second; } - void put_in_pool(node_type_ptr_t p) + void priv_put_in_pool(const node_ptr &p) { - void_ptr &pool_first_ref = impl.end()[-2]; - void_ptr &pool_last_ref = impl.back(); + node_base_ptr &pool_first_ref = *(this->index.end()-2); + node_base_ptr &pool_last_ref = this->index.back(); multiallocation_chain holder; - holder.incorporate_after(holder.before_begin(), pool_first_ref, pool_last_ref, internal_data.pool_size); + holder.incorporate_after( holder.before_begin() + , node_ptr_traits::static_cast_from(pool_first_ref) + , node_ptr_traits::static_cast_from(pool_last_ref) + , internal_data.pool_size); holder.push_front(p); ++this->internal_data.pool_size; - std::pair ret(holder.extract_data()); + std::pair ret(holder.extract_data()); pool_first_ref = ret.first; - pool_last_ref = ret.second; + pool_last_ref = ret.second; } - node_type_ptr_t get_from_pool() + node_ptr priv_get_from_pool() { - if(!impl.back()){ - return node_type_ptr_t(0); + //Precondition: index is not empty + BOOST_ASSERT(!this->index.empty()); + node_base_ptr &pool_first_ref = *(this->index.end() - 2); + node_base_ptr &pool_last_ref = this->index.back(); + multiallocation_chain holder; + holder.incorporate_after( holder.before_begin() + , node_ptr_traits::static_cast_from(pool_first_ref) + , node_ptr_traits::static_cast_from(pool_last_ref) + , internal_data.pool_size); + node_ptr ret = holder.pop_front(); + --this->internal_data.pool_size; + if(!internal_data.pool_size){ + pool_first_ref = pool_last_ref = node_ptr(); } else{ - void_ptr &pool_first_ref = impl.end()[-2]; - void_ptr &pool_last_ref = impl.back(); - multiallocation_chain holder; - holder.incorporate_after(holder.before_begin(), pool_first_ref, pool_last_ref, internal_data.pool_size); - node_type_ptr_t ret = holder.front(); - holder.pop_front(); - --this->internal_data.pool_size; - if(!internal_data.pool_size){ - pool_first_ref = pool_last_ref = void_ptr(0); - } - else{ - std::pair data(holder.extract_data()); - pool_first_ref = data.first; - pool_last_ref = data.second; - } - return ret; + std::pair data(holder.extract_data()); + pool_first_ref = data.first; + pool_last_ref = data.second; } + return ret; } - void insert_iter_prolog(size_type n, difference_type d) + node_ptr priv_get_end_node() const { - initialize_end_node(n); - const void* old_ptr = &impl[0]; - //size_type old_capacity = capacity(); - //size_type old_size = size(); - impl.insert(impl.begin()+d, n, 0); - bool realloced = &impl[0] != old_ptr; - //Fix the pointers for the newly allocated buffer - if(realloced){ - align_nodes(impl.begin(), impl.begin()+d); - } + return node_ptr_traits::pointer_to + (static_cast(const_cast(this->internal_data.end_node))); } - template - void assign_dispatch(InputIterator first, InputIterator last, boost::mpl::false_) + void priv_delete_node(const node_ptr &n) { - STABLE_VECTOR_CHECK_INVARIANT; - iterator first1 = this->begin(); - iterator last1 = this->end(); - for ( ; first1 != last1 && first != last; ++first1, ++first) - *first1 = *first; - if (first == last){ - this->erase(first1, last1); - } - else{ - this->insert(last1, first, last); - } - } - - template - void assign_dispatch(Integer n, Integer t, boost::mpl::true_) - { - typedef constant_iterator cvalue_iterator; - this->assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_()); - } - - iterator priv_erase(const_iterator first, const_iterator last, allocator_v1) - { - STABLE_VECTOR_CHECK_INVARIANT; - difference_type d1 = first - this->cbegin(), d2 = last - this->cbegin(); - if(d1 != d2){ - impl_iterator it1(impl.begin() + d1), it2(impl.begin() + d2); - for(impl_iterator it = it1; it != it2; ++it) - this->delete_node(*it); - impl_iterator e = impl.erase(it1, it2); - this->align_nodes(e, get_last_align()); - } - return iterator(this->begin() + d1); - } - - impl_iterator get_last_align() - { - return impl.end() - (ExtraPointers - 1); - } - - const_impl_iterator get_last_align() const - { - return impl.cend() - (ExtraPointers - 1); - } - - template - iterator priv_erase(const_iterator first, const_iterator last, AllocatorVersion, - typename boost::container::container_detail::enable_if_c - - ::value>::type * = 0) - { - STABLE_VECTOR_CHECK_INVARIANT; - return priv_erase(first, last, allocator_v1()); - } - - static node_type_ptr_t node_ptr_cast(const void_ptr &p) - { - return node_type_ptr_t(static_cast(container_detail::to_raw_pointer(p))); - } - - static node_type_base_ptr_t node_base_ptr_cast(const void_ptr &p) - { - return node_type_base_ptr_t(static_cast(container_detail::to_raw_pointer(p))); - } - - static value_type& value(const void_ptr &p) - { - return node_ptr_cast(p)->value; - } - - void initialize_end_node(size_type impl_capacity = 0) - { - if(impl.empty()){ - impl.reserve(impl_capacity + ExtraPointers); - impl.resize (ExtraPointers, void_ptr(0)); - impl[0] = &this->internal_data.end_node; - this->internal_data.end_node.up = &impl[0]; - } - } - - void readjust_end_node() - { - if(!this->impl.empty()){ - void_ptr &end_node_ref = *(this->get_last_align()-1); - end_node_ref = this->get_end_node(); - this->internal_data.end_node.up = &end_node_ref; - } - else{ - this->internal_data.end_node.up = void_ptr(&this->internal_data.end_node.up); - } - } - - node_type_ptr_t get_end_node() const - { - const node_type_base_t* cp = &this->internal_data.end_node; - node_type_base_t* p = const_cast(cp); - return node_ptr_cast(p); - } - - template - void_ptr new_node(const void_ptr &up, Iter it) - { - node_type_ptr_t p = this->allocate_one(); - try{ - boost::container::construct_in_place(this->node_alloc(), container_detail::addressof(p->value), it); - //This does not throw - ::new(static_cast(container_detail::to_raw_pointer(p))) node_type_base_t; - p->set_pointer(up); - } - catch(...){ - this->deallocate_one(p); - throw; - } - return p; - } - - void delete_node(const void_ptr &p) - { - node_type_ptr_t n(node_ptr_cast(p)); allocator_traits:: - destroy(this->node_alloc(), container_detail::to_raw_pointer(n)); - this->put_in_pool(n); + destroy(this->priv_node_alloc(), container_detail::addressof(n->value)); + static_cast(container_detail::to_raw_pointer(n))->~node_base_type(); + this->priv_put_in_pool(n); } - static void align_nodes(impl_iterator first, impl_iterator last) + template + void priv_build_node_from_it(const node_ptr &p, const index_iterator &up_index, const Iterator &it) { - while(first!=last){ - node_ptr_cast(*first)->up = void_ptr(&*first); - ++first; - } + //This can throw + boost::container::construct_in_place + ( this->priv_node_alloc() + , container_detail::addressof(p->value) + , it); + //This does not throw + ::new(static_cast(container_detail::to_raw_pointer(p))) + node_base_type(index_traits_type::ptr_to_node_base_ptr(*up_index)); } - void insert_not_iter(const_iterator position, size_type n, const T& t) + template + void priv_build_node_from_convertible(const node_ptr &p, BOOST_FWD_REF(ValueConvertible) value_convertible) { - typedef constant_iterator cvalue_iterator; - this->insert_iter(position, cvalue_iterator(t, n), cvalue_iterator(), std::forward_iterator_tag()); + //This can throw + boost::container::allocator_traits::construct + ( this->priv_node_alloc() + , container_detail::addressof(p->value) + , ::boost::forward(value_convertible)); + //This does not throw + ::new(static_cast(container_detail::to_raw_pointer(p))) node_base_type; } - template - void insert_iter(const_iterator position,InputIterator first,InputIterator last, boost::mpl::true_) + void priv_swap_members(stable_vector &x) { - typedef typename std::iterator_traits::iterator_category category; - this->insert_iter(position, first, last, category()); - } - - template - void insert_iter(const_iterator position,InputIterator first,InputIterator last,std::input_iterator_tag) - { - for(; first!=last; ++first){ - this->insert(position, *first); - } - } - - template - iterator insert_iter(const_iterator position, InputIterator first, InputIterator last, std::forward_iterator_tag) - { - size_type n = (size_type)std::distance(first,last); - difference_type d = position-this->cbegin(); - if(n){ - this->insert_iter_prolog(n, d); - const impl_iterator it(impl.begin() + d); - this->insert_iter_fwd(it, first, last, n); - //Fix the pointers for the newly allocated buffer - this->align_nodes(it + n, get_last_align()); - } - return this->begin() + d; - } - - template - void insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v1) - { - size_type i=0; - try{ - while(first!=last){ - it[i] = this->new_node(void_ptr_ptr(&it[i]), first); - ++first; - ++i; - } - } - catch(...){ - impl_iterator e = impl.erase(it + i, it + n); - this->align_nodes(e, get_last_align()); - throw; - } - } - - template - void insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v2) - { - multiallocation_chain mem(node_alloc().allocate_individual(n)); - - size_type i = 0; - node_type_ptr_t p = 0; - try{ - while(first != last){ - p = mem.front(); - mem.pop_front(); - //This can throw - boost::container::construct_in_place(this->node_alloc(), container_detail::addressof(p->value), first); - //This does not throw - ::new(static_cast(container_detail::to_raw_pointer(p))) node_type_base_t; - p->set_pointer(void_ptr_ptr(&it[i])); - ++first; - it[i] = p; - ++i; - } - } - catch(...){ - node_alloc().deallocate_one(p); - node_alloc().deallocate_many(boost::move(mem)); - impl_iterator e = impl.erase(it+i, it+n); - this->align_nodes(e, get_last_align()); - throw; - } - } - - template - void insert_iter_fwd(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n) - { - size_type i = 0; - node_type_ptr_t p = 0; - try{ - while(first != last){ - p = this->get_from_pool(); - if(!p){ - insert_iter_fwd_alloc(it+i, first, last, n-i, alloc_version()); - break; - } - //This can throw - boost::container::construct_in_place(this->node_alloc(), container_detail::addressof(p->value), first); - //This does not throw - ::new(static_cast(container_detail::to_raw_pointer(p))) node_type_base_t; - p->set_pointer(void_ptr_ptr(&it[i])); - ++first; - it[i]=p; - ++i; - } - } - catch(...){ - put_in_pool(p); - impl_iterator e = impl.erase(it+i, it+n); - this->align_nodes(e, get_last_align()); - throw; - } - } - - template - void insert_iter(const_iterator position, InputIterator first, InputIterator last, boost::mpl::false_) - { - this->insert_not_iter(position, first, last); + container_detail::do_swap(this->internal_data.pool_size, x.internal_data.pool_size); + index_traits_type::readjust_end_node(this->index, this->internal_data.end_node); + index_traits_type::readjust_end_node(x.index, x.internal_data.end_node); } #if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) - bool invariant()const + bool priv_invariant()const { - if(impl.empty()) - return !capacity() && !size(); - if(get_end_node() != *(impl.end() - ExtraPointers)){ + index_type & index_ref = const_cast(this->index); + + if(index.empty()) + return !this->capacity() && !this->size(); + if(this->priv_get_end_node() != *(index.end() - ExtraPointers)){ return false; } - for(const_impl_iterator it = impl.begin(), it_end = get_last_align(); it != it_end; ++it){ - if(const_void_ptr(node_ptr_cast(*it)->up) != - const_void_ptr(const_void_ptr_ptr(&*it))) - return false; + + if(!index_traits_type::invariants(index_ref)){ + return false; } - size_type n = capacity()-size(); - const void_ptr &pool_head = impl.back(); + + size_type n = this->capacity() - this->size(); + node_base_ptr &pool_first_ref = *(index_ref.end() - 2); + node_base_ptr &pool_last_ref = index_ref.back(); + multiallocation_chain holder; + holder.incorporate_after( holder.before_begin() + , node_ptr_traits::static_cast_from(pool_first_ref) + , node_ptr_traits::static_cast_from(pool_last_ref) + , internal_data.pool_size); + typename multiallocation_chain::iterator beg(holder.begin()), end(holder.end()); size_type num_pool = 0; - node_type_ptr_t p = node_ptr_cast(pool_head); - while(p){ + while(beg != end){ ++num_pool; - p = node_ptr_cast(p->up); + ++beg; } - return n >= num_pool; + return n >= num_pool && num_pool == internal_data.pool_size; } class invariant_checker @@ -1715,7 +1827,7 @@ class stable_vector public: invariant_checker(const stable_vector& v):p(&v){} - ~invariant_checker(){BOOST_ASSERT(p->invariant());} + ~invariant_checker(){BOOST_ASSERT(p->priv_invariant());} void touch(){} }; #endif @@ -1725,51 +1837,29 @@ class stable_vector { private: BOOST_MOVABLE_BUT_NOT_COPYABLE(ebo_holder) + public: -/* - explicit ebo_holder(BOOST_RV_REF(ebo_holder) x) - : node_allocator_type(boost::move(static_cast(x))) - , pool_size(0) - , end_node() - {} -*/ template explicit ebo_holder(BOOST_FWD_REF(AllocatorRLValue) a) : node_allocator_type(boost::forward(a)) , pool_size(0) , end_node() - { - this->set_end_pointer_to_default_constructed(); - } + {} ebo_holder() : node_allocator_type() , pool_size(0) , end_node() - { - this->set_end_pointer_to_default_constructed(); - } - - void set_end_pointer_to_default_constructed() - { - end_node.set_pointer(void_ptr(&end_node.up)); - } + {} size_type pool_size; - node_type_base_t end_node; + node_base_type end_node; } internal_data; - void priv_swap_members(stable_vector &x) - { - container_detail::do_swap(this->internal_data.pool_size, x.internal_data.pool_size); - this->readjust_end_node(); - x.readjust_end_node(); - } + node_allocator_type &priv_node_alloc() { return internal_data; } + const node_allocator_type &priv_node_alloc() const { return internal_data; } - node_allocator_type &node_alloc() { return internal_data; } - const node_allocator_type &node_alloc() const { return internal_data; } - - impl_type impl; + index_type index; /// @endcond }; diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index 2a64cec..4af2ae2 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -68,13 +69,8 @@ #include #include -#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED namespace boost { namespace container { -#else -namespace boost { -namespace container { -#endif /// @cond namespace container_detail { @@ -97,10 +93,11 @@ class basic_string_base public: typedef A allocator_type; //! The stored allocator type - typedef allocator_type stored_allocator_type; + typedef allocator_type stored_allocator_type; typedef typename allocator_traits_type::pointer pointer; typedef typename allocator_traits_type::value_type value_type; typedef typename allocator_traits_type::size_type size_type; + typedef ::boost::intrusive::pointer_traits pointer_traits; basic_string_base() : members_() @@ -128,10 +125,7 @@ class basic_string_base { if(!this->is_short()){ this->deallocate_block(); - allocator_traits_type::destroy - ( this->alloc() - , static_cast(static_cast(&this->members_.m_repr.r)) - ); + this->is_short(true); } } @@ -203,11 +197,17 @@ class basic_string_base long_raw_t r; short_t s; - short_t &short_repr() const - { return *const_cast(&s); } + const short_t &short_repr() const + { return s; } - long_t &long_repr() const - { return *const_cast(reinterpret_cast(&r)); } + const long_t &long_repr() const + { return *static_cast(static_cast(&r)); } + + short_t &short_repr() + { return s; } + + long_t &long_repr() + { return *static_cast(static_cast(&r)); } }; struct members_holder @@ -242,20 +242,22 @@ class basic_string_base { return static_cast(this->members_.m_repr.s.h.is_short != 0); } void is_short(bool yes) - { - if(yes && !this->is_short()){ + { + const bool was_short = this->is_short(); + if(yes && !was_short){ allocator_traits_type::destroy ( this->alloc() , static_cast(static_cast(&this->members_.m_repr.r)) ); + this->members_.m_repr.s.h.is_short = true; } - else{ + else if(!yes && was_short){ allocator_traits_type::construct ( this->alloc() , static_cast(static_cast(&this->members_.m_repr.r)) ); + this->members_.m_repr.s.h.is_short = false; } - this->members_.m_repr.s.h.is_short = yes; } private: @@ -279,7 +281,7 @@ class basic_string_base size_type &received_size, pointer reuse = 0) { if(this->is_short() && (command & (expand_fwd | expand_bwd)) ){ - reuse = pointer(0); + reuse = pointer(); command &= ~(expand_fwd | expand_bwd); } return this->allocation_command @@ -297,7 +299,7 @@ class basic_string_base (void)limit_size; (void)reuse; if(!(command & allocate_new)) - return std::pair(pointer(0), false); + return std::pair(pointer(), false); received_size = preferred_size; return std::make_pair(this->alloc().allocate(received_size), false); } @@ -358,7 +360,7 @@ class basic_string_base pointer p = this->allocation_command(allocate_new, n, new_cap, new_cap).first; this->is_short(false); this->priv_long_addr(p); - this->priv_size(0); + this->priv_long_size(0); this->priv_storage(new_cap); } } @@ -384,13 +386,26 @@ class basic_string_base { return this->priv_storage() - 1; } pointer priv_short_addr() const - { return pointer(&this->members_.m_repr.short_repr().data[0]); } + { return pointer_traits::pointer_to(const_cast(this->members_.m_repr.short_repr().data[0])); } pointer priv_long_addr() const { return this->members_.m_repr.long_repr().start; } pointer priv_addr() const - { return this->is_short() ? pointer(&this->members_.m_repr.short_repr().data[0]) : this->members_.m_repr.long_repr().start; } + { + return this->is_short() + ? priv_short_addr() + : priv_long_addr() + ; + } + + pointer priv_end_addr() const + { + return this->is_short() + ? this->priv_short_addr() + this->priv_short_size() + : this->priv_long_addr() + this->priv_long_size() + ; + } void priv_long_addr(pointer addr) { this->members_.m_repr.long_repr().start = addr; } @@ -416,7 +431,7 @@ class basic_string_base } size_type priv_size() const - { return this->is_short() ? priv_short_size() : priv_long_size(); } + { return this->is_short() ? this->priv_short_size() : this->priv_long_size(); } size_type priv_short_size() const { return this->members_.m_repr.short_repr().h.length; } @@ -439,7 +454,7 @@ class basic_string_base void priv_long_size(size_type sz) { - this->members_.m_repr.long_repr().length = static_cast(sz); + this->members_.m_repr.long_repr().length = sz; } void swap_data(basic_string_base& other) @@ -449,16 +464,22 @@ class basic_string_base container_detail::do_swap(this->members_.m_repr, other.members_.m_repr); } else{ - repr_t copied(this->members_.m_repr); - this->members_.m_repr.long_repr() = other.members_.m_repr.long_repr(); - other.members_.m_repr = copied; + short_t short_backup(this->members_.m_repr.short_repr()); + long_t long_backup (other.members_.m_repr.long_repr()); + other.members_.m_repr.long_repr().~long_t(); + ::new(&this->members_.m_repr.long_repr()) long_t; + this->members_.m_repr.long_repr() = long_backup; + other.members_.m_repr.short_repr() = short_backup; } } else{ if(other.is_short()){ - repr_t copied(other.members_.m_repr); - other.members_.m_repr.long_repr() = this->members_.m_repr.long_repr(); - this->members_.m_repr = copied; + short_t short_backup(other.members_.m_repr.short_repr()); + long_t long_backup (this->members_.m_repr.long_repr()); + this->members_.m_repr.long_repr().~long_t(); + ::new(&other.members_.m_repr.long_repr()) long_t; + other.members_.m_repr.long_repr() = long_backup; + this->members_.m_repr.short_repr() = short_backup; } else{ container_detail::do_swap(this->members_.m_repr.long_repr(), other.members_.m_repr.long_repr()); @@ -586,6 +607,7 @@ class basic_string 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 ::boost::intrusive::pointer_traits pointer_traits; /// @endcond public: // Constructor, destructor, assignment. @@ -624,7 +646,10 @@ class basic_string //! Throws: If allocator_type's default constructor throws. basic_string(const basic_string& s) : base_t(allocator_traits_type::select_on_container_copy_construction(s.alloc())) - { this->priv_range_initialize(s.begin(), s.end()); } + { + this->priv_terminate_string(); + this->assign(s.begin(), s.end()); + } //! Effects: Move constructor. Moves s's resources to *this. //! @@ -642,7 +667,10 @@ class basic_string //! Throws: If allocation throws. basic_string(const basic_string& s, const allocator_type &a) : base_t(a) - { this->priv_range_initialize(s.begin(), s.end()); } + { + this->priv_terminate_string(); + this->assign(s.begin(), s.end()); + } //! Effects: Move constructor using the specified allocator. //! Moves s's resources to *this. @@ -653,11 +681,12 @@ class basic_string basic_string(BOOST_RV_REF(basic_string) s, const allocator_type &a) : base_t(a) { + this->priv_terminate_string(); if(a == this->alloc()){ this->swap_data(s); } else{ - this->priv_range_initialize(s.begin(), s.end()); + this->assign(s.begin(), s.end()); } } @@ -667,10 +696,11 @@ class basic_string const allocator_type& a = allocator_type()) : base_t(a) { + this->priv_terminate_string(); if (pos > s.size()) this->throw_out_of_range(); else - this->priv_range_initialize + this->assign (s.begin() + pos, s.begin() + pos + container_detail::min_value(n, s.size() - pos)); } @@ -679,23 +709,29 @@ class basic_string basic_string(const CharT* s, size_type n, const allocator_type& a = allocator_type()) : base_t(a) - { this->priv_range_initialize(s, s + n); } + { + this->priv_terminate_string(); + this->assign(s, s + n); + } //! Effects: Constructs a basic_string taking the allocator as parameter, //! and is initialized by the null-terminated s c-string. basic_string(const CharT* s, const allocator_type& a = allocator_type()) : base_t(a) - { this->priv_range_initialize(s, s + Traits::length(s)); } + { + this->priv_terminate_string(); + this->assign(s, s + Traits::length(s)); + } //! Effects: Constructs a basic_string taking the allocator as parameter, //! and is initialized by n copies of c. basic_string(size_type n, CharT c, const allocator_type& a = allocator_type()) : base_t(a) - { - this->priv_range_initialize(cvalue_iterator(c, n), - cvalue_iterator()); + { + this->priv_terminate_string(); + this->assign(n, c); } //! Effects: Constructs a basic_string taking the allocator as parameter, @@ -705,10 +741,8 @@ class basic_string const allocator_type& a = allocator_type()) : base_t(a) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_initialize_dispatch(f, l, Result()); + this->priv_terminate_string(); + this->assign(f, l); } //! Effects: Destroys the basic_string. All used memory is deallocated. @@ -735,8 +769,8 @@ class basic_string if(!this->is_short()){ this->deallocate_block(); this->is_short(true); - Traits::assign(*this->priv_addr(), this->priv_null()); - this->priv_size(0); + Traits::assign(*this->priv_addr(), CharT(0)); + this->priv_short_size(0); } } container_detail::assign_alloc(this->alloc(), x.alloc(), flag); @@ -811,7 +845,7 @@ class basic_string //! //! Complexity: Constant. iterator end() - { return this->priv_addr() + this->priv_size(); } + { return this->priv_end_addr(); } //! Effects: Returns a const_iterator to the end of the vector. //! @@ -819,7 +853,7 @@ class basic_string //! //! Complexity: Constant. const_iterator end() const - { return this->priv_addr() + this->priv_size(); } + { return this->priv_end_addr(); } //! Effects: Returns a const_iterator to the end of the vector. //! @@ -827,7 +861,7 @@ class basic_string //! //! Complexity: Constant. const_iterator cend() const - { return this->priv_addr() + this->priv_size(); } + { return this->priv_end_addr(); } //! Effects: Returns a reverse_iterator pointing to the beginning //! of the reversed vector. @@ -836,7 +870,7 @@ class basic_string //! //! Complexity: Constant. reverse_iterator rbegin() - { return reverse_iterator(this->priv_addr() + this->priv_size()); } + { return reverse_iterator(this->priv_end_addr()); } //! Effects: Returns a const_reverse_iterator pointing to the beginning //! of the reversed vector. @@ -854,7 +888,7 @@ class basic_string //! //! Complexity: Constant. const_reverse_iterator crbegin() const - { return const_reverse_iterator(this->priv_addr() + this->priv_size()); } + { return const_reverse_iterator(this->priv_end_addr()); } //! Effects: Returns a reverse_iterator pointing to the end //! of the reversed vector. @@ -943,7 +977,7 @@ class basic_string //! Complexity: Linear to the difference between size() and new_size. void resize(size_type n, CharT c) { - if (n <= size()) + if (n <= this->size()) this->erase(this->begin() + n, this->end()); else this->append(n - this->size(), c); @@ -956,7 +990,7 @@ class basic_string //! //! Complexity: Linear to the difference between size() and new_size. void resize(size_type n) - { resize(n, this->priv_null()); } + { resize(n, CharT(0)); } //! Effects: If n is less than or equal to capacity(), this call has no //! effect. Otherwise, it is a request for allocation of additional memory. @@ -966,8 +1000,9 @@ class basic_string //! Throws: If memory allocation allocation throws void reserve(size_type res_arg) { - if (res_arg > this->max_size()) + if (res_arg > this->max_size()){ this->throw_length_error(); + } if (this->capacity() < res_arg){ size_type n = container_detail::max_value(res_arg, this->size()) + 1; @@ -976,13 +1011,14 @@ class basic_string (allocate_new, n, new_cap, new_cap).first; size_type new_length = 0; + const pointer addr = this->priv_addr(); new_length += priv_uninitialized_copy - (this->priv_addr(), this->priv_addr() + this->priv_size(), new_start); + (addr, addr + this->priv_size(), new_start); this->priv_construct_null(new_start + new_length); this->deallocate_block(); this->is_short(false); this->priv_long_addr(new_start); - this->priv_size(new_length); + this->priv_long_size(new_length); this->priv_storage(new_cap); } } @@ -1003,8 +1039,8 @@ class basic_string //! Complexity: Linear to the number of elements in the vector. void clear() { - if (!empty()) { - Traits::assign(*this->priv_addr(), this->priv_null()); + if (!this->empty()) { + Traits::assign(*this->priv_addr(), CharT(0)); this->priv_size(0); } } @@ -1021,7 +1057,7 @@ class basic_string if(this->priv_storage() > InternalBufferChars){ //Check if we should pass from dynamically allocated buffer //to the internal storage - if(this->priv_size() < (InternalBufferChars)){ + if(this->priv_size() < InternalBufferChars){ //Dynamically allocated buffer attributes pointer long_addr = this->priv_long_addr(); size_type long_storage = this->priv_long_storage(); @@ -1078,9 +1114,10 @@ class basic_string //! Throws: std::range_error if n >= size() //! //! Complexity: Constant. - reference at(size_type n) { - if (n >= size()) - this->throw_out_of_range(); + reference at(size_type n) + { + if (n >= this->size()) + this->throw_out_of_range(); return *(this->priv_addr() + n); } @@ -1093,7 +1130,7 @@ class basic_string //! //! Complexity: Constant. const_reference at(size_type n) const { - if (n >= size()) + if (n >= this->size()) this->throw_out_of_range(); return *(this->priv_addr() + n); } @@ -1177,14 +1214,16 @@ class basic_string //! Effects: Equivalent to append(static_cast(1), c). void push_back(CharT c) { - if (this->priv_size() < this->capacity()){ - this->priv_construct_null(this->priv_addr() + (this->priv_size() + 1)); - Traits::assign(this->priv_addr()[this->priv_size()], c); - this->priv_size(this->priv_size()+1); + const size_type old_size = this->priv_size(); + if (old_size < this->capacity()){ + const pointer addr = this->priv_addr(); + this->priv_construct_null(addr + old_size + 1); + Traits::assign(addr[old_size], c); + this->priv_size(old_size+1); } else{ //No enough memory, insert a new object at the end - this->append((size_type)1, c); + this->append(size_type(1), c); } } @@ -1212,8 +1251,8 @@ class basic_string //! Throws: If memory allocation throws or out_of_range if pos > str.size(). //! //! Returns: *this - basic_string& assign(const basic_string& s, - size_type pos, size_type n) { + basic_string& assign(const basic_string& s, size_type pos, size_type n) + { if (pos > s.size()) this->throw_out_of_range(); return this->assign(s.begin() + pos, @@ -1249,12 +1288,29 @@ class basic_string //! //! Returns: *this template - basic_string& assign(InputIter first, InputIter last) + basic_string& assign(InputIter first, InputIter last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + >::type * = 0 + #endif + ) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - return this->priv_assign_dispatch(first, last, Result()); + size_type cur = 0; + const pointer addr = this->priv_addr(); + CharT *ptr = container_detail::to_raw_pointer(addr); + const size_type old_size = this->priv_size(); + while (first != last && cur != old_size) { + Traits::assign(*ptr, *first); + ++first; + ++cur; + ++ptr; + } + if (first == last) + this->erase(addr + cur, addr + old_size); + else + this->append(first, last); + return *this; } //! Requires: pos <= size(). @@ -1266,9 +1322,10 @@ class basic_string //! Returns: *this basic_string& insert(size_type pos, const basic_string& s) { - if (pos > size()) + const size_type size = this->size(); + if (pos > size) this->throw_out_of_range(); - if (this->size() > this->max_size() - s.size()) + if (size > this->max_size() - s.size()) this->throw_length_error(); this->insert(this->priv_addr() + pos, s.begin(), s.end()); return *this; @@ -1282,13 +1339,14 @@ class basic_string //! Throws: If memory allocation throws or out_of_range if pos1 > size() or pos2 > str.size(). //! //! Returns: *this - basic_string& insert(size_type pos1, const basic_string& s, - size_type pos2, size_type n) + basic_string& insert(size_type pos1, const basic_string& s, size_type pos2, size_type n) { - if (pos1 > this->size() || pos2 > s.size()) + const size_type size = this->size(); + const size_type str_size = s.size(); + if (pos1 > size || pos2 > str_size) this->throw_out_of_range(); - size_type len = container_detail::min_value(n, s.size() - pos2); - if (this->size() > this->max_size() - len) + size_type len = container_detail::min_value(n, str_size - pos2); + if (size > this->max_size() - len) this->throw_length_error(); const CharT *beg_ptr = container_detail::to_raw_pointer(s.begin()) + pos2; const CharT *end_ptr = beg_ptr + len; @@ -1327,7 +1385,7 @@ class basic_string //! Returns: *this basic_string& insert(size_type pos, const CharT* s) { - if (pos > size()) + if (pos > this->size()) this->throw_out_of_range(); size_type len = Traits::length(s); if (this->size() > this->max_size() - len) @@ -1359,7 +1417,7 @@ class basic_string //! Returns: An iterator which refers to the copy of the inserted character. iterator insert(const_iterator p, CharT c) { - size_type new_offset = p - this->priv_addr() + 1; + size_type new_offset = p - this->priv_addr(); this->insert(p, cvalue_iterator(c, 1), cvalue_iterator()); return this->priv_addr() + new_offset; } @@ -1369,28 +1427,144 @@ class basic_string //! //! Effects: Inserts n copies of c before the character referred to by p. //! - //! Returns: An iterator which refers to the copy of the first - //! inserted character, or p if n == 0. - void insert(const_iterator p, size_type n, CharT c) - { - this->insert(p, cvalue_iterator(c, n), cvalue_iterator()); - } + //! Returns: an iterator to the first inserted element or p if n is 0. + iterator insert(const_iterator p, size_type n, CharT c) + { return this->insert(p, cvalue_iterator(c, n), cvalue_iterator()); } //! Requires: p is a valid iterator on *this. [first,last) is a valid range. //! //! Effects: Equivalent to insert(p - begin(), basic_string(first, last)). //! - //! Returns: An iterator which refers to the copy of the first - //! inserted character, or p if first == last. + //! Returns: an iterator to the first inserted element or p if first == last. template - void insert(const_iterator p, InputIter first, InputIter last) + iterator insert(const_iterator p, InputIter first, InputIter last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_insert_dispatch(p, first, last, Result()); + const size_type n_pos = p - this->cbegin(); + for ( ; first != last; ++first, ++p) { + p = this->insert(p, *first); + } + return this->begin() + n_pos; } + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator insert(const_iterator p, ForwardIter first, ForwardIter last + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !container_detail::is_input_iterator::value + >::type * = 0 + ) + { + const size_type n_pos = p - this->cbegin(); + if (first != last) { + const size_type n = std::distance(first, last); + const size_type old_size = this->priv_size(); + const size_type remaining = this->capacity() - old_size; + const pointer old_start = this->priv_addr(); + bool enough_capacity = false; + std::pair allocation_ret; + size_type new_cap = 0; + + //Check if we have enough capacity + if (remaining >= n){ + enough_capacity = true; + } + else { + //Otherwise expand current buffer or allocate new storage + new_cap = this->next_capacity(n); + allocation_ret = this->allocation_command + (allocate_new | expand_fwd | expand_bwd, old_size + n + 1, + new_cap, new_cap, old_start); + + //Check forward expansion + if(old_start == allocation_ret.first){ + enough_capacity = true; + this->priv_storage(new_cap); + } + } + + //Reuse same buffer + if(enough_capacity){ + const size_type elems_after = old_size - (p - old_start); + const size_type old_length = old_size; + if (elems_after >= n) { + const pointer pointer_past_last = old_start + old_size + 1; + priv_uninitialized_copy(old_start + (old_size - n + 1), + pointer_past_last, pointer_past_last); + + this->priv_size(old_size+n); + Traits::move(const_cast(container_detail::to_raw_pointer(p + n)), + container_detail::to_raw_pointer(p), + (elems_after - n) + 1); + this->priv_copy(first, last, const_cast(container_detail::to_raw_pointer(p))); + } + else { + ForwardIter mid = first; + std::advance(mid, elems_after + 1); + + priv_uninitialized_copy(mid, last, old_start + old_size + 1); + const size_type newer_size = old_size + (n - elems_after); + this->priv_size(newer_size); + priv_uninitialized_copy + (p, const_iterator(old_start + old_length + 1), + old_start + newer_size); + this->priv_size(newer_size + elems_after); + this->priv_copy(first, mid, const_cast(container_detail::to_raw_pointer(p))); + } + } + else{ + pointer new_start = allocation_ret.first; + if(!allocation_ret.second){ + //Copy data to new buffer + size_type new_length = 0; + //This can't throw, since characters are POD + new_length += priv_uninitialized_copy + (const_iterator(old_start), p, new_start); + new_length += priv_uninitialized_copy + (first, last, new_start + new_length); + new_length += priv_uninitialized_copy + (p, const_iterator(old_start + old_size), + new_start + new_length); + this->priv_construct_null(new_start + new_length); + + this->deallocate_block(); + this->is_short(false); + this->priv_long_addr(new_start); + this->priv_long_size(new_length); + this->priv_long_storage(new_cap); + } + else{ + //value_type is POD, so backwards expansion is much easier + //than with vector + value_type * const oldbuf = container_detail::to_raw_pointer(old_start); + value_type * const newbuf = container_detail::to_raw_pointer(new_start); + const value_type *const pos = container_detail::to_raw_pointer(p); + const size_type before = pos - oldbuf; + + //First move old data + Traits::move(newbuf, oldbuf, before); + Traits::move(newbuf + before + n, pos, old_size - before); + //Now initialize the new data + priv_uninitialized_copy(first, last, new_start + before); + this->priv_construct_null(new_start + (old_size + n)); + this->is_short(false); + this->priv_long_addr(new_start); + this->priv_long_size(old_size + n); + this->priv_long_storage(new_cap); + } + } + } + return this->begin() + n_pos; + } + #endif + //! Requires: pos <= size() //! //! Effects: Determines the effective length xlen of the string to be removed as the smaller of n and size() - pos. @@ -1404,9 +1578,10 @@ class basic_string //! Returns: *this basic_string& erase(size_type pos = 0, size_type n = npos) { - if (pos > size()) + if (pos > this->size()) this->throw_out_of_range(); - erase(this->priv_addr() + pos, this->priv_addr() + pos + container_detail::min_value(n, size() - pos)); + const pointer addr = this->priv_addr(); + erase(addr + pos, addr + pos + container_detail::min_value(n, this->size() - pos)); return *this; } @@ -1419,11 +1594,12 @@ class basic_string iterator erase(const_iterator p) { // The move includes the terminating null. - CharT *ptr = const_cast(container_detail::to_raw_pointer(p)); + CharT * const ptr = const_cast(container_detail::to_raw_pointer(p)); + const size_type old_size = this->priv_size(); Traits::move(ptr, container_detail::to_raw_pointer(p + 1), - this->priv_size() - (p - this->priv_addr())); - this->priv_size(this->priv_size()-1); + old_size - (p - this->priv_addr())); + this->priv_size(old_size-1); return iterator(ptr); } @@ -1439,11 +1615,12 @@ class basic_string { CharT * f = const_cast(container_detail::to_raw_pointer(first)); if (first != last) { // The move includes the terminating null. - size_type num_erased = last - first; + const size_type num_erased = last - first; + const size_type old_size = this->priv_size(); Traits::move(f, container_detail::to_raw_pointer(last), - (this->priv_size() + 1)-(last - this->priv_addr())); - size_type new_length = this->priv_size() - num_erased; + (old_size + 1)-(last - this->priv_addr())); + const size_type new_length = old_size - num_erased; this->priv_size(new_length); } return iterator(f); @@ -1456,8 +1633,9 @@ class basic_string //! Effects: Equivalent to erase(size() - 1, 1). void pop_back() { - Traits::assign(this->priv_addr()[this->priv_size()-1], this->priv_null()); - this->priv_size(this->priv_size()-1);; + const size_type old_size = this->priv_size(); + Traits::assign(this->priv_addr()[old_size-1], CharT(0)); + this->priv_size(old_size-1);; } //! Requires: pos1 <= size(). @@ -1469,13 +1647,15 @@ class basic_string //! Returns: *this basic_string& replace(size_type pos1, size_type n1, const basic_string& str) { - if (pos1 > size()) + if (pos1 > this->size()) this->throw_out_of_range(); - const size_type len = container_detail::min_value(n1, size() - pos1); + const size_type len = container_detail::min_value(n1, this->size() - pos1); if (this->size() - len >= this->max_size() - str.size()) this->throw_length_error(); - return this->replace(this->priv_addr() + pos1, this->priv_addr() + pos1 + len, - str.begin(), str.end()); + const pointer addr = this->priv_addr(); + return this->replace( const_iterator(addr + pos1) + , const_iterator(addr + pos1 + len) + , str.begin(), str.end()); } //! Requires: pos1 <= size() and pos2 <= str.size(). @@ -1490,14 +1670,16 @@ class basic_string basic_string& replace(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2) { - if (pos1 > size() || pos2 > str.size()) + if (pos1 > this->size() || pos2 > str.size()) this->throw_out_of_range(); - const size_type len1 = container_detail::min_value(n1, size() - pos1); + const size_type len1 = container_detail::min_value(n1, this->size() - pos1); const size_type len2 = container_detail::min_value(n2, str.size() - pos2); if (this->size() - len1 >= this->max_size() - len2) this->throw_length_error(); - return this->replace(this->priv_addr() + pos1, this->priv_addr() + pos1 + len1, - str.priv_addr() + pos2, str.priv_addr() + pos2 + len2); + const pointer addr = this->priv_addr(); + const pointer straddr = str.priv_addr(); + return this->replace(addr + pos1, addr + pos1 + len1, + straddr + pos2, straddr + pos2 + len2); } //! Requires: pos1 <= size() and s points to an array of at least n2 elements of CharT. @@ -1514,16 +1696,15 @@ class basic_string //! if the length of the resulting string would exceed max_size() //! //! Returns: *this - basic_string& replace(size_type pos1, size_type n1, - const CharT* s, size_type n2) + basic_string& replace(size_type pos1, size_type n1, const CharT* s, size_type n2) { - if (pos1 > size()) + if (pos1 > this->size()) this->throw_out_of_range(); - const size_type len = container_detail::min_value(n1, size() - pos1); + const size_type len = container_detail::min_value(n1, this->size() - pos1); if (n2 > this->max_size() || size() - len >= this->max_size() - n2) this->throw_length_error(); - return this->replace(this->priv_addr() + pos1, this->priv_addr() + pos1 + len, - s, s + n2); + const pointer addr = this->priv_addr(); + return this->replace(addr + pos1, addr + pos1 + len, s, s + n2); } //! Requires: pos1 <= size() and s points to an array of at least n2 elements of CharT. @@ -1542,13 +1723,14 @@ class basic_string //! Returns: *this basic_string& replace(size_type pos, size_type n1, const CharT* s) { - if (pos > size()) + if (pos > this->size()) this->throw_out_of_range(); - const size_type len = container_detail::min_value(n1, size() - pos); + const size_type len = container_detail::min_value(n1, this->size() - pos); const size_type n2 = Traits::length(s); - if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + if (n2 > this->max_size() || this->size() - len >= this->max_size() - n2) this->throw_length_error(); - return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, + const pointer addr = this->priv_addr(); + return this->replace(addr + pos, addr + pos + len, s, s + Traits::length(s)); } @@ -1562,12 +1744,13 @@ class basic_string //! Returns: *this basic_string& replace(size_type pos1, size_type n1, size_type n2, CharT c) { - if (pos1 > size()) + if (pos1 > this->size()) this->throw_out_of_range(); - const size_type len = container_detail::min_value(n1, size() - pos1); - if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + const size_type len = container_detail::min_value(n1, this->size() - pos1); + if (n2 > this->max_size() || this->size() - len >= this->max_size() - n2) this->throw_length_error(); - return this->replace(this->priv_addr() + pos1, this->priv_addr() + pos1 + len, n2, c); + const pointer addr = this->priv_addr(); + return this->replace(addr + pos1, addr + pos1 + len, n2, c); } //! Requires: [begin(),i1) and [i1,i2) are valid ranges. @@ -1631,14 +1814,51 @@ class basic_string //! //! Returns: *this template - basic_string& replace(const_iterator i1, const_iterator i2, InputIter j1, InputIter j2) + basic_string& replace(const_iterator i1, const_iterator i2, InputIter j1, InputIter j2 + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - return this->priv_replace_dispatch(i1, i2, j1, j2, Result()); + for ( ; i1 != i2 && j1 != j2; ++i1, ++j1){ + Traits::assign(*const_cast(container_detail::to_raw_pointer(i1)), *j1); + } + + if (j1 == j2) + this->erase(i1, i2); + else + this->insert(i2, j1, j2); + return *this; } + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + basic_string& replace(const_iterator i1, const_iterator i2, ForwardIter j1, ForwardIter j2 + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !container_detail::is_input_iterator::value + >::type * = 0 + ) + { + difference_type n = std::distance(j1, j2); + const difference_type len = i2 - i1; + if (len >= n) { + this->priv_copy(j1, j2, const_cast(container_detail::to_raw_pointer(i1))); + this->erase(i1 + n, i2); + } + else { + ForwardIter m = j1; + std::advance(m, len); + this->priv_copy(j1, m, const_cast(container_detail::to_raw_pointer(i1))); + this->insert(i2, m, j2); + } + return *this; + } + #endif + //! Requires: pos <= size() //! //! Effects: Determines the effective length rlen of the string to copy as the @@ -1652,9 +1872,9 @@ class basic_string //! Returns: rlen size_type copy(CharT* s, size_type n, size_type pos = 0) const { - if (pos > size()) + if (pos > this->size()) this->throw_out_of_range(); - const size_type len = container_detail::min_value(n, size() - pos); + const size_type len = container_detail::min_value(n, this->size() - pos); Traits::copy(s, container_detail::to_raw_pointer(this->priv_addr() + pos), len); return len; } @@ -1703,12 +1923,13 @@ class basic_string //! Returns: find(basic_string(s,n),pos). size_type find(const CharT* s, size_type pos, size_type n) const { - if (pos + n > size()) + if (pos + n > this->size()) return npos; else { - pointer finish = this->priv_addr() + this->priv_size(); + const pointer addr = this->priv_addr(); + pointer finish = addr + this->priv_size(); const const_iterator result = - std::search(container_detail::to_raw_pointer(this->priv_addr() + pos), + std::search(container_detail::to_raw_pointer(addr + pos), container_detail::to_raw_pointer(finish), s, s + n, Eq_traits()); return result != finish ? result - begin() : npos; @@ -1721,19 +1942,21 @@ class basic_string //! //! Returns: find(basic_string(s), pos). size_type find(const CharT* s, size_type pos = 0) const - { return find(s, pos, Traits::length(s)); } + { return this->find(s, pos, Traits::length(s)); } //! Throws: Nothing //! //! Returns: find(basic_string(1,c), pos). size_type find(CharT c, size_type pos = 0) const { - if (pos >= size()) + const size_type size = this->size(); + if (pos >= size) return npos; else { - pointer finish = this->priv_addr() + this->priv_size(); + const pointer addr = this->priv_addr(); + pointer finish = addr + size; const const_iterator result = - std::find_if(this->priv_addr() + pos, finish, + std::find_if(addr + pos, finish, std::bind2nd(Eq_traits(), c)); return result != finish ? result - begin() : npos; } @@ -1757,7 +1980,7 @@ class basic_string //! Returns: rfind(basic_string(s, n), pos). size_type rfind(const CharT* s, size_type pos, size_type n) const { - const size_type len = size(); + const size_type len = this->size(); if (n > len) return npos; @@ -1786,7 +2009,7 @@ class basic_string //! Returns: rfind(basic_string(1,c),pos). size_type rfind(CharT c, size_type pos = npos) const { - const size_type len = size(); + const size_type len = this->size(); if (len < 1) return npos; @@ -1816,14 +2039,15 @@ class basic_string //! Returns: find_first_of(basic_string(s, n), pos). size_type find_first_of(const CharT* s, size_type pos, size_type n) const { - if (pos >= size()) + const size_type size = this->size(); + if (pos >= size) return npos; else { - pointer finish = this->priv_addr() + this->priv_size(); - const_iterator result = std::find_first_of(this->priv_addr() + pos, finish, - s, s + n, - Eq_traits()); - return result != finish ? result - begin() : npos; + const pointer addr = this->priv_addr(); + pointer finish = addr + size; + const_iterator result = std::find_first_of + (addr + pos, finish, s, s + n, Eq_traits()); + return result != finish ? result - this->begin() : npos; } } @@ -1860,17 +2084,17 @@ class basic_string //! Returns: find_last_of(basic_string(s, n), pos). size_type find_last_of(const CharT* s, size_type pos, size_type n) const { - const size_type len = size(); + const size_type len = this->size(); if (len < 1) return npos; else { - const const_iterator last = this->priv_addr() + container_detail::min_value(len - 1, pos) + 1; + const pointer addr = this->priv_addr(); + const const_iterator last = addr + container_detail::min_value(len - 1, pos) + 1; const const_reverse_iterator rresult = std::find_first_of(const_reverse_iterator(last), rend(), - s, s + n, - Eq_traits()); - return rresult != rend() ? (rresult.base() - 1) - this->priv_addr() : npos; + s, s + n, Eq_traits()); + return rresult != rend() ? (rresult.base() - 1) - addr : npos; } } @@ -1906,13 +2130,14 @@ class basic_string //! Returns: find_first_not_of(basic_string(s, n), pos). size_type find_first_not_of(const CharT* s, size_type pos, size_type n) const { - if (pos > size()) + if (pos > this->size()) return npos; else { - pointer finish = this->priv_addr() + this->priv_size(); - const_iterator result = std::find_if(this->priv_addr() + pos, finish, - Not_within_traits(s, s + n)); - return result != finish ? result - this->priv_addr() : npos; + const pointer addr = this->priv_addr(); + const pointer finish = addr + this->priv_size(); + const const_iterator result = std::find_if + (addr + pos, finish, Not_within_traits(s, s + n)); + return result != finish ? result - addr : npos; } } @@ -1929,12 +2154,13 @@ class basic_string //! Returns: find_first_not_of(basic_string(1, c), pos). size_type find_first_not_of(CharT c, size_type pos = 0) const { - if (pos > size()) + if (pos > this->size()) return npos; else { - pointer finish = this->priv_addr() + this->priv_size(); - const_iterator result - = std::find_if(this->priv_addr() + pos, finish, + const pointer addr = this->priv_addr(); + const pointer finish = addr + this->priv_size(); + const const_iterator result + = std::find_if(addr + pos, finish, std::not1(std::bind2nd(Eq_traits(), c))); return result != finish ? result - begin() : npos; } @@ -1957,7 +2183,7 @@ class basic_string //! Returns: find_last_not_of(basic_string(s, n), pos). size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const { - const size_type len = size(); + const size_type len = this->size(); if (len < 1) return npos; @@ -1983,13 +2209,13 @@ class basic_string //! Returns: find_last_not_of(basic_string(1, c), pos). size_type find_last_not_of(CharT c, size_type pos = npos) const { - const size_type len = size(); + const size_type len = this->size(); if (len < 1) return npos; else { const const_iterator last = begin() + container_detail::min_value(len - 1, pos) + 1; - const_reverse_iterator rresult = + const const_reverse_iterator rresult = std::find_if(const_reverse_iterator(last), rend(), std::not1(std::bind2nd(Eq_traits(), c))); return rresult != rend() ? (rresult.base() - 1) - begin() : npos; @@ -2006,10 +2232,11 @@ class basic_string //! Returns: basic_string(data()+pos,rlen). basic_string substr(size_type pos = 0, size_type n = npos) const { - if (pos > size()) + if (pos > this->size()) this->throw_out_of_range(); - return basic_string(this->priv_addr() + pos, - this->priv_addr() + pos + container_detail::min_value(n, size() - pos), this->alloc()); + const pointer addr = this->priv_addr(); + return basic_string(addr + pos, + addr + pos + container_detail::min_value(n, size() - pos), this->alloc()); } //! Effects: Determines the effective length rlen of the string to copy as @@ -2022,7 +2249,11 @@ class basic_string //! Otherwise, returns a value < 0 if size() < str.size(), a 0 value if size() == str.size(), //! and value > 0 if size() > str.size() int compare(const basic_string& str) const - { return s_compare(this->priv_addr(), this->priv_addr() + this->priv_size(), str.priv_addr(), str.priv_addr() + str.priv_size()); } + { + const pointer addr = this->priv_addr(); + const pointer str_addr = str.priv_addr(); + return s_compare(addr, addr + this->priv_size(), str_addr, str_addr + str.priv_size()); + } //! Requires: pos1 <= size() //! @@ -2034,11 +2265,13 @@ class basic_string //! Returns:basic_string(*this,pos1,n1).compare(str). int compare(size_type pos1, size_type n1, const basic_string& str) const { - if (pos1 > size()) + if (pos1 > this->size()) this->throw_out_of_range(); - return s_compare(this->priv_addr() + pos1, - this->priv_addr() + pos1 + container_detail::min_value(n1, size() - pos1), - str.priv_addr(), str.priv_addr() + str.priv_size()); + const pointer addr = this->priv_addr(); + const pointer str_addr = str.priv_addr(); + return s_compare(addr + pos1, + addr + pos1 + container_detail::min_value(n1, this->size() - pos1), + str_addr, str_addr + str.priv_size()); } //! Requires: pos1 <= size() and pos2 <= str.size() @@ -2051,19 +2284,24 @@ class basic_string //! Returns: basic_string(*this, pos1, n1).compare(basic_string(str, pos2, n2)). int compare(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2) const { - if (pos1 > size() || pos2 > str.size()) + if (pos1 > this->size() || pos2 > str.size()) this->throw_out_of_range(); - return s_compare(this->priv_addr() + pos1, - this->priv_addr() + pos1 + container_detail::min_value(n1, size() - pos1), - str.priv_addr() + pos2, - str.priv_addr() + pos2 + container_detail::min_value(n2, size() - pos2)); + const pointer addr = this->priv_addr(); + const pointer str_addr = str.priv_addr(); + return s_compare(addr + pos1, + addr + pos1 + container_detail::min_value(n1, this->size() - pos1), + str_addr + pos2, + str_addr + pos2 + container_detail::min_value(n2, str.size() - pos2)); } //! Throws: Nothing //! //! Returns: compare(basic_string(s)). int compare(const CharT* s) const - { return s_compare(this->priv_addr(), this->priv_addr() + this->priv_size(), s, s + Traits::length(s)); } + { + const pointer addr = this->priv_addr(); + return s_compare(addr, addr + this->priv_size(), s, s + Traits::length(s)); + } //! Requires: pos1 > size() and s points to an array of at least n2 elements of CharT. @@ -2074,10 +2312,11 @@ class basic_string int compare(size_type pos1, size_type n1, const CharT* s, size_type n2) const { - if (pos1 > size()) + if (pos1 > this->size()) this->throw_out_of_range(); - return s_compare(this->priv_addr() + pos1, - this->priv_addr() + pos1 + container_detail::min_value(n1, size() - pos1), + const pointer addr = this->priv_addr(); + return s_compare( addr + pos1, + addr + pos1 + container_detail::min_value(n1, this->size() - pos1), s, s + n2); } @@ -2109,12 +2348,12 @@ class basic_string { //Allocate a new buffer. size_type real_cap = 0; - pointer long_addr = this->priv_long_addr(); - size_type long_size = this->priv_long_size(); - size_type long_storage = this->priv_long_storage(); + const pointer long_addr = this->priv_long_addr(); + const size_type long_size = this->priv_long_size(); + const size_type long_storage = this->priv_long_storage(); //We can make this nothrow as chars are always NoThrowCopyables try{ - std::pair ret = this->allocation_command + const std::pair ret = this->allocation_command (allocate_new, long_size+1, long_size+1, real_cap, long_addr); //Copy and update Traits::copy( container_detail::to_raw_pointer(ret.first) @@ -2145,55 +2384,12 @@ class basic_string } void priv_construct_null(pointer p) - { this->construct(p, 0); } - - static CharT priv_null() - { return (CharT) 0; } + { this->construct(p, CharT(0)); } // Helper functions used by constructors. It is a severe error for // any of them to be called anywhere except from within constructors. void priv_terminate_string() - { this->priv_construct_null(this->priv_addr() + this->priv_size()); } - - template - void priv_range_initialize(InputIter f, InputIter l, - std::input_iterator_tag) - { - this->allocate_initial_block(InternalBufferChars); - this->priv_construct_null(this->priv_addr() + this->priv_size()); - this->append(f, l); - } - - template - void priv_range_initialize(ForwardIter f, ForwardIter l, - std::forward_iterator_tag) - { - difference_type n = std::distance(f, l); - this->allocate_initial_block(container_detail::max_value(n+1, InternalBufferChars)); - priv_uninitialized_copy(f, l, this->priv_addr()); - this->priv_size(n); - this->priv_terminate_string(); - } - - template - void priv_range_initialize(InputIter f, InputIter l) - { - typedef typename std::iterator_traits::iterator_category Category; - this->priv_range_initialize(f, l, Category()); - } - - template - void priv_initialize_dispatch(Integer n, Integer x, container_detail::true_) - { - this->allocate_initial_block(container_detail::max_value(n+1, InternalBufferChars)); - priv_uninitialized_fill_n(this->priv_addr(), n, x); - this->priv_size(n); - this->priv_terminate_string(); - } - - template - void priv_initialize_dispatch(InputIter f, InputIter l, container_detail::false_) - { this->priv_range_initialize(f, l); } + { this->priv_construct_null(this->priv_end_addr()); } template inline void priv_uninitialized_fill_n(FwdIt first, Count count, const CharT val) @@ -2241,154 +2437,6 @@ class basic_string return (constructed); } - template - basic_string& priv_assign_dispatch(Integer n, Integer x, container_detail::true_) - { return this->assign((size_type) n, (CharT) x); } - - template - basic_string& priv_assign_dispatch(InputIter f, InputIter l, - container_detail::false_) - { - size_type cur = 0; - CharT *ptr = container_detail::to_raw_pointer(this->priv_addr()); - while (f != l && cur != this->priv_size()) { - Traits::assign(*ptr, *f); - ++f; - ++cur; - ++ptr; - } - if (f == l) - this->erase(this->priv_addr() + cur, this->priv_addr() + this->priv_size()); - else - this->append(f, l); - return *this; - } - - template - void priv_insert(const_iterator p, InputIter first, InputIter last, std::input_iterator_tag) - { - for ( ; first != last; ++first, ++p) { - p = this->insert(p, *first); - } - } - - template - void priv_insert(const_iterator position, ForwardIter first, - ForwardIter last, std::forward_iterator_tag) - { - if (first != last) { - size_type n = std::distance(first, last); - size_type remaining = this->capacity() - this->priv_size(); - const size_type old_size = this->size(); - pointer old_start = this->priv_addr(); - bool enough_capacity = false; - std::pair allocation_ret; - size_type new_cap = 0; - - //Check if we have enough capacity - if (remaining >= n){ - enough_capacity = true; - } - else { - //Otherwise expand current buffer or allocate new storage - new_cap = this->next_capacity(n); - allocation_ret = this->allocation_command - (allocate_new | expand_fwd | expand_bwd, old_size + n + 1, - new_cap, new_cap, old_start); - - //Check forward expansion - if(old_start == allocation_ret.first){ - enough_capacity = true; - this->priv_storage(new_cap); - } - } - - //Reuse same buffer - if(enough_capacity){ - const size_type elems_after = - this->priv_size() - (position - this->priv_addr()); - size_type old_length = this->priv_size(); - if (elems_after >= n) { - pointer pointer_past_last = this->priv_addr() + this->priv_size() + 1; - priv_uninitialized_copy(this->priv_addr() + (this->priv_size() - n + 1), - pointer_past_last, pointer_past_last); - - this->priv_size(this->priv_size()+n); - Traits::move(const_cast(container_detail::to_raw_pointer(position + n)), - container_detail::to_raw_pointer(position), - (elems_after - n) + 1); - this->priv_copy(first, last, const_cast(container_detail::to_raw_pointer(position))); - } - else { - ForwardIter mid = first; - std::advance(mid, elems_after + 1); - - priv_uninitialized_copy(mid, last, this->priv_addr() + this->priv_size() + 1); - this->priv_size(this->priv_size() + (n - elems_after)); - priv_uninitialized_copy - (position, const_iterator(this->priv_addr() + old_length + 1), - this->priv_addr() + this->priv_size()); - this->priv_size(this->priv_size() + elems_after); - this->priv_copy(first, mid, const_cast(container_detail::to_raw_pointer(position))); - } - } - else{ - pointer new_start = allocation_ret.first; - if(!allocation_ret.second){ - //Copy data to new buffer - size_type new_length = 0; - //This can't throw, since characters are POD - new_length += priv_uninitialized_copy - (const_iterator(this->priv_addr()), position, new_start); - new_length += priv_uninitialized_copy - (first, last, new_start + new_length); - new_length += priv_uninitialized_copy - (position, const_iterator(this->priv_addr() + this->priv_size()), - new_start + new_length); - this->priv_construct_null(new_start + new_length); - - this->deallocate_block(); - this->is_short(false); - this->priv_long_addr(new_start); - this->priv_long_size(new_length); - this->priv_long_storage(new_cap); - } - else{ - //value_type is POD, so backwards expansion is much easier - //than with vector - value_type *oldbuf = container_detail::to_raw_pointer(old_start); - value_type *newbuf = container_detail::to_raw_pointer(new_start); - const value_type *pos = container_detail::to_raw_pointer(position); - size_type before = pos - oldbuf; - - //First move old data - Traits::move(newbuf, oldbuf, before); - Traits::move(newbuf + before + n, pos, old_size - before); - //Now initialize the new data - priv_uninitialized_copy(first, last, new_start + before); - this->priv_construct_null(new_start + (old_size + n)); - this->is_short(false); - this->priv_long_addr(new_start); - this->priv_long_size(old_size + n); - this->priv_long_storage(new_cap); - } - } - } - } - - template - void priv_insert_dispatch(const_iterator p, Integer n, Integer x, - container_detail::true_) - { insert(p, (size_type) n, (CharT) x); } - - template - void priv_insert_dispatch(const_iterator p, InputIter first, InputIter last, - container_detail::false_) - { - typedef typename std::iterator_traits::iterator_category Category; - priv_insert(p, first, last, Category()); - } - template void priv_copy(InputIterator first, InputIterator last, OutIterator result) { @@ -2414,40 +2462,6 @@ class basic_string return this->priv_replace(first, last, f, l, Category()); } - - template - basic_string& priv_replace(const_iterator first, const_iterator last, - InputIter f, InputIter l, std::input_iterator_tag) - { - for ( ; first != last && f != l; ++first, ++f) - Traits::assign(*first, *f); - - if (f == l) - this->erase(first, last); - else - this->insert(last, f, l); - return *this; - } - - template - basic_string& priv_replace(const_iterator first, const_iterator last, - ForwardIter f, ForwardIter l, - std::forward_iterator_tag) - { - difference_type n = std::distance(f, l); - const difference_type len = last - first; - if (len >= n) { - this->priv_copy(f, l, const_cast(container_detail::to_raw_pointer(first))); - this->erase(first + n, last); - } - else { - ForwardIter m = f; - std::advance(m, len); - this->priv_copy(f, m, const_cast(container_detail::to_raw_pointer(first))); - this->insert(last, m, l); - } - return *this; - } /// @endcond }; diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index c6e5b51..91f4207 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -86,7 +86,7 @@ class vector_const_iterator { return *m_ptr; } const value_type * operator->() const - { return container_detail::to_raw_pointer(m_ptr); } + { return container_detail::to_raw_pointer(m_ptr); } reference operator[](difference_type off) const { return m_ptr[off]; } @@ -408,40 +408,29 @@ template class vector : private container_detail::vector_alloc_holder { /// @cond - typedef vector self_t; typedef container_detail::vector_alloc_holder base_t; typedef allocator_traits allocator_traits_type; /// @endcond public: - //! The type of object, T, stored in the vector - typedef T value_type; - //! Pointer to T - typedef typename allocator_traits_type::pointer pointer; - //! Const pointer to T - typedef typename allocator_traits_type::const_pointer const_pointer; - //! Reference to T - typedef typename allocator_traits_type::reference reference; - //! Const reference to T - typedef typename allocator_traits_type::const_reference const_reference; - //! An unsigned integral type - typedef typename allocator_traits_type::size_type size_type; - //! A signed integral type - typedef typename allocator_traits_type::difference_type difference_type; - //! The allocator type - typedef A allocator_type; - //! The random access iterator - typedef container_detail::vector_iterator iterator; - //! The random access const_iterator - typedef container_detail::vector_const_iterator const_iterator; + ////////////////////////////////////////////// + // + // types + // + ////////////////////////////////////////////// - //! Iterator used to iterate backwards through a vector. - typedef std::reverse_iterator - reverse_iterator; - //! Const iterator used to iterate backwards through a vector. - typedef std::reverse_iterator - const_reverse_iterator; - //! The stored allocator type - typedef allocator_type stored_allocator_type; + typedef T value_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + typedef typename ::boost::container::allocator_traits::const_pointer const_pointer; + typedef typename ::boost::container::allocator_traits::reference reference; + typedef typename ::boost::container::allocator_traits::const_reference const_reference; + typedef typename ::boost::container::allocator_traits::size_type size_type; + typedef typename ::boost::container::allocator_traits::difference_type difference_type; + typedef A allocator_type; + typedef allocator_type stored_allocator_type; + typedef BOOST_CONTAINER_IMPDEF(container_detail::vector_iterator) iterator; + typedef BOOST_CONTAINER_IMPDEF(container_detail::vector_const_iterator) const_iterator; + typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator) reverse_iterator; + typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator) const_reverse_iterator; /// @cond private: @@ -459,6 +448,11 @@ class vector : private container_detail::vector_alloc_holder /// @endcond public: + ////////////////////////////////////////////// + // + // construct/copy/destroy + // + ////////////////////////////////////////////// //! Effects: Constructs a vector taking the allocator as parameter. //! @@ -488,23 +482,7 @@ class vector : private container_detail::vector_alloc_holder //! Complexity: Linear to n. explicit vector(size_type n) : base_t() - { - //Allocate - size_type real_cap; - std::pair ret = - this->allocation_command(allocate_new, n, n, real_cap, this->members_.m_start); - T *new_mem = container_detail::to_raw_pointer(ret.first); - //Anti-exception rollback - typename value_traits::ArrayDeallocator scoped_alloc(new_mem, this->alloc(), real_cap); - //Default constructor - container_detail::default_construct_aux_proxy proxy(this->alloc(), n); - proxy.uninitialized_copy_remaining_to(new_mem); - //All ok, commit - this->members_.m_start = ret.first; - this->members_.m_size = n; - this->members_.m_capacity = real_cap; - scoped_alloc.release(); - } + { this->resize(n); } //! Effects: Constructs a vector that will use a copy of allocator a //! and inserts n copies of value. @@ -515,7 +493,19 @@ class vector : private container_detail::vector_alloc_holder //! Complexity: 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); } + { this->resize(n, value); } + + //! Effects: Constructs a vector that will use a copy of allocator a + //! and inserts a copy of the range [first, last) in the vector. + //! + //! Throws: If allocator_type's default constructor or allocation + //! throws or T's constructor taking an dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + vector(InIt first, InIt last, const allocator_type& a = allocator_type()) + : base_t(a) + { this->assign(first, last); } //! Effects: Copy constructs a vector. //! @@ -571,22 +561,10 @@ class vector : private container_detail::vector_alloc_holder } else{ this->assign( container_detail::to_raw_pointer(mx.members_.m_start) - , container_detail::to_raw_pointer(mx.members_.m_start + mx.members_.m_size)); + , container_detail::to_raw_pointer(mx.members_.m_start) + mx.members_.m_size); } } - //! Effects: Constructs a vector that will use a copy of allocator a - //! and inserts a copy of the range [first, last) in the vector. - //! - //! Throws: If allocator_type's default constructor or allocation - //! throws or T's constructor taking an dereferenced InIt throws. - //! - //! Complexity: Linear to the range [first, last). - template - vector(InIt first, InIt last, const allocator_type& a = allocator_type()) - : base_t(a) - { this->assign(first, last); } - //! Effects: Destroys the vector. All stored values are destroyed //! and used memory is deallocated. //! @@ -596,6 +574,141 @@ class vector : private container_detail::vector_alloc_holder ~vector() BOOST_CONTAINER_NOEXCEPT {} //vector_alloc_holder clears the data + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy/move constructor/assignment throws. + //! + //! Complexity: Linear to the number of elements in x. + vector& operator=(BOOST_COPY_ASSIGN_REF(vector) x) + { + if (&x != this){ + allocator_type &this_alloc = this->alloc(); + const allocator_type &x_alloc = x.alloc(); + container_detail::bool_ flag; + if(flag && this_alloc != x_alloc){ + this->clear(); + this->shrink_to_fit(); + } + container_detail::assign_alloc(this_alloc, x_alloc, flag); + this->assign( container_detail::to_raw_pointer(x.members_.m_start) + , container_detail::to_raw_pointer(x.members_.m_start + x.members_.m_size)); + } + return *this; + } + + //! Effects: Move assignment. All mx's values are transferred to *this. + //! + //! Postcondition: x.empty(). *this contains a the elements x had + //! before the function. + //! + //! Throws: Nothing + //! + //! Complexity: Linear. + vector& operator=(BOOST_RV_REF(vector) x) + //iG BOOST_CONTAINER_NOEXCEPT_IF(!allocator_type::propagate_on_container_move_assignment::value || is_nothrow_move_assignable::value);) + BOOST_CONTAINER_NOEXCEPT + { + if (&x != this){ + allocator_type &this_alloc = this->alloc(); + allocator_type &x_alloc = x.alloc(); + //If allocators are equal we can just swap pointers + if(this_alloc == x_alloc){ + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + this->swap_members(x); + //Move allocator if needed + container_detail::bool_ flag; + container_detail::move_alloc(this_alloc, x_alloc, flag); + } + //If unequal allocators, then do a one by one move + else{ + this->assign( boost::make_move_iterator(container_detail::to_raw_pointer(x.members_.m_start)) + , boost::make_move_iterator(container_detail::to_raw_pointer(x.members_.m_start + x.members_.m_size))); + } + } + return *this; + } + + //! Effects: Assigns the the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or T's copy/move constructor/assignment or + //! T's constructor/assignment from dereferencing InpIt throws. + //! + //! Complexity: Linear to n. + template + void assign(InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + //&& container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) + { + //Overwrite all elements we can from [first, last) + iterator cur = this->begin(); + 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, this->cend()); + } + else{ + //There are more elements in the range, insert the remaining ones + this->insert(this->cend(), first, last); + } + } + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or + //! T's copy/move constructor/assignment throws. + //! + //! Complexity: Linear to n. + void assign(size_type n, const value_type& val) + { this->assign(cvalue_iterator(val, n), cvalue_iterator()); } + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + allocator_type get_allocator() const BOOST_CONTAINER_NOEXCEPT + { return this->alloc(); } + + //! Effects: Returns a reference to the internal allocator. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. + const stored_allocator_type &get_stored_allocator() const BOOST_CONTAINER_NOEXCEPT + { return this->alloc(); } + + //! Effects: Returns a reference to the internal allocator. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. + stored_allocator_type &get_stored_allocator() BOOST_CONTAINER_NOEXCEPT + { return this->alloc(); } + + ////////////////////////////////////////////// + // + // iterators + // + ////////////////////////////////////////////// + //! Effects: Returns an iterator to the first element contained in the vector. //! //! Throws: Nothing. @@ -698,67 +811,19 @@ class vector : private container_detail::vector_alloc_holder const_reverse_iterator crend() const BOOST_CONTAINER_NOEXCEPT { return const_reverse_iterator(this->begin()); } - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first - //! element of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference front() BOOST_CONTAINER_NOEXCEPT - { return *this->members_.m_start; } + ////////////////////////////////////////////// + // + // capacity + // + ////////////////////////////////////////////// - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first - //! element of the container. + //! Effects: Returns true if the vector contains no elements. //! //! Throws: Nothing. //! //! Complexity: Constant. - const_reference front() const BOOST_CONTAINER_NOEXCEPT - { return *this->members_.m_start; } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the last - //! element of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference back() BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start[this->members_.m_size - 1]; } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the last - //! element of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference back() const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start[this->members_.m_size - 1]; } - - //! Returns: A pointer such that [data(),data() + size()) is a valid range. - //! For a non-empty vector, data() == &front(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - pointer data() BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start; } - - //! Returns: A pointer such that [data(),data() + size()) is a valid range. - //! For a non-empty vector, data() == &front(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_pointer data() const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start; } + bool empty() const BOOST_CONTAINER_NOEXCEPT + { return !this->members_.m_size; } //! Effects: Returns the number of the elements contained in the vector. //! @@ -776,6 +841,45 @@ class vector : private container_detail::vector_alloc_holder size_type max_size() const BOOST_CONTAINER_NOEXCEPT { return allocator_traits_type::max_size(this->alloc()); } + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size) + { + if (new_size < this->size()){ + //Destroy last elements + this->erase(const_iterator(this->members_.m_start + new_size), this->end()); + } + else{ + const size_type n = new_size - this->size(); + this->reserve(new_size); + container_detail::default_construct_aux_proxy proxy(this->alloc(), n); + this->priv_forward_range_insert(this->cend().get_ptr(), n, proxy); + } + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size, const T& x) + { + 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); + } + } + //! Effects: Number of elements for which memory has been allocated. //! capacity() is always greater than or equal to size(). //! @@ -785,86 +889,6 @@ class vector : private container_detail::vector_alloc_holder size_type capacity() const BOOST_CONTAINER_NOEXCEPT { return this->members_.m_capacity; } - //! Effects: Returns true if the vector contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const BOOST_CONTAINER_NOEXCEPT - { return !this->members_.m_size; } - - //! Requires: size() > n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference operator[](size_type n) - { return this->members_.m_start[n]; } - - //! Requires: size() > n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference operator[](size_type n) const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start[n]; } - - //! Requires: size() > n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - reference at(size_type n) - { this->priv_check_range(n); return this->members_.m_start[n]; } - - //! Requires: size() > n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - const_reference at(size_type n) const - { this->priv_check_range(n); return this->members_.m_start[n]; } - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: Constant. - allocator_type get_allocator() const BOOST_CONTAINER_NOEXCEPT - { return this->alloc(); } - - //! Effects: Returns a reference to the internal allocator. - //! - //! Throws: Nothing - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension. - const stored_allocator_type &get_stored_allocator() const BOOST_CONTAINER_NOEXCEPT - { return this->alloc(); } - - //! Effects: Returns a reference to the internal allocator. - //! - //! Throws: Nothing - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension. - stored_allocator_type &get_stored_allocator() BOOST_CONTAINER_NOEXCEPT - { return this->alloc(); } - //! Effects: If n is less than or equal to capacity(), this call has no //! effect. Otherwise, it is a request for allocation of additional memory. //! If the request is successful, then capacity() is greater than or equal to @@ -926,110 +950,138 @@ class vector : private container_detail::vector_alloc_holder } } - //! Effects: Makes *this contain the same elements as x. + //! Effects: Tries to deallocate the excess of memory created + //! with previous allocations. The size of the vector is unchanged //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. + //! Throws: If memory allocation throws, or T's copy/move constructor throws. //! - //! Throws: If memory allocation throws or T's copy/move constructor/assignment throws. - //! - //! Complexity: Linear to the number of elements in x. - vector& operator=(BOOST_COPY_ASSIGN_REF(vector) x) - { - if (&x != this){ - allocator_type &this_alloc = this->alloc(); - const allocator_type &x_alloc = x.alloc(); - container_detail::bool_ flag; - if(flag && this_alloc != x_alloc){ - this->clear(); - this->shrink_to_fit(); - } - container_detail::assign_alloc(this_alloc, x_alloc, flag); - this->assign( container_detail::to_raw_pointer(x.members_.m_start) - , container_detail::to_raw_pointer(x.members_.m_start + x.members_.m_size)); - } - return *this; - } + //! Complexity: Linear to size(). + void shrink_to_fit() + { priv_shrink_to_fit(alloc_version()); } - //! Effects: Move assignment. All mx's values are transferred to *this. - //! - //! Postcondition: x.empty(). *this contains a the elements x had - //! before the function. - //! - //! Throws: Nothing - //! - //! Complexity: Linear. - vector& operator=(BOOST_RV_REF(vector) x) - //iG BOOST_CONTAINER_NOEXCEPT_IF(!allocator_type::propagate_on_container_move_assignment::value || is_nothrow_move_assignable::value);) - BOOST_CONTAINER_NOEXCEPT - { - if (&x != this){ - allocator_type &this_alloc = this->alloc(); - allocator_type &x_alloc = x.alloc(); - //If allocators are equal we can just swap pointers - if(this_alloc == x_alloc){ - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - this->swap_members(x); - //Move allocator if needed - container_detail::bool_ flag; - container_detail::move_alloc(this_alloc, x_alloc, flag); - } - //If unequal allocators, then do a one by one move - else{ - this->assign( boost::make_move_iterator(container_detail::to_raw_pointer(x.members_.m_start)) - , boost::make_move_iterator(container_detail::to_raw_pointer(x.members_.m_start + x.members_.m_size))); - } - } - return *this; - } + ////////////////////////////////////////////// + // + // element access + // + ////////////////////////////////////////////// - //! Effects: Assigns the n copies of val to *this. + //! Requires: !empty() //! - //! Throws: If memory allocation throws or - //! T's copy/move constructor/assignment throws. + //! Effects: Returns a reference to the first + //! element of the container. //! - //! Complexity: Linear to n. - void assign(size_type n, const value_type& val) - { this->assign(cvalue_iterator(val, n), cvalue_iterator()); } + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() BOOST_CONTAINER_NOEXCEPT + { return *this->members_.m_start; } - //! Effects: Assigns the the range [first, last) to *this. + //! Requires: !empty() //! - //! Throws: If memory allocation throws or T's copy/move constructor/assignment or - //! T's constructor/assignment from dereferencing InpIt throws. + //! Effects: Returns a const reference to the first + //! element of the container. //! - //! Complexity: Linear to n. - template - void assign(InIt first, InIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const BOOST_CONTAINER_NOEXCEPT + { return *this->members_.m_start; } - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //! Effects: Inserts a copy of x at the end of the vector. + //! Requires: !empty() //! - //! Throws: If memory allocation throws or - //! T's copy/move constructor throws. + //! Effects: Returns a reference to the last + //! element of the container. //! - //! Complexity: Amortized constant time. - void push_back(const T &x); + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference back() BOOST_CONTAINER_NOEXCEPT + { return this->members_.m_start[this->members_.m_size - 1]; } - //! Effects: Constructs a new element in the end of the vector - //! and moves the resources of mx to this new element. + //! Requires: !empty() //! - //! Throws: If memory allocation throws or - //! T's move constructor throws. + //! Effects: Returns a const reference to the last + //! element of the container. //! - //! Complexity: Amortized constant time. - void push_back(T &&x); - #else - BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) - #endif + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference back() const BOOST_CONTAINER_NOEXCEPT + { return this->members_.m_start[this->members_.m_size - 1]; } + + //! Requires: size() > n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference operator[](size_type n) + { return this->members_.m_start[n]; } + + //! Requires: size() > n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference operator[](size_type n) const BOOST_CONTAINER_NOEXCEPT + { return this->members_.m_start[n]; } + + //! Requires: size() > n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + reference at(size_type n) + { this->priv_check_range(n); return this->members_.m_start[n]; } + + //! Requires: size() > n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + const_reference at(size_type n) const + { this->priv_check_range(n); return this->members_.m_start[n]; } + + ////////////////////////////////////////////// + // + // data access + // + ////////////////////////////////////////////// + + //! Returns: A pointer such that [data(),data() + size()) is a valid range. + //! For a non-empty vector, data() == &front(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + T* data() BOOST_CONTAINER_NOEXCEPT + { return container_detail::to_raw_pointer(this->members_.m_start); } + + //! Returns: A pointer such that [data(),data() + size()) is a valid range. + //! For a non-empty vector, data() == &front(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const T * data() const BOOST_CONTAINER_NOEXCEPT + { return container_detail::to_raw_pointer(this->members_.m_start); } + + ////////////////////////////////////////////// + // + // modifiers + // + ////////////////////////////////////////////// #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Inserts an object of type T constructed with @@ -1051,7 +1103,7 @@ class vector : private container_detail::vector_alloc_holder else{ typedef container_detail::advanced_insert_aux_emplace type; type &&proxy = type(this->alloc(), ::boost::forward(args)...); - priv_range_insert(back_pos, 1, proxy); + this->priv_forward_range_insert(back_pos, 1, proxy); } } @@ -1072,7 +1124,7 @@ class vector : private container_detail::vector_alloc_holder size_type pos_n = position - cbegin(); typedef container_detail::advanced_insert_aux_emplace type; type &&proxy = type(this->alloc(), ::boost::forward(args)...); - priv_range_insert(position.get_ptr(), 1, proxy); + this->priv_forward_range_insert(position.get_ptr(), 1, proxy); return iterator(this->members_.m_start + pos_n); } @@ -1093,7 +1145,7 @@ class vector : private container_detail::vector_alloc_holder container_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ proxy \ (this->alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ - priv_range_insert(back_pos, 1, proxy); \ + this->priv_forward_range_insert(back_pos, 1, proxy); \ } \ } \ \ @@ -1105,7 +1157,7 @@ class vector : private container_detail::vector_alloc_holder container_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ proxy \ (this->alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ - priv_range_insert(container_detail::to_raw_pointer(pos.get_ptr()), 1, proxy); \ + this->priv_forward_range_insert(container_detail::to_raw_pointer(pos.get_ptr()), 1,proxy);\ return iterator(this->members_.m_start + pos_n); \ } \ //! @@ -1113,21 +1165,28 @@ class vector : private container_detail::vector_alloc_holder #include BOOST_PP_LOCAL_ITERATE() #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING - - //! Effects: Swaps the contents of *this and x. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - void swap(vector& x) - { - //Just swap internals - this->swap_members(x); - //And now the allocator - container_detail::bool_ flag; - container_detail::swap_alloc(this->alloc(), x.alloc(), flag); - } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: Inserts a copy of x at the end of the vector. + //! + //! Throws: If memory allocation throws or + //! T's copy/move constructor throws. + //! + //! Complexity: Amortized constant time. + void push_back(const T &x); + + //! Effects: Constructs a new element in the end of the vector + //! and moves the resources of mx to this new element. + //! + //! Throws: If memory allocation throws or + //! T's move constructor throws. + //! + //! Complexity: Amortized constant time. + void push_back(T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) + #endif + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Requires: position must be a valid iterator of *this. //! @@ -1152,32 +1211,63 @@ class vector : private container_detail::vector_alloc_holder BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator) #endif - //! Requires: pos must be a valid iterator of *this. + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert n copies of x before pos. + //! + //! Returns: an iterator to the first inserted element or p if n is 0. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + iterator insert(const_iterator p, size_type n, const T& x) + { return this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); } + + //! Requires: p must be a valid iterator of *this. //! //! Effects: Insert a copy of the [first, last) range before pos. //! + //! Returns: an iterator to the first inserted element or pos if first == last. + //! //! Throws: If memory allocation throws, T's constructor from a //! dereferenced InpIt throws or T's copy/move constructor/assignment throws. //! //! Complexity: Linear to std::distance [first, last). template - void insert(const_iterator pos, InIt first, InIt last) + iterator insert(const_iterator pos, InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_insert_dispatch(pos, first, last, Result()); + const size_type n_pos = pos - this->cbegin(); + iterator it(pos.get_ptr()); + for(;first != last; ++first){ + it = this->emplace(it, *first); + ++it; + } + return this->begin() + n_pos; } - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert n copies of x before pos. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void insert(const_iterator p, size_type n, const T& x) - { this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); } + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator insert(const_iterator pos, FwdIt first, FwdIt last + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !container_detail::is_input_iterator::value + >::type * = 0 + ) + { + const size_type n_pos = pos - this->cbegin(); + const size_type n = std::distance(first, last); + container_detail::advanced_insert_aux_proxy proxy(this->alloc(), first, last); + this->priv_forward_range_insert(pos.get_ptr(), n, proxy); + return this->begin() + n_pos; + } + #endif //! Effects: Removes the last element from the vector. //! @@ -1230,43 +1320,18 @@ class vector : private container_detail::vector_alloc_holder return iterator(first.get_ptr()); } - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. + //! Effects: Swaps the contents of *this and x. //! - //! Throws: If memory allocation throws, or T's copy constructor throws. + //! Throws: Nothing. //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size, const T& x) + //! Complexity: Constant. + void swap(vector& 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); - } - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size) - { - 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); - container_detail::default_construct_aux_proxy proxy(this->alloc(), n); - priv_range_insert(this->cend().get_ptr(), n, proxy); - } + //Just swap internals + this->swap_members(x); + //And now the allocator + container_detail::bool_ flag; + container_detail::swap_alloc(this->alloc(), x.alloc(), flag); } //! Effects: Erases all the elements of the vector. @@ -1277,15 +1342,6 @@ class vector : private container_detail::vector_alloc_holder void clear() BOOST_CONTAINER_NOEXCEPT { this->prot_destroy_all(); } - //! Effects: Tries to deallocate the excess of memory created - //! with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy/move constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { priv_shrink_to_fit(alloc_version()); } - /// @cond //Absolutely experimental. This function might change, disappear or simply crash! @@ -1344,7 +1400,7 @@ class vector : private container_detail::vector_alloc_holder container_detail::is_same::value >::type * = 0) { if(this->members_.m_capacity){ - if(!size()){ + if(!this->size()){ this->prot_deallocate(); } else{ @@ -1399,25 +1455,7 @@ class vector : private container_detail::vector_alloc_holder } } - template - void priv_range_insert(const_iterator pos, FwdIt first, FwdIt last, std::forward_iterator_tag) - { - if(first != last){ - const size_type n = std::distance(first, last); - container_detail::advanced_insert_aux_proxy proxy(this->alloc(), first, last); - priv_range_insert(pos.get_ptr(), n, proxy); - } - } - - template - void priv_range_insert(const_iterator pos, InIt first, InIt last, std::input_iterator_tag) - { - for(;first != last; ++first){ - this->emplace(pos, *first); - } - } - - void priv_range_insert(pointer pos, const size_type n, advanced_insert_aux_int_t &interf) + void priv_forward_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; @@ -1564,7 +1602,7 @@ class vector : private container_detail::vector_alloc_holder //New situation in Case A (hole_size == 0): // range is moved through move assignments // - // first_pos last_pos old_limit + // first_pos last_pos limit_pos // | | | // ____________V_______V__________________V_____________ //| prefix' | | | range |suffix'|raw_mem ~ @@ -1573,10 +1611,10 @@ class vector : private container_detail::vector_alloc_holder // |_>_>_>_>_>^ // // - //New situation in Case B (hole_size >= 0): + //New situation in Case B (hole_size > 0): // range is moved through uninitialized moves // - // first_pos last_pos old_limit + // first_pos last_pos limit_pos // | | | // ____________V_______V__________________V________________ //| prefix' | | | [hole] | range | @@ -1587,31 +1625,33 @@ class vector : private container_detail::vector_alloc_holder //New situation in Case C (hole_size == 0): // range is moved through move assignments and uninitialized moves // - // first_pos last_pos old_limit + // first_pos last_pos limit_pos // | | | // ____________V_______V__________________V___ //| prefix' | | | range | //|___________________________________|___^___| // | | // |_>_>_>_>_>_>_>_>_>_>_>^ - size_type priv_insert_ordered_at_shift_range(size_type first_pos, size_type last_pos, size_type limit_pos, size_type shift_count) + size_type priv_insert_ordered_at_shift_range + (size_type first_pos, size_type last_pos, size_type limit_pos, size_type shift_count) { BOOST_ASSERT(first_pos <= last_pos); BOOST_ASSERT(last_pos <= limit_pos); // T* const begin_ptr = container_detail::to_raw_pointer(this->members_.m_start); + T* const first_ptr = begin_ptr + first_pos; + T* const last_ptr = begin_ptr + last_pos; size_type hole_size = 0; //Case A: if((last_pos + shift_count) <= limit_pos){ //All move assigned - boost::move_backward(begin_ptr + first_pos, begin_ptr + last_pos, begin_ptr + last_pos + shift_count); + boost::move_backward(first_ptr, last_ptr, last_ptr + shift_count); } //Case B: else if((first_pos + shift_count) >= limit_pos){ //All uninitialized_moved - ::boost::container::uninitialized_move_alloc - (this->alloc(), begin_ptr + first_pos, begin_ptr + last_pos, begin_ptr + first_pos + shift_count); + ::boost::container::uninitialized_move_alloc(this->alloc(), first_ptr, last_ptr, first_ptr + shift_count); hole_size = last_pos + shift_count - limit_pos; } //Case C: @@ -1619,10 +1659,9 @@ class vector : private container_detail::vector_alloc_holder //Some uninitialized_moved T* const limit_ptr = begin_ptr + limit_pos; T* const boundary_ptr = limit_ptr - shift_count; - ::boost::container::uninitialized_move_alloc - (this->alloc(), boundary_ptr, begin_ptr + last_pos, limit_ptr); + ::boost::container::uninitialized_move_alloc(this->alloc(), boundary_ptr, last_ptr, limit_ptr); //The rest is move assigned - boost::move_backward(begin_ptr + first_pos, boundary_ptr, limit_ptr); + boost::move_backward(first_ptr, boundary_ptr, limit_ptr); } return hole_size; } @@ -1999,173 +2038,10 @@ class vector : private container_detail::vector_alloc_holder } } - template - 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 - 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 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 = container_detail::to_raw_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 - ::boost::container::uninitialized_copy_or_move_alloc(this->alloc(), mid, last, end); - this->members_.m_size = n; - } - } - else if(!ret.second){ - typename value_traits::ArrayDeallocator scoped_alloc(ret.first, this->alloc(), real_cap); - ::boost::container::uninitialized_copy_or_move_alloc(this->alloc(), first, last, container_detail::to_raw_pointer(ret.first)); - scoped_alloc.release(); - //Destroy and deallocate old buffer - if(this->members_.m_start != 0){ - this->destroy_n(container_detail::to_raw_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 = container_detail::to_raw_pointer(this->members_.m_start); - size_type old_size = this->members_.m_size; - typename value_traits::OldArrayDestructor old_values_destroyer(old_start, this->alloc(), 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 - container_detail::to_raw_pointer(ret.first); - size_type first_count = container_detail::min_value(n, old_offset); - - FwdIt mid = first; - std::advance(mid, first_count); - ::boost::container::uninitialized_copy_or_move_alloc - (this->alloc(), first, mid, container_detail::to_raw_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 = container_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 - void priv_assign_dispatch(Integer n, Integer val, container_detail::true_) - { this->assign((size_type) n, (value_type)val); } - - template - void priv_assign_dispatch(InIt first, InIt last, container_detail::false_) - { - //Dispatch depending on integer/iterator - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_assign_aux(first, last, ItCat()); - } - - template - void priv_insert_dispatch(const_iterator pos, Integer n, Integer val, container_detail::true_) - { this->insert(pos, (size_type)n, (T)val); } - - template - void priv_insert_dispatch(const_iterator pos, InIt first, - InIt last, container_detail::false_) - { - //Dispatch depending on integer/iterator - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_range_insert(pos, 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()) + if (n >= this->size()) throw std::out_of_range("vector::at"); } diff --git a/proj/to-do.txt b/proj/to-do.txt index 072519c..b548cbc 100644 --- a/proj/to-do.txt +++ b/proj/to-do.txt @@ -34,10 +34,128 @@ Write forward_list check move if noexcept conditions in vector, deque and stable_vector +Add noexcept testing using static_assert (Howard Hinnants's suggestion): + + #include + + struct A + { + void foo() noexcept; + }; + + static_assert(noexcept(std::declval().foo()), "A::foo() should be noexcept"); + Detect always equal or unequal allocators at compiler time. operator== returns true_type or false_type change virtual functions with pointers to avoid template instantiation for every type Add hash for containers -Add std:: hashing support \ No newline at end of file +Add std:: hashing support + +Take out from class definition iterators in slist & list + +Fix trivial destructor after move and other optimizing traits + +Define typedefs exactly like the standard to generate better documentation. for implementation defined types: + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + #define BOOST_CONTAINER_IMPLDEF(TYPE) TYPE + #else + #define BOOST_CONTAINER_IMPLDEF(TYPE) implementation_defined + #endif +Mark previous() in slist/and forward_list as non-standard + +Replace all insert_const_ref_type with BOOST_MOVE_CONVERSION_AWARE_CATCH_XXX + + + +Function order: + +----------type------------ +value_type; +pointer; +const_pointer; +reference; +const_reference; +size_type; +difference_type; +allocator_type; +stored_allocator_type; +iterator; +const_iterator; +reverse_iterator; +const_reverse_iterator; +----------func------------ +container() +container(allocator_type) +container(size_type) +container(size_type, value_type, allocator_type = ()) +container(InpIt, InpIt) +container(const container &) +container(container &&) +container(const container &, allocator_type) +container(container &&, allocator_type) +container(initializer_list, allocator) +~container() +container operator=(const container &) +container operator=(container &&) +container operator=(initializer_list) +assign(size_type, const T &) + +assign(InpIt, InptIt) +assign(initializer_list) +get_allocator() + +begin() +begin() const +end() +end() const +rbegin() +rbegin() const +rend() +rend() const + +cbegin() const +cend() const +crbegin() const +crend() const + +empty() +size() +max_size() +resize(size_type) +resize(size_type, cont T&) +capacity() +reserve(size_type) +shrink_to_fit() + +front() +front() const +back() +back() const +operator[] () +operator[] ()const +at() +at() const + + +data() +data() const + +emplace_front() +emplace_back() +emplace() +push_front(const T&) +push_front(T&&) +push_back(const T&) +push_back(T&&) +insert(iterator, const T &) +insert(iterator, T &&) +insert(size_type, const T &) +insert(InpIt, InpIt) +pop_front() +pop_back() +erase(const_iterator) +erase(const_iterator, const_iterator) +swap(container &) +clear() \ No newline at end of file diff --git a/proj/vc7ide/allocator_traits_test.vcproj b/proj/vc7ide/allocator_traits_test.vcproj index ad50eba..6e73236 100644 --- a/proj/vc7ide/allocator_traits_test.vcproj +++ b/proj/vc7ide/allocator_traits_test.vcproj @@ -132,6 +132,9 @@ Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93815995-89BD-b043-5E8B-65FBE52E2AFB}"> + + diff --git a/proj/vc7ide/container.sln b/proj/vc7ide/container.sln index 591f0fc..68beb93 100644 --- a/proj/vc7ide/container.sln +++ b/proj/vc7ide/container.sln @@ -51,6 +51,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scoped_allocator_usage_test ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hash_table_test", "hash_table_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792606}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -111,6 +115,10 @@ Global {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Debug.Build.0 = Debug|Win32 {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Release.ActiveCfg = Release|Win32 {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/container.vcproj b/proj/vc7ide/container.vcproj index fcd9e8a..ca5a3e3 100644 --- a/proj/vc7ide/container.vcproj +++ b/proj/vc7ide/container.vcproj @@ -145,6 +145,9 @@ + + @@ -261,7 +264,7 @@ RelativePath="..\..\..\..\boost\container\detail\math_functions.hpp"> + RelativePath="..\..\..\..\boost\container\detail\memory_util.hpp"> diff --git a/test/check_equal_containers.hpp b/test/check_equal_containers.hpp index 69d642c..092846f 100644 --- a/test/check_equal_containers.hpp +++ b/test/check_equal_containers.hpp @@ -12,6 +12,8 @@ #define BOOST_CONTAINER_TEST_CHECK_EQUAL_CONTAINER_HPP #include +#include +#include #include #include #include @@ -20,6 +22,24 @@ namespace boost{ namespace container { namespace test{ +template< class T1, class T2> +bool CheckEqual( const T1 &t1, const T2 &t2 + , typename boost::container::container_detail::enable_if_c + ::value && + !boost::container::container_detail::is_pair::value + >::type* = 0) +{ return t1 == t2; } + +template< class Pair1, class Pair2> +bool CheckEqual( const Pair1 &pair1, const Pair2 &pair2 + , typename boost::container::container_detail::enable_if_c + ::value && + boost::container::container_detail::is_pair::value + >::type* = 0) +{ + return CheckEqual(pair1.first, pair2.first) && CheckEqual(pair1.second, pair2.second); +} + //Function to check if both containers are equal template @@ -38,9 +58,7 @@ bool CheckEqualContainers(const MyBoostCont *boostcont, const MyStdCont *stdcont } std::size_t i = 0; for(; itboost != itboostend; ++itboost, ++itstd, ++i){ - value_type val(*itstd); - const value_type &v = *itboost; - if(v != val) + if(!CheckEqual(*itstd, *itboost)) return false; } return true; diff --git a/test/deque_test.cpp b/test/deque_test.cpp index 53f17a3..fbc4ab6 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -63,7 +63,7 @@ bool deque_copyable_only(V1 *cntdeque, V2 *stddeque, container_detail::true_type typedef typename V1::value_type IntType; std::size_t size = cntdeque->size(); stddeque->insert(stddeque->end(), 50, 1); - cntdeque->insert(cntdeque->end(), 50, 1); + cntdeque->insert(cntdeque->end(), 50, IntType(1)); if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; { IntType move_me(1); diff --git a/test/dummy_test_allocator.hpp b/test/dummy_test_allocator.hpp index dd0d872..332892e 100644 --- a/test/dummy_test_allocator.hpp +++ b/test/dummy_test_allocator.hpp @@ -111,7 +111,7 @@ class dummy_test_allocator dummy_test_allocator(const dummy_test_allocator &) {} - pointer address(reference value) + pointer address(reference value) { return pointer(container_detail::addressof(value)); } const_pointer address(const_reference value) const diff --git a/test/expand_bwd_test_allocator.hpp b/test/expand_bwd_test_allocator.hpp index 556a26c..fbab8c7 100644 --- a/test/expand_bwd_test_allocator.hpp +++ b/test/expand_bwd_test_allocator.hpp @@ -108,7 +108,7 @@ class expand_bwd_test_allocator { return m_size; } friend void swap(self_t &alloc1, self_t &alloc2) - { + { container_detail::do_swap(alloc1.mp_buffer, alloc2.mp_buffer); container_detail::do_swap(alloc1.m_size, alloc2.m_size); container_detail::do_swap(alloc1.m_offset, alloc2.m_offset); diff --git a/test/input_from_forward_iterator.hpp b/test/input_from_forward_iterator.hpp new file mode 100644 index 0000000..348d144 --- /dev/null +++ b/test/input_from_forward_iterator.hpp @@ -0,0 +1,80 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_FORWARD_TO_INPUT_ITERATOR_HPP +#define BOOST_CONTAINER_TEST_FORWARD_TO_INPUT_ITERATOR_HPP + +#include + +namespace boost{ +namespace container { +namespace test{ + +template +class input_iterator_wrapper + : public std::iterator< std::input_iterator_tag + , typename std::iterator_traits::value_type + , typename std::iterator_traits::difference_type + , typename std::iterator_traits::pointer + , typename std::iterator_traits::reference + > +{ + FwdIterator m_it; + + public: + input_iterator_wrapper() + : m_it(0) + {} + + explicit input_iterator_wrapper(FwdIterator it) + : m_it(it) + {} + + //Default copy constructor... + //input_iterator_wrapper(const input_iterator_wrapper&); + + //Default assignment... + //input_iterator_wrapper &operator=(const input_iterator_wrapper&); + + //Default destructor... + //~input_iterator_wrapper(); + + typename std::iterator_traits::reference operator*() const + { return *m_it; } + + typename std::iterator_traits::pointer operator->() const + { return m_it.operator->(); } + + input_iterator_wrapper& operator++() + { ++m_it; return *this; } + + input_iterator_wrapper operator++(int ) + { + input_iterator_wrapper tmp(m_it); + ++m_it; + return tmp; + } + + friend bool operator==(const input_iterator_wrapper &left, const input_iterator_wrapper &right) + { return left.m_it == right.m_it; } + + friend bool operator!=(const input_iterator_wrapper &left, const input_iterator_wrapper &right) + { return left.m_it != right.m_it; } +}; + +template +input_iterator_wrapper make_input_from_forward_iterator(const FwdIterator &it) +{ return input_iterator_wrapper(it); } + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#endif //BOOST_CONTAINER_TEST_FORWARD_TO_INPUT_ITERATOR_HPP diff --git a/test/list_test.hpp b/test/list_test.hpp index 6862ffe..85f1b73 100644 --- a/test/list_test.hpp +++ b/test/list_test.hpp @@ -18,6 +18,7 @@ #include #include #include "print_container.hpp" +#include "input_from_forward_iterator.hpp" #include #include @@ -177,7 +178,20 @@ int list_test (bool copied_allocators_equal = true) aux_vect2[i] = -1; } boostlist->assign(boost::make_move_iterator(&aux_vect[0]) - ,boost::make_move_iterator(&aux_vect[50])); + ,boost::make_move_iterator(&aux_vect[50])); + stdlist->assign(&aux_vect2[0], &aux_vect2[50]); + if(!CheckEqualContainers(boostlist, stdlist)) return 1; + + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + boostlist->assign(boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) + ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[50]))); stdlist->assign(&aux_vect2[0], &aux_vect2[50]); if(!CheckEqualContainers(boostlist, stdlist)) return 1; } @@ -206,10 +220,36 @@ int list_test (bool copied_allocators_equal = true) for(int i = 0; i < 50; ++i){ aux_vect2[i] = -1; } - boostlist->insert(boostlist->begin() + typename MyBoostList::iterator old_begin = boostlist->begin(); + typename MyBoostList::iterator it_insert = + boostlist->insert(boostlist->begin() ,boost::make_move_iterator(&aux_vect[0]) ,boost::make_move_iterator(&aux_vect[50])); + if(it_insert != boostlist->begin() || std::distance(it_insert, old_begin) != 50) + return 1; + stdlist->insert(stdlist->begin(), &aux_vect2[0], &aux_vect2[50]); + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; + + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + + old_begin = boostlist->begin(); + it_insert = boostlist->insert(boostlist->end() + ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) + ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[50]))); + if(std::distance(it_insert, boostlist->end()) != 50) + return 1; + stdlist->insert(stdlist->end(), &aux_vect2[0], &aux_vect2[50]); + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; } boostlist->unique(); diff --git a/test/movable_int.hpp b/test/movable_int.hpp index 9402b16..d895845 100644 --- a/test/movable_int.hpp +++ b/test/movable_int.hpp @@ -73,6 +73,12 @@ class movable_int int get_int() const { return m_int; } + friend bool operator==(const movable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const movable_int &r) + { return l == r.get_int(); } + private: int m_int; }; @@ -144,6 +150,12 @@ class movable_and_copyable_int int get_int() const { return m_int; } + friend bool operator==(const movable_and_copyable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const movable_and_copyable_int &r) + { return l == r.get_int(); } + private: int m_int; }; @@ -202,6 +214,12 @@ class copyable_int int get_int() const { return m_int; } + friend bool operator==(const copyable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const copyable_int &r) + { return l == r.get_int(); } + private: int m_int; }; @@ -256,10 +274,17 @@ class non_copymovable_int int get_int() const { return m_int; } + friend bool operator==(const non_copymovable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const non_copymovable_int &r) + { return l == r.get_int(); } + private: int m_int; }; + } //namespace test { } //namespace container { } //namespace boost { diff --git a/test/scoped_allocator_usage_test.cpp b/test/scoped_allocator_usage_test.cpp index bb841a2..c0a4827 100644 --- a/test/scoped_allocator_usage_test.cpp +++ b/test/scoped_allocator_usage_test.cpp @@ -20,8 +20,6 @@ class SimpleAllocator { public: typedef Ty value_type; - typedef typename std::allocator::pointer pointer; - typedef typename std::allocator::size_type size_type; SimpleAllocator(int value) : m_state(value) @@ -32,12 +30,12 @@ public: : m_state(other.m_state) {} - pointer allocate(size_type n) + Ty* allocate(std::size_t n) { return m_allocator.allocate(n); } - void deallocate(pointer p, size_type n) + void deallocate(Ty* p, std::size_t n) { m_allocator.deallocate(p, n); } diff --git a/test/set_test.hpp b/test/set_test.hpp index 2afe4ce..20554df 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -88,13 +88,13 @@ int set_test () IntType move_me(i); aux_vect3[i] = boost::move(move_me); } -/* - MyBoostSet *boostset3 = MyBoostSet + + MyBoostSet *boostset3 = new MyBoostSet ( ordered_unique_range , boost::make_move_iterator(&aux_vect[0]) , boost::make_move_iterator(aux_vect + 50)); MyStdSet *stdset3 = new MyStdSet(aux_vect2, aux_vect2 + 50); - MyBoostMultiSet *boostmultiset3 = MyBoostMultiSet + MyBoostMultiSet *boostmultiset3 = new MyBoostMultiSet ( ordered_range , boost::make_move_iterator(&aux_vect3[0]) , boost::make_move_iterator(aux_vect3 + 50)); @@ -108,15 +108,15 @@ int set_test () std::cout << "Error in construct(MyBoostMultiSet3)" << std::endl; return 1; } -*/ + delete boostset2; delete boostmultiset2; delete stdset2; delete stdmultiset2; - //delete boostset3; - //delete boostmultiset3; - //delete stdset3; - //delete stdmultiset3; + delete boostset3; + delete boostmultiset3; + delete stdset3; + delete stdmultiset3; } int i, j; diff --git a/test/stable_vector_test.cpp b/test/stable_vector_test.cpp index fe7d9e1..c69efe4 100644 --- a/test/stable_vector_test.cpp +++ b/test/stable_vector_test.cpp @@ -30,13 +30,13 @@ namespace boost { namespace container { //Explicit instantiation to detect compilation errors -template class stable_vector >; -template class stable_vector >; -template class stable_vector >; }} diff --git a/test/vector_test.hpp b/test/vector_test.hpp index a46d42b..5c262b0 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -8,6 +8,9 @@ // ////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_TEST_VECTOR_TEST_HEADER +#define BOOST_CONTAINER_TEST_VECTOR_TEST_HEADER + #include #include #include @@ -24,6 +27,7 @@ #include #include #include "emplace_test.hpp" +#include "input_from_forward_iterator.hpp" namespace boost{ namespace container { @@ -133,10 +137,11 @@ int vector_test() for(int i = 0; i < 50; ++i){ aux_vect2[i] = -1; } - - boostvector->insert(boostvector->end() + typename MyBoostVector::iterator insert_it = + boostvector->insert(boostvector->end() ,boost::make_move_iterator(&aux_vect[0]) ,boost::make_move_iterator(aux_vect + 50)); + if(std::size_t(std::distance(insert_it, boostvector->end())) != 50) return 1; stdvector->insert(stdvector->end(), aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; @@ -147,22 +152,47 @@ int vector_test() if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; } { + boostvector->resize(100); + stdvector->resize(100); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType new_int(-1); + IntType new_int(-2); aux_vect[i] = boost::move(new_int); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ - aux_vect2[i] = -1; + aux_vect2[i] = -2; } - boostvector->insert(boostvector->begin() + typename MyBoostVector::size_type old_size = boostvector->size(); + typename MyBoostVector::iterator insert_it = + boostvector->insert(boostvector->begin() + old_size ,boost::make_move_iterator(&aux_vect[0]) ,boost::make_move_iterator(aux_vect + 50)); - stdvector->insert(stdvector->begin(), aux_vect2, aux_vect2 + 50); + if(boostvector->begin() + old_size != insert_it) return 1; + stdvector->insert(stdvector->begin() + old_size, aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + for(int i = 0; i < 50; ++i){ + IntType new_int(-3); + aux_vect[i] = boost::move(new_int); + } + + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -3; + } + old_size = boostvector->size(); + //Now try with input iterators instead + insert_it = boostvector->insert(boostvector->begin() + old_size + ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) + ,boost::make_move_iterator(make_input_from_forward_iterator(aux_vect + 50)) + ); + if(boostvector->begin() + old_size != insert_it) return 1; + stdvector->insert(stdvector->begin() + old_size, aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; } -/* +/* //deque has no reserve boostvector->reserve(boostvector->size()*2); stdvector->reserve(stdvector->size()*2); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; @@ -175,13 +205,27 @@ int vector_test() MyStdVector(*stdvector).swap(*stdvector); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + { //push_back with not enough capacity IntType push_back_this(1); boostvector->push_back(boost::move(push_back_this)); stdvector->push_back(int(1)); boostvector->push_back(IntType(1)); stdvector->push_back(int(1)); - if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + } + { //push_back with enough capacity + boostvector->pop_back(); + boostvector->pop_back(); + stdvector->pop_back(); + stdvector->pop_back(); + + IntType push_back_this(1); + boostvector->push_back(boost::move(push_back_this)); + stdvector->push_back(int(1)); + boostvector->push_back(IntType(1)); + stdvector->push_back(int(1)); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + } if(!vector_copyable_only(boostvector, stdvector ,container_detail::bool_::value>())){ @@ -204,14 +248,22 @@ int vector_test() //Test insertion from list { std::list l(50, int(1)); - boostvector->insert(boostvector->begin(), l.begin(), l.end()); + typename MyBoostVector::iterator it_insert = + boostvector->insert(boostvector->begin(), l.begin(), l.end()); + if(boostvector->begin() != it_insert) return 1; stdvector->insert(stdvector->begin(), l.begin(), l.end()); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; boostvector->assign(l.begin(), l.end()); stdvector->assign(l.begin(), l.end()); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + boostvector->clear(); + stdvector->clear(); + boostvector->assign(make_input_from_forward_iterator(l.begin()), make_input_from_forward_iterator(l.end())); + stdvector->assign(l.begin(), l.end()); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; } -/* +/* deque has no reserve or capacity std::size_t cap = boostvector->capacity(); boostvector->reserve(cap*2); stdvector->reserve(cap*2); @@ -252,3 +304,6 @@ int vector_test() } //namespace boost{ #include + +#endif //BOOST_CONTAINER_TEST_VECTOR_TEST_HEADER +