From 6acbbb6f9b5d613bff2034dad4303d31ec334c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 3 Mar 2013 12:26:48 +0000 Subject: [PATCH] Vector performance improvements: dispatching to memcpy when possible. [SVN r83271] --- bench/bench_static_vector.cpp | 9 +- doc/container.qbk | 1 + include/boost/container/allocator_traits.hpp | 3 + include/boost/container/deque.hpp | 10 +- .../container/detail/advanced_insert_int.hpp | 5 +- include/boost/container/detail/flat_tree.hpp | 2 +- .../boost/container/detail/memory_util.hpp | 6 + include/boost/container/detail/utilities.hpp | 741 +++++++++++++----- include/boost/container/scoped_allocator.hpp | 6 +- include/boost/container/stable_vector.hpp | 2 +- include/boost/container/string.hpp | 4 +- include/boost/container/vector.hpp | 247 +++--- proj/vc7ide/container.vcproj | 174 ++-- test/Jamfile.v2 | 2 +- test/dummy_test_allocator.hpp | 19 +- test/expand_bwd_test_allocator.hpp | 6 +- test/heap_allocator_v1.hpp | 2 +- test/vector_test.hpp | 6 + 18 files changed, 781 insertions(+), 464 deletions(-) diff --git a/bench/bench_static_vector.cpp b/bench/bench_static_vector.cpp index 7e87f06..f36e145 100644 --- a/bench/bench_static_vector.cpp +++ b/bench/bench_static_vector.cpp @@ -92,7 +92,6 @@ cpu_times time_it() rotateTime.resume(); std::rotate(v.begin(), v.begin() + v.size()/2, v.end()); rotateTime.stop(); - destructionTime.resume(); delete &v; } @@ -120,16 +119,16 @@ int main() try { std::cout << "N = " << N << "\n\n"; - std::cout << "varray benchmark:\n"; + std::cout << "varray benchmark:" << std::endl; cpu_times time_varray = time_it,N > >(); - std::cout << "boost::container::static_vector benchmark\n"; + std::cout << "boost::container::static_vector benchmark" << std::endl; cpu_times time_boost_static_vector = time_it,N > >(); - std::cout << "boost::container::vector benchmark\n"; + std::cout << "boost::container::vector benchmark" << std::endl; cpu_times time_boost_vector = time_it > >(); - std::cout << "std::vector benchmark\n"; + std::cout << "std::vector benchmark" << std::endl; cpu_times time_standard_vector = time_it > >(); std::cout << "varray/boost::container::vector total time comparison:"; diff --git a/doc/container.qbk b/doc/container.qbk index 152ae74..e38288b 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -661,6 +661,7 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_54_00 Boost 1.54 Release] +* Speed improvements in `vector` constructors/copy/move/swap, dispatching to memcpy when possible. * Support for `BOOST_NO_EXCEPTIONS` [@https://svn.boost.org/trac/boost/ticket/7227 #7227]. * Fixed bugs [@https://svn.boost.org/trac/boost/ticket/7921 #7921], [@https://svn.boost.org/trac/boost/ticket/7969 #7969], diff --git a/include/boost/container/allocator_traits.hpp b/include/boost/container/allocator_traits.hpp index 3e9ce0f..964025f 100644 --- a/include/boost/container/allocator_traits.hpp +++ b/include/boost/container/allocator_traits.hpp @@ -32,7 +32,10 @@ #include //numeric_limits<>::max() #include //placement new #include //std::allocator + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #include +#endif ///@cond diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index 0962f0b..d8dc2a4 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -830,11 +830,11 @@ class deque : protected deque_base if (len > size()) { FwdIt mid = first; std::advance(mid, this->size()); - boost::copy_or_move(first, mid, begin()); + boost::container::copy(first, mid, begin()); this->insert(this->cend(), mid, last); } else{ - this->erase(boost::copy_or_move(first, last, this->begin()), cend()); + this->erase(boost::container::copy(first, last, this->begin()), cend()); } } #endif @@ -1840,12 +1840,10 @@ class deque : protected deque_base ++cur_node) { FwdIt mid = first; std::advance(mid, this->s_buffer_size()); - ::boost::container::uninitialized_copy_or_move_alloc - (this->alloc(), first, mid, *cur_node); + ::boost::container::uninitialized_copy_alloc(this->alloc(), first, mid, *cur_node); first = mid; } - ::boost::container::uninitialized_copy_or_move_alloc - (this->alloc(), first, last, this->members_.m_finish.m_first); + ::boost::container::uninitialized_copy_alloc(this->alloc(), first, last, this->members_.m_finish.m_first); } BOOST_CATCH(...){ this->priv_destroy_range(this->members_.m_start, iterator(*cur_node, cur_node)); diff --git a/include/boost/container/detail/advanced_insert_int.hpp b/include/boost/container/detail/advanced_insert_int.hpp index 2abf805..86e2628 100644 --- a/include/boost/container/detail/advanced_insert_int.hpp +++ b/include/boost/container/detail/advanced_insert_int.hpp @@ -65,13 +65,12 @@ struct insert_range_proxy void uninitialized_copy_n_and_update(Iterator p, size_type n) { - this->first_ = ::boost::container::uninitialized_copy_or_move_alloc_n_source - (this->a_, this->first_, n, p); + this->first_ = ::boost::container::uninitialized_copy_alloc_n_source(this->a_, this->first_, n, p); } void copy_n_and_update(Iterator p, size_type n) { - this->first_ = ::boost::container::copy_or_move_n_source(this->first_, n, p); + this->first_ = ::boost::container::copy_n_source(this->first_, n, p); } A &a_; diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index ac35981..90f0352 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -157,7 +157,7 @@ class flat_tree void swap(Data &d) { value_compare& mycomp = *this, & othercomp = d; - container_detail::do_swap(mycomp, othercomp); + boost::container::swap_dispatch(mycomp, othercomp); this->m_vect.swap(d.m_vect); } diff --git a/include/boost/container/detail/memory_util.hpp b/include/boost/container/detail/memory_util.hpp index c00172c..ac9a899 100644 --- a/include/boost/container/detail/memory_util.hpp +++ b/include/boost/container/detail/memory_util.hpp @@ -51,6 +51,12 @@ #define BOOST_PP_ITERATION_PARAMS_1 (3, (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS+1, )) #include BOOST_PP_ITERATE() +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME swap +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEGIN namespace boost { namespace container { namespace container_detail { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, 1, )) +#include BOOST_PP_ITERATE() + namespace boost { namespace container { namespace container_detail { diff --git a/include/boost/container/detail/utilities.hpp b/include/boost/container/detail/utilities.hpp index 02141a4..f56c3bf 100644 --- a/include/boost/container/detail/utilities.hpp +++ b/include/boost/container/detail/utilities.hpp @@ -19,17 +19,74 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include +#include +#include #include #include +#include //std::distance namespace boost { namespace container { + +////////////////////////////////////////////////////////////////////////////// +// +// swap +// +////////////////////////////////////////////////////////////////////////////// + +namespace container_swap { + +template::value > +struct has_member_swap +{ + static const bool value = boost::container::container_detail:: + has_member_function_callable_with_swap::value; +}; + +template +struct has_member_swap +{ + static const bool value = false; +}; + +} //namespace container_swap { + +template inline +typename container_detail::enable_if_c + ::value, void>::type +swap_dispatch(T &left, T &right) //swap using member swap +{ + left.swap(right); // may throw +} + +template inline +typename container_detail::enable_if_c + ::value && boost::has_move_emulation_enabled::value, void>::type + swap_dispatch(T &left, T &right) +{ + T temp(boost::move(left)); // may throw + left = boost::move(right); // may throw + right = boost::move(temp); // may throw +} + +template inline +typename container_detail::enable_if_c + ::value && !boost::has_move_emulation_enabled::value, void>::type + swap_dispatch(T &left, T &right) +{ + using std::swap; + swap(left, right); // may throw +} + namespace container_detail { template @@ -79,13 +136,6 @@ inline typename Pointer::element_type* to_raw_pointer(const Pointer &p) { return boost::container::container_detail::to_raw_pointer(p.operator->()); } -//!To avoid ADL problems with swap -template -inline void do_swap(T& x, T& y) -{ - using std::swap; - swap(x, y); -} template inline void swap_alloc(AllocatorType &, AllocatorType &, container_detail::false_type) @@ -94,7 +144,7 @@ inline void swap_alloc(AllocatorType &, AllocatorType &, container_detail::false template inline void swap_alloc(AllocatorType &l, AllocatorType &r, container_detail::true_type) -{ container_detail::do_swap(l, r); } +{ boost::container::swap_dispatch(l, r); } template inline void assign_alloc(AllocatorType &, const AllocatorType &, container_detail::false_type) @@ -127,14 +177,121 @@ struct ct_rounded_size enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo }; }; +template +struct are_elements_contiguous +{ + static const bool value = false; +}; + +template +struct are_elements_contiguous +{ + static const bool value = true; +}; + +template +struct are_contiguous_and_same +{ + static const bool is_same_io = + is_same< typename remove_const< typename ::std::iterator_traits::value_type >::type + , typename ::std::iterator_traits::value_type + >::value; + static const bool value = is_same_io && + are_elements_contiguous::value && + are_elements_contiguous::value; +}; + +template +struct is_memcpy_copy_assignable +{ + static const bool value = are_contiguous_and_same::value && + boost::has_trivial_assign< typename ::std::iterator_traits::value_type >::value; +}; + +template +struct is_memcpy_copy_constructible +{ + static const bool value = are_contiguous_and_same::value && + boost::has_trivial_copy< typename ::std::iterator_traits::value_type >::value; +}; + +template +struct enable_if_memcpy_copy_constructible + : public enable_if_c::value, R> +{}; + +template +struct disable_if_memcpy_copy_constructible + : public enable_if_c::value, R> +{}; + +template +struct enable_if_memcpy_copy_assignable + : public enable_if_c::value, R> +{}; + +template +struct disable_if_memcpy_copy_assignable + : public enable_if_c::value, R> +{}; + +template + // F models ForwardIterator +inline F memcpy(I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ + typedef typename std::iterator_traits::value_type value_type; + typename std::iterator_traits::difference_type n = std::distance(f, l); + ::memcpy(container_detail::addressof(*r), container_detail::addressof(*f), sizeof(value_type)*n); + std::advance(r, n); + return r; +} + +template + // F models ForwardIterator +F memcpy_n(I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ + typedef typename std::iterator_traits::value_type value_type; + ::memcpy(container_detail::addressof(*r), container_detail::addressof(*f), sizeof(value_type)*n); + std::advance(r, n); + return r; +} + +template + // F models ForwardIterator +I memcpy_n_source(I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ + typedef typename std::iterator_traits::value_type value_type; + ::memcpy(container_detail::addressof(*r), container_detail::addressof(*f), sizeof(value_type)*n); + std::advance(f, n); + return f; +} + +template + // F models ForwardIterator +I memcpy_n_source_dest(I f, typename std::iterator_traits::difference_type n, F &r) BOOST_CONTAINER_NOEXCEPT +{ + typedef typename std::iterator_traits::value_type value_type; + ::memcpy(container_detail::addressof(*r), container_detail::addressof(*f), sizeof(value_type)*n); + std::advance(f, n); + std::advance(r, n); + return f; +} + + } //namespace container_detail { + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_move_alloc // ////////////////////////////////////////////////////////////////////////////// + //! Effects: //! \code //! for (; f != l; ++r, ++f) @@ -146,7 +303,8 @@ template // F models ForwardIterator -F uninitialized_move_alloc(A &a, I f, I l, F r) +inline typename container_detail::disable_if_memcpy_copy_constructible::type + uninitialized_move_alloc(A &a, I f, I l, F r) { F back = r; BOOST_TRY{ @@ -165,6 +323,14 @@ F uninitialized_move_alloc(A &a, I f, I l, F r) return r; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_constructible::type + uninitialized_move_alloc(A &, I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy(f, l, r); } + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_move_alloc_n @@ -182,7 +348,8 @@ template // F models ForwardIterator -F uninitialized_move_alloc_n(A &a, I f, typename std::iterator_traits::difference_type n, F r) +inline typename container_detail::disable_if_memcpy_copy_constructible::type + uninitialized_move_alloc_n(A &a, I f, typename std::iterator_traits::difference_type n, F r) { F back = r; BOOST_TRY{ @@ -201,6 +368,14 @@ F uninitialized_move_alloc_n(A &a, I f, typename std::iterator_traits::differ return r; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_constructible::type + uninitialized_move_alloc_n(A &, I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n(f, n, r); } + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_move_alloc_n_source @@ -218,7 +393,8 @@ template // F models ForwardIterator -I uninitialized_move_alloc_n_source(A &a, I f, typename std::iterator_traits::difference_type n, F r) +inline typename container_detail::disable_if_memcpy_copy_constructible::type + uninitialized_move_alloc_n_source(A &a, I f, typename std::iterator_traits::difference_type n, F r) { F back = r; BOOST_TRY{ @@ -237,6 +413,14 @@ I uninitialized_move_alloc_n_source(A &a, I f, typename std::iterator_traits: return f; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_constructible::type + uninitialized_move_alloc_n_source(A &, I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n_source(f, n, r); } + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_copy_alloc @@ -254,7 +438,8 @@ template // F models ForwardIterator -F uninitialized_copy_alloc(A &a, I f, I l, F r) +inline typename container_detail::disable_if_memcpy_copy_constructible::type + uninitialized_copy_alloc(A &a, I f, I l, F r) { F back = r; BOOST_TRY{ @@ -273,6 +458,14 @@ F uninitialized_copy_alloc(A &a, I f, I l, F r) return r; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_constructible::type + uninitialized_copy_alloc(A &, I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy(f, l, r); } + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_copy_alloc_n @@ -290,7 +483,8 @@ template // F models ForwardIterator -F uninitialized_copy_alloc_n(A &a, I f, typename std::iterator_traits::difference_type n, F r) +inline typename container_detail::disable_if_memcpy_copy_constructible::type + uninitialized_copy_alloc_n(A &a, I f, typename std::iterator_traits::difference_type n, F r) { F back = r; BOOST_TRY{ @@ -309,6 +503,14 @@ F uninitialized_copy_alloc_n(A &a, I f, typename std::iterator_traits::differ return r; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_constructible::type + uninitialized_copy_alloc_n(A &, I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n(f, n, r); } + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_copy_alloc_n_source @@ -326,7 +528,8 @@ template // F models ForwardIterator -I uninitialized_copy_alloc_n_source(A &a, I f, typename std::iterator_traits::difference_type n, F r) +inline typename container_detail::disable_if_memcpy_copy_constructible::type + uninitialized_copy_alloc_n_source(A &a, I f, typename std::iterator_traits::difference_type n, F r) { F back = r; BOOST_TRY{ @@ -345,131 +548,13 @@ I uninitialized_copy_alloc_n_source(A &a, I f, typename std::iterator_traits: return f; } -////////////////////////////////////////////////////////////////////////////// -// -// uninitialized_copy_alloc -// -////////////////////////////////////////////////////////////////////////////// - -//! Effects: -//! \code -//! for (; f != l; ++r, ++f) -//! allocator_traits::construct(a, &*r, *f); -//! \endcode -//! -//! Returns: r template -void uninitialized_fill_alloc(A &a, F f, F l, const T &t) -{ - F back = f; - BOOST_TRY{ - while (f != l) { - allocator_traits::construct(a, container_detail::to_raw_pointer(&*f), t); - ++f; - } - } - BOOST_CATCH(...){ - for (; back != l; ++back){ - allocator_traits::destroy(a, container_detail::to_raw_pointer(&*back)); - } - BOOST_RETHROW; - } - BOOST_CATCH_END -} - -////////////////////////////////////////////////////////////////////////////// -// -// uninitialized_copy_or_move_alloc -// -////////////////////////////////////////////////////////////////////////////// - -template - // F models ForwardIterator -F uninitialized_copy_or_move_alloc - (A &a, I f, I l, F r - ,typename boost::container::container_detail::enable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - return ::boost::container::uninitialized_move_alloc(a, f, l, r); -} - -template - // F models ForwardIterator -F uninitialized_copy_or_move_alloc - (A &a, I f, I l, F r - ,typename boost::container::container_detail::disable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - return ::boost::container::uninitialized_copy_alloc(a, f, l, r); -} - -////////////////////////////////////////////////////////////////////////////// -// -// uninitialized_copy_or_move_alloc_n -// -////////////////////////////////////////////////////////////////////////////// - -template - // F models ForwardIterator -F uninitialized_copy_or_move_alloc_n - (A &a, I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::enable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - return ::boost::container::uninitialized_move_alloc_n(a, f, n, r); -} - -template - // F models ForwardIterator -F uninitialized_copy_or_move_alloc_n - (A &a, I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::disable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - return ::boost::container::uninitialized_copy_alloc_n(a, f, n, r); -} - - -////////////////////////////////////////////////////////////////////////////// -// -// uninitialized_copy_or_move_alloc_n_source -// -////////////////////////////////////////////////////////////////////////////// - -template - // F models ForwardIterator -I uninitialized_copy_or_move_alloc_n_source - (A &a, I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::enable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - return ::boost::container::uninitialized_move_alloc_n_source(a, f, n, r); -} - -template - // F models ForwardIterator -I uninitialized_copy_or_move_alloc_n_source - (A &a, I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::disable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - return ::boost::container::uninitialized_copy_alloc_n_source(a, f, n, r); -} + typename I, // I models InputIterator + typename F> // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_constructible::type + uninitialized_copy_alloc_n_source(A &, I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n_source(f, n, r); } ////////////////////////////////////////////////////////////////////////////// // @@ -487,7 +572,7 @@ I uninitialized_copy_or_move_alloc_n_source template // F models ForwardIterator -F uninitialized_default_alloc_n(A &a, typename allocator_traits::difference_type n, F r) +inline F uninitialized_default_alloc_n(A &a, typename allocator_traits::difference_type n, F r) { F back = r; BOOST_TRY{ @@ -506,6 +591,41 @@ F uninitialized_default_alloc_n(A &a, typename allocator_traits::difference_t return r; } +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_fill_alloc +// +////////////////////////////////////////////////////////////////////////////// + +//! Effects: +//! \code +//! for (; f != l; ++r, ++f) +//! allocator_traits::construct(a, &*r, *f); +//! \endcode +//! +//! Returns: r +template + +inline void uninitialized_fill_alloc(A &a, F f, F l, const T &t) +{ + F back = f; + BOOST_TRY{ + while (f != l) { + allocator_traits::construct(a, container_detail::to_raw_pointer(&*f), t); + ++f; + } + } + BOOST_CATCH(...){ + for (; back != l; ++back){ + allocator_traits::destroy(a, container_detail::to_raw_pointer(&*back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END +} + ////////////////////////////////////////////////////////////////////////////// // @@ -524,7 +644,7 @@ template // F models ForwardIterator -F uninitialized_fill_alloc_n(A &a, const T &v, typename allocator_traits::difference_type n, F r) +inline F uninitialized_fill_alloc_n(A &a, const T &v, typename allocator_traits::difference_type n, F r) { F back = r; BOOST_TRY{ @@ -545,30 +665,15 @@ F uninitialized_fill_alloc_n(A &a, const T &v, typename allocator_traits::dif ////////////////////////////////////////////////////////////////////////////// // -// copy_or_move +// copy // ////////////////////////////////////////////////////////////////////////////// template // F models ForwardIterator -inline F copy_or_move(I f, I l, F r - ,typename boost::container::container_detail::enable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - while (f != l) { - *r = ::boost::move(*f); - ++f; ++r; - } - return r; -} - -template - // F models ForwardIterator -inline F copy_or_move(I f, I l, F r - ,typename boost::container::container_detail::disable_if - < boost::move_detail::is_move_iterator >::type* = 0) +typename F> // F models ForwardIterator +inline typename container_detail::disable_if_memcpy_copy_assignable::type + copy(I f, I l, F r) { while (f != l) { *r = *f; @@ -577,32 +682,24 @@ inline F copy_or_move(I f, I l, F r return r; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + copy(I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy(f, l, r); } + ////////////////////////////////////////////////////////////////////////////// // -// copy_or_move_n +// copy_n // ////////////////////////////////////////////////////////////////////////////// template // F models ForwardIterator -inline F copy_or_move_n(I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::enable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - while (n--) { - *r = ::boost::move(*f); - ++f; ++r; - } - return r; -} - -template - // F models ForwardIterator -inline F copy_or_move_n(I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::disable_if - < boost::move_detail::is_move_iterator >::type* = 0) +inline typename container_detail::disable_if_memcpy_copy_assignable::type + copy_n(I f, typename std::iterator_traits::difference_type n, F r) { while (n--) { *r = *f; @@ -611,32 +708,24 @@ inline F copy_or_move_n(I f, typename std::iterator_traits::difference_type n return r; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + copy_n(I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n(f, n, r); } + ////////////////////////////////////////////////////////////////////////////// // -// copy_or_move_n_source +// copy_n_source // ////////////////////////////////////////////////////////////////////////////// template // F models ForwardIterator -inline I copy_or_move_n_source(I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::enable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - while (n--) { - *r = ::boost::move(*f); - ++f; ++r; - } - return f; -} - -template - // F models ForwardIterator -inline I copy_or_move_n_source(I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::disable_if - < boost::move_detail::is_move_iterator >::type* = 0) +inline typename container_detail::disable_if_memcpy_copy_assignable::type + copy_n_source(I f, typename std::iterator_traits::difference_type n, F r) { while (n--) { *r = *f; @@ -645,6 +734,39 @@ inline I copy_or_move_n_source(I f, typename std::iterator_traits::difference return f; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + copy_n_source(I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n_source(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// copy_n_source_dest +// +////////////////////////////////////////////////////////////////////////////// + +template + // F models ForwardIterator +inline typename container_detail::disable_if_memcpy_copy_assignable::type + copy_n_source_dest(I f, typename std::iterator_traits::difference_type n, F &r) +{ + while (n--) { + *r = *f; + ++f; ++r; + } + return f; +} + +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + copy_n_source_dest(I f, typename std::iterator_traits::difference_type n, F &r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n_source_dest(f, n, r); } + ////////////////////////////////////////////////////////////////////////////// // // move @@ -654,7 +776,8 @@ inline I copy_or_move_n_source(I f, typename std::iterator_traits::difference template // F models ForwardIterator -inline F move(I f, I l, F r) +inline typename container_detail::disable_if_memcpy_copy_assignable::type + move(I f, I l, F r) { while (f != l) { *r = ::boost::move(*f); @@ -663,6 +786,12 @@ inline F move(I f, I l, F r) return r; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + move(I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy(f, l, r); } ////////////////////////////////////////////////////////////////////////////// // @@ -673,7 +802,8 @@ inline F move(I f, I l, F r) template // F models ForwardIterator -inline F move_n(I f, typename std::iterator_traits::difference_type n, F r) +inline typename container_detail::disable_if_memcpy_copy_assignable::type + move_n(I f, typename std::iterator_traits::difference_type n, F r) { while (n--) { *r = ::boost::move(*f); @@ -682,6 +812,12 @@ inline F move_n(I f, typename std::iterator_traits::difference_type n, F r) return r; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + move_n(I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n(f, n, r); } ////////////////////////////////////////////////////////////////////////////// // @@ -690,9 +826,10 @@ inline F move_n(I f, typename std::iterator_traits::difference_type n, F r) ////////////////////////////////////////////////////////////////////////////// template - // F models ForwardIterator -inline I move_n_source(I f, typename std::iterator_traits::difference_type n, F r) + // F models ForwardIterator +inline typename container_detail::disable_if_memcpy_copy_assignable::type + move_n_source(I f, typename std::iterator_traits::difference_type n, F r) { while (n--) { *r = ::boost::move(*f); @@ -701,9 +838,42 @@ inline I move_n_source(I f, typename std::iterator_traits::difference_type n, return f; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + move_n_source(I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n_source(f, n, r); } + ////////////////////////////////////////////////////////////////////////////// // -// destroy_n +// move_n_source_dest +// +////////////////////////////////////////////////////////////////////////////// + +template + // F models ForwardIterator +inline typename container_detail::disable_if_memcpy_copy_assignable::type + move_n_source_dest(I f, typename std::iterator_traits::difference_type n, F &r) +{ + while (n--) { + *r = ::boost::move(*f); + ++f; ++r; + } + return f; +} + +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + move_n_source_dest(I f, typename std::iterator_traits::difference_type n, F &r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n_source_dest(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// destroy_n // ////////////////////////////////////////////////////////////////////////////// @@ -734,23 +904,170 @@ inline void destroy_alloc_n(A &, I, typename std::iterator_traits::difference ////////////////////////////////////////////////////////////////////////////// template - -void deep_swap_alloc_n(A &a, F short_range_f, typename allocator_traits::size_type n_i - , G large_range_f, typename allocator_traits::size_type n_j) + > +inline typename container_detail::disable_if_memcpy_copy_assignable::type + deep_swap_alloc_n( A &a, F short_range_f, typename allocator_traits::size_type n_i + , G large_range_f, typename allocator_traits::size_type n_j) { typename allocator_traits::size_type n = 0; - typedef typename allocator_traits::value_type value_type; for (; n != n_i ; ++short_range_f, ++large_range_f, ++n){ - //boost::swap(*first_sm, *first_la); // may throw - value_type temp(boost::move(*short_range_f)); // may throw - *short_range_f = boost::move(*large_range_f); // may throw - *large_range_f = boost::move(temp); // may throw + boost::container::swap_dispatch(*short_range_f, *large_range_f); + } + boost::container::uninitialized_move_alloc_n(a, large_range_f, n_j - n_i, short_range_f); // may throw + boost::container::destroy_alloc_n(a, large_range_f, n_j - n_i); +} + +static const std::size_t DeepSwapAllocNMaxStorage = std::size_t(1) << std::size_t(11); //2K bytes + +template + +inline typename container_detail::enable_if_c + < container_detail::is_memcpy_copy_assignable::value && (MaxTmpBytes <= DeepSwapAllocNMaxStorage) && false + , void>::type + deep_swap_alloc_n( A &a, F short_range_f, typename allocator_traits::size_type n_i + , G large_range_f, typename allocator_traits::size_type n_j) +{ + typedef typename allocator_traits::value_type value_type; + typedef typename boost::aligned_storage + ::value>::type storage_type; + storage_type storage; + + const std::size_t n_i_bytes = sizeof(value_type)*n_i; + unsigned char *const large_ptr = static_cast(static_cast(container_detail::addressof(*large_range_f))); + unsigned char *const short_ptr = static_cast(static_cast(container_detail::addressof(*short_range_f))); + unsigned char *const stora_ptr = static_cast(static_cast(container_detail::addressof(storage))); + ::memcpy(stora_ptr, large_ptr, n_i_bytes); + ::memcpy(large_ptr, short_ptr, n_i_bytes); + ::memcpy(short_ptr, stora_ptr, n_i_bytes); + std::advance(large_range_f, n_i); + std::advance(short_range_f, n_i); + boost::container::uninitialized_move_alloc_n(a, large_range_f, n_j - n_i, short_range_f); // may throw + boost::container::destroy_alloc_n(a, large_range_f, n_j - n_i); +} + +template + +inline typename container_detail::enable_if_c + < container_detail::is_memcpy_copy_assignable::value && true//(MaxTmpBytes > DeepSwapAllocNMaxStorage) + , void>::type + deep_swap_alloc_n( A &a, F short_range_f, typename allocator_traits::size_type n_i + , G large_range_f, typename allocator_traits::size_type n_j) +{ + typedef typename allocator_traits::value_type value_type; + typedef typename boost::aligned_storage + ::value>::type storage_type; + storage_type storage; + const std::size_t sizeof_storage = sizeof(storage); + + std::size_t n_i_bytes = sizeof(value_type)*n_i; + char *large_ptr = static_cast(static_cast(container_detail::addressof(*large_range_f))); + char *short_ptr = static_cast(static_cast(container_detail::addressof(*short_range_f))); + char *stora_ptr = static_cast(static_cast(container_detail::addressof(storage))); + + std::size_t szt_times = n_i_bytes/sizeof_storage; + const std::size_t szt_rem = n_i_bytes%sizeof_storage; + + //Loop unrolling using Duff's device, as it seems it helps on some architectures + const std::size_t Unroll = 4; + std::size_t n = (szt_times + (Unroll-1))/Unroll; + const std::size_t branch_number = ((!szt_times)*Unroll) + (szt_times % Unroll); + switch(branch_number){ + case 4: + break; + case 0: do{ + ::memcpy(stora_ptr, large_ptr, sizeof_storage); + ::memcpy(large_ptr, short_ptr, sizeof_storage); + ::memcpy(short_ptr, stora_ptr, sizeof_storage); + large_ptr += sizeof_storage; + short_ptr += sizeof_storage; + case 3: + ::memcpy(stora_ptr, large_ptr, sizeof_storage); + ::memcpy(large_ptr, short_ptr, sizeof_storage); + ::memcpy(short_ptr, stora_ptr, sizeof_storage); + large_ptr += sizeof_storage; + short_ptr += sizeof_storage; + case 2: + ::memcpy(stora_ptr, large_ptr, sizeof_storage); + ::memcpy(large_ptr, short_ptr, sizeof_storage); + ::memcpy(short_ptr, stora_ptr, sizeof_storage); + large_ptr += sizeof_storage; + short_ptr += sizeof_storage; + case 1: + ::memcpy(stora_ptr, large_ptr, sizeof_storage); + ::memcpy(large_ptr, short_ptr, sizeof_storage); + ::memcpy(short_ptr, stora_ptr, sizeof_storage); + large_ptr += sizeof_storage; + short_ptr += sizeof_storage; + } while(--n); + } + ::memcpy(stora_ptr, large_ptr, szt_rem); + ::memcpy(large_ptr, short_ptr, szt_rem); + ::memcpy(short_ptr, stora_ptr, szt_rem); + std::advance(large_range_f, n_i); + std::advance(short_range_f, n_i); + boost::container::uninitialized_move_alloc_n(a, large_range_f, n_j - n_i, short_range_f); // may throw + boost::container::destroy_alloc_n(a, large_range_f, n_j - n_i); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// copy_assign_range_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +template + +void copy_assign_range_alloc_n( A &a, I inp_start, typename allocator_traits::size_type n_i + , O out_start, typename allocator_traits::size_type n_o ) +{ + if (n_o < n_i){ + inp_start = boost::container::copy_n_source_dest(inp_start, n_o, out_start); // may throw + boost::container::uninitialized_copy_alloc_n(a, inp_start, n_i - n_o, out_start);// may throw + } + else{ + out_start = boost::container::copy_n(inp_start, n_i, out_start); // may throw + boost::container::destroy_alloc_n(a, out_start, n_o - n_i); + } +} + +////////////////////////////////////////////////////////////////////////////// +// +// move_assign_range_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +template + +void move_assign_range_alloc_n( A &a, I inp_start, typename allocator_traits::size_type n_i + , O out_start, typename allocator_traits::size_type n_o ) +{ + if (n_o < n_i){ + inp_start = boost::container::move_n_source_dest(inp_start, n_o, out_start); // may throw + boost::container::uninitialized_move_alloc_n(a, inp_start, n_i - n_o, out_start); // may throw + } + else{ + out_start = boost::container::move_n(inp_start, n_i, out_start); // may throw + boost::container::destroy_alloc_n(a, out_start, n_o - n_i); } - uninitialized_move_alloc_n(a, large_range_f, n_j - n, short_range_f); // may throw - destroy_alloc_n(a, large_range_f, n_j - n); } } //namespace container { diff --git a/include/boost/container/scoped_allocator.hpp b/include/boost/container/scoped_allocator.hpp index 39fd4da..022c73e 100644 --- a/include/boost/container/scoped_allocator.hpp +++ b/include/boost/container/scoped_allocator.hpp @@ -584,6 +584,7 @@ class scoped_allocator_adaptor_base typedef OuterAlloc outer_allocator_type; typedef scoped_allocator_adaptor inner_allocator_type; + typedef allocator_traits inner_traits_type; typedef boost::integral_constant< bool, outer_traits_type::propagate_on_container_copy_assignment::value || @@ -723,6 +724,7 @@ class scoped_allocator_adaptor_base inner_allocator_type; \ + typedef allocator_traits inner_traits_type; \ typedef boost::integral_constant< \ bool, \ outer_traits_type::propagate_on_container_copy_assignment::value || \ @@ -860,6 +862,7 @@ class scoped_allocator_adaptor_base typedef OuterAlloc outer_allocator_type; typedef allocator_traits outer_traits_type; typedef scoped_allocator_adaptor inner_allocator_type; + typedef allocator_traits inner_traits_type; typedef typename outer_traits_type:: propagate_on_container_copy_assignment propagate_on_container_copy_assignment; typedef typename outer_traits_type:: @@ -1029,6 +1032,7 @@ class scoped_allocator_adaptor //! Type: `scoped_allocator_adaptor` if `sizeof...(InnerAllocs)` is zero; otherwise, //! `scoped_allocator_adaptor`. typedef typename base_type::inner_allocator_type inner_allocator_type; + typedef allocator_traits inner_traits_type; typedef typename outer_traits_type::value_type value_type; typedef typename outer_traits_type::size_type size_type; typedef typename outer_traits_type::difference_type difference_type; @@ -1220,7 +1224,7 @@ class scoped_allocator_adaptor return scoped_allocator_adaptor (internal_type_t() ,outer_traits_type::select_on_container_copy_construction(this->outer_allocator()) - ,outer_traits_type::select_on_container_copy_construction(this->inner_allocator()) + ,inner_traits_type::select_on_container_copy_construction(this->inner_allocator()) ); } /// @cond diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index 40f9de7..2de4ae1 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -1714,7 +1714,7 @@ class stable_vector void priv_swap_members(stable_vector &x) { - container_detail::do_swap(this->internal_data.pool_size, x.internal_data.pool_size); + boost::container::swap_dispatch(this->internal_data.pool_size, x.internal_data.pool_size); index_traits_type::readjust_end_node(this->index, this->internal_data.end_node); index_traits_type::readjust_end_node(x.index, x.internal_data.end_node); } diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index 74dd051..4aa6ce7 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -426,7 +426,7 @@ class basic_string_base { if(this->is_short()){ if(other.is_short()){ - container_detail::do_swap(this->members_.m_repr, other.members_.m_repr); + boost::container::swap_dispatch(this->members_.m_repr, other.members_.m_repr); } else{ short_t short_backup(this->members_.m_repr.short_repr()); @@ -447,7 +447,7 @@ class basic_string_base this->members_.m_repr.short_repr() = short_backup; } else{ - container_detail::do_swap(this->members_.m_repr.long_repr(), other.members_.m_repr.long_repr()); + boost::container::swap_dispatch(this->members_.m_repr.long_repr(), other.members_.m_repr.long_repr()); } } } diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 092114d..4319e6b 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -410,9 +410,9 @@ struct vector_alloc_holder void swap(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT { - container_detail::do_swap(this->m_start, x.m_start); - container_detail::do_swap(this->m_size, x.m_size); - container_detail::do_swap(this->m_capacity, x.m_capacity); + boost::container::swap_dispatch(this->m_start, x.m_start); + boost::container::swap_dispatch(this->m_size, x.m_size); + boost::container::swap_dispatch(this->m_capacity, x.m_capacity); } void move_from_empty(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT @@ -430,16 +430,6 @@ struct vector_alloc_holder const Allocator &alloc() const BOOST_CONTAINER_NOEXCEPT { return *this; } - void deallocate() BOOST_CONTAINER_NOEXCEPT - { - if(this->m_capacity){ - this->alloc().deallocate(this->m_start, this->m_capacity); - this->m_start = pointer(); - this->m_size = 0; - this->m_capacity = 0; - } - } - const pointer &start() const BOOST_CONTAINER_NOEXCEPT { return m_start; } const size_type &capacity() const BOOST_CONTAINER_NOEXCEPT { return m_capacity; } void start(const pointer &p) BOOST_CONTAINER_NOEXCEPT { m_start = p; } @@ -497,7 +487,7 @@ struct vector_alloc_holderalloc(), container_detail::to_raw_pointer(holder.start()), m_size, this->start()); + (this->alloc(), container_detail::to_raw_pointer(holder.start()), m_size, container_detail::to_raw_pointer(this->start())); } template @@ -509,7 +499,7 @@ struct vector_alloc_holderfirst_allocation(n); ::boost::container::uninitialized_move_alloc_n - (this->alloc(), container_detail::to_raw_pointer(holder.start()), n, this->start()); + (this->alloc(), container_detail::to_raw_pointer(holder.start()), n, container_detail::to_raw_pointer(this->start())); } void first_allocation(size_type cap) @@ -551,9 +541,6 @@ struct vector_alloc_holder void priv_swap_members_impl(vector_alloc_holder &x) { + const std::size_t MaxTmpStorage = sizeof(value_type)*Allocator::internal_capacity; value_type *const first_this = container_detail::to_raw_pointer(this->start()); value_type *const first_x = container_detail::to_raw_pointer(x.start()); if(this->m_size < x.m_size){ - deep_swap_alloc_n(this->alloc(), first_this, this->m_size, first_x, x.m_size); + boost::container::deep_swap_alloc_n(this->alloc(), first_this, this->m_size, first_x, x.m_size); } else{ - deep_swap_alloc_n(this->alloc(), first_x, x.m_size, first_this, this->m_size); + boost::container::deep_swap_alloc_n(this->alloc(), first_x, x.m_size, first_this, this->m_size); } - container_detail::do_swap(this->m_size, x.m_size); + boost::container::swap_dispatch(this->m_size, x.m_size); } }; @@ -743,7 +731,7 @@ class vector vector(const vector &x) : m_holder(allocator_traits_type::select_on_container_copy_construction(x.m_holder.alloc()), x.size()) { - ::boost::container::uninitialized_copy_or_move_alloc_n_source + ::boost::container::uninitialized_copy_alloc_n ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start()) , x.size(), container_detail::to_raw_pointer(this->m_holder.start())); } @@ -784,7 +772,7 @@ class vector vector(const vector &x, const allocator_type &a) : m_holder(a, x.size()) { - ::boost::container::uninitialized_copy_or_move_alloc_n_source + ::boost::container::uninitialized_copy_alloc_n_source ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start()) , x.size(), container_detail::to_raw_pointer(this->m_holder.start())); } @@ -820,7 +808,8 @@ class vector //! Complexity: Linear to the number of elements. ~vector() BOOST_CONTAINER_NOEXCEPT { - destroy_alloc_n(this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size); + boost::container::destroy_alloc_n + (this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size); //vector_alloc_holder deallocates the data } @@ -893,7 +882,8 @@ class vector { //Overwrite all elements we can from [first, last) iterator cur = this->begin(); - for ( ; first != last && cur != end(); ++cur, ++first){ + const iterator end_it = this->end(); + for ( ; first != last && cur != end_it; ++cur, ++first){ *cur = *first; } @@ -1507,7 +1497,7 @@ class vector ,container_detail::to_raw_pointer(vector_iterator_get_ptr(first)) )); const size_type destroyed = (end_pos - ptr); - destroy_alloc_n(this->get_stored_allocator(), ptr, destroyed); + boost::container::destroy_alloc_n(this->get_stored_allocator(), ptr, destroyed); this->m_holder.m_size -= destroyed; } return iterator(vector_iterator_get_ptr(first)); @@ -1607,16 +1597,7 @@ class vector T* const other_start = container_detail::to_raw_pointer(x.m_holder.start()); const size_type this_sz = m_holder.m_size; const size_type other_sz = static_cast(x.m_holder.m_size); - if (this_sz < other_sz){ - move_n(other_start, this_sz, this_start); // may throw - uninitialized_move_alloc_n( this->m_holder.alloc(), other_start + this_sz - , other_sz - this_sz, this_start + this_sz); // may throw - } - else - { - move_n(other_start, other_sz, this_start); - destroy_alloc_n(this->m_holder.alloc(), this_start + other_sz, this_sz - other_sz); - } + boost::container::move_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz); this->m_holder.m_size = other_sz; } @@ -1658,16 +1639,7 @@ class vector T* const other_start = container_detail::to_raw_pointer(x.m_holder.start()); const size_type this_sz = m_holder.m_size; const size_type other_sz = static_cast(x.m_holder.m_size); - if (this_sz < other_sz){ - copy_or_move_n(other_start, this_sz, this_start); // may throw - uninitialized_copy_or_move_alloc_n( this->m_holder.alloc(), other_start + this_sz - , other_sz - this_sz, this_start + this_sz); // may throw - } - else - { - copy_or_move_n(other_start, other_sz, this_start); - destroy_alloc_n(this->m_holder.alloc(), this_start + other_sz, this_sz - other_sz); - } + boost::container::copy_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz); this->m_holder.m_size = other_sz; } @@ -1707,7 +1679,7 @@ class vector const size_type sz = m_holder.m_size; ::boost::container::uninitialized_move_alloc_n_source ( this->m_holder.alloc(), raw_beg, sz, container_detail::to_raw_pointer(p) ); - destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz); + boost::container::destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz); this->m_holder.start(p); this->m_holder.capacity(new_cap); } @@ -1741,7 +1713,7 @@ class vector #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_expand_bwd; #endif - this->priv_range_insert_expand_backwards + this->priv_forward_range_insert_expand_backwards ( container_detail::to_raw_pointer(ret.first) , real_cap , container_detail::to_raw_pointer(this->m_holder.start()) @@ -1758,7 +1730,7 @@ class vector const size_type sz = m_holder.m_size; ::boost::container::uninitialized_move_alloc_n_source ( this->m_holder.alloc(), raw_beg, sz, container_detail::to_raw_pointer(ret.first) ); - destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz); + boost::container::destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz); this->m_holder.start(ret.first); this->m_holder.capacity(real_cap); } @@ -1783,13 +1755,14 @@ class vector void priv_destroy_last_n(size_type n) BOOST_CONTAINER_NOEXCEPT { T* const end_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; - destroy_alloc_n(this->get_stored_allocator(), end_pos-n, n); + boost::container::destroy_alloc_n(this->get_stored_allocator(), end_pos-n, n); this->m_holder.m_size -= n; } void priv_destroy_all() BOOST_CONTAINER_NOEXCEPT { - destroy_alloc_n(this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size); + boost::container::destroy_alloc_n + (this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size); this->m_holder.m_size = 0; } @@ -1833,7 +1806,7 @@ class vector } } - void priv_shrink_to_fit(allocator_v0) + void priv_shrink_to_fit(allocator_v0) BOOST_CONTAINER_NOEXCEPT {} void priv_shrink_to_fit(allocator_v1) @@ -1842,7 +1815,9 @@ class vector if(cp){ const size_type sz = this->size(); if(!sz){ - this->m_holder.deallocate(); + this->m_holder.alloc().deallocate(this->m_holder.m_start, cp); + this->m_holder.m_start = pointer(); + this->m_holder.m_capacity = 0; } else if(sz < cp){ //Allocate a new buffer. @@ -1854,7 +1829,7 @@ class vector #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_alloc; #endif - this->priv_range_insert_new_allocation + this->priv_forward_range_insert_new_allocation ( container_detail::to_raw_pointer(p) , sz , container_detail::to_raw_pointer(this->m_holder.start()) @@ -1864,18 +1839,21 @@ class vector } } - void priv_shrink_to_fit(allocator_v2) + void priv_shrink_to_fit(allocator_v2) BOOST_CONTAINER_NOEXCEPT { - if(this->m_holder.capacity()){ - if(!size()){ - this->m_holder.deallocate(); + const size_type cp = this->m_holder.capacity(); + if(cp){ + const size_type sz = this->size(); + if(!sz){ + this->m_holder.alloc().deallocate(this->m_holder.m_start, cp); + this->m_holder.m_start = pointer(); + this->m_holder.m_capacity = 0; } else{ size_type received_size; if(this->m_holder.allocation_command ( shrink_in_place | nothrow_allocation - , this->capacity(), this->size() - , received_size, this->m_holder.start()).first){ + , cp, sz, received_size, this->m_holder.start()).first){ this->m_holder.capacity(received_size); #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_shrink; @@ -1893,38 +1871,6 @@ class vector return iterator(pos); } - template - iterator priv_forward_range_insert - (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v0) - { - //Check if we have enough memory or try to expand current memory - const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; - - if (n > remaining){ - //This will trigger an error - throw_bad_alloc(); - } - const size_type n_pos = pos - this->m_holder.start(); - T *const raw_pos = container_detail::to_raw_pointer(pos); - this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy); - return iterator(this->m_holder.start() + n_pos); - } - - template - iterator priv_forward_range_insert_at_end - (const size_type n, const InsertionProxy insert_range_proxy, allocator_v0) - { - //Check if we have enough memory or try to expand current memory - const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; - - if (n > remaining){ - //This will trigger an error - throw_bad_alloc(); - } - this->priv_range_insert_at_end_expand_forward(n, insert_range_proxy); - return this->end(); - } - template iterator priv_forward_range_insert_no_capacity (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) @@ -1938,44 +1884,19 @@ class vector #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_alloc; #endif - this->priv_range_insert_new_allocation + this->priv_forward_range_insert_new_allocation ( new_buf, new_cap, raw_pos, n, insert_range_proxy); return iterator(this->m_holder.start() + n_pos); } - template - iterator priv_forward_range_insert - (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) - { - //Check if we have enough memory or try to expand current memory - const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; - T *const raw_pos = container_detail::to_raw_pointer(pos); - - if (n <= remaining){ - const size_type n_pos = pos - this->m_holder.start(); - this->priv_range_insert_expand_forward - (raw_pos, n, insert_range_proxy); - return iterator(this->m_holder.start() + n_pos); - } - else{ - return this->priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version()); - } - } - - template - iterator priv_forward_range_insert_at_end - (const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) - { - return this->priv_forward_range_insert(vector_iterator_get_ptr(this->cend()), n, insert_range_proxy, allocator_v1()); - } template iterator priv_forward_range_insert_no_capacity (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v2) { //Check if we have enough memory or try to expand current memory - const size_type n_pos = pos - this->m_holder.start(); T *const raw_pos = container_detail::to_raw_pointer(pos); + const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start()); size_type real_cap = 0; //There is not enough memory, allocate a new @@ -1993,14 +1914,14 @@ class vector #endif this->m_holder.capacity(real_cap); //Expand forward - this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy); + this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy); } //Backwards (and possibly forward) expansion else{ #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_expand_bwd; #endif - this->priv_range_insert_expand_backwards + this->priv_forward_range_insert_expand_backwards ( container_detail::to_raw_pointer(ret.first) , real_cap, raw_pos, n, insert_range_proxy); } @@ -2010,7 +1931,7 @@ class vector #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_alloc; #endif - this->priv_range_insert_new_allocation + this->priv_forward_range_insert_new_allocation ( container_detail::to_raw_pointer(ret.first) , real_cap, raw_pos, n, insert_range_proxy); } @@ -2018,6 +1939,42 @@ class vector return iterator(this->m_holder.start() + n_pos); } + template + iterator priv_forward_range_insert + (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v0) + { + //Check if we have enough memory or try to expand current memory + const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; + + if (n > remaining){ + //This will trigger an error + throw_bad_alloc(); + } + const size_type n_pos = pos - this->m_holder.start(); + T *const raw_pos = container_detail::to_raw_pointer(pos); + this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy); + return iterator(this->m_holder.start() + n_pos); + } + + template + iterator priv_forward_range_insert + (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) + { + //Check if we have enough memory or try to expand current memory + const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; + T *const raw_pos = container_detail::to_raw_pointer(pos); + + if (n <= remaining){ + const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start()); + this->priv_forward_range_insert_expand_forward + (raw_pos, n, insert_range_proxy); + return iterator(this->m_holder.start() + n_pos); + } + else{ + return this->priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version()); + } + } + template iterator priv_forward_range_insert (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v2) @@ -2031,13 +1988,35 @@ class vector } else{ //Expand forward - const size_type n_pos = pos - this->m_holder.start(); T *const raw_pos = container_detail::to_raw_pointer(pos); - this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy); + const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start()); + this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy); return iterator(this->m_holder.start() + n_pos); } } + template + iterator priv_forward_range_insert_at_end + (const size_type n, const InsertionProxy insert_range_proxy, allocator_v0) + { + //Check if we have enough memory or try to expand current memory + const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; + + if (n > remaining){ + //This will trigger an error + throw_bad_alloc(); + } + this->priv_forward_range_insert_at_end_expand_forward(n, insert_range_proxy); + return this->end(); + } + + template + iterator priv_forward_range_insert_at_end + (const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) + { + return this->priv_forward_range_insert(vector_iterator_get_ptr(this->cend()), n, insert_range_proxy, allocator_v1()); + } + template iterator priv_forward_range_insert_at_end (const size_type n, const InsertionProxy insert_range_proxy, allocator_v2) @@ -2196,7 +2175,7 @@ class vector private: template - void priv_range_insert_at_end_expand_forward(const size_type n, InsertionProxy insert_range_proxy) + void priv_forward_range_insert_at_end_expand_forward(const size_type n, InsertionProxy insert_range_proxy) { T* const old_finish = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; insert_range_proxy.uninitialized_copy_n_and_update(old_finish, n); @@ -2204,7 +2183,7 @@ class vector } template - void priv_range_insert_expand_forward(T* const pos, const size_type n, InsertionProxy insert_range_proxy) + void priv_forward_range_insert_expand_forward(T* const pos, const size_type n, InsertionProxy insert_range_proxy) { //n can't be 0, because there is nothing to do in that case if(!n) return; @@ -2240,7 +2219,7 @@ class vector this->m_holder.m_size += n; } BOOST_CATCH(...){ - destroy_alloc_n(this->get_stored_allocator(), pos + n, elems_after); + boost::container::destroy_alloc_n(this->get_stored_allocator(), pos + n, elems_after); BOOST_RETHROW } BOOST_CATCH_END @@ -2248,7 +2227,7 @@ class vector } template - void priv_range_insert_new_allocation + void priv_forward_range_insert_new_allocation (T* const new_start, size_type new_cap, T* const pos, const size_type n, InsertionProxy insert_range_proxy) { //n can be zero, if we want to reallocate! @@ -2278,7 +2257,7 @@ class vector //Destroy and deallocate old elements //If there is allocated memory, destroy and deallocate if(!value_traits::trivial_dctr_after_move) - destroy_alloc_n(this->get_stored_allocator(), old_buffer, this->m_holder.m_size); + boost::container::destroy_alloc_n(this->get_stored_allocator(), old_buffer, this->m_holder.m_size); this->m_holder.alloc().deallocate(this->m_holder.start(), this->m_holder.capacity()); } this->m_holder.start(new_start); @@ -2290,7 +2269,7 @@ class vector } template - void priv_range_insert_expand_backwards + void priv_forward_range_insert_expand_backwards (T* const new_start, const size_type new_capacity, T* const pos, const size_type n, InsertionProxy insert_range_proxy) { @@ -2374,7 +2353,7 @@ class vector //they have trivial destructor after move size_type n_destroy = old_finish - to_destroy; if(!value_traits::trivial_dctr_after_move) - destroy_alloc_n(this->get_stored_allocator(), to_destroy, n_destroy); + boost::container::destroy_alloc_n(this->get_stored_allocator(), to_destroy, n_destroy); this->m_holder.m_size -= n_destroy; } } @@ -2448,7 +2427,7 @@ class vector //they have trivial destructor after being moved const size_type n_destroy = s_before - n; if(!value_traits::trivial_dctr_after_move) - destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy); + boost::container::destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy); this->m_holder.m_size -= n_destroy; } } @@ -2504,7 +2483,7 @@ class vector //have trivial destructor after being moved size_type n_destroy = s_before - n; if(!value_traits::trivial_dctr_after_move) - destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy); + boost::container::destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy); this->m_holder.m_size -= n_destroy; } } @@ -2585,7 +2564,7 @@ class vector this->m_holder.m_size += n_after; } BOOST_CATCH(...){ - destroy_alloc_n(this->get_stored_allocator(), pos, mid_last_dist); + boost::container::destroy_alloc_n(this->get_stored_allocator(), pos, mid_last_dist); BOOST_RETHROW } BOOST_CATCH_END diff --git a/proj/vc7ide/container.vcproj b/proj/vc7ide/container.vcproj index 9f42b17..21e2815 100644 --- a/proj/vc7ide/container.vcproj +++ b/proj/vc7ide/container.vcproj @@ -95,93 +95,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -331,6 +244,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 25add18..af84010 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -21,7 +21,7 @@ rule test_all for local fileb in [ glob *.cpp ] { - all_rules += [ run $(fileb) /boost/timer//boost_timer /boost/system//boost_system /boost/thread//boost_thread + all_rules += [ run $(fileb) : # additional args : # test-files : # requirements diff --git a/test/dummy_test_allocator.hpp b/test/dummy_test_allocator.hpp index 993cccf..afdd042 100644 --- a/test/dummy_test_allocator.hpp +++ b/test/dummy_test_allocator.hpp @@ -314,15 +314,20 @@ class propagation_test_allocator friend bool operator!=(const propagation_test_allocator &, const propagation_test_allocator &) { return false; } + void swap(propagation_test_allocator &r) + { + ++this->swaps_; ++r.swaps_; + boost::container::swap_dispatch(this->id_, r.id_); + boost::container::swap_dispatch(this->ctr_copies_, r.ctr_copies_); + boost::container::swap_dispatch(this->ctr_moves_, r.ctr_moves_); + boost::container::swap_dispatch(this->assign_copies_, r.assign_copies_); + boost::container::swap_dispatch(this->assign_moves_, r.assign_moves_); + boost::container::swap_dispatch(this->swaps_, r.swaps_); + } + friend void swap(propagation_test_allocator &l, propagation_test_allocator &r) { - ++l.swaps_; ++r.swaps_; - container_detail::do_swap(l.id_, r.id_); - container_detail::do_swap(l.ctr_copies_, r.ctr_copies_); - container_detail::do_swap(l.ctr_moves_, r.ctr_moves_); - container_detail::do_swap(l.assign_copies_, r.assign_copies_); - container_detail::do_swap(l.assign_moves_, r.assign_moves_); - container_detail::do_swap(l.swaps_, r.swaps_); + l.swap(r); } unsigned int id_; diff --git a/test/expand_bwd_test_allocator.hpp b/test/expand_bwd_test_allocator.hpp index 882552a..81bf016 100644 --- a/test/expand_bwd_test_allocator.hpp +++ b/test/expand_bwd_test_allocator.hpp @@ -112,9 +112,9 @@ class expand_bwd_test_allocator friend void swap(self_t &alloc1, self_t &alloc2) { - container_detail::do_swap(alloc1.mp_buffer, alloc2.mp_buffer); - container_detail::do_swap(alloc1.m_size, alloc2.m_size); - container_detail::do_swap(alloc1.m_offset, alloc2.m_offset); + boost::container::swap_dispatch(alloc1.mp_buffer, alloc2.mp_buffer); + boost::container::swap_dispatch(alloc1.m_size, alloc2.m_size); + boost::container::swap_dispatch(alloc1.m_offset, alloc2.m_offset); } //Experimental version 2 expand_bwd_test_allocator functions diff --git a/test/heap_allocator_v1.hpp b/test/heap_allocator_v1.hpp index b7724d2..43603f7 100644 --- a/test/heap_allocator_v1.hpp +++ b/test/heap_allocator_v1.hpp @@ -133,7 +133,7 @@ class heap_allocator_v1 //!Swap segment manager. Does not throw. If each heap_allocator_v1 is placed in //!different memory segments, the result is undefined. friend void swap(self_t &alloc1, self_t &alloc2) - { detail::do_swap(alloc1.mp_mngr, alloc2.mp_mngr); } + { boost::container::boost::container::swap_dispatch(alloc1.mp_mngr, alloc2.mp_mngr); } }; //!Equality test for same type of heap_allocator_v1 diff --git a/test/vector_test.hpp b/test/vector_test.hpp index 3771eaf..aba9ee4 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -80,6 +80,12 @@ bool vector_copyable_only(V1 *boostvector, V2 *stdvector, boost::container::cont stdvector->push_back(int(3)); if(!test::CheckEqualContainers(boostvector, stdvector)) return false; } + { + V1 *pv1 = new V1(*boostvector); + V2 *pv2 = new V2(*stdvector); + delete pv1; + delete pv2; + } return true; }