From 3c256c228284702bb2fa383092feecfdfb910188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 1 Sep 2012 11:01:03 +0000 Subject: [PATCH] Implemented LWG Issue #149 (range insertion now returns an iterator) & cleaned up insertion code in most containers [SVN r80348] --- doc/container.qbk | 4 +- include/boost/container/deque.hpp | 280 +++++----- .../container/detail/advanced_insert_int.hpp | 15 +- include/boost/container/detail/algorithms.hpp | 24 + include/boost/container/detail/flat_tree.hpp | 340 +++++++----- include/boost/container/detail/iterators.hpp | 86 +++- .../boost/container/detail/preprocessor.hpp | 79 ++- include/boost/container/detail/stored_ref.hpp | 92 ---- include/boost/container/detail/tree.hpp | 165 +++--- include/boost/container/flat_map.hpp | 8 +- include/boost/container/flat_set.hpp | 8 +- include/boost/container/list.hpp | 266 +++++----- include/boost/container/map.hpp | 4 +- include/boost/container/set.hpp | 4 +- include/boost/container/slist.hpp | 285 +++++------ include/boost/container/stable_vector.hpp | 313 ++++++------ include/boost/container/string.hpp | 482 +++++++++--------- include/boost/container/vector.hpp | 414 ++++++++------- proj/to-do.txt | 11 + proj/vc7ide/allocator_traits_test.vcproj | 3 + proj/vc7ide/container.sln | 8 + proj/vc7ide/container.vcproj | 5 +- test/check_equal_containers.hpp | 27 +- test/deque_test.cpp | 2 +- test/input_from_forward_iterator.hpp | 80 +++ test/list_test.hpp | 44 +- test/movable_int.hpp | 25 + test/set_test.hpp | 16 +- test/vector_test.hpp | 45 +- 29 files changed, 1659 insertions(+), 1476 deletions(-) delete mode 100644 include/boost/container/detail/stored_ref.hpp create mode 100644 test/input_from_forward_iterator.hpp diff --git a/doc/container.qbk b/doc/container.qbk index 3b99566..0c760e0 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -617,7 +617,7 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_52_00 Boost 1.52 Release] * Fixed bugs - [@https://svn.boost.org/trac/boost/ticket/6606 #6606], + [@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], @@ -641,11 +641,11 @@ use [*Boost.Container]? There are several reasons for that: * Added Scoped Allocator Model support. * Fixed bugs + [@https://svn.boost.org/trac/boost/ticket/6606 #6606], [@https://svn.boost.org/trac/boost/ticket/6533 #6533], [@https://svn.boost.org/trac/boost/ticket/6536 #6536], [@https://svn.boost.org/trac/boost/ticket/6566 #6566], [@https://svn.boost.org/trac/boost/ticket/6575 #6575], - [@https://svn.boost.org/trac/boost/ticket/6615 #6615], [endsect] diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index d3ca4ca..c7f1aca 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -943,14 +943,18 @@ class deque : protected deque_base //! throws or T's constructor taking an dereferenced InIt throws. //! //! Complexity: Linear to the range [first, last). - template - deque(InpIt first, InpIt last, const allocator_type& a = allocator_type()) + template + deque(InIt first, InIt last, const allocator_type& a = allocator_type() + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + >::type * = 0 + #endif + ) : Base(a) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_initialize_dispatch(first, last, Result()); + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_range_initialize(first, last, ItCat()); } //! Effects: Destroys the deque. All stored values are destroyed @@ -1043,23 +1047,61 @@ class deque : protected deque_base //! //! Complexity: Linear to n. void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } + { + typedef constant_iterator c_it; + this->assign(c_it(val, n), c_it()); + } //! Effects: Assigns the the range [first, last) to *this. //! //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InpIt throws. + //! T's constructor from dereferencing InIt throws. //! //! Complexity: Linear to n. - template - void assign(InpIt first, InpIt last) + template + void assign(InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); + iterator cur = begin(); + for ( ; first != last && cur != end(); ++cur, ++first){ + *cur = *first; + } + if (first == last){ + this->erase(cur, cend()); + } + else{ + this->insert(cend(), first, last); + } } + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + void assign(FwdIt first, FwdIt last + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !container_detail::is_input_iterator::value + >::type * = 0 + ) + { + const size_type len = std::distance(first, last); + if (len > size()) { + FwdIt mid = first; + std::advance(mid, size()); + boost::copy_or_move(first, mid, begin()); + this->insert(cend(), mid, last); + } + else{ + this->erase(boost::copy_or_move(first, last, begin()), cend()); + } + } + #endif + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Inserts a copy of x at the end of the deque. //! @@ -1142,6 +1184,8 @@ class deque : protected deque_base //! //! Effects: Insert a copy of x before position. //! + //! Returns: an iterator to the inserted element. + //! //! Throws: If memory allocation throws or x's copy constructor throws. //! //! Complexity: If position is end(), amortized constant time @@ -1152,6 +1196,8 @@ class deque : protected deque_base //! //! Effects: Insert a new element before position with mx's resources. //! + //! Returns: an iterator to the inserted element. + //! //! Throws: If memory allocation throws. //! //! Complexity: If position is end(), amortized constant time @@ -1165,29 +1211,63 @@ class deque : protected deque_base //! //! Effects: Insert n copies of x before pos. //! + //! Returns: an iterator to the first inserted element or pos if n is 0. + //! //! Throws: If memory allocation throws or T's copy constructor throws. //! //! Complexity: Linear to n. - void insert(const_iterator pos, size_type n, const value_type& x) - { this->priv_fill_insert(pos, n, x); } + iterator insert(const_iterator pos, size_type n, const value_type& x) + { + typedef constant_iterator c_it; + return this->insert(pos, c_it(x, n), c_it()); + } //! Requires: pos must be a valid iterator of *this. //! //! Effects: Insert a copy of the [first, last) range before pos. //! + //! Returns: an iterator to the first inserted element or pos if first == last. + //! //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws or T's copy constructor throws. + //! dereferenced InIt throws or T's copy constructor throws. //! //! Complexity: Linear to std::distance [first, last). - template - void insert(const_iterator pos, InpIt first, InpIt last) + template + iterator insert(const_iterator pos, InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_insert_dispatch(pos, first, last, Result()); + size_type n = 0; + iterator it(pos); + for(;first != last; ++first, ++n){ + it = this->emplace(it, *first); + ++it; + } + it -= n; + return it; } + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator insert(const_iterator p, FwdIt first, FwdIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) + { + container_detail::advanced_insert_aux_proxy proxy(this->alloc(), first, last); + return priv_insert_aux_impl(p, (size_type)std::distance(first, last), proxy); + } + #endif + #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Inserts an object of type T constructed with @@ -1257,11 +1337,9 @@ class deque : protected deque_base return (this->end()-1); } else{ - size_type n = p - this->cbegin(); typedef container_detail::advanced_insert_aux_emplace type; type &&proxy = type(this->alloc(), boost::forward(args)...); - this->priv_insert_aux_impl(p, 1, proxy); - return iterator(this->begin() + n); + return this->priv_insert_aux_impl(p, 1, proxy); } } @@ -1320,12 +1398,10 @@ class deque : protected deque_base return (this->end()-1); \ } \ else{ \ - size_type pos_num = p - this->cbegin(); \ container_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ proxy \ (this->alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ - this->priv_insert_aux_impl(p, 1, proxy); \ - return iterator(this->begin() + pos_num); \ + return this->priv_insert_aux_impl(p, 1, proxy); \ } \ } \ //! @@ -1361,7 +1437,7 @@ class deque : protected deque_base if (new_size < len) this->priv_erase_last_n(len - new_size); else{ - size_type n = new_size - this->size(); + const size_type n = new_size - this->size(); container_detail::default_construct_aux_proxy proxy(this->alloc(), n); priv_insert_back_aux_impl(n, proxy); } @@ -1500,9 +1576,7 @@ class deque : protected deque_base return (end()-1); } else { - size_type n = position - cbegin(); - this->priv_insert_aux(position, size_type(1), x); - return iterator(this->begin() + n); + return this->insert(position, size_type(1), x); } } @@ -1517,10 +1591,7 @@ class deque : protected deque_base return(end()-1); } else { - //Just call more general insert(pos, size, value) and return iterator - size_type n = position - begin(); - this->priv_insert_aux(position, move_it(r_iterator(mx, 1)), move_it(r_iterator())); - return iterator(this->begin() + n); + return this->insert(position, move_it(r_iterator(mx, 1)), move_it(r_iterator())); } } @@ -1532,7 +1603,7 @@ class deque : protected deque_base this->priv_push_front_simple_commit(); } else{ - this->priv_insert_aux(cbegin(), size_type(1), t); + this->insert(cbegin(), size_type(1), t); } } @@ -1544,7 +1615,7 @@ class deque : protected deque_base this->priv_push_front_simple_commit(); } else{ - this->priv_insert_aux(cbegin(), move_it(r_iterator(t, 1)), move_it(r_iterator())); + this->insert(cbegin(), move_it(r_iterator(t, 1)), move_it(r_iterator())); } } @@ -1556,7 +1627,7 @@ class deque : protected deque_base this->priv_push_back_simple_commit(); } else{ - this->priv_insert_aux(cend(), size_type(1), t); + this->insert(cend(), size_type(1), t); } } @@ -1568,7 +1639,7 @@ class deque : protected deque_base this->priv_push_back_simple_commit(); } else{ - this->priv_insert_aux(cend(), move_it(r_iterator(t, 1)), move_it(r_iterator())); + this->insert(cend(), move_it(r_iterator(t, 1)), move_it(r_iterator())); } } @@ -1600,50 +1671,6 @@ class deque : protected deque_base void priv_push_front_simple_commit() { --this->members_.m_start.m_cur; } - template - void priv_insert_aux(const_iterator pos, InpIt first, InpIt last, std::input_iterator_tag) - { - iterator it(pos); - for(;first != last; ++first){ - it = this->emplace(it, *first); - ++it; - } - } - - template - void priv_insert_aux(const_iterator pos, FwdIt first, FwdIt last, std::forward_iterator_tag) - { this->priv_insert_aux(pos, first, last); } - - // assign(), a generalized assignment member function. Two - // versions: one that takes a count, and one that takes a range. - // The range version is a member template, so we dispatch on whether - // or not the type is an integer. - void priv_fill_assign(size_type n, const T& val) - { - if (n > size()) { - std::fill(begin(), end(), val); - this->insert(cend(), n - size(), val); - } - else { - this->erase(cbegin() + n, cend()); - std::fill(begin(), end(), val); - } - } - - template - void priv_initialize_dispatch(Integer n, Integer x, container_detail::true_) - { - this->priv_initialize_map(n); - this->priv_fill_initialize(x); - } - - template - void priv_initialize_dispatch(InpIt first, InpIt last, container_detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_range_initialize(first, last, ItCat()); - } - void priv_destroy_range(iterator p, iterator p2) { for(;p != p2; ++p){ @@ -1664,71 +1691,10 @@ class deque : protected deque_base } } - template - void priv_assign_dispatch(Integer n, Integer val, container_detail::true_) - { this->priv_fill_assign((size_type) n, (value_type)val); } - - template - void priv_assign_dispatch(InpIt first, InpIt last, container_detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_assign_aux(first, last, ItCat()); - } - - template - void priv_assign_aux(InpIt first, InpIt last, std::input_iterator_tag) - { - iterator cur = begin(); - for ( ; first != last && cur != end(); ++cur, ++first) - *cur = *first; - if (first == last) - this->erase(cur, cend()); - else - this->insert(cend(), first, last); - } - - template - void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag) - { - size_type len = std::distance(first, last); - if (len > size()) { - FwdIt mid = first; - std::advance(mid, size()); - boost::copy_or_move(first, mid, begin()); - this->insert(cend(), mid, last); - } - else - this->erase(boost::copy_or_move(first, last, begin()), cend()); - } - - template - void priv_insert_dispatch(const_iterator pos, Integer n, Integer x, container_detail::true_) - { this->priv_fill_insert(pos, (size_type) n, (value_type)x); } - - template - void priv_insert_dispatch(const_iterator pos,InpIt first, InpIt last, container_detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_insert_aux(pos, first, last, ItCat()); - } - - void priv_insert_aux(const_iterator pos, size_type n, const value_type& x) - { - typedef constant_iterator c_it; - this->priv_insert_aux(pos, c_it(x, n), c_it()); - } - - //Just forward all operations to priv_insert_aux_impl - template - void priv_insert_aux(const_iterator p, FwdIt first, FwdIt last) - { - container_detail::advanced_insert_aux_proxy proxy(this->alloc(), first, last); - priv_insert_aux_impl(p, (size_type)std::distance(first, last), proxy); - } - - void priv_insert_aux_impl(const_iterator p, size_type n, advanced_insert_aux_int_t &interf) + iterator priv_insert_aux_impl(const_iterator p, size_type n, advanced_insert_aux_int_t &interf) { iterator pos(p); + const size_type pos_n = p - this->cbegin(); if(!this->members_.m_map){ this->priv_initialize_map(0); pos = this->begin(); @@ -1782,9 +1748,10 @@ class deque : protected deque_base interf.copy_remaining_to(pos); } } + return this->begin() + pos_n; } - void priv_insert_back_aux_impl(size_type n, advanced_insert_aux_int_t &interf) + iterator priv_insert_back_aux_impl(size_type n, advanced_insert_aux_int_t &interf) { if(!this->members_.m_map){ this->priv_initialize_map(0); @@ -1794,9 +1761,10 @@ class deque : protected deque_base iterator old_finish = this->members_.m_finish; interf.uninitialized_copy_some_and_update(old_finish, n, true); this->members_.m_finish = new_finish; + return iterator(this->members_.m_finish - n); } - void priv_insert_front_aux_impl(size_type n, advanced_insert_aux_int_t &interf) + iterator priv_insert_front_aux_impl(size_type n, advanced_insert_aux_int_t &interf) { if(!this->members_.m_map){ this->priv_initialize_map(0); @@ -1805,13 +1773,13 @@ class deque : protected deque_base iterator new_start = this->priv_reserve_elements_at_front(n); interf.uninitialized_copy_some_and_update(new_start, difference_type(n), true); this->members_.m_start = new_start; + return new_start; } - - void priv_fill_insert(const_iterator pos, size_type n, const value_type& x) + iterator priv_fill_insert(const_iterator pos, size_type n, const value_type& x) { typedef constant_iterator c_it; - this->insert(pos, c_it(x, n), c_it()); + return this->insert(pos, c_it(x, n), c_it()); } // Precondition: this->members_.m_start and this->members_.m_finish have already been initialized, @@ -1834,13 +1802,13 @@ class deque : protected deque_base BOOST_CATCH_END } - template - void priv_range_initialize(InpIt first, InpIt last, std::input_iterator_tag) + template + void priv_range_initialize(InIt first, InIt last, std::input_iterator_tag) { this->priv_initialize_map(0); BOOST_TRY { for ( ; first != last; ++first) - this->push_back(*first); + this->emplace_back(*first); } BOOST_CATCH(...){ this->clear(); diff --git a/include/boost/container/detail/advanced_insert_int.hpp b/include/boost/container/detail/advanced_insert_int.hpp index a97af28..e7adcd2 100644 --- a/include/boost/container/detail/advanced_insert_int.hpp +++ b/include/boost/container/detail/advanced_insert_int.hpp @@ -173,7 +173,6 @@ struct default_construct_aux_proxy #ifdef BOOST_CONTAINER_PERFECT_FORWARDING #include -#include #include #include //#include //For debugging purposes @@ -227,8 +226,7 @@ struct advanced_insert_aux_non_movable_emplace if(!this->used_){ alloc_traits::construct( this->a_ , container_detail::to_raw_pointer(&*p) - , ::boost::container::container_detail:: - stored_ref::forward(get(this->args_))... + , ::boost::forward(get(this->args_))... ); this->used_ = true; } @@ -241,8 +239,7 @@ struct advanced_insert_aux_non_movable_emplace if(!this->used_){ alloc_traits::construct( this->a_ , container_detail::to_raw_pointer(&*p) - , ::boost::container::container_detail:: - stored_ref::forward(get(this->args_))... + , ::boost::forward(get(this->args_))... ); this->used_ = true; } @@ -288,7 +285,7 @@ struct advanced_insert_aux_emplace aligned_storage::value> v; value_type *vp = static_cast(static_cast(&v)); alloc_traits::construct(this->a_, vp, - ::boost::container::container_detail::stored_ref::forward(get(this->args_))...); + ::boost::forward(get(this->args_))...); scoped_destructor d(this->a_, vp); *p = ::boost::move(*vp); d.release(); @@ -305,7 +302,7 @@ struct advanced_insert_aux_emplace aligned_storage::value> v; value_type *vp = static_cast(static_cast(&v)); alloc_traits::construct(this->a_, vp, - ::boost::container::container_detail::stored_ref::forward(get(this->args_))...); + ::boost::forward(get(this->args_))...); try { *p = ::boost::move(*vp); } catch (...) { @@ -413,7 +410,7 @@ struct BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) alloc_traits::construct(this->a_, vp \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_MEMBER_FORWARD, _)); \ scoped_destructor d(this->a_, vp); \ - *p = ::boost::move(*vp); \ + *p = ::boost::move(*vp); \ d.release(); \ this->used_ = true; \ } \ @@ -430,7 +427,7 @@ struct BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) alloc_traits::construct(this->a_, vp \ BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_MEMBER_FORWARD, _)); \ scoped_destructor d(this->a_, vp); \ - *p = ::boost::move(*vp); \ + *p = ::boost::move(*vp); \ d.release(); \ this->used_ = true; \ } \ diff --git a/include/boost/container/detail/algorithms.hpp b/include/boost/container/detail/algorithms.hpp index dc09575..824e44b 100644 --- a/include/boost/container/detail/algorithms.hpp +++ b/include/boost/container/detail/algorithms.hpp @@ -34,6 +34,30 @@ namespace boost { namespace container { +template +struct is_default_construct_iterator +{ + static const bool value = false; +}; + +template +struct is_default_construct_iterator > +{ + static const bool value = true; +}; + +template +struct is_emplace_iterator +{ + static const bool value = false; +}; + +template +struct is_emplace_iterator > +{ + static const bool value = true; +}; + template inline void construct_in_place(A &a, T* dest, InpIt source) { boost::container::allocator_traits::construct(a, dest, *source); } diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 23be0bf..55fac62 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -214,6 +214,21 @@ class flat_tree : m_data(comp, a) { this->m_data.m_vect.insert(this->m_data.m_vect.end(), first, last); } + template + flat_tree( bool unique_insertion + , InputIterator first, InputIterator last + , const Compare& comp = Compare() + , const allocator_type& a = allocator_type()) + : m_data(comp, a) + { + if(unique_insertion){ + this->insert_unique(first, last); + } + else{ + this->insert_equal(first, last); + } + } + ~flat_tree() { } @@ -290,9 +305,9 @@ class flat_tree std::pair insert_unique(const value_type& val) { insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(val, data); + std::pair ret = this->priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, val); + ret.first = this->priv_insert_commit(data, val); } return ret; } @@ -300,9 +315,9 @@ class flat_tree std::pair insert_unique(BOOST_RV_REF(value_type) val) { insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(val, data); + std::pair ret = this->priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, boost::move(val)); + ret.first = this->priv_insert_commit(data, boost::move(val)); } return ret; } @@ -324,9 +339,9 @@ class flat_tree iterator insert_unique(const_iterator pos, const value_type& val) { insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(pos, val, data); + std::pair ret = this->priv_insert_unique_prepare(pos, val, data); if(ret.second){ - ret.first = priv_insert_commit(data, val); + ret.first = this->priv_insert_commit(data, val); } return ret.first; } @@ -334,9 +349,9 @@ class flat_tree iterator insert_unique(const_iterator pos, BOOST_RV_REF(value_type) mval) { insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(pos, mval, data); + std::pair ret = this->priv_insert_unique_prepare(pos, mval, data); if(ret.second){ - ret.first = priv_insert_commit(data, boost::move(mval)); + ret.first = this->priv_insert_commit(data, boost::move(mval)); } return ret.first; } @@ -345,45 +360,164 @@ class flat_tree { insert_commit_data data; this->priv_insert_equal_prepare(pos, val, data); - return priv_insert_commit(data, val); + return this->priv_insert_commit(data, val); } iterator insert_equal(const_iterator pos, BOOST_RV_REF(value_type) mval) { insert_commit_data data; this->priv_insert_equal_prepare(pos, mval, data); - return priv_insert_commit(data, boost::move(mval)); + return this->priv_insert_commit(data, boost::move(mval)); } template void insert_unique(InIt first, InIt last) + { this->priv_insert_unique_loop(first, last); } + + template + void insert_equal(InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) + { this->priv_insert_equal_loop(first, last); } + + template + void insert_equal(InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { - for ( ; first != last; ++first) - this->insert_unique(*first); + const size_type len = static_cast(std::distance(first, last)); + this->reserve(this->size()+len); + this->priv_insert_equal_loop(first, last); + } + + //Ordered + + template + void insert_equal(ordered_range_t, InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) + { this->priv_insert_equal_loop_ordered(first, last); } + + template + void insert_equal(ordered_range_t, FwdIt first, FwdIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_forward_iterator::value + >::type * = 0 + #endif + ) + { + const size_type len = static_cast(std::distance(first, last)); + this->reserve(this->size()+len); + this->priv_insert_equal_loop_ordered(first, last); + } + + template + void insert_equal(ordered_range_t, BidirIt first, BidirIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_input_iterator::value && + !container_detail::is_forward_iterator::value + >::type * = 0 + #endif + ) + { + size_type len = static_cast(std::distance(first, last)); + const size_type BurstSize = 16; + size_type positions[BurstSize]; + + //Prereserve all memory so that iterators are not invalidated + this->reserve(this->size()+len); + const const_iterator beg(this->cbegin()); + const_iterator pos(beg); + //Loop in burst sizes + while(len){ + const size_type burst = len < BurstSize ? len : BurstSize; + const const_iterator cend(this->cend()); + len -= burst; + for(size_type i = 0; i != burst; ++i){ + //Get the insertion position for each key + pos = const_cast(*this).priv_upper_bound(pos, cend, KeyOfValue()(*first)); + positions[i] = static_cast(pos - beg); + ++first; + } + //Insert all in a single step in the precalculated positions + this->m_data.m_vect.insert_ordered_at(burst, positions + burst, first); + //Next search position updated + pos += burst; + } } template - void insert_equal(InIt first, InIt last) - { - typedef typename - std::iterator_traits::iterator_category ItCat; - this->priv_insert_equal(first, last, ItCat()); - } + void insert_unique(ordered_unique_range_t, InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator::value || + container_detail::is_forward_iterator::value + >::type * = 0 + #endif + ) + { this->priv_insert_unique_loop_hint(first, last); } - template - void insert_equal(ordered_range_t, InIt first, InIt last) + template + void insert_unique(ordered_unique_range_t, BidirIt first, BidirIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !(container_detail::is_input_iterator::value || + container_detail::is_forward_iterator::value) + >::type * = 0 + #endif + ) { - typedef typename - std::iterator_traits::iterator_category ItCat; - this->priv_insert_equal(ordered_range_t(), first, last, ItCat()); - } + size_type len = static_cast(std::distance(first, last)); + const size_type BurstSize = 16; + size_type positions[BurstSize]; + size_type skips[BurstSize]; - template - void insert_unique(ordered_unique_range_t, InIt first, InIt last) - { - typedef typename - std::iterator_traits::iterator_category ItCat; - this->priv_insert_unique(ordered_unique_range_t(), first, last, ItCat()); + //Prereserve all memory so that iterators are not invalidated + this->reserve(this->size()+len); + const const_iterator beg(this->cbegin()); + const_iterator pos(beg); + const value_compare &value_comp = this->m_data; + //Loop in burst sizes + while(len){ + skips[0u] = 0u; + const size_type burst = len < BurstSize ? len : BurstSize; + size_type unique_burst = 0u; + const const_iterator cend(this->cend()); + while(unique_burst < burst && len > 0){ + //Get the insertion position for each key + const value_type & val = *first++; + --len; + pos = const_cast(*this).priv_lower_bound(pos, cend, KeyOfValue()(val)); + //Check if already present + if(pos != cend && !value_comp(*pos, val)){ + ++skips[unique_burst]; + continue; + } + + //If not present, calculate position + positions[unique_burst] = static_cast(pos - beg); + if(++unique_burst < burst) + skips[unique_burst] = 0u; + } + //Insert all in a single step in the precalculated positions + this->m_data.m_vect.insert_ordered_at(unique_burst, positions + unique_burst, skips + unique_burst, first); + //Next search position updated + pos += unique_burst; + } } #ifdef BOOST_CONTAINER_PERFECT_FORWARDING @@ -398,9 +532,9 @@ class flat_tree value_destructor d(a, val); insert_commit_data data; std::pair ret = - priv_insert_unique_prepare(val, data); + this->priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, boost::move(val)); + ret.first = this->priv_insert_commit(data, boost::move(val)); } return ret; } @@ -414,9 +548,9 @@ class flat_tree stored_allocator_traits::construct(a, &val, ::boost::forward(args)... ); value_destructor d(a, val); insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(hint, val, data); + std::pair ret = this->priv_insert_unique_prepare(hint, val, data); if(ret.second){ - ret.first = priv_insert_commit(data, boost::move(val)); + ret.first = this->priv_insert_commit(data, boost::move(val)); } return ret.first; } @@ -444,7 +578,7 @@ class flat_tree value_destructor d(a, val); insert_commit_data data; this->priv_insert_equal_prepare(hint, val, data); - iterator i = priv_insert_commit(data, boost::move(val)); + iterator i = this->priv_insert_commit(data, boost::move(val)); return i; } @@ -462,9 +596,9 @@ class flat_tree BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ value_destructor d(a, val); \ insert_commit_data data; \ - std::pair ret = priv_insert_unique_prepare(val, data); \ + std::pair ret = this->priv_insert_unique_prepare(val, data); \ if(ret.second){ \ - ret.first = priv_insert_commit(data, boost::move(val)); \ + ret.first = this->priv_insert_commit(data, boost::move(val)); \ } \ return ret; \ } \ @@ -480,9 +614,9 @@ class flat_tree BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ value_destructor d(a, val); \ insert_commit_data data; \ - std::pair ret = priv_insert_unique_prepare(hint, val, data); \ + std::pair ret = this->priv_insert_unique_prepare(hint, val, data); \ if(ret.second){ \ - ret.first = priv_insert_commit(data, boost::move(val)); \ + ret.first = this->priv_insert_commit(data, boost::move(val)); \ } \ return ret.first; \ } \ @@ -513,7 +647,7 @@ class flat_tree value_destructor d(a, val); \ insert_commit_data data; \ this->priv_insert_equal_prepare(hint, val, data); \ - iterator i = priv_insert_commit(data, boost::move(val)); \ + iterator i = this->priv_insert_commit(data, boost::move(val)); \ return i; \ } \ @@ -653,7 +787,7 @@ class flat_tree std::pair priv_insert_unique_prepare (const value_type& val, insert_commit_data &commit_data) - { return priv_insert_unique_prepare(this->begin(), this->end(), val, commit_data); } + { return this->priv_insert_unique_prepare(this->begin(), this->end(), val, commit_data); } std::pair priv_insert_unique_prepare (const_iterator pos, const value_type& val, insert_commit_data &commit_data) @@ -794,102 +928,38 @@ class flat_tree return std::pair(first, first); } - template - void priv_insert_equal(ordered_range_t, BidirIt first, BidirIt last, std::bidirectional_iterator_tag) + template + void priv_insert_equal_loop(InIt first, InIt last) { - size_type len = static_cast(std::distance(first, last)); - const size_type BurstSize = 16; - size_type positions[BurstSize]; - - //Prereserve all memory so that iterators are not invalidated - this->reserve(this->size()+len); - const const_iterator beg(this->cbegin()); - const_iterator pos(beg); - //Loop in burst sizes - while(len){ - const size_type burst = len < BurstSize ? len : BurstSize; - const const_iterator cend(this->cend()); - len -= burst; - for(size_type i = 0; i != burst; ++i){ - //Get the insertion position for each key - pos = const_cast(*this).priv_upper_bound(pos, cend, KeyOfValue()(*first)); - positions[i] = static_cast(pos - beg); - ++first; - } - //Insert all in a single step in the precalculated positions - this->m_data.m_vect.insert_ordered_at(burst, positions + burst, first); - //Next search position updated - pos += burst; - } - } - - template - void priv_insert_unique(ordered_unique_range_t, BidirIt first, BidirIt last, std::bidirectional_iterator_tag) - { - size_type len = static_cast(std::distance(first, last)); - const size_type BurstSize = 16; - size_type positions[BurstSize]; - size_type skips[BurstSize]; - - //Prereserve all memory so that iterators are not invalidated - this->reserve(this->size()+len); - const const_iterator beg(this->cbegin()); - const_iterator pos(beg); - const value_compare &value_comp = this->m_data; - //Loop in burst sizes - while(len){ - skips[0u] = 0u; - const size_type burst = len < BurstSize ? len : BurstSize; - size_type unique_burst = 0u; - const const_iterator cend(this->cend()); - while(unique_burst < burst && len > 0){ - //Get the insertion position for each key - const value_type & val = *first++; - --len; - pos = const_cast(*this).priv_lower_bound(pos, cend, KeyOfValue()(val)); - //Check if already present - if(pos != cend && !value_comp(*pos, val)){ - ++skips[unique_burst]; - continue; - } - - //If not present, calculate position - positions[unique_burst] = static_cast(pos - beg); - if(++unique_burst < burst) - skips[unique_burst] = 0u; - } - //Insert all in a single step in the precalculated positions - this->m_data.m_vect.insert_ordered_at(unique_burst, positions + unique_burst, skips + unique_burst, first); - //Next search position updated - pos += unique_burst; - } - } -/* - template - void priv_insert_equal_forward(ordered_range_t, FwdIt first, FwdIt last, std::forward_iterator_tag) - { this->priv_insert_equal(first, last, std::forward_iterator_tag()); } -*/ - template - void priv_insert_equal(ordered_range_t, InIt first, InIt last, std::input_iterator_tag) - { this->priv_insert_equal(first, last, std::input_iterator_tag()); } - - template - void priv_insert_unique(ordered_unique_range_t, InIt first, InIt last, std::input_iterator_tag) - { this->priv_insert_unique(first, last, std::input_iterator_tag()); } -/* - template - void priv_insert_equal_forward(FwdIt first, FwdIt last, std::forward_iterator_tag) - { - const size_type len = static_cast(std::distance(first, last)); - this->reserve(this->size()+len); - this->priv_insert_equal(first, last, std::input_iterator_tag()); - } -*/ - template - void priv_insert_equal(InIt first, InIt last, std::input_iterator_tag) - { - for ( ; first != last; ++first) + for ( ; first != last; ++first){ this->insert_equal(*first); + } + } + + template + void priv_insert_equal_loop_ordered(InIt first, InIt last) + { + const_iterator pos(this->cend()); + for ( ; first != last; ++first){ + pos = this->insert_equal(pos, *first); + } + } + + template + void priv_insert_unique_loop(InIt first, InIt last) + { + for ( ; first != last; ++first){ + this->insert_unique(*first); + } + } + + template + void priv_insert_unique_loop_ordered(InIt first, InIt last) + { + const_iterator pos(this->cend()); + for ( ; first != last; ++first){ + pos = this->insert_unique(pos, *first); + } } }; diff --git a/include/boost/container/detail/iterators.hpp b/include/boost/container/detail/iterators.hpp index 374b55c..78a0dda 100644 --- a/include/boost/container/detail/iterators.hpp +++ b/include/boost/container/detail/iterators.hpp @@ -22,10 +22,10 @@ #include #include #include +#include #ifdef BOOST_CONTAINER_PERFECT_FORWARDING #include -#include #else #include #endif @@ -222,14 +222,12 @@ class default_construct_iterator default_construct_iterator operator-(Difference off) const { return *this + (-off); } - const T& operator*() const - { return dereference(); } - - const T* operator->() const - { return &(dereference()); } - - const T& operator[] (Difference n) const - { return dereference(); } + //This pseudo-iterator's dereference operations have no sense since value is not + //constructed until ::boost::container::construct_in_place is called. + //So comment them to catch bad uses + //const T& operator*() const; + //const T& operator[](difference_type) const; + //const T* operator->() const; private: Difference m_num; @@ -445,14 +443,12 @@ class emplace_iterator this_type operator-(difference_type off) const { return *this + (-off); } - const T& operator*() const - { return dereference(); } - - const T& operator[](difference_type) const - { return dereference(); } - - const T* operator->() const - { return &(dereference()); } + //This pseudo-iterator's dereference operations have no sense since value is not + //constructed until ::boost::container::construct_in_place is called. + //So comment them to catch bad uses + //const T& operator*() const; + //const T& operator[](difference_type) const; + //const T* operator->() const; template void construct_in_place(A &a, T* ptr) @@ -506,8 +502,7 @@ struct emplace_functor void inplace_impl(A &a, T* ptr, const container_detail::index_tuple&) { allocator_traits::construct - (a, ptr, container_detail::stored_ref::forward - (container_detail::get(args_))...); + (a, ptr, ::boost::forward(container_detail::get(args_))...); } container_detail::tuple args_; @@ -539,6 +534,59 @@ struct emplace_functor #endif +namespace container_detail { + +template +struct has_iterator_category +{ + template + static char test(int, typename X::iterator_category*); + + template + static int test(int, ...); + + static const bool value = (1 == sizeof(test(0, 0))); +}; + + +template::value > +struct is_input_iterator +{ + static const bool value = is_same::value; +}; + +template +struct is_input_iterator +{ + static const bool value = false; +}; + +template::value > +struct is_forward_iterator +{ + static const bool value = is_same::value; +}; + +template +struct is_forward_iterator +{ + static const bool value = false; +}; + +template::value > +struct is_bidirectional_iterator +{ + static const bool value = is_same::value; +}; + +template +struct is_bidirectional_iterator +{ + static const bool value = false; +}; + +} //namespace container_detail { + } //namespace container { } //namespace boost { diff --git a/include/boost/container/detail/preprocessor.hpp b/include/boost/container/detail/preprocessor.hpp index 1818094..5129ea1 100644 --- a/include/boost/container/detail/preprocessor.hpp +++ b/include/boost/container/detail/preprocessor.hpp @@ -16,11 +16,6 @@ #endif #include - -#ifndef BOOST_NO_RVALUE_REFERENCES -#include -#endif //#ifndef BOOST_NO_RVALUE_REFERENCES - #include #ifdef BOOST_CONTAINER_PERFECT_FORWARDING @@ -78,19 +73,10 @@ const BOOST_PP_CAT(Q, n) & BOOST_PP_CAT(q, n) \ #ifndef BOOST_NO_RVALUE_REFERENCES - #if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) - - #define BOOST_CONTAINER_PP_PARAM_INIT(z, n, data) \ - BOOST_PP_CAT(m_p, n) (static_cast( BOOST_PP_CAT(p, n) )) \ - - #else //#if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) - #define BOOST_CONTAINER_PP_PARAM_INIT(z, n, data) \ BOOST_PP_CAT(m_p, n) (::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) )) \ //! - #endif //BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - #else //BOOST_NO_RVALUE_REFERENCES #define BOOST_CONTAINER_PP_PARAM_INIT(z, n, data) \ @@ -102,8 +88,68 @@ const BOOST_PP_CAT(Q, n) & BOOST_PP_CAT(q, n) \ #if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) + namespace boost { + namespace container { + namespace container_detail { + template + struct ref_holder; + + template + struct ref_holder + { + ref_holder(T &t) + : t_(t) + {} + T &t_; + T & get() { return t_; } + }; + + template + struct ref_holder + { + ref_holder(const T &t) + : t_(t) + {} + const T &t_; + const T & get() { return t_; } + }; + + template + struct ref_holder + { + ref_holder(const T &t) + : t_(t) + {} + const T &t_; + const T & get() { return t_; } + }; + + template + struct ref_holder + { + ref_holder(T &&t) + : t_(t) + {} + T &t_; + T && get() { return ::boost::move(t_); } + }; + + template + struct ref_holder + { + ref_holder(T &&t) + : t(t) + {} + T &t; + T && get() { return ::boost::move(t_); } + }; + + } //namespace container_detail { + } //namespace container { + } //namespace boost { + #define BOOST_CONTAINER_PP_PARAM_DEFINE(z, n, data) \ - BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \ + ::boost::container::container_detail::ref_holder BOOST_PP_CAT(m_p, n); \ //! #else //BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG @@ -123,8 +169,7 @@ const BOOST_PP_CAT(Q, n) & BOOST_PP_CAT(q, n) \ #if !defined(BOOST_NO_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) - #define BOOST_CONTAINER_PP_MEMBER_FORWARD(z, n, data) \ - ::boost::container::container_detail::stored_ref< BOOST_PP_CAT(P, n) >::forward( BOOST_PP_CAT(this->m_p, n) ) \ + #define BOOST_CONTAINER_PP_MEMBER_FORWARD(z, n, data) BOOST_PP_CAT(this->m_p, n).get() \ //! #else //!defined(BOOST_NO_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) diff --git a/include/boost/container/detail/stored_ref.hpp b/include/boost/container/detail/stored_ref.hpp deleted file mode 100644 index 80fda89..0000000 --- a/include/boost/container/detail/stored_ref.hpp +++ /dev/null @@ -1,92 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost -// Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// See http://www.boost.org/libs/container for documentation. -// -////////////////////////////////////////////////////////////////////////////// - -#ifndef BOOST_CONTAINER_DETAIL_STORED_REF_HPP -#define BOOST_CONTAINER_DETAIL_STORED_REF_HPP - -#include "config_begin.hpp" -#include - -#ifndef BOOST_NO_RVALUE_REFERENCES - -namespace boost{ -namespace container{ -namespace container_detail{ - -template -struct stored_ref -{ - - static T && forward(T &t) - #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - { return t; } - #else - { return boost::move(t); } - #endif -}; - -template -struct stored_ref -{ - static const T && forward(const T &t) - #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - { return t; } - #else - { return static_cast(t); } - #endif -}; - -template -struct stored_ref -{ - static T && forward(T &t) - #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - { return t; } - #else - { return boost::move(t); } - #endif -}; - -template -struct stored_ref -{ - static const T && forward(const T &t) - #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - { return t; } - #else - { return static_cast(t); } - #endif -}; - -template -struct stored_ref -{ - static const T & forward(const T &t) - { return t; } -}; - -template -struct stored_ref -{ - static T & forward(T &t) - { return t; } -}; - -} //namespace container_detail{ -} //namespace container{ -} //namespace boost{ - -#else -#error "This header can be included only for compiler with rvalue references" -#endif //BOOST_NO_RVALUE_REFERENCES - -#include - -#endif //BOOST_CONTAINER_DETAIL_STORED_REF_HPP diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index 3ab1536..96db26f 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -476,21 +476,77 @@ class rbtree {} template - rbtree(InputIterator first, InputIterator last, const key_compare& comp, - const allocator_type& a, bool unique_insertion) + rbtree(bool unique_insertion, InputIterator first, InputIterator last, const key_compare& comp, + const allocator_type& a + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator::value + || container_detail::is_same::value + >::type * = 0 + #endif + ) : AllocHolder(a, comp) { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_nodes(first, last, unique_insertion, alloc_version(), ItCat()); + if(unique_insertion){ + this->insert_unique(first, last); + } + else{ + this->insert_equal(first, last); + } + } + + template + rbtree(bool unique_insertion, InputIterator first, InputIterator last, const key_compare& comp, + const allocator_type& a + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !(container_detail::is_input_iterator::value + || container_detail::is_same::value) + >::type * = 0 + #endif + ) + : AllocHolder(a, comp) + { + if(unique_insertion){ + this->insert_unique(first, last); + } + else{ + //Optimized allocation and construction + this->allocate_many_and_construct + (first, std::distance(first, last), insert_equal_end_hint_functor(this->icont())); + } } template rbtree( ordered_range_t, InputIterator first, InputIterator last - , const key_compare& comp = key_compare(), const allocator_type& a = allocator_type()) + , const key_compare& comp = key_compare(), const allocator_type& a = allocator_type() + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator::value + || container_detail::is_same::value + >::type * = 0 + #endif + ) : AllocHolder(a, comp) { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_ordered_nodes(first, last, alloc_version(), ItCat()); + this->insert_equal(first, last); + } + + template + rbtree( ordered_range_t, InputIterator first, InputIterator last + , const key_compare& comp = key_compare(), const allocator_type& a = allocator_type() + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !(container_detail::is_input_iterator::value + || container_detail::is_same::value) + >::type * = 0 + #endif + ) + : AllocHolder(a, comp) + { + //Optimized allocation and construction + this->allocate_many_and_construct + (first, std::distance(first, last), push_back_functor(this->icont())); } rbtree(const rbtree& x) @@ -943,14 +999,14 @@ class rbtree { return const_iterator(this->non_const_icont().upper_bound(k, KeyNodeCompare(value_comp()))); } std::pair equal_range(const key_type& k) - { + { std::pair ret = this->icont().equal_range(k, KeyNodeCompare(value_comp())); return std::pair(iterator(ret.first), iterator(ret.second)); } std::pair equal_range(const key_type& k) const - { + { std::pair ret = this->non_const_icont().equal_range(k, KeyNodeCompare(value_comp())); return std::pair @@ -958,108 +1014,39 @@ class rbtree } private: - //Iterator range version - template - void priv_create_and_insert_nodes - (InpIterator beg, InpIterator end, bool unique, allocator_v1, std::input_iterator_tag) - { - if(unique){ - for (; beg != end; ++beg){ - this->insert_unique(*beg); - } - } - else{ - for (; beg != end; ++beg){ - this->insert_equal(*beg); - } - } - } - template - void priv_create_and_insert_nodes - (InpIterator beg, InpIterator end, bool unique, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_nodes(beg, end, unique, allocator_v1(), std::input_iterator_tag()); - } + class insert_equal_end_hint_functor; + friend class insert_equal_end_hint_functor; - class insertion_functor; - friend class insertion_functor; - - class insertion_functor + class insert_equal_end_hint_functor { Icont &icont_; + const iconst_iterator cend_; public: - insertion_functor(Icont &icont) - : icont_(icont) + insert_equal_end_hint_functor(Icont &icont) + : icont_(icont), cend_(this->icont_.cend()) {} void operator()(Node &n) - { this->icont_.insert_equal(this->icont_.cend(), n); } + { this->icont_.insert_equal(cend_, n); } }; + class push_back_functor; + friend class push_back_functor; - template - void priv_create_and_insert_nodes - (FwdIterator beg, FwdIterator end, bool unique, allocator_v2, std::forward_iterator_tag) - { - if(beg != end){ - if(unique){ - priv_create_and_insert_nodes(beg, end, unique, allocator_v2(), std::input_iterator_tag()); - } - else{ - //Optimized allocation and construction - this->allocate_many_and_construct - (beg, std::distance(beg, end), insertion_functor(this->icont())); - } - } - } - - //Iterator range version - template - void priv_create_and_insert_ordered_nodes - (InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) - { - const_iterator cend_n(this->cend()); - for (; beg != end; ++beg){ - this->insert_before(cend_n, *beg); - } - } - - template - void priv_create_and_insert_ordered_nodes - (InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_ordered_nodes(beg, end, allocator_v1(), std::input_iterator_tag()); - } - - class back_insertion_functor; - friend class back_insertion_functor; - - class back_insertion_functor + class push_back_functor { Icont &icont_; public: - back_insertion_functor(Icont &icont) + push_back_functor(Icont &icont) : icont_(icont) {} void operator()(Node &n) { this->icont_.push_back(n); } }; - - - template - void priv_create_and_insert_ordered_nodes - (FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) - { - if(beg != end){ - //Optimized allocation and construction - this->allocate_many_and_construct - (beg, std::distance(beg, end), back_insertion_functor(this->icont())); - } - } }; template flat_map(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_flat_tree(comp, container_detail::force(a)) - { m_flat_tree.insert_unique(first, last); } + : m_flat_tree(true, first, last, comp, container_detail::force(a)) + {} //! Effects: Constructs an empty flat_map using the specified comparison object and //! allocator, and inserts elements from the ordered unique range [first ,last). This function @@ -988,8 +988,8 @@ class flat_multimap flat_multimap(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_flat_tree(comp, container_detail::force(a)) - { m_flat_tree.insert_equal(first, last); } + : m_flat_tree(false, first, last, comp, container_detail::force(a)) + {} //! Effects: Constructs an empty flat_multimap using the specified comparison object and //! allocator, and inserts elements from the ordered range [first ,last). This function diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 09c95eb..513d487 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -125,8 +125,8 @@ class flat_set flat_set(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) - { m_flat_tree.insert_unique(first, last); } + : m_flat_tree(true, first, last, comp, a) + {} //! Effects: Constructs an empty flat_set using the specified comparison object and //! allocator, and inserts elements from the ordered unique range [first ,last). This function @@ -777,8 +777,8 @@ class flat_multiset flat_multiset(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) - { m_flat_tree.insert_equal(first, last); } + : m_flat_tree(false, first, last, comp, a) + {} //! Effects: Constructs an empty flat_multiset using the specified comparison object and //! allocator, and inserts elements from the ordered range [first ,last ). This function diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index c3e3562..a991860 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -660,18 +660,8 @@ class list //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size, const T& x) { - const_iterator iend = this->cend(); - size_type len = this->size(); - - if(len > new_size){ - size_type to_erase = len - new_size; - while(to_erase--){ - --iend; - } - this->erase(iend, this->cend()); - } - else{ - this->priv_create_and_insert_nodes(iend, new_size - len, x); + if(!priv_try_shrink(new_size)){ + this->insert(this->cend(), new_size - this->size(), x); } } @@ -683,29 +673,9 @@ class list //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size) { - const_iterator iend = this->end(); - size_type len = this->size(); - - if(len > new_size){ - size_type to_erase = len - new_size; - const_iterator ifirst; - if(to_erase < len/2u){ - ifirst = iend; - while(to_erase--){ - --ifirst; - } - } - else{ - ifirst = this->begin(); - size_type to_skip = len - to_erase; - while(to_skip--){ - ++ifirst; - } - } - this->erase(ifirst, iend); - } - else{ - this->priv_create_and_insert_nodes(this->cend(), new_size - len); + if(!priv_try_shrink(new_size)){ + typedef default_construct_iterator default_iterator; + this->insert(this->cend(), default_iterator(new_size - this->size()), default_iterator()); } } @@ -776,33 +746,76 @@ class list //! //! Effects: Inserts n copies of x before p. //! + //! Returns: an iterator to the first inserted element or p if n is 0. + //! //! Throws: If memory allocation throws or T's copy constructor throws. //! //! Complexity: Linear to n. - void insert(const_iterator p, size_type n, const T& x) - { this->priv_create_and_insert_nodes(p, n, x); } + iterator insert(const_iterator p, size_type n, const T& x) + { + typedef constant_iterator cvalue_iterator; + return this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); + } //! Requires: p must be a valid iterator of *this. //! //! Effects: Insert a copy of the [first, last) range before p. //! + //! Returns: an iterator to the first inserted element or p if first == last. + //! //! Throws: If memory allocation throws, T's constructor from a //! dereferenced InpIt throws. //! //! Complexity: Linear to std::distance [first, last). template - void insert(const_iterator p, InpIt first, InpIt last) + iterator insert(const_iterator p, InpIt first, InpIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && (container_detail::is_input_iterator::value + || container_detail::is_same::value + ) + >::type * = 0 + #endif + ) { - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_insert_dispatch(p, first, last, Result()); + const typename Icont::iterator ipos(p.get()); + iterator ret_it(ipos); + if(first != last){ + ret_it = iterator(this->icont().insert(ipos, *this->create_node_from_it(first))); + ++first; + } + for (; first != last; ++first){ + this->icont().insert(ipos, *this->create_node_from_it(first)); + } + return ret_it; } + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator insert(const_iterator p, FwdIt first, FwdIt last + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !(container_detail::is_input_iterator::value + || container_detail::is_same::value + ) + >::type * = 0 + ) + { + //Optimized allocation and construction + insertion_functor func(this->icont(), p.get()); + this->allocate_many_and_construct(first, std::distance(first, last), func); + return iterator(func.inserted_first()); + } + #endif + #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. @@ -812,6 +825,8 @@ class list //! //! 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. @@ -919,7 +934,10 @@ class list //! //! Complexity: Linear to n. void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } + { + typedef constant_iterator cvalue_iterator; + return this->assign(cvalue_iterator(val, n), cvalue_iterator()); + } //! Effects: Assigns the the range [first, last) to *this. //! @@ -928,11 +946,23 @@ class list //! //! Complexity: Linear to n. template - void assign(InpIt first, InpIt last) + 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 + ) { - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); + 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); + } } //! Requires: p must point to an element contained @@ -1151,6 +1181,34 @@ class list /// @cond private: + bool priv_try_shrink(size_type new_size) + { + const size_type len = this->size(); + if(len > new_size){ + const const_iterator iend = this->cend(); + size_type to_erase = len - new_size; + const_iterator ifirst; + if(to_erase < len/2u){ + ifirst = iend; + while(to_erase--){ + --ifirst; + } + } + else{ + ifirst = this->cbegin(); + size_type to_skip = len - to_erase; + while(to_skip--){ + ++ifirst; + } + } + this->erase(ifirst, iend); + return true; + } + else{ + return false; + } + } + iterator priv_insert(const_iterator p, const T &x) { NodePtr tmp = AllocHolder::create_node(x); @@ -1175,117 +1233,39 @@ class list void priv_push_front (BOOST_RV_REF(T) x) { this->insert(this->cbegin(), boost::move(x)); } - //Iterator range version - template - void priv_create_and_insert_nodes - (const_iterator pos, InpIterator beg, InpIterator end) - { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_nodes(pos, beg, end, alloc_version(), ItCat()); - } - - template - void priv_create_and_insert_nodes - (const_iterator pos, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) - { - for (; beg != end; ++beg){ - this->icont().insert(pos.get(), *this->create_node_from_it(beg)); - } - } - - template - void priv_create_and_insert_nodes - (const_iterator pos, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_nodes(pos, beg, end, allocator_v1(), std::input_iterator_tag()); - } - class insertion_functor; friend class insertion_functor; class insertion_functor { Icont &icont_; - typename Icont::const_iterator pos_; + typedef typename Icont::iterator iiterator; + typedef typename Icont::const_iterator iconst_iterator; + + const iconst_iterator pos_; + iiterator ret_; + bool first_; public: insertion_functor(Icont &icont, typename Icont::const_iterator pos) - : icont_(icont), pos_(pos) + : icont_(icont), pos_(pos), ret_(pos.unconst()), first_(true) {} void operator()(Node &n) - { this->icont_.insert(pos_, n); } + { + if(first_){ + ret_ = this->icont_.insert(pos_, n); + first_ = false; + } + else{ + this->icont_.insert(pos_, n); + } + } + + iiterator inserted_first() const + { return ret_; } }; - - template - void priv_create_and_insert_nodes - (const_iterator pos, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) - { - if(beg != end){ - //Optimized allocation and construction - this->allocate_many_and_construct - (beg, std::distance(beg, end), insertion_functor(this->icont(), pos.get())); - } - } - - //Default constructed version - void priv_create_and_insert_nodes(const_iterator pos, size_type n) - { - typedef default_construct_iterator default_iterator; - this->priv_create_and_insert_nodes(pos, default_iterator(n), default_iterator()); - } - - //Copy constructed version - void priv_create_and_insert_nodes(const_iterator pos, size_type n, const T& x) - { - typedef constant_iterator cvalue_iterator; - this->priv_create_and_insert_nodes(pos, cvalue_iterator(x, n), cvalue_iterator()); - } - - //Dispatch to detect iterator range or integer overloads - template - void priv_insert_dispatch(const_iterator p, - InputIter first, InputIter last, - container_detail::false_) - { this->priv_create_and_insert_nodes(p, first, last); } - - template - void priv_insert_dispatch(const_iterator p, Integer n, Integer x, container_detail::true_) - { this->insert(p, (size_type)n, x); } - - void priv_fill_assign(size_type n, const T& val) - { - iterator i = this->begin(), iend = this->end(); - - for ( ; i != iend && n > 0; ++i, --n) - *i = val; - if (n > 0){ - this->priv_create_and_insert_nodes(this->cend(), n, val); - } - else{ - this->erase(i, cend()); - } - } - - template - void priv_assign_dispatch(Integer n, Integer val, container_detail::true_) - { this->priv_fill_assign((size_type) n, (T) val); } - - template - void priv_assign_dispatch(InputIter first2, InputIter last2, container_detail::false_) - { - iterator first1 = this->begin(); - iterator last1 = this->end(); - for ( ; first1 != last1 && first2 != last2; ++first1, ++first2) - *first1 = *first2; - if (first2 == last2) - this->erase(first1, last1); - else{ - this->priv_create_and_insert_nodes(last1, first2, last2); - } - } - //Functors for member algorithm defaults struct value_less { diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index d4bd6e6..d31122c 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -155,7 +155,7 @@ class map template map(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, true) + : m_tree(true, first, last, comp, a) { //Allocator type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename A::value_type>::value)); @@ -902,7 +902,7 @@ class multimap multimap(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, false) + : m_tree(false, first, last, comp, a) { //Allocator type must be std::pair BOOST_STATIC_ASSERT((container_detail::is_same, typename A::value_type>::value)); diff --git a/include/boost/container/set.hpp b/include/boost/container/set.hpp index 09ada20..44a854c 100644 --- a/include/boost/container/set.hpp +++ b/include/boost/container/set.hpp @@ -118,7 +118,7 @@ class set template set(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, true) + : m_tree(true, first, last, comp, a) {} //! Effects: Constructs an empty set using the specified comparison object and @@ -705,7 +705,7 @@ class multiset multiset(InputIterator first, InputIterator last, const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, false) + : m_tree(false, first, last, comp, a) {} //! Effects: Constructs an empty multiset using the specified comparison object and diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index 5771935..553fb54 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -336,7 +337,7 @@ class slist //! Complexity: Linear to n. explicit slist(size_type n, const value_type& x, const allocator_type& a = allocator_type()) : AllocHolder(a) - { this->priv_create_and_insert_nodes(this->before_begin(), n, x); } + { this->insert_after(this->cbefore_begin(), n, x); } //! Effects: Constructs a list that will use a copy of allocator a //! and inserts a copy of the range [first, last) in the list. @@ -349,7 +350,7 @@ class slist slist(InpIt first, InpIt last, const allocator_type& a = allocator_type()) : AllocHolder(a) - { this->insert_after(this->before_begin(), first, last); } + { this->insert_after(this->cbefore_begin(), first, last); } //! Effects: Copy constructs a list. //! @@ -360,7 +361,7 @@ class slist //! Complexity: Linear to the elements x contains. slist(const slist& x) : AllocHolder(x) - { this->insert_after(this->before_begin(), x.begin(), x.end()); } + { this->insert_after(this->cbefore_begin(), x.begin(), x.end()); } //! Effects: Move constructor. Moves mx's resources to *this. //! @@ -380,7 +381,7 @@ class slist //! Complexity: Linear to the elements x contains. slist(const slist& x, const allocator_type &a) : AllocHolder(a) - { this->insert_after(this->before_begin(), x.begin(), x.end()); } + { this->insert_after(this->cbefore_begin(), x.begin(), x.end()); } //! Effects: Move constructor using the specified allocator. //! Moves x's resources to *this. @@ -485,7 +486,10 @@ class slist //! //! Complexity: Linear to n. void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } + { + typedef constant_iterator cvalue_iterator; + return this->assign(cvalue_iterator(val, n), cvalue_iterator()); + } //! Effects: Assigns the range [first, last) to *this. //! @@ -494,11 +498,27 @@ class slist //! //! Complexity: Linear to n. template - void assign(InpIt first, InpIt last) + 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 + ) { - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); + iterator end_n(this->end()); + iterator prev(this->before_begin()); + iterator node(this->begin()); + while (node != end_n && first != last){ + *node = *first; + prev = node; + ++node; + ++first; + } + if (first != last) + this->insert_after(prev, first, last); + else + this->erase_after(prev, end_n); } //! Effects: Returns an iterator to the first element contained in the list. @@ -535,7 +555,7 @@ class slist //! Effects: Returns a non-dereferenceable iterator that, //! when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. + //! as the argument to insert_after, erase_after, etc. //! //! Throws: Nothing. //! @@ -545,7 +565,7 @@ class slist //! Effects: Returns a non-dereferenceable const_iterator //! that, when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. + //! as the argument to insert_after, erase_after, etc. //! //! Throws: Nothing. //! @@ -571,7 +591,7 @@ class slist //! Effects: Returns a non-dereferenceable const_iterator //! that, when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. + //! as the argument to insert_after, erase_after, etc. //! //! Throws: Nothing. //! @@ -734,20 +754,28 @@ class slist //! //! Effects: Inserts n copies of x after prev_pos. //! + //! Returns: an iterator to the last inserted element or prev_pos if n is 0. + //! //! Throws: If memory allocation throws or T's copy constructor throws. //! + //! //! Complexity: Linear to n. //! //! Note: Does not affect the validity of iterators and references of //! previous values. - void insert_after(const_iterator prev_pos, size_type n, const value_type& x) - { this->priv_create_and_insert_nodes(prev_pos, n, x); } + iterator insert_after(const_iterator prev_pos, size_type n, const value_type& x) + { + typedef constant_iterator cvalue_iterator; + return this->insert_after(prev_pos, cvalue_iterator(x, n), cvalue_iterator()); + } //! Requires: prev_pos must be a valid iterator of *this. //! //! Effects: Inserts the range pointed by [first, last) //! after the p prev_pos. //! + //! Returns: an iterator to the last inserted element or prev_pos if first == last. + //! //! Throws: If memory allocation throws, T's constructor from a //! dereferenced InpIt throws. //! @@ -755,18 +783,49 @@ class slist //! //! Note: Does not affect the validity of iterators and references of //! previous values. - template - void insert_after(const_iterator prev_pos, InIter first, InIter last) + template + iterator insert_after(const_iterator prev_pos, InpIt first, InpIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && (container_detail::is_input_iterator::value + || container_detail::is_same::value + ) + >::type * = 0 + #endif + ) { - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_insert_after_range_dispatch(prev_pos, first, last, Result()); + iterator ret_it(prev_pos.get()); + for (; first != last; ++first){ + ret_it = iterator(this->icont().insert_after(ret_it.get(), *this->create_node_from_it(first))); + } + return ret_it; } + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator insert_after(const_iterator prev, FwdIt first, FwdIt last + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !(container_detail::is_input_iterator::value + || container_detail::is_same::value + ) + >::type * = 0 + ) + { + //Optimized allocation and construction + insertion_functor func(this->icont(), prev.get()); + this->allocate_many_and_construct(first, std::distance(first, last), func); + return iterator(func.inserted_first()); + } + #endif + //! 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. @@ -787,6 +846,8 @@ class slist //! //! 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. @@ -797,24 +858,36 @@ class slist //! //! 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. - void insert(const_iterator p, size_type n, const value_type& x) - { return this->insert_after(previous(p), n, x); } + 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 - void insert(const_iterator p, InIter first, InIter last) - { return this->insert_after(previous(p), first, last); } + 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) @@ -948,15 +1021,10 @@ class slist //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size, const T& x) { - typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; - while (++(cur_next = cur) != end_n && new_size > 0){ - --new_size; - cur = cur_next; + const_iterator last_pos; + if(!priv_try_shrink(new_size, last_pos)){ + this->insert_after(last_pos, new_size, x); } - if (cur_next != end_n) - this->erase_after(const_iterator(cur), const_iterator(end_n)); - else - this->insert_after(const_iterator(cur), new_size, x); } //! Effects: Inserts or erases elements at the end such that @@ -967,19 +1035,10 @@ class slist //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size) { - typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; - size_type len = this->size(); - size_type left = new_size; - - while (++(cur_next = cur) != end_n && left > 0){ - --left; - cur = cur_next; - } - if (cur_next != end_n){ - this->erase_after(const_iterator(cur), const_iterator(end_n)); - } - else{ - this->priv_create_and_insert_nodes(const_iterator(cur), new_size - len); + 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()); } } @@ -1279,6 +1338,24 @@ class slist /// @cond private: + + 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; + while (++(cur_next = cur) != end_n && new_size > 0){ + --new_size; + cur = cur_next; + } + last_pos = const_iterator(cur); + if (cur_next != end_n){ + this->erase_after(last_pos, const_iterator(end_n)); + return true; + } + else{ + return false; + } + } + iterator priv_insert(const_iterator p, const value_type& x) { return this->insert_after(previous(p), x); } @@ -1288,129 +1365,31 @@ class slist void priv_push_front(const value_type &x) { this->icont().push_front(*this->create_node(x)); } - //Iterator range version - template - void priv_create_and_insert_nodes - (const_iterator prev, InpIterator beg, InpIterator end) - { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_nodes(prev, beg, end, alloc_version(), ItCat()); - } - - template - void priv_create_and_insert_nodes - (const_iterator prev, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) - { - for (; beg != end; ++beg){ - this->icont().insert_after(prev.get(), *this->create_node_from_it(beg)); - ++prev; - } - } - - template - void priv_create_and_insert_nodes - (const_iterator prev, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_nodes(prev, beg, end, allocator_v1(), std::input_iterator_tag()); - } - class insertion_functor; friend class insertion_functor; class insertion_functor { Icont &icont_; - typename Icont::const_iterator prev_; + typedef typename Icont::iterator iiterator; + typedef typename Icont::const_iterator iconst_iterator; + const iconst_iterator prev_; + iiterator ret_; public: insertion_functor(Icont &icont, typename Icont::const_iterator prev) - : icont_(icont), prev_(prev) + : icont_(icont), prev_(prev), ret_(prev.unconst()) {} void operator()(Node &n) - { prev_ = this->icont_.insert_after(prev_, n); } + { + ret_ = this->icont_.insert_after(prev_, n); + } + + iiterator inserted_first() const + { return ret_; } }; - template - void priv_create_and_insert_nodes - (const_iterator prev, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) - { - //Optimized allocation and construction - this->allocate_many_and_construct - (beg, std::distance(beg, end), insertion_functor(this->icont(), prev.get())); - } - - //Default constructed version - void priv_create_and_insert_nodes(const_iterator prev, size_type n) - { - typedef default_construct_iterator default_iterator; - this->priv_create_and_insert_nodes(prev, default_iterator(n), default_iterator()); - } - - //Copy constructed version - void priv_create_and_insert_nodes(const_iterator prev, size_type n, const T& x) - { - typedef constant_iterator cvalue_iterator; - this->priv_create_and_insert_nodes(prev, cvalue_iterator(x, n), cvalue_iterator()); - } - - //Dispatch to detect iterator range or integer overloads - template - void priv_insert_dispatch(const_iterator prev, - InputIter first, InputIter last, - container_detail::false_) - { this->priv_create_and_insert_nodes(prev, first, last); } - - template - void priv_insert_dispatch(const_iterator prev, Integer n, Integer x, container_detail::true_) - { this->priv_create_and_insert_nodes(prev, (size_type)n, x); } - - void priv_fill_assign(size_type n, const T& val) - { - iterator end_n(this->end()); - iterator prev(this->before_begin()); - iterator node(this->begin()); - for ( ; node != end_n && n > 0 ; --n){ - *node = val; - prev = node; - ++node; - } - if (n > 0) - this->priv_create_and_insert_nodes(prev, n, val); - else - this->erase_after(prev, end_n); - } - - template - void priv_assign_dispatch(Int n, Int val, container_detail::true_) - { this->priv_fill_assign((size_type) n, (T)val); } - - template - void priv_assign_dispatch(InpIt first, InpIt last, container_detail::false_) - { - iterator end_n(this->end()); - iterator prev(this->before_begin()); - iterator node(this->begin()); - while (node != end_n && first != last){ - *node = *first; - prev = node; - ++node; - ++first; - } - if (first != last) - this->priv_create_and_insert_nodes(prev, first, last); - else - this->erase_after(prev, end_n); - } - - template - void priv_insert_after_range_dispatch(const_iterator prev_pos, Int n, Int x, container_detail::true_) - { this->priv_create_and_insert_nodes(prev_pos, (size_type)n, x); } - - template - void priv_insert_after_range_dispatch(const_iterator prev_pos, InIter first, InIter last, container_detail::false_) - { this->priv_create_and_insert_nodes(prev_pos, first, last); } - //Functors for member algorithm defaults struct value_less { diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index d91eccd..f43db03 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -93,7 +93,7 @@ class clear_on_destroy { if(do_clear_){ c_.clear(); - c_.clear_pool(); + c_.priv_clear_pool(); } } @@ -172,6 +172,9 @@ class iterator iterator(const iterator::template rebind_pointer::type>& x) : pn(x.pn) {} + + node_type_ptr_t node() const + { return pn; } private: static node_type_ptr_t node_ptr_cast(const void_ptr &p) @@ -413,14 +416,14 @@ class stable_vector typename boost::container::container_detail::enable_if_c ::value>::type * = 0) - { return node_alloc().allocate(1); } + { return this->priv_node_alloc().allocate(1); } template node_type_ptr_t allocate_one(AllocatorVersion, typename boost::container::container_detail::enable_if_c ::value>::type * = 0) - { return node_alloc().allocate_one(); } + { return this->priv_node_alloc().allocate_one(); } void deallocate_one(node_type_ptr_t p) { return this->deallocate_one(p, alloc_version()); } @@ -430,14 +433,14 @@ class stable_vector typename boost::container::container_detail::enable_if_c ::value>::type * = 0) - { node_alloc().deallocate(p, 1); } + { this->priv_node_alloc().deallocate(p, 1); } template void deallocate_one(node_type_ptr_t p, AllocatorVersion, typename boost::container::container_detail::enable_if_c ::value>::type * = 0) - { node_alloc().deallocate_one(p); } + { this->priv_node_alloc().deallocate_one(p); } friend class stable_vector_detail::clear_on_destroy; ///@endcond @@ -497,7 +500,7 @@ class stable_vector //! //! Complexity: Constant. explicit stable_vector(const allocator_type& al) - : internal_data(al),impl(al) + : internal_data(al), impl(al) { STABLE_VECTOR_CHECK_INVARIANT; } @@ -510,7 +513,7 @@ class stable_vector //! //! Complexity: Linear to n. explicit stable_vector(size_type n) - : internal_data(),impl() + : internal_data(), impl() { stable_vector_detail::clear_on_destroy cod(*this); this->resize(n); @@ -526,10 +529,10 @@ class stable_vector //! //! Complexity: Linear to n. stable_vector(size_type n, const T& t, const allocator_type& al = allocator_type()) - : internal_data(al),impl(al) + : internal_data(al), impl(al) { stable_vector_detail::clear_on_destroy cod(*this); - this->insert(this->cbegin(), n, t); + this->insert(this->cend(), n, t); STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -543,10 +546,10 @@ class stable_vector //! Complexity: Linear to the range [first, last). template stable_vector(InputIterator first,InputIterator last, const allocator_type& al = allocator_type()) - : internal_data(al),impl(al) + : internal_data(al), impl(al) { stable_vector_detail::clear_on_destroy cod(*this); - this->insert(this->cbegin(), first, last); + this->insert(this->cend(), first, last); STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -558,12 +561,12 @@ class stable_vector //! Complexity: Linear to the elements x contains. stable_vector(const stable_vector& x) : internal_data(allocator_traits:: - select_on_container_copy_construction(x.node_alloc())) + select_on_container_copy_construction(x.priv_node_alloc())) , impl(allocator_traits:: select_on_container_copy_construction(x.impl.get_stored_allocator())) { stable_vector_detail::clear_on_destroy cod(*this); - this->insert(this->cbegin(), x.begin(), x.end()); + this->insert(this->cend(), x.begin(), x.end()); STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -574,7 +577,7 @@ class stable_vector //! //! Complexity: Constant. stable_vector(BOOST_RV_REF(stable_vector) x) - : internal_data(boost::move(x.node_alloc())), impl(boost::move(x.impl)) + : internal_data(boost::move(x.priv_node_alloc())), impl(boost::move(x.impl)) { this->priv_swap_members(x); } @@ -588,7 +591,7 @@ class stable_vector : internal_data(a), impl(a) { stable_vector_detail::clear_on_destroy cod(*this); - this->insert(this->cbegin(), x.begin(), x.end()); + this->insert(this->cend(), x.begin(), x.end()); STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -602,12 +605,12 @@ class stable_vector stable_vector(BOOST_RV_REF(stable_vector) x, const allocator_type &a) : internal_data(a), impl(a) { - if(this->node_alloc() == x.node_alloc()){ + if(this->priv_node_alloc() == x.priv_node_alloc()){ this->priv_swap_members(x); } else{ stable_vector_detail::clear_on_destroy cod(*this); - this->insert(this->cbegin(), x.begin(), x.end()); + this->insert(this->cend(), x.begin(), x.end()); STABLE_VECTOR_CHECK_INVARIANT; cod.release(); } @@ -622,7 +625,7 @@ class stable_vector ~stable_vector() { this->clear(); - clear_pool(); + priv_clear_pool(); } //! Effects: Makes *this contain the same elements as x. @@ -637,15 +640,15 @@ class stable_vector { STABLE_VECTOR_CHECK_INVARIANT; if (&x != this){ - node_allocator_type &this_alloc = this->node_alloc(); - const node_allocator_type &x_alloc = x.node_alloc(); + node_allocator_type &this_alloc = this->priv_node_alloc(); + const node_allocator_type &x_alloc = x.priv_node_alloc(); container_detail::bool_ flag; if(flag && this_alloc != x_alloc){ this->clear(); this->shrink_to_fit(); } - container_detail::assign_alloc(this->node_alloc(), x.node_alloc(), flag); + container_detail::assign_alloc(this->priv_node_alloc(), x.priv_node_alloc(), flag); container_detail::assign_alloc(this->impl.get_stored_allocator(), x.impl.get_stored_allocator(), flag); this->assign(x.begin(), x.end()); } @@ -663,8 +666,8 @@ class stable_vector stable_vector& operator=(BOOST_RV_REF(stable_vector) x) { if (&x != this){ - node_allocator_type &this_alloc = this->node_alloc(); - node_allocator_type &x_alloc = x.node_alloc(); + node_allocator_type &this_alloc = this->priv_node_alloc(); + node_allocator_type &x_alloc = x.priv_node_alloc(); //If allocators are equal we can just swap pointers if(this_alloc == x_alloc){ //Destroy objects but retain memory @@ -674,7 +677,7 @@ class stable_vector //Move allocator if needed container_detail::bool_ flag; - container_detail::move_alloc(this->node_alloc(), x.node_alloc(), flag); + container_detail::move_alloc(this->priv_node_alloc(), x.priv_node_alloc(), flag); } //If unequal allocators, then do a one by one move else{ @@ -693,9 +696,25 @@ class stable_vector //! //! Complexity: Linear to n. template - void assign(InputIterator first,InputIterator last) + void assign(InputIterator first,InputIterator last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + >::type * = 0 + #endif + ) { - assign_dispatch(first, last, boost::is_integral()); + STABLE_VECTOR_CHECK_INVARIANT; + iterator first1 = this->begin(); + iterator last1 = this->end(); + for ( ; first1 != last1 && first != last; ++first1, ++first) + *first1 = *first; + if (first == last){ + this->erase(first1, last1); + } + else{ + this->insert(last1, first, last); + } } @@ -707,7 +726,7 @@ class stable_vector void assign(size_type n,const T& t) { typedef constant_iterator cvalue_iterator; - return assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_()); + this->assign(cvalue_iterator(t, n), cvalue_iterator()); } //! Effects: Returns a copy of the internal allocator. @@ -715,7 +734,8 @@ class stable_vector //! Throws: If allocator's copy constructor throws. //! //! Complexity: Constant. - allocator_type get_allocator()const {return this->node_alloc();} + allocator_type get_allocator()const + { return this->priv_node_alloc(); } //! Effects: Returns a reference to the internal allocator. //! @@ -725,7 +745,7 @@ class stable_vector //! //! Note: Non-standard extension. const stored_allocator_type &get_stored_allocator() const BOOST_CONTAINER_NOEXCEPT - { return node_alloc(); } + { return this->priv_node_alloc(); } //! Effects: Returns a reference to the internal allocator. //! @@ -735,7 +755,7 @@ class stable_vector //! //! Note: Non-standard extension. stored_allocator_type &get_stored_allocator() BOOST_CONTAINER_NOEXCEPT - { return node_alloc(); } + { return this->priv_node_alloc(); } //! Effects: Returns an iterator to the first element contained in the stable_vector. @@ -928,7 +948,7 @@ class stable_vector } //Now fill pool if data is not enough if((n - size) > this->internal_data.pool_size){ - this->add_to_pool((n - size) - this->internal_data.pool_size); + this->priv_add_to_pool((n - size) - this->internal_data.pool_size); } } } @@ -1066,6 +1086,8 @@ class stable_vector //! //! Effects: Insert a copy of x before position. //! + //! Returns: An iterator to the inserted element. + //! //! Throws: If memory allocation throws or x's copy constructor throws. //! //! Complexity: If position is end(), amortized constant time @@ -1086,6 +1108,8 @@ class stable_vector //! //! Effects: Insert a new element before position with mx's resources. //! + //! Returns: an iterator to the inserted element. + //! //! Throws: If memory allocation throws. //! //! Complexity: If position is end(), amortized constant time @@ -1104,33 +1128,70 @@ class stable_vector //! Requires: pos must be a valid iterator of *this. //! - //! Effects: Insert n copies of x before pos. + //! Effects: Insert n copies of x before position. + //! + //! Returns: an iterator to the first inserted element or position if n is 0. //! //! Throws: If memory allocation throws or T's copy constructor throws. //! //! Complexity: Linear to n. - void insert(const_iterator position, size_type n, const T& t) + iterator insert(const_iterator position, size_type n, const T& t) { STABLE_VECTOR_CHECK_INVARIANT; - this->insert_not_iter(position, n, t); + typedef constant_iterator cvalue_iterator; + return this->insert(position, cvalue_iterator(t, n), cvalue_iterator()); } //! Requires: pos must be a valid iterator of *this. //! //! Effects: Insert a copy of the [first, last) range before pos. //! + //! Returns: an iterator to the first inserted element or position if first == last. + //! //! Throws: If memory allocation throws, T's constructor from a //! dereferenced InpIt throws or T's copy constructor throws. //! //! Complexity: Linear to std::distance [first, last). template - void insert(const_iterator position,InputIterator first, InputIterator last) + iterator insert(const_iterator position,InputIterator first, InputIterator last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { STABLE_VECTOR_CHECK_INVARIANT; - this->insert_iter(position,first,last, - boost::mpl::not_ >()); + const size_type pos_n = position - this->cbegin(); + for(; first != last; ++first){ + this->emplace(position, *first); + } + return this->begin() + pos_n; } + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator insert(const_iterator position, FwdIt first, FwdIt last + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !container_detail::is_input_iterator::value + >::type * = 0 + ) + { + size_type n = (size_type)std::distance(first,last); + difference_type d = position - this->cbegin(); + if(n){ + this->insert_iter_prolog(n, d); + const impl_iterator it(impl.begin() + d); + this->priv_insert_iter_fwd(it, first, last, n); + //Fix the pointers for the newly allocated buffer + this->align_nodes(it + n, get_last_align()); + } + return this->begin() + d; + } + #endif + #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Inserts an object of type T constructed with @@ -1230,7 +1291,18 @@ class stable_vector //! Complexity: Linear to the distance between first and last //! plus linear to the elements between pos and the last element. iterator erase(const_iterator first, const_iterator last) - { return priv_erase(first, last, alloc_version()); } + { + STABLE_VECTOR_CHECK_INVARIANT; + difference_type d1 = first - this->cbegin(), d2 = last - this->cbegin(); + if(d1 != d2){ + impl_iterator it1(impl.begin() + d1), it2(impl.begin() + d2); + for(impl_iterator it = it1; it != it2; ++it) + this->delete_node(*it); + impl_iterator e = impl.erase(it1, it2); + this->align_nodes(e, get_last_align()); + } + return iterator(this->begin() + d1); + } //! Effects: Swaps the contents of *this and x. //! @@ -1241,7 +1313,7 @@ class stable_vector { STABLE_VECTOR_CHECK_INVARIANT; container_detail::bool_ flag; - container_detail::swap_alloc(this->node_alloc(), x.node_alloc(), flag); + container_detail::swap_alloc(this->priv_node_alloc(), x.priv_node_alloc(), flag); //vector's allocator is swapped here this->impl.swap(x.impl); this->priv_swap_members(x); @@ -1265,7 +1337,7 @@ class stable_vector { if(this->capacity()){ //First empty allocated node pool - this->clear_pool(); + this->priv_clear_pool(); //If empty completely destroy the index, let's recover default-constructed state if(this->empty()){ this->impl.clear(); @@ -1291,14 +1363,14 @@ class stable_vector iterator priv_insert(const_iterator position, const value_type &t) { typedef constant_iterator cvalue_iterator; - return this->insert_iter(position, cvalue_iterator(t, 1), cvalue_iterator(), std::forward_iterator_tag()); + return this->insert(position, cvalue_iterator(t, 1), cvalue_iterator()); } void priv_push_back(const value_type &t) { this->insert(end(), t); } template - void clear_pool(AllocatorVersion, + void priv_clear_pool(AllocatorVersion, typename boost::container::container_detail::enable_if_c ::value>::type * = 0) @@ -1320,7 +1392,7 @@ class stable_vector } template - void clear_pool(AllocatorVersion, + void priv_clear_pool(AllocatorVersion, typename boost::container::container_detail::enable_if_c ::value>::type * = 0) @@ -1330,24 +1402,24 @@ class stable_vector void_ptr &pool_last_ref = impl.back(); multiallocation_chain holder; holder.incorporate_after(holder.before_begin(), pool_first_ref, pool_last_ref, internal_data.pool_size); - node_alloc().deallocate_individual(boost::move(holder)); + this->priv_node_alloc().deallocate_individual(boost::move(holder)); pool_first_ref = pool_last_ref = 0; this->internal_data.pool_size = 0; } } - void clear_pool() + void priv_clear_pool() { - this->clear_pool(alloc_version()); + this->priv_clear_pool(alloc_version()); } - void add_to_pool(size_type n) + void priv_add_to_pool(size_type n) { - this->add_to_pool(n, alloc_version()); + this->priv_add_to_pool(n, alloc_version()); } template - void add_to_pool(size_type n, AllocatorVersion, + void priv_add_to_pool(size_type n, AllocatorVersion, typename boost::container::container_detail::enable_if_c ::value>::type * = 0) @@ -1359,7 +1431,7 @@ class stable_vector } template - void add_to_pool(size_type n, AllocatorVersion, + void priv_add_to_pool(size_type n, AllocatorVersion, typename boost::container::container_detail::enable_if_c ::value>::type * = 0) @@ -1369,7 +1441,7 @@ class stable_vector multiallocation_chain holder; holder.incorporate_after(holder.before_begin(), pool_first_ref, pool_last_ref, internal_data.pool_size); //BOOST_STATIC_ASSERT((::boost::has_move_emulation_enabled::value == true)); - multiallocation_chain m (node_alloc().allocate_individual(n)); + multiallocation_chain m (this->priv_node_alloc().allocate_individual(n)); holder.splice_after(holder.before_begin(), m, m.before_begin(), m.last(), n); this->internal_data.pool_size += n; std::pair data(holder.extract_data()); @@ -1390,7 +1462,7 @@ class stable_vector pool_last_ref = ret.second; } - node_type_ptr_t get_from_pool() + node_type_ptr_t priv_get_from_pool() { if(!impl.back()){ return node_type_ptr_t(0); @@ -1429,43 +1501,6 @@ class stable_vector } } - template - void assign_dispatch(InputIterator first, InputIterator last, boost::mpl::false_) - { - STABLE_VECTOR_CHECK_INVARIANT; - iterator first1 = this->begin(); - iterator last1 = this->end(); - for ( ; first1 != last1 && first != last; ++first1, ++first) - *first1 = *first; - if (first == last){ - this->erase(first1, last1); - } - else{ - this->insert(last1, first, last); - } - } - - template - void assign_dispatch(Integer n, Integer t, boost::mpl::true_) - { - typedef constant_iterator cvalue_iterator; - this->assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_()); - } - - iterator priv_erase(const_iterator first, const_iterator last, allocator_v1) - { - STABLE_VECTOR_CHECK_INVARIANT; - difference_type d1 = first - this->cbegin(), d2 = last - this->cbegin(); - if(d1 != d2){ - impl_iterator it1(impl.begin() + d1), it2(impl.begin() + d2); - for(impl_iterator it = it1; it != it2; ++it) - this->delete_node(*it); - impl_iterator e = impl.erase(it1, it2); - this->align_nodes(e, get_last_align()); - } - return iterator(this->begin() + d1); - } - impl_iterator get_last_align() { return impl.end() - (ExtraPointers - 1); @@ -1476,16 +1511,6 @@ class stable_vector return impl.cend() - (ExtraPointers - 1); } - template - iterator priv_erase(const_iterator first, const_iterator last, AllocatorVersion, - typename boost::container::container_detail::enable_if_c - - ::value>::type * = 0) - { - STABLE_VECTOR_CHECK_INVARIANT; - return priv_erase(first, last, allocator_v1()); - } - static node_type_ptr_t node_ptr_cast(const void_ptr &p) { return node_type_ptr_t(static_cast(container_detail::to_raw_pointer(p))); @@ -1535,7 +1560,7 @@ class stable_vector { node_type_ptr_t p = this->allocate_one(); try{ - boost::container::construct_in_place(this->node_alloc(), container_detail::addressof(p->value), it); + boost::container::construct_in_place(this->priv_node_alloc(), container_detail::addressof(p->value), it); //This does not throw ::new(static_cast(container_detail::to_raw_pointer(p))) node_type_base_t; p->set_pointer(up); @@ -1551,7 +1576,7 @@ class stable_vector { node_type_ptr_t n(node_ptr_cast(p)); allocator_traits:: - destroy(this->node_alloc(), container_detail::to_raw_pointer(n)); + destroy(this->priv_node_alloc(), container_detail::to_raw_pointer(n)); this->put_in_pool(n); } @@ -1563,44 +1588,8 @@ class stable_vector } } - void insert_not_iter(const_iterator position, size_type n, const T& t) - { - typedef constant_iterator cvalue_iterator; - this->insert_iter(position, cvalue_iterator(t, n), cvalue_iterator(), std::forward_iterator_tag()); - } - - template - void insert_iter(const_iterator position,InputIterator first,InputIterator last, boost::mpl::true_) - { - typedef typename std::iterator_traits::iterator_category category; - this->insert_iter(position, first, last, category()); - } - - template - void insert_iter(const_iterator position,InputIterator first,InputIterator last,std::input_iterator_tag) - { - for(; first!=last; ++first){ - this->insert(position, *first); - } - } - - template - iterator insert_iter(const_iterator position, InputIterator first, InputIterator last, std::forward_iterator_tag) - { - size_type n = (size_type)std::distance(first,last); - difference_type d = position-this->cbegin(); - if(n){ - this->insert_iter_prolog(n, d); - const impl_iterator it(impl.begin() + d); - this->insert_iter_fwd(it, first, last, n); - //Fix the pointers for the newly allocated buffer - this->align_nodes(it + n, get_last_align()); - } - return this->begin() + d; - } - template - void insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v1) + void priv_insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v1) { size_type i=0; try{ @@ -1618,9 +1607,9 @@ class stable_vector } template - void insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v2) + void priv_insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v2) { - multiallocation_chain mem(node_alloc().allocate_individual(n)); + multiallocation_chain mem(this->priv_node_alloc().allocate_individual(n)); size_type i = 0; node_type_ptr_t p = 0; @@ -1629,7 +1618,7 @@ class stable_vector p = mem.front(); mem.pop_front(); //This can throw - boost::container::construct_in_place(this->node_alloc(), container_detail::addressof(p->value), first); + boost::container::construct_in_place(this->priv_node_alloc(), container_detail::addressof(p->value), first); //This does not throw ::new(static_cast(container_detail::to_raw_pointer(p))) node_type_base_t; p->set_pointer(void_ptr_ptr(&it[i])); @@ -1639,8 +1628,8 @@ class stable_vector } } catch(...){ - node_alloc().deallocate_one(p); - node_alloc().deallocate_many(boost::move(mem)); + this->priv_node_alloc().deallocate_one(p); + this->priv_node_alloc().deallocate_many(boost::move(mem)); impl_iterator e = impl.erase(it+i, it+n); this->align_nodes(e, get_last_align()); throw; @@ -1648,19 +1637,19 @@ class stable_vector } template - void insert_iter_fwd(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n) + void priv_insert_iter_fwd(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n) { size_type i = 0; node_type_ptr_t p = 0; try{ while(first != last){ - p = this->get_from_pool(); + p = this->priv_get_from_pool(); if(!p){ - insert_iter_fwd_alloc(it+i, first, last, n-i, alloc_version()); + this->priv_insert_iter_fwd_alloc(it+i, first, last, n-i, alloc_version()); break; } //This can throw - boost::container::construct_in_place(this->node_alloc(), container_detail::addressof(p->value), first); + boost::container::construct_in_place(this->priv_node_alloc(), container_detail::addressof(p->value), first); //This does not throw ::new(static_cast(container_detail::to_raw_pointer(p))) node_type_base_t; p->set_pointer(void_ptr_ptr(&it[i])); @@ -1677,14 +1666,15 @@ class stable_vector } } - template - void insert_iter(const_iterator position, InputIterator first, InputIterator last, boost::mpl::false_) + void priv_swap_members(stable_vector &x) { - this->insert_not_iter(position, first, last); + container_detail::do_swap(this->internal_data.pool_size, x.internal_data.pool_size); + this->readjust_end_node(); + x.readjust_end_node(); } #if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) - bool invariant()const + bool priv_invariant()const { if(impl.empty()) return !capacity() && !size(); @@ -1715,7 +1705,7 @@ class stable_vector public: invariant_checker(const stable_vector& v):p(&v){} - ~invariant_checker(){BOOST_ASSERT(p->invariant());} + ~invariant_checker(){BOOST_ASSERT(p->priv_invariant());} void touch(){} }; #endif @@ -1725,14 +1715,8 @@ class stable_vector { private: BOOST_MOVABLE_BUT_NOT_COPYABLE(ebo_holder) + public: -/* - explicit ebo_holder(BOOST_RV_REF(ebo_holder) x) - : node_allocator_type(boost::move(static_cast(x))) - , pool_size(0) - , end_node() - {} -*/ template explicit ebo_holder(BOOST_FWD_REF(AllocatorRLValue) a) : node_allocator_type(boost::forward(a)) @@ -1759,15 +1743,8 @@ class stable_vector node_type_base_t end_node; } internal_data; - void priv_swap_members(stable_vector &x) - { - container_detail::do_swap(this->internal_data.pool_size, x.internal_data.pool_size); - this->readjust_end_node(); - x.readjust_end_node(); - } - - node_allocator_type &node_alloc() { return internal_data; } - const node_allocator_type &node_alloc() const { return internal_data; } + node_allocator_type &priv_node_alloc() { return internal_data; } + const node_allocator_type &priv_node_alloc() const { return internal_data; } impl_type impl; /// @endcond diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index 49f2974..ff1f8fd 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -68,13 +68,8 @@ #include #include -#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED namespace boost { namespace container { -#else -namespace boost { -namespace container { -#endif /// @cond namespace container_detail { @@ -624,7 +619,10 @@ class basic_string //! Throws: If allocator_type's default constructor throws. basic_string(const basic_string& s) : base_t(allocator_traits_type::select_on_container_copy_construction(s.alloc())) - { this->priv_range_initialize(s.begin(), s.end()); } + { + this->priv_terminate_string(); + this->assign(s.begin(), s.end()); + } //! Effects: Move constructor. Moves s's resources to *this. //! @@ -642,7 +640,10 @@ class basic_string //! Throws: If allocation throws. basic_string(const basic_string& s, const allocator_type &a) : base_t(a) - { this->priv_range_initialize(s.begin(), s.end()); } + { + this->priv_terminate_string(); + this->assign(s.begin(), s.end()); + } //! Effects: Move constructor using the specified allocator. //! Moves s's resources to *this. @@ -653,11 +654,12 @@ class basic_string basic_string(BOOST_RV_REF(basic_string) s, const allocator_type &a) : base_t(a) { + this->priv_terminate_string(); if(a == this->alloc()){ this->swap_data(s); } else{ - this->priv_range_initialize(s.begin(), s.end()); + this->assign(s.begin(), s.end()); } } @@ -667,10 +669,11 @@ class basic_string const allocator_type& a = allocator_type()) : base_t(a) { + this->priv_terminate_string(); if (pos > s.size()) this->throw_out_of_range(); else - this->priv_range_initialize + this->assign (s.begin() + pos, s.begin() + pos + container_detail::min_value(n, s.size() - pos)); } @@ -679,23 +682,29 @@ class basic_string basic_string(const CharT* s, size_type n, const allocator_type& a = allocator_type()) : base_t(a) - { this->priv_range_initialize(s, s + n); } + { + this->priv_terminate_string(); + this->assign(s, s + n); + } //! Effects: Constructs a basic_string taking the allocator as parameter, //! and is initialized by the null-terminated s c-string. basic_string(const CharT* s, const allocator_type& a = allocator_type()) : base_t(a) - { this->priv_range_initialize(s, s + Traits::length(s)); } + { + this->priv_terminate_string(); + this->assign(s, s + Traits::length(s)); + } //! Effects: Constructs a basic_string taking the allocator as parameter, //! and is initialized by n copies of c. basic_string(size_type n, CharT c, const allocator_type& a = allocator_type()) : base_t(a) - { - this->priv_range_initialize(cvalue_iterator(c, n), - cvalue_iterator()); + { + this->priv_terminate_string(); + this->assign(n, c); } //! Effects: Constructs a basic_string taking the allocator as parameter, @@ -705,10 +714,8 @@ class basic_string const allocator_type& a = allocator_type()) : base_t(a) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_initialize_dispatch(f, l, Result()); + this->priv_terminate_string(); + this->assign(f, l); } //! Effects: Destroys the basic_string. All used memory is deallocated. @@ -1213,8 +1220,8 @@ class basic_string //! Throws: If memory allocation throws or out_of_range if pos > str.size(). //! //! Returns: *this - basic_string& assign(const basic_string& s, - size_type pos, size_type n) { + basic_string& assign(const basic_string& s, size_type pos, size_type n) + { if (pos > s.size()) this->throw_out_of_range(); return this->assign(s.begin() + pos, @@ -1250,12 +1257,28 @@ class basic_string //! //! Returns: *this template - basic_string& assign(InputIter first, InputIter last) + basic_string& assign(InputIter first, InputIter last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + >::type * = 0 + #endif + ) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - return this->priv_assign_dispatch(first, last, Result()); + size_type cur = 0; + CharT *ptr = container_detail::to_raw_pointer(this->priv_addr()); + const size_type old_size = this->priv_size(); + while (first != last && cur != old_size) { + Traits::assign(*ptr, *first); + ++first; + ++cur; + ++ptr; + } + if (first == last) + this->erase(this->priv_addr() + cur, this->priv_addr() + old_size); + else + this->append(first, last); + return *this; } //! Requires: pos <= size(). @@ -1283,8 +1306,7 @@ class basic_string //! Throws: If memory allocation throws or out_of_range if pos1 > size() or pos2 > str.size(). //! //! Returns: *this - basic_string& insert(size_type pos1, const basic_string& s, - size_type pos2, size_type n) + basic_string& insert(size_type pos1, const basic_string& s, size_type pos2, size_type n) { if (pos1 > this->size() || pos2 > s.size()) this->throw_out_of_range(); @@ -1369,23 +1391,144 @@ class basic_string //! Requires: p is a valid iterator on *this. //! //! Effects: Inserts n copies of c before the character referred to by p. - void insert(const_iterator p, size_type n, CharT c) - { - this->insert(p, cvalue_iterator(c, n), cvalue_iterator()); - } + //! + //! Returns: an iterator to the first inserted element or p if n is 0. + iterator insert(const_iterator p, size_type n, CharT c) + { return this->insert(p, cvalue_iterator(c, n), cvalue_iterator()); } //! Requires: p is a valid iterator on *this. [first,last) is a valid range. //! //! Effects: Equivalent to insert(p - begin(), basic_string(first, last)). + //! + //! Returns: an iterator to the first inserted element or p if first == last. template - void insert(const_iterator p, InputIter first, InputIter last) + iterator insert(const_iterator p, InputIter first, InputIter last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_insert_dispatch(p, first, last, Result()); + const size_type n_pos = p - this->cbegin(); + for ( ; first != last; ++first, ++p) { + p = this->insert(p, *first); + } + return this->begin() + n_pos; } + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator insert(const_iterator p, ForwardIter first, ForwardIter last + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !container_detail::is_input_iterator::value + >::type * = 0 + ) + { + const size_type n_pos = p - this->cbegin(); + if (first != last) { + const size_type n = std::distance(first, last); + const size_type old_size = this->priv_size(); + const size_type remaining = this->capacity() - old_size; + const pointer old_start = this->priv_addr(); + bool enough_capacity = false; + std::pair allocation_ret; + size_type new_cap = 0; + + //Check if we have enough capacity + if (remaining >= n){ + enough_capacity = true; + } + else { + //Otherwise expand current buffer or allocate new storage + new_cap = this->next_capacity(n); + allocation_ret = this->allocation_command + (allocate_new | expand_fwd | expand_bwd, old_size + n + 1, + new_cap, new_cap, old_start); + + //Check forward expansion + if(old_start == allocation_ret.first){ + enough_capacity = true; + this->priv_storage(new_cap); + } + } + + //Reuse same buffer + if(enough_capacity){ + const size_type elems_after = old_size - (p - this->priv_addr()); + const size_type old_length = old_size; + if (elems_after >= n) { + const pointer pointer_past_last = this->priv_addr() + old_size + 1; + priv_uninitialized_copy(this->priv_addr() + (old_size - n + 1), + pointer_past_last, pointer_past_last); + + this->priv_size(old_size+n); + Traits::move(const_cast(container_detail::to_raw_pointer(p + n)), + container_detail::to_raw_pointer(p), + (elems_after - n) + 1); + this->priv_copy(first, last, const_cast(container_detail::to_raw_pointer(p))); + } + else { + ForwardIter mid = first; + std::advance(mid, elems_after + 1); + + priv_uninitialized_copy(mid, last, this->priv_addr() + old_size + 1); + this->priv_size(old_size + (n - elems_after)); + priv_uninitialized_copy + (p, const_iterator(this->priv_addr() + old_length + 1), + this->priv_addr() + this->priv_size()); + this->priv_size(this->priv_size() + elems_after); + this->priv_copy(first, mid, const_cast(container_detail::to_raw_pointer(p))); + } + } + else{ + pointer new_start = allocation_ret.first; + if(!allocation_ret.second){ + //Copy data to new buffer + size_type new_length = 0; + //This can't throw, since characters are POD + new_length += priv_uninitialized_copy + (const_iterator(this->priv_addr()), p, new_start); + new_length += priv_uninitialized_copy + (first, last, new_start + new_length); + new_length += priv_uninitialized_copy + (p, const_iterator(this->priv_addr() + old_size), + new_start + new_length); + this->priv_construct_null(new_start + new_length); + + this->deallocate_block(); + this->is_short(false); + this->priv_long_addr(new_start); + this->priv_long_size(new_length); + this->priv_long_storage(new_cap); + } + else{ + //value_type is POD, so backwards expansion is much easier + //than with vector + value_type * const oldbuf = container_detail::to_raw_pointer(old_start); + value_type * const newbuf = container_detail::to_raw_pointer(new_start); + const value_type *const pos = container_detail::to_raw_pointer(p); + const size_type before = pos - oldbuf; + + //First move old data + Traits::move(newbuf, oldbuf, before); + Traits::move(newbuf + before + n, pos, old_size - before); + //Now initialize the new data + priv_uninitialized_copy(first, last, new_start + before); + this->priv_construct_null(new_start + (old_size + n)); + this->is_short(false); + this->priv_long_addr(new_start); + this->priv_long_size(old_size + n); + this->priv_long_storage(new_cap); + } + } + } + return this->begin() + n_pos; + } + #endif + //! Requires: pos <= size() //! //! Effects: Determines the effective length xlen of the string to be removed as the smaller of n and size() - pos. @@ -1472,8 +1615,9 @@ class basic_string const size_type len = container_detail::min_value(n1, size() - pos1); if (this->size() - len >= this->max_size() - str.size()) this->throw_length_error(); - return this->replace(this->priv_addr() + pos1, this->priv_addr() + pos1 + len, - str.begin(), str.end()); + return this->replace( const_iterator(this->priv_addr() + pos1) + , const_iterator(this->priv_addr() + pos1 + len) + , str.begin(), str.end()); } //! Requires: pos1 <= size() and pos2 <= str.size(). @@ -1512,16 +1656,14 @@ class basic_string //! if the length of the resulting string would exceed max_size() //! //! Returns: *this - basic_string& replace(size_type pos1, size_type n1, - const CharT* s, size_type n2) + basic_string& replace(size_type pos1, size_type n1, const CharT* s, size_type n2) { if (pos1 > size()) this->throw_out_of_range(); const size_type len = container_detail::min_value(n1, size() - pos1); if (n2 > this->max_size() || size() - len >= this->max_size() - n2) this->throw_length_error(); - return this->replace(this->priv_addr() + pos1, this->priv_addr() + pos1 + len, - s, s + n2); + return this->replace(this->priv_addr() + pos1, this->priv_addr() + pos1 + len, s, s + n2); } //! Requires: pos1 <= size() and s points to an array of at least n2 elements of CharT. @@ -1629,14 +1771,51 @@ class basic_string //! //! Returns: *this template - basic_string& replace(const_iterator i1, const_iterator i2, InputIter j1, InputIter j2) + basic_string& replace(const_iterator i1, const_iterator i2, InputIter j1, InputIter j2 + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - return this->priv_replace_dispatch(i1, i2, j1, j2, Result()); + for ( ; i1 != i2 && j1 != j2; ++i1, ++j1){ + Traits::assign(*const_cast(container_detail::to_raw_pointer(i1)), *j1); + } + + if (j1 == j2) + this->erase(i1, i2); + else + this->insert(i2, j1, j2); + return *this; } + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + basic_string& replace(const_iterator i1, const_iterator i2, ForwardIter j1, ForwardIter j2 + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !container_detail::is_input_iterator::value + >::type * = 0 + ) + { + difference_type n = std::distance(j1, j2); + const difference_type len = i2 - i1; + if (len >= n) { + this->priv_copy(j1, j2, const_cast(container_detail::to_raw_pointer(i1))); + this->erase(i1 + n, i2); + } + else { + ForwardIter m = j1; + std::advance(m, len); + this->priv_copy(j1, m, const_cast(container_detail::to_raw_pointer(i1))); + this->insert(i2, m, j2); + } + return *this; + } + #endif + //! Requires: pos <= size() //! //! Effects: Determines the effective length rlen of the string to copy as the @@ -2153,46 +2332,6 @@ class basic_string void priv_terminate_string() { this->priv_construct_null(this->priv_addr() + this->priv_size()); } - template - void priv_range_initialize(InputIter f, InputIter l, - std::input_iterator_tag) - { - this->allocate_initial_block(InternalBufferChars); - this->priv_construct_null(this->priv_addr() + this->priv_size()); - this->append(f, l); - } - - template - void priv_range_initialize(ForwardIter f, ForwardIter l, - std::forward_iterator_tag) - { - difference_type n = std::distance(f, l); - this->allocate_initial_block(container_detail::max_value(n+1, InternalBufferChars)); - priv_uninitialized_copy(f, l, this->priv_addr()); - this->priv_size(n); - this->priv_terminate_string(); - } - - template - void priv_range_initialize(InputIter f, InputIter l) - { - typedef typename std::iterator_traits::iterator_category Category; - this->priv_range_initialize(f, l, Category()); - } - - template - void priv_initialize_dispatch(Integer n, Integer x, container_detail::true_) - { - this->allocate_initial_block(container_detail::max_value(n+1, InternalBufferChars)); - priv_uninitialized_fill_n(this->priv_addr(), n, x); - this->priv_size(n); - this->priv_terminate_string(); - } - - template - void priv_initialize_dispatch(InputIter f, InputIter l, container_detail::false_) - { this->priv_range_initialize(f, l); } - template inline void priv_uninitialized_fill_n(FwdIt first, Count count, const CharT val) { @@ -2238,14 +2377,9 @@ class basic_string BOOST_CATCH_END return (constructed); } - - template - basic_string& priv_assign_dispatch(Integer n, Integer x, container_detail::true_) - { return this->assign((size_type) n, (CharT) x); } - +/* template - basic_string& priv_assign_dispatch(InputIter f, InputIter l, - container_detail::false_) + basic_string& priv_assign_dispatch(InputIter f, InputIter l, container_detail::false_) { size_type cur = 0; CharT *ptr = container_detail::to_raw_pointer(this->priv_addr()); @@ -2262,131 +2396,7 @@ class basic_string this->append(f, l); return *this; } - - template - void priv_insert(const_iterator p, InputIter first, InputIter last, std::input_iterator_tag) - { - for ( ; first != last; ++first, ++p) { - p = this->insert(p, *first); - } - } - - template - void priv_insert(const_iterator position, ForwardIter first, - ForwardIter last, std::forward_iterator_tag) - { - if (first != last) { - const size_type n = std::distance(first, last); - const size_type old_size = this->priv_size(); - const size_type remaining = this->capacity() - old_size; - const pointer old_start = this->priv_addr(); - bool enough_capacity = false; - std::pair allocation_ret; - size_type new_cap = 0; - - //Check if we have enough capacity - if (remaining >= n){ - enough_capacity = true; - } - else { - //Otherwise expand current buffer or allocate new storage - new_cap = this->next_capacity(n); - allocation_ret = this->allocation_command - (allocate_new | expand_fwd | expand_bwd, old_size + n + 1, - new_cap, new_cap, old_start); - - //Check forward expansion - if(old_start == allocation_ret.first){ - enough_capacity = true; - this->priv_storage(new_cap); - } - } - - //Reuse same buffer - if(enough_capacity){ - const size_type elems_after = old_size - (position - this->priv_addr()); - const size_type old_length = old_size; - if (elems_after >= n) { - const pointer pointer_past_last = this->priv_addr() + old_size + 1; - priv_uninitialized_copy(this->priv_addr() + (old_size - n + 1), - pointer_past_last, pointer_past_last); - - this->priv_size(old_size+n); - Traits::move(const_cast(container_detail::to_raw_pointer(position + n)), - container_detail::to_raw_pointer(position), - (elems_after - n) + 1); - this->priv_copy(first, last, const_cast(container_detail::to_raw_pointer(position))); - } - else { - ForwardIter mid = first; - std::advance(mid, elems_after + 1); - - priv_uninitialized_copy(mid, last, this->priv_addr() + old_size + 1); - this->priv_size(old_size + (n - elems_after)); - priv_uninitialized_copy - (position, const_iterator(this->priv_addr() + old_length + 1), - this->priv_addr() + this->priv_size()); - this->priv_size(this->priv_size() + elems_after); - this->priv_copy(first, mid, const_cast(container_detail::to_raw_pointer(position))); - } - } - else{ - pointer new_start = allocation_ret.first; - if(!allocation_ret.second){ - //Copy data to new buffer - size_type new_length = 0; - //This can't throw, since characters are POD - new_length += priv_uninitialized_copy - (const_iterator(this->priv_addr()), position, new_start); - new_length += priv_uninitialized_copy - (first, last, new_start + new_length); - new_length += priv_uninitialized_copy - (position, const_iterator(this->priv_addr() + old_size), - new_start + new_length); - this->priv_construct_null(new_start + new_length); - - this->deallocate_block(); - this->is_short(false); - this->priv_long_addr(new_start); - this->priv_long_size(new_length); - this->priv_long_storage(new_cap); - } - else{ - //value_type is POD, so backwards expansion is much easier - //than with vector - value_type * const oldbuf = container_detail::to_raw_pointer(old_start); - value_type * const newbuf = container_detail::to_raw_pointer(new_start); - const value_type *const pos = container_detail::to_raw_pointer(position); - const size_type before = pos - oldbuf; - - //First move old data - Traits::move(newbuf, oldbuf, before); - Traits::move(newbuf + before + n, pos, old_size - before); - //Now initialize the new data - priv_uninitialized_copy(first, last, new_start + before); - this->priv_construct_null(new_start + (old_size + n)); - this->is_short(false); - this->priv_long_addr(new_start); - this->priv_long_size(old_size + n); - this->priv_long_storage(new_cap); - } - } - } - } - - template - void priv_insert_dispatch(const_iterator p, Integer n, Integer x, - container_detail::true_) - { insert(p, (size_type) n, (CharT) x); } - - template - void priv_insert_dispatch(const_iterator p, InputIter first, InputIter last, - container_detail::false_) - { - typedef typename std::iterator_traits::iterator_category Category; - priv_insert(p, first, last, Category()); - } - +*/ template void priv_copy(InputIterator first, InputIterator last, OutIterator result) { @@ -2412,40 +2422,6 @@ class basic_string return this->priv_replace(first, last, f, l, Category()); } - - template - basic_string& priv_replace(const_iterator first, const_iterator last, - InputIter f, InputIter l, std::input_iterator_tag) - { - for ( ; first != last && f != l; ++first, ++f) - Traits::assign(*first, *f); - - if (f == l) - this->erase(first, last); - else - this->insert(last, f, l); - return *this; - } - - template - basic_string& priv_replace(const_iterator first, const_iterator last, - ForwardIter f, ForwardIter l, - std::forward_iterator_tag) - { - difference_type n = std::distance(f, l); - const difference_type len = last - first; - if (len >= n) { - this->priv_copy(f, l, const_cast(container_detail::to_raw_pointer(first))); - this->erase(first + n, last); - } - else { - ForwardIter m = f; - std::advance(m, len); - this->priv_copy(f, m, const_cast(container_detail::to_raw_pointer(first))); - this->insert(last, m, l); - } - return *this; - } /// @endcond }; diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index f24699e..1180d96 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -489,8 +489,10 @@ class vector : private container_detail::vector_alloc_holder explicit vector(size_type n) : base_t() { + this->resize(n); +/* //Allocate - size_type real_cap; + 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); @@ -503,7 +505,7 @@ class vector : private container_detail::vector_alloc_holder this->members_.m_start = ret.first; this->members_.m_size = n; this->members_.m_capacity = real_cap; - scoped_alloc.release(); + scoped_alloc.release();*/ } //! Effects: Constructs a vector that will use a copy of allocator a @@ -515,7 +517,10 @@ class vector : private container_detail::vector_alloc_holder //! Complexity: Linear to n. vector(size_type n, const T& value, const allocator_type& a = allocator_type()) : base_t(a) - { this->insert(this->cend(), n, value); } + { + this->resize(n, value); +// this->insert(this->cend(), n, value); + } //! Effects: Copy constructs a vector. //! @@ -571,7 +576,7 @@ class vector : private container_detail::vector_alloc_holder } else{ this->assign( container_detail::to_raw_pointer(mx.members_.m_start) - , container_detail::to_raw_pointer(mx.members_.m_start + mx.members_.m_size)); + , container_detail::to_raw_pointer(mx.members_.m_start) + mx.members_.m_size); } } @@ -1002,14 +1007,155 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Linear to n. template - void assign(InIt first, InIt last) + void assign(InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); + //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. //! @@ -1051,7 +1197,7 @@ class vector : private container_detail::vector_alloc_holder else{ typedef container_detail::advanced_insert_aux_emplace type; type &&proxy = type(this->alloc(), ::boost::forward(args)...); - priv_range_insert(back_pos, 1, proxy); + this->priv_forward_range_insert(back_pos, 1, proxy); } } @@ -1072,7 +1218,7 @@ class vector : private container_detail::vector_alloc_holder size_type pos_n = position - cbegin(); typedef container_detail::advanced_insert_aux_emplace type; type &&proxy = type(this->alloc(), ::boost::forward(args)...); - priv_range_insert(position.get_ptr(), 1, proxy); + this->priv_forward_range_insert(position.get_ptr(), 1, proxy); return iterator(this->members_.m_start + pos_n); } @@ -1093,7 +1239,7 @@ class vector : private container_detail::vector_alloc_holder container_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ proxy \ (this->alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ - priv_range_insert(back_pos, 1, proxy); \ + this->priv_forward_range_insert(back_pos, 1, proxy); \ } \ } \ \ @@ -1105,7 +1251,7 @@ class vector : private container_detail::vector_alloc_holder container_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ proxy \ (this->alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ - priv_range_insert(container_detail::to_raw_pointer(pos.get_ptr()), 1, proxy); \ + this->priv_forward_range_insert(container_detail::to_raw_pointer(pos.get_ptr()), 1,proxy);\ return iterator(this->members_.m_start + pos_n); \ } \ //! @@ -1152,32 +1298,63 @@ class vector : private container_detail::vector_alloc_holder BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator) #endif - //! Requires: pos must be a valid iterator of *this. + //! Requires: p must be a valid iterator of *this. //! //! Effects: Insert a copy of the [first, last) range before pos. //! + //! Returns: an iterator to the first inserted element or pos if first == last. + //! //! Throws: If memory allocation throws, T's constructor from a //! dereferenced InpIt throws or T's copy/move constructor/assignment throws. //! //! Complexity: Linear to std::distance [first, last). template - void insert(const_iterator pos, InIt first, InIt last) + iterator insert(const_iterator pos, InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && container_detail::is_input_iterator::value + >::type * = 0 + #endif + ) { - //Dispatch depending on integer/iterator - const bool aux_boolean = container_detail::is_convertible::value; - typedef container_detail::bool_ Result; - this->priv_insert_dispatch(pos, first, last, Result()); + const size_type n_pos = pos - this->cbegin(); + iterator it(pos.get_ptr()); + for(;first != last; ++first){ + it = this->emplace(it, *first); + ++it; + } + return this->begin() + n_pos; } - //! Requires: pos must be a valid iterator of *this. + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator insert(const_iterator pos, FwdIt first, FwdIt last + , typename container_detail::enable_if_c + < !container_detail::is_convertible::value + && !container_detail::is_input_iterator::value + >::type * = 0 + ) + { + const size_type n_pos = pos - this->cbegin(); + const size_type n = std::distance(first, last); + container_detail::advanced_insert_aux_proxy proxy(this->alloc(), first, last); + this->priv_forward_range_insert(pos.get_ptr(), n, proxy); + return this->begin() + n_pos; + } + #endif + + //! 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. - void insert(const_iterator p, size_type n, const T& x) - { this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); } + 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. //! @@ -1262,10 +1439,10 @@ class vector : private container_detail::vector_alloc_holder this->erase(const_iterator(this->members_.m_start + new_size), this->end()); } else{ - size_type n = new_size - this->size(); + const size_type n = new_size - this->size(); this->reserve(new_size); container_detail::default_construct_aux_proxy proxy(this->alloc(), n); - priv_range_insert(this->cend().get_ptr(), n, proxy); + this->priv_forward_range_insert(this->cend().get_ptr(), n, proxy); } } @@ -1399,27 +1576,7 @@ class vector : private container_detail::vector_alloc_holder } } - template - void priv_range_insert(const_iterator pos, FwdIt first, FwdIt last, std::forward_iterator_tag) - { - if(first != last){ - const size_type n = std::distance(first, last); - container_detail::advanced_insert_aux_proxy proxy(this->alloc(), first, last); - priv_range_insert(pos.get_ptr(), n, proxy); - } - } - - template - void priv_range_insert(const_iterator pos, InIt first, InIt last, std::input_iterator_tag) - { - iterator it(pos.get_ptr()); - for(;first != last; ++first){ - it = this->emplace(it, *first); - ++it; - } - } - - void priv_range_insert(pointer pos, const size_type n, advanced_insert_aux_int_t &interf) + void priv_forward_range_insert(pointer pos, const size_type n, advanced_insert_aux_int_t &interf) { //Check if we have enough memory or try to expand current memory size_type remaining = this->members_.m_capacity - this->members_.m_size; @@ -1575,7 +1732,7 @@ class vector : private container_detail::vector_alloc_holder // |_>_>_>_>_>^ // // - //New situation in Case B (hole_size >= 0): + //New situation in Case B (hole_size > 0): // range is moved through uninitialized moves // // first_pos last_pos old_limit @@ -2001,173 +2158,10 @@ class vector : private container_detail::vector_alloc_holder } } - template - void priv_assign_aux(InIt first, InIt last, std::input_iterator_tag) - { - //Overwrite all elements we can from [first, last) - iterator cur = begin(); - for ( ; first != last && cur != end(); ++cur, ++first){ - *cur = *first; - } - - if (first == last){ - //There are no more elements in the sequence, erase remaining - this->erase(cur, cend()); - } - else{ - //There are more elements in the range, insert the remaining ones - this->insert(this->cend(), first, last); - } - } - - template - void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag) - { - size_type n = std::distance(first, last); - if(!n){ - this->prot_destroy_all(); - return; - } - //Check if we have enough memory or try to expand current memory - size_type remaining = this->members_.m_capacity - this->members_.m_size; - bool same_buffer_start; - std::pair ret; - size_type real_cap = this->members_.m_capacity; - - if (n <= remaining){ - same_buffer_start = true; - } - else{ - //There is not enough memory, allocate a new buffer - size_type new_cap = this->next_capacity(n); - ret = this->allocation_command - (allocate_new | expand_fwd | expand_bwd, - this->size() + n, new_cap, real_cap, this->members_.m_start); - same_buffer_start = ret.second && this->members_.m_start == ret.first; - if(same_buffer_start){ - this->members_.m_capacity = real_cap; - } - } - - if(same_buffer_start){ - T *start = container_detail::to_raw_pointer(this->members_.m_start); - if (this->size() >= n){ - //There is memory, but there are more old elements than new ones - //Overwrite old elements with new ones - std::copy(first, last, start); - //Destroy remaining old elements - this->destroy_n(start + n, this->members_.m_size - n); - this->members_.m_size = n; - } - else{ - //There is memory, but there are less old elements than new ones - //First overwrite some old elements with new ones - FwdIt mid = first; - std::advance(mid, this->size()); - // iG T *end = std::copy(first, mid, start); - T *end = std::copy(first, mid, start); - //Initialize the remaining new elements in the uninitialized memory - ::boost::container::uninitialized_copy_or_move_alloc(this->alloc(), mid, last, end); - this->members_.m_size = n; - } - } - else if(!ret.second){ - typename value_traits::ArrayDeallocator scoped_alloc(ret.first, this->alloc(), real_cap); - ::boost::container::uninitialized_copy_or_move_alloc(this->alloc(), first, last, container_detail::to_raw_pointer(ret.first)); - scoped_alloc.release(); - //Destroy and deallocate old buffer - if(this->members_.m_start != 0){ - this->destroy_n(container_detail::to_raw_pointer(this->members_.m_start), this->members_.m_size); - this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); - } - this->members_.m_start = ret.first; - this->members_.m_size = n; - this->members_.m_capacity = real_cap; - } - else{ - //Backwards expansion - //If anything goes wrong, this object will destroy old objects - T *old_start = container_detail::to_raw_pointer(this->members_.m_start); - size_type old_size = this->members_.m_size; - typename value_traits::OldArrayDestructor old_values_destroyer(old_start, this->alloc(), old_size); - //If something goes wrong size will be 0 - //but holding the whole buffer - this->members_.m_size = 0; - this->members_.m_start = ret.first; - this->members_.m_capacity = real_cap; - - //Backup old buffer data - size_type old_offset = old_start - container_detail::to_raw_pointer(ret.first); - size_type first_count = container_detail::min_value(n, old_offset); - - FwdIt mid = first; - std::advance(mid, first_count); - ::boost::container::uninitialized_copy_or_move_alloc - (this->alloc(), first, mid, container_detail::to_raw_pointer(ret.first)); - - if(old_offset > n){ - //All old elements will be destroyed by "old_values_destroyer" - this->members_.m_size = n; - } - else{ - //We have constructed objects from the new begin until - //the old end so release the rollback destruction - old_values_destroyer.release(); - this->members_.m_start = ret.first; - this->members_.m_size = first_count + old_size; - //Now overwrite the old values - size_type second_count = container_detail::min_value(old_size, n - first_count); - FwdIt mid2 = mid; - std::advance(mid2, second_count); - // iG std::copy(mid, mid2, old_start); - std::copy(mid, mid2, old_start); - - //Check if we still have to append elements in the - //uninitialized end - if(second_count == old_size){ - // iG std::copy(mid2, last, old_start + old_size); - std::copy(mid2, last, old_start + old_size); - } - else{ - //We have to destroy some old values - this->destroy_n - (old_start + second_count, old_size - second_count); - this->members_.m_size = n; - } - this->members_.m_size = n; - } - } - } - - template - void priv_assign_dispatch(Integer n, Integer val, container_detail::true_) - { this->assign((size_type) n, (value_type)val); } - - template - void priv_assign_dispatch(InIt first, InIt last, container_detail::false_) - { - //Dispatch depending on integer/iterator - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_assign_aux(first, last, ItCat()); - } - - template - void priv_insert_dispatch(const_iterator pos, Integer n, Integer val, container_detail::true_) - { this->insert(pos, (size_type)n, (T)val); } - - template - void priv_insert_dispatch(const_iterator pos, InIt first, - InIt last, container_detail::false_) - { - //Dispatch depending on integer/iterator - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_range_insert(pos, first, last, ItCat()); - } - void priv_check_range(size_type n) const { //If n is out of range, throw an out_of_range exception - if (n >= size()) + if (n >= this->size()) throw std::out_of_range("vector::at"); } diff --git a/proj/to-do.txt b/proj/to-do.txt index 072519c..7cb2844 100644 --- a/proj/to-do.txt +++ b/proj/to-do.txt @@ -34,6 +34,17 @@ Write forward_list check move if noexcept conditions in vector, deque and stable_vector +Add noexcept testing using static_assert (Howard Hinnants's suggestion): + + #include + + struct A + { + void foo() noexcept; + }; + + static_assert(noexcept(std::declval().foo()), "A::foo() should be noexcept"); + Detect always equal or unequal allocators at compiler time. operator== returns true_type or false_type change virtual functions with pointers to avoid template instantiation for every type diff --git a/proj/vc7ide/allocator_traits_test.vcproj b/proj/vc7ide/allocator_traits_test.vcproj index ad50eba..6e73236 100644 --- a/proj/vc7ide/allocator_traits_test.vcproj +++ b/proj/vc7ide/allocator_traits_test.vcproj @@ -132,6 +132,9 @@ Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93815995-89BD-b043-5E8B-65FBE52E2AFB}"> + + diff --git a/proj/vc7ide/container.sln b/proj/vc7ide/container.sln index 591f0fc..68beb93 100644 --- a/proj/vc7ide/container.sln +++ b/proj/vc7ide/container.sln @@ -51,6 +51,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scoped_allocator_usage_test ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hash_table_test", "hash_table_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792606}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -111,6 +115,10 @@ Global {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Debug.Build.0 = Debug|Win32 {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Release.ActiveCfg = Release|Win32 {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/container.vcproj b/proj/vc7ide/container.vcproj index fcd9e8a..ca5a3e3 100644 --- a/proj/vc7ide/container.vcproj +++ b/proj/vc7ide/container.vcproj @@ -145,6 +145,9 @@ + + @@ -261,7 +264,7 @@ RelativePath="..\..\..\..\boost\container\detail\math_functions.hpp"> + RelativePath="..\..\..\..\boost\container\detail\memory_util.hpp"> diff --git a/test/check_equal_containers.hpp b/test/check_equal_containers.hpp index 69d642c..c094711 100644 --- a/test/check_equal_containers.hpp +++ b/test/check_equal_containers.hpp @@ -12,6 +12,8 @@ #define BOOST_CONTAINER_TEST_CHECK_EQUAL_CONTAINER_HPP #include +#include +#include #include #include #include @@ -20,6 +22,24 @@ namespace boost{ namespace container { namespace test{ +template< class T1, class T2> +bool CheckEqual( const T1 &t1, const T2 &t2 + , typename boost::container::container_detail::enable_if_c + ::value && + !boost::container::container_detail::is_pair::value + >::type* = 0) +{ return t1 == t2; } + +template< class Pair1, class Pair2> +bool CheckEqual( const Pair1 &pair1, const Pair2 &pair2 + , typename boost::container::container_detail::enable_if_c + ::value && + boost::container::container_detail::is_pair::value + >::type* = 0) +{ + return CheckEqual(pair1.first, pair2.first) && CheckEqual(pair1.second, pair2.second); +} + //Function to check if both containers are equal template @@ -38,10 +58,13 @@ bool CheckEqualContainers(const MyBoostCont *boostcont, const MyStdCont *stdcont } std::size_t i = 0; for(; itboost != itboostend; ++itboost, ++itstd, ++i){ - value_type val(*itstd); + + if(!CheckEqual(*itstd, *itboost)) + return false; +/* value_type val(*itstd); const value_type &v = *itboost; if(v != val) - return false; + return false;*/ } return true; } diff --git a/test/deque_test.cpp b/test/deque_test.cpp index 53f17a3..fbc4ab6 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -63,7 +63,7 @@ bool deque_copyable_only(V1 *cntdeque, V2 *stddeque, container_detail::true_type typedef typename V1::value_type IntType; std::size_t size = cntdeque->size(); stddeque->insert(stddeque->end(), 50, 1); - cntdeque->insert(cntdeque->end(), 50, 1); + cntdeque->insert(cntdeque->end(), 50, IntType(1)); if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; { IntType move_me(1); diff --git a/test/input_from_forward_iterator.hpp b/test/input_from_forward_iterator.hpp new file mode 100644 index 0000000..348d144 --- /dev/null +++ b/test/input_from_forward_iterator.hpp @@ -0,0 +1,80 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_FORWARD_TO_INPUT_ITERATOR_HPP +#define BOOST_CONTAINER_TEST_FORWARD_TO_INPUT_ITERATOR_HPP + +#include + +namespace boost{ +namespace container { +namespace test{ + +template +class input_iterator_wrapper + : public std::iterator< std::input_iterator_tag + , typename std::iterator_traits::value_type + , typename std::iterator_traits::difference_type + , typename std::iterator_traits::pointer + , typename std::iterator_traits::reference + > +{ + FwdIterator m_it; + + public: + input_iterator_wrapper() + : m_it(0) + {} + + explicit input_iterator_wrapper(FwdIterator it) + : m_it(it) + {} + + //Default copy constructor... + //input_iterator_wrapper(const input_iterator_wrapper&); + + //Default assignment... + //input_iterator_wrapper &operator=(const input_iterator_wrapper&); + + //Default destructor... + //~input_iterator_wrapper(); + + typename std::iterator_traits::reference operator*() const + { return *m_it; } + + typename std::iterator_traits::pointer operator->() const + { return m_it.operator->(); } + + input_iterator_wrapper& operator++() + { ++m_it; return *this; } + + input_iterator_wrapper operator++(int ) + { + input_iterator_wrapper tmp(m_it); + ++m_it; + return tmp; + } + + friend bool operator==(const input_iterator_wrapper &left, const input_iterator_wrapper &right) + { return left.m_it == right.m_it; } + + friend bool operator!=(const input_iterator_wrapper &left, const input_iterator_wrapper &right) + { return left.m_it != right.m_it; } +}; + +template +input_iterator_wrapper make_input_from_forward_iterator(const FwdIterator &it) +{ return input_iterator_wrapper(it); } + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#endif //BOOST_CONTAINER_TEST_FORWARD_TO_INPUT_ITERATOR_HPP diff --git a/test/list_test.hpp b/test/list_test.hpp index 6862ffe..85f1b73 100644 --- a/test/list_test.hpp +++ b/test/list_test.hpp @@ -18,6 +18,7 @@ #include #include #include "print_container.hpp" +#include "input_from_forward_iterator.hpp" #include #include @@ -177,7 +178,20 @@ int list_test (bool copied_allocators_equal = true) aux_vect2[i] = -1; } boostlist->assign(boost::make_move_iterator(&aux_vect[0]) - ,boost::make_move_iterator(&aux_vect[50])); + ,boost::make_move_iterator(&aux_vect[50])); + stdlist->assign(&aux_vect2[0], &aux_vect2[50]); + if(!CheckEqualContainers(boostlist, stdlist)) return 1; + + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + boostlist->assign(boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) + ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[50]))); stdlist->assign(&aux_vect2[0], &aux_vect2[50]); if(!CheckEqualContainers(boostlist, stdlist)) return 1; } @@ -206,10 +220,36 @@ int list_test (bool copied_allocators_equal = true) for(int i = 0; i < 50; ++i){ aux_vect2[i] = -1; } - boostlist->insert(boostlist->begin() + typename MyBoostList::iterator old_begin = boostlist->begin(); + typename MyBoostList::iterator it_insert = + boostlist->insert(boostlist->begin() ,boost::make_move_iterator(&aux_vect[0]) ,boost::make_move_iterator(&aux_vect[50])); + if(it_insert != boostlist->begin() || std::distance(it_insert, old_begin) != 50) + return 1; + stdlist->insert(stdlist->begin(), &aux_vect2[0], &aux_vect2[50]); + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; + + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + + old_begin = boostlist->begin(); + it_insert = boostlist->insert(boostlist->end() + ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) + ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[50]))); + if(std::distance(it_insert, boostlist->end()) != 50) + return 1; + stdlist->insert(stdlist->end(), &aux_vect2[0], &aux_vect2[50]); + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; } boostlist->unique(); diff --git a/test/movable_int.hpp b/test/movable_int.hpp index 9402b16..d895845 100644 --- a/test/movable_int.hpp +++ b/test/movable_int.hpp @@ -73,6 +73,12 @@ class movable_int int get_int() const { return m_int; } + friend bool operator==(const movable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const movable_int &r) + { return l == r.get_int(); } + private: int m_int; }; @@ -144,6 +150,12 @@ class movable_and_copyable_int int get_int() const { return m_int; } + friend bool operator==(const movable_and_copyable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const movable_and_copyable_int &r) + { return l == r.get_int(); } + private: int m_int; }; @@ -202,6 +214,12 @@ class copyable_int int get_int() const { return m_int; } + friend bool operator==(const copyable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const copyable_int &r) + { return l == r.get_int(); } + private: int m_int; }; @@ -256,10 +274,17 @@ class non_copymovable_int int get_int() const { return m_int; } + friend bool operator==(const non_copymovable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const non_copymovable_int &r) + { return l == r.get_int(); } + private: int m_int; }; + } //namespace test { } //namespace container { } //namespace boost { diff --git a/test/set_test.hpp b/test/set_test.hpp index 2afe4ce..20554df 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -88,13 +88,13 @@ int set_test () IntType move_me(i); aux_vect3[i] = boost::move(move_me); } -/* - MyBoostSet *boostset3 = MyBoostSet + + MyBoostSet *boostset3 = new MyBoostSet ( ordered_unique_range , boost::make_move_iterator(&aux_vect[0]) , boost::make_move_iterator(aux_vect + 50)); MyStdSet *stdset3 = new MyStdSet(aux_vect2, aux_vect2 + 50); - MyBoostMultiSet *boostmultiset3 = MyBoostMultiSet + MyBoostMultiSet *boostmultiset3 = new MyBoostMultiSet ( ordered_range , boost::make_move_iterator(&aux_vect3[0]) , boost::make_move_iterator(aux_vect3 + 50)); @@ -108,15 +108,15 @@ int set_test () std::cout << "Error in construct(MyBoostMultiSet3)" << std::endl; return 1; } -*/ + delete boostset2; delete boostmultiset2; delete stdset2; delete stdmultiset2; - //delete boostset3; - //delete boostmultiset3; - //delete stdset3; - //delete stdmultiset3; + delete boostset3; + delete boostmultiset3; + delete stdset3; + delete stdmultiset3; } int i, j; diff --git a/test/vector_test.hpp b/test/vector_test.hpp index a46d42b..f868686 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -8,6 +8,9 @@ // ////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_TEST_VECTOR_TEST_HEADER +#define BOOST_CONTAINER_TEST_VECTOR_TEST_HEADER + #include #include #include @@ -24,6 +27,7 @@ #include #include #include "emplace_test.hpp" +#include "input_from_forward_iterator.hpp" namespace boost{ namespace container { @@ -133,10 +137,11 @@ int vector_test() for(int i = 0; i < 50; ++i){ aux_vect2[i] = -1; } - - boostvector->insert(boostvector->end() + typename MyBoostVector::iterator insert_it = + boostvector->insert(boostvector->end() ,boost::make_move_iterator(&aux_vect[0]) ,boost::make_move_iterator(aux_vect + 50)); + if(std::size_t(std::distance(insert_it, boostvector->end())) != 50) return 1; stdvector->insert(stdvector->end(), aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; @@ -156,9 +161,30 @@ int vector_test() for(int i = 0; i < 50; ++i){ aux_vect2[i] = -1; } - boostvector->insert(boostvector->begin() + typename MyBoostVector::iterator insert_it = + boostvector->insert(boostvector->begin() ,boost::make_move_iterator(&aux_vect[0]) ,boost::make_move_iterator(aux_vect + 50)); + if(boostvector->begin() != insert_it) return 1; + stdvector->insert(stdvector->begin(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + for(int i = 0; i < 50; ++i){ + IntType new_int(-1); + aux_vect[i] = boost::move(new_int); + } + + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + //Now try with input iterators instead + insert_it = boostvector->insert(boostvector->begin() +// ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) +// ,boost::make_move_iterator(make_input_from_forward_iterator(aux_vect + 50)) + ,boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(aux_vect + 50) + ); + if(boostvector->begin() != insert_it) return 1; stdvector->insert(stdvector->begin(), aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; } @@ -204,12 +230,20 @@ int vector_test() //Test insertion from list { std::list l(50, int(1)); - boostvector->insert(boostvector->begin(), l.begin(), l.end()); + typename MyBoostVector::iterator it_insert = + boostvector->insert(boostvector->begin(), l.begin(), l.end()); + if(boostvector->begin() != it_insert) return 1; stdvector->insert(stdvector->begin(), l.begin(), l.end()); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; boostvector->assign(l.begin(), l.end()); stdvector->assign(l.begin(), l.end()); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + boostvector->clear(); + stdvector->clear(); + boostvector->assign(make_input_from_forward_iterator(l.begin()), make_input_from_forward_iterator(l.end())); + stdvector->assign(l.begin(), l.end()); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; } /* std::size_t cap = boostvector->capacity(); @@ -252,3 +286,6 @@ int vector_test() } //namespace boost{ #include + +#endif //BOOST_CONTAINER_TEST_VECTOR_TEST_HEADER +