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 60ef8c2..8b71c43 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -617,13 +617,15 @@ use [*Boost.Container]? There are several reasons for that: [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] 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/detail/iterators.hpp b/include/boost/container/detail/iterators.hpp index 78a0dda..3e77931 100644 --- a/include/boost/container/detail/iterators.hpp +++ b/include/boost/container/detail/iterators.hpp @@ -585,6 +585,22 @@ 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 { @@ -593,4 +609,3 @@ struct is_bidirectional_iterator #include #endif //#ifndef BOOST_CONTAINER_DETAIL_ITERATORS_HPP - diff --git a/include/boost/container/detail/workaround.hpp b/include/boost/container/detail/workaround.hpp index c444074..7838a5d 100644 --- a/include/boost/container/detail/workaround.hpp +++ b/include/boost/container/detail/workaround.hpp @@ -31,6 +31,10 @@ #define BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST #endif +//Macros for documentation purposes. For code, expands to the argument +#define BOOST_CONTAINER_IMPDEF(TYPE) TYPE +#define BOOST_CONTAINER_SEEDOC(TYPE) TYPE + #include #endif //#ifndef BOOST_CONTAINER_DETAIL_WORKAROUND_HPP diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index a991860..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,95 +737,146 @@ 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. + ////////////////////////////////////////////// + // + // modifiers + // + ////////////////////////////////////////////// + + #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the list. //! - //! Throws: If memory allocation throws, or T's copy constructor throws. + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size, const T& x) + //! Complexity: Constant + template + void emplace_back(Args&&... 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. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + void emplace_front(Args&&... args) + { this->emplace(this->cbegin(), 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: Constant + template + iterator emplace(const_iterator p, Args&&... args) { - if(!priv_try_shrink(new_size)){ - this->insert(this->cend(), new_size - this->size(), x); - } + NodePtr pnode(AllocHolder::create_node(boost::forward(args)...)); + return iterator(this->icont().insert(p.get(), *pnode)); } - //! 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(!priv_try_shrink(new_size)){ - typedef default_construct_iterator default_iterator; - this->insert(this->cend(), default_iterator(new_size - this->size()), default_iterator()); - } - } + #else //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING - //! Effects: Swaps the contents of *this and x. + #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, _)) \ + { \ + this->emplace(this->cend() \ + 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, >) \ + void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + this->emplace(this->cbegin() \ + 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(const_iterator p \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + NodePtr pnode (AllocHolder::create_node \ + (BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ + return iterator(this->icont().insert(p.get(), *pnode)); \ + } \ //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - void swap(ThisType& x) - { AllocHolder::swap(x); } + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() - //! 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; - } + #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING - //! Effects: Move assignment. All mx's values are transferred to *this. + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: Inserts a copy of x at the beginning of the list. //! - //! Postcondition: x.empty(). *this contains a the elements x had - //! before the function. + //! Throws: If memory allocation throws or + //! T's copy constructor throws. //! - //! Throws: If allocator_type'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. //! - //! 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; - } + //! 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. //! @@ -809,104 +945,21 @@ class list } #endif - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //! Requires: position must be a valid iterator of *this. + //! Effects: Removes the first element from the list. //! - //! 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. + //! Throws: Nothing. //! //! Complexity: Amortized constant time. - iterator insert(const_iterator position, const T &x); + void pop_front() + { this->erase(this->cbegin()); } - //! Requires: position must be a valid iterator of *this. + //! Effects: Removes the last element from the list. //! - //! Effects: Insert a new element before position with mx's resources. - //! - //! Returns: an iterator to the inserted element. - //! - //! Throws: If memory allocation throws. + //! Throws: Nothing. //! //! 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 - - #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 list. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - void emplace_back(Args&&... 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. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - void emplace_front(Args&&... args) - { - this->emplace(this->cbegin(), 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: Constant - template - iterator emplace(const_iterator p, Args&&... args) - { - NodePtr pnode(AllocHolder::create_node(boost::forward(args)...)); - return iterator(this->icont().insert(p.get(), *pnode)); - } - - #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, >) \ - void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ - { \ - this->emplace(this->cend() \ - 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, >) \ - void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ - { \ - this->emplace(this->cbegin() \ - 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(const_iterator p \ - BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ - { \ - NodePtr pnode (AllocHolder::create_node \ - (BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ - return iterator(this->icont().insert(p.get(), *pnode)); \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + void pop_back() + { const_iterator tmp = this->cend(); this->erase(--tmp); } //! Requires: p must be a valid iterator of *this. //! @@ -928,41 +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) - { - typedef constant_iterator cvalue_iterator; - return this->assign(cvalue_iterator(val, n), cvalue_iterator()); - } + //! 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 - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - , typename container_detail::enable_if_c - < !container_detail::is_convertible::value - >::type * = 0 - #endif - ) + //! 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 { - 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); - } + 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 @@ -978,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 @@ -998,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 @@ -1017,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 @@ -1037,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. //! @@ -1062,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. @@ -1119,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. @@ -1148,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. //! @@ -1178,6 +1312,16 @@ 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: diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index 553fb54..c5ca7fa 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -53,6 +54,9 @@ namespace container { /// @cond +template +class slist; + namespace container_detail { template @@ -96,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 @@ -142,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; @@ -186,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. @@ -347,8 +354,7 @@ 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->cbefore_begin(), first, last); } @@ -400,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 @@ -455,31 +470,6 @@ class slist return *this; } - //! 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: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return allocator_type(this->node_alloc()); } - - const stored_allocator_type &get_stored_allocator() const - { return this->node_alloc(); } - - stored_allocator_type &get_stored_allocator() - { return this->node_alloc(); } - - public: - //! Effects: Assigns the n copies of val to *this. //! //! Throws: If memory allocation throws or T's copy constructor throws. @@ -521,6 +511,58 @@ class slist this->erase_after(prev, end_n); } + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + 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(); } + + ////////////////////////////////////////////// + // + // iterators + // + ////////////////////////////////////////////// + + //! 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: 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 to insert_after, erase_after, etc. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator before_begin() const + { return this->cbefore_begin(); } + //! Effects: Returns an iterator to the first element contained in the list. //! //! Throws: Nothing. @@ -553,16 +595,6 @@ 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 to insert_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 to insert_after, erase_after, etc. @@ -570,8 +602,8 @@ class slist //! 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. //! @@ -589,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 to insert_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. //! @@ -615,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() //! @@ -653,64 +732,88 @@ class slist const_reference front() const { return *this->begin(); } - //! Effects: Inserts a copy of t in the beginning of the list. + ////////////////////////////////////////////// + // + // 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 front 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); } + template + void emplace_front(Args&&... args) + { this->emplace_after(this->cbefore_begin(), boost::forward(args)...); } - #if defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - void push_front(T &x) { push_front(const_cast(x)); } + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... after prev + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + iterator emplace_after(const_iterator prev, Args&&... args) + { + NodePtr pnode(AllocHolder::create_node(boost::forward(args)...)); + return iterator(this->icont().insert_after(prev.get(), *pnode)); + } - 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 + #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, >) \ + void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + this->emplace(this->cbegin() \ + 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, _)) \ + { \ + NodePtr pnode (AllocHolder::create_node \ + (BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ + return iterator(this->icont().insert_after(prev.get(), *pnode)); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: Inserts a copy of x at the 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 t to this new element. + //! and moves the resources of mx 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))); } + void push_front(T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_front, T, void, priv_push_front) + #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())); } - - //! 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())); } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Requires: p must be a valid iterator of *this. //! - //! Effects: Inserts a copy of the value after the p pointed + //! Effects: Inserts a copy of the value after the position pointed //! by prev_p. //! //! Returns: An iterator to the inserted element. @@ -721,18 +824,7 @@ class slist //! //! 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 + iterator insert_after(const_iterator prev_pos, const T &x); //! Requires: prev_pos must be a valid iterator of *this. //! @@ -747,8 +839,10 @@ class slist //! //! 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)))); } + 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. //! @@ -772,7 +866,7 @@ class slist //! Requires: prev_pos must be a valid iterator of *this. //! //! Effects: Inserts the range pointed by [first, last) - //! after the p prev_pos. + //! after the position prev_pos. //! //! Returns: an iterator to the last inserted element or prev_pos if first == last. //! @@ -820,145 +914,13 @@ class slist } #endif - //! Requires: p must be a valid iterator of *this. + //! Effects: Removes the first element from the list. //! - //! 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, 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. - //! - //! Returns: an iterator to the inserted element. - //! - //! 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. - //! - //! 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) - { - 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()); - } - - #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 front of the list - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. + //! Throws: Nothing. //! //! Complexity: Amortized constant time. - template - 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 - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - iterator emplace_after(const_iterator prev, Args&&... args) - { - NodePtr pnode(AllocHolder::create_node(boost::forward(args)...)); - return iterator(this->icont().insert_after(prev.get(), *pnode)); - } - - #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, >) \ - void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ - { \ - this->emplace(this->cbegin() \ - 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 (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, _)) \ - { \ - NodePtr pnode (AllocHolder::create_node \ - (BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ - return iterator(this->icont().insert_after(prev.get(), *pnode)); \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + 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. @@ -992,55 +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) - { - const_iterator last_pos; - if(!priv_try_shrink(new_size, last_pos)){ - this->insert_after(last_pos, 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) - { - 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()); - } - } + //! 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. //! @@ -1050,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 //! @@ -1065,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. //! @@ -1089,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. @@ -1114,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. @@ -1142,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. //! @@ -1220,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. @@ -1280,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. @@ -1306,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. //! @@ -1336,9 +1293,242 @@ class slist 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(); } + + ////////////////////////////////////////////// + // + // list compatibility interface + // + ////////////////////////////////////////////// + + #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! 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) + { + 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()); + } + + //! 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) { typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; @@ -1356,14 +1546,13 @@ class slist } } - iterator priv_insert(const_iterator p, const value_type& x) - { return this->insert_after(previous(p), x); } + template + iterator priv_insert(const_iterator p, BOOST_FWD_REF(U) x) + { return this->insert_after(previous(p), ::boost::forward(x)); } - 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))); } - - void priv_push_front(const value_type &x) - { this->icont().push_front(*this->create_node(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; diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index f6c55c9..3e45e7e 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -466,9 +466,6 @@ class stable_vector typedef typename index_traits_type::index_iterator index_iterator; typedef typename index_traits_type:: const_index_iterator const_index_iterator; - - typedef typename container_detail:: - move_const_ref_type::type insert_const_ref_type; typedef boost::intrusive:: pointer_traits ptr_traits; @@ -601,27 +598,35 @@ class stable_vector { 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 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 index_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; + ////////////////////////////////////////////// + // + // 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: @@ -636,6 +641,11 @@ class stable_vector ///@endcond public: + ////////////////////////////////////////////// + // + // construct/copy/destroy + // + ////////////////////////////////////////////// //! Effects: Default constructs a stable_vector. //! @@ -842,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 @@ -870,17 +892,6 @@ class stable_vector } } - //! 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: Returns a copy of the internal allocator. //! //! Throws: If allocator's copy constructor throws. @@ -909,6 +920,12 @@ class stable_vector stored_allocator_type &get_stored_allocator() BOOST_CONTAINER_NOEXCEPT { return this->priv_node_alloc(); } + ////////////////////////////////////////////// + // + // iterators + // + ////////////////////////////////////////////// + //! Effects: Returns an iterator to the first element contained in the stable_vector. //! //! Throws: Nothing. @@ -1011,6 +1028,20 @@ class stable_vector const_reverse_iterator crend()const { return this->rend(); } + ////////////////////////////////////////////// + // + // capacity + // + ////////////////////////////////////////////// + + //! Effects: Returns true if the stable_vector contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return this->index.size() <= ExtraPointers; } + //! Effects: Returns the number of the elements contained in the stable_vector. //! //! Throws: Nothing. @@ -1030,31 +1061,22 @@ class stable_vector size_type max_size() const { return this->index.max_size() - ExtraPointers; } - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). + //! 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. - size_type capacity() const + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type n) { - 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); + typedef default_construct_iterator default_iterator; + STABLE_VECTOR_CHECK_INVARIANT; + 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: Returns true if the stable_vector contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { 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. //! @@ -1070,20 +1092,21 @@ class stable_vector this->erase(this->cbegin() + n, this->cend()); } - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). //! - //! 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) + //! Complexity: Constant. + size_type capacity() const { - typedef default_construct_iterator default_iterator; - STABLE_VECTOR_CHECK_INVARIANT; - 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()); + 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 @@ -1116,6 +1139,86 @@ class stable_vector } } + //! 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 @@ -1168,49 +1271,86 @@ class stable_vector return operator[](n); } - //! 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; } + ////////////////////////////////////////////// + // + // modifiers + // + ////////////////////////////////////////////// - //! 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; } + #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //! Requires: !empty() + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the stable_vector. //! - //! Effects: Returns a reference to the last - //! element of the container. + //! Throws: If memory allocation throws or the in-place constructor throws. //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference back() - { return static_cast(*this->index[this->size() - ExtraPointers]).value; } + //! Complexity: Amortized constant time. + template + void emplace_back(Args &&...args) + { + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor &&ef = EmplaceFunctor(boost::forward(args)...); + this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); + } - //! Requires: !empty() + //! Requires: position must be a valid iterator of *this. //! - //! Effects: Returns a const reference to the last - //! element of the container. + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before position //! - //! Throws: Nothing. + //! Throws: If memory allocation throws or the in-place constructor throws. //! - //! Complexity: Constant. - const_reference back()const - { return static_cast(*this->index[this->size() - ExtraPointers]).value; } + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + template + iterator emplace(const_iterator position, Args && ...args) + { + //Just call more general insert(pos, size, value) and return iterator + size_type pos_n = position - cbegin(); + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor &&ef = EmplaceFunctor(boost::forward(args)...); + this->insert(position, EmplaceIterator(ef), EmplaceIterator()); + return iterator(this->begin() + pos_n); + } + + #else + + #define BOOST_PP_LOCAL_MACRO(n) \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + BOOST_PP_EXPR_IF(n, <) BOOST_PP_ENUM_PARAMS(n, P) BOOST_PP_EXPR_IF(n, >) \ + EmplaceFunctor; \ + typedef emplace_iterator EmplaceIterator; \ + EmplaceFunctor ef BOOST_PP_LPAREN_IF(n) \ + BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) \ + BOOST_PP_RPAREN_IF(n); \ + this->insert(this->cend() , EmplaceIterator(ef), EmplaceIterator()); \ + } \ + \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + iterator emplace(const_iterator pos \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + BOOST_PP_EXPR_IF(n, <) BOOST_PP_ENUM_PARAMS(n, P) BOOST_PP_EXPR_IF(n, >) \ + EmplaceFunctor; \ + typedef emplace_iterator EmplaceIterator; \ + EmplaceFunctor ef BOOST_PP_LPAREN_IF(n) \ + BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) \ + BOOST_PP_RPAREN_IF(n); \ + size_type pos_n = pos - this->cbegin(); \ + this->insert(pos, EmplaceIterator(ef), EmplaceIterator()); \ + return iterator(this->begin() + pos_n); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Inserts a copy of x at the end of the stable_vector. @@ -1232,16 +1372,6 @@ class stable_vector BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) #endif - //! Effects: Removes the last element from the stable_vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant time. - void pop_back() - { this->erase(this->end()-1); } - - - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Requires: position must be a valid iterator of *this. //! @@ -1355,80 +1485,13 @@ class stable_vector } #endif - #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 stable_vector. + //! Effects: Removes the last element from the stable_vector. //! - //! Throws: If memory allocation throws or the in-place constructor throws. + //! Throws: Nothing. //! - //! Complexity: Amortized constant time. - template - void emplace_back(Args &&...args) - { - typedef emplace_functor EmplaceFunctor; - typedef emplace_iterator EmplaceIterator; - EmplaceFunctor &&ef = EmplaceFunctor(boost::forward(args)...); - this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); - } - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... before position - //! - //! Throws: If memory allocation throws or the in-place constructor throws. - //! - //! Complexity: If position is end(), amortized constant time - //! Linear time otherwise. - template - iterator emplace(const_iterator position, Args && ...args) - { - //Just call more general insert(pos, size, value) and return iterator - size_type pos_n = position - cbegin(); - typedef emplace_functor EmplaceFunctor; - typedef emplace_iterator EmplaceIterator; - EmplaceFunctor &&ef = EmplaceFunctor(boost::forward(args)...); - this->insert(position, EmplaceIterator(ef), EmplaceIterator()); - return iterator(this->begin() + pos_n); - } - - #else - - #define BOOST_PP_LOCAL_MACRO(n) \ - BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ - void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ - { \ - typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ - BOOST_PP_EXPR_IF(n, <) BOOST_PP_ENUM_PARAMS(n, P) BOOST_PP_EXPR_IF(n, >) \ - EmplaceFunctor; \ - typedef emplace_iterator EmplaceIterator; \ - EmplaceFunctor ef BOOST_PP_LPAREN_IF(n) \ - BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) \ - BOOST_PP_RPAREN_IF(n); \ - this->insert(this->cend() , EmplaceIterator(ef), EmplaceIterator()); \ - } \ - \ - BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ - iterator emplace(const_iterator pos \ - BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ - { \ - typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ - BOOST_PP_EXPR_IF(n, <) BOOST_PP_ENUM_PARAMS(n, P) BOOST_PP_EXPR_IF(n, >) \ - EmplaceFunctor; \ - typedef emplace_iterator EmplaceIterator; \ - EmplaceFunctor ef BOOST_PP_LPAREN_IF(n) \ - BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) \ - BOOST_PP_RPAREN_IF(n); \ - size_type pos_n = pos - this->cbegin(); \ - this->insert(pos, EmplaceIterator(ef), EmplaceIterator()); \ - return iterator(this->begin() + pos_n); \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + //! Complexity: Constant time. + void pop_back() + { this->erase(--this->cend()); } //! Effects: Erases the element at position pos. //! @@ -1491,36 +1554,6 @@ 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() - { - 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()); - } - } - } - } - /// @cond private: diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 87a09bc..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,25 +482,7 @@ class vector : private container_detail::vector_alloc_holder //! Complexity: Linear to n. explicit vector(size_type n) : base_t() - { - this->resize(n); -/* - //Allocate - size_type real_cap = 0; - 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. @@ -517,10 +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->resize(n, value); -// 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. //! @@ -580,18 +565,6 @@ class vector : private container_detail::vector_alloc_holder } } - //! 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. //! @@ -601,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. @@ -703,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. //! @@ -781,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(). //! @@ -790,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 @@ -931,251 +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()); } - - //! Effects: Assigns the the range [first, last) to *this. + //! Throws: Nothing. //! - //! Throws: If memory allocation throws or T's copy/move constructor/assignment or - //! T's constructor/assignment from dereferencing InpIt throws. + //! Complexity: Constant. + reference front() BOOST_CONTAINER_NOEXCEPT + { return *this->members_.m_start; } + + //! Requires: !empty() //! - //! 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 = 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); - } - } - - #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 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()); - 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); - std::copy(mid, mid2, old_start); - - //Check if we still have to append elements in the - //uninitialized end - if(second_count == 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; - } - } - } - #endif - - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //! Effects: Inserts a copy of x at the end of the vector. + //! Effects: Returns a const reference to the first + //! element of the container. //! - //! Throws: If memory allocation throws or - //! T's copy/move constructor throws. + //! Throws: Nothing. //! - //! Complexity: Amortized constant time. - void push_back(const T &x); + //! Complexity: Constant. + const_reference front() const BOOST_CONTAINER_NOEXCEPT + { return *this->members_.m_start; } - //! 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 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. + 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]; } + + //! 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 @@ -1259,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. //! @@ -1298,6 +1211,18 @@ class vector : private container_detail::vector_alloc_holder BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator) #endif + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert n copies of x before pos. + //! + //! Returns: an iterator to the first inserted element or p if n is 0. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + iterator insert(const_iterator p, size_type n, const T& x) + { 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. @@ -1344,18 +1269,6 @@ class vector : private container_detail::vector_alloc_holder } #endif - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert n copies of x before pos. - //! - //! Returns: an iterator to the first inserted element or p if n is 0. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - iterator insert(const_iterator p, size_type n, const T& x) - { return this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); } - //! Effects: Removes the last element from the vector. //! //! Throws: Nothing. @@ -1407,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{ - 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); - } + //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. @@ -1454,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! diff --git a/proj/to-do.txt b/proj/to-do.txt index 7cb2844..b548cbc 100644 --- a/proj/to-do.txt +++ b/proj/to-do.txt @@ -51,4 +51,111 @@ change virtual functions with pointers to avoid template instantiation for every 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