Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r84991 - in trunk: boost/circular_buffer libs/circular_buffer/test
From: antoshkka_at_[hidden]
Date: 2013-07-09 11:06:16


Author: apolukhin
Date: 2013-07-09 11:06:16 EDT (Tue, 09 Jul 2013)
New Revision: 84991
URL: http://svn.boost.org/trac/boost/changeset/84991

Log:
Improved rvalues move support for elements of circular_buffer (refs #7888):
* set_capacity and rset_capacity now work with move-only types if move constructor of type marked with `noexcept`
* force placement ::new usage
* minor optimizations (move values in more cases)
* more tests

Text files modified:
   trunk/boost/circular_buffer/base.hpp | 46 ++++++++++++----------
   trunk/boost/circular_buffer/details.hpp | 77 +++++++++++++++++++++++++++++----------
   trunk/libs/circular_buffer/test/base_test.cpp | 48 ++++++++++++++++++++++++
   3 files changed, 129 insertions(+), 42 deletions(-)

Modified: trunk/boost/circular_buffer/base.hpp
==============================================================================
--- trunk/boost/circular_buffer/base.hpp Tue Jul 9 09:50:24 2013 (r84990)
+++ trunk/boost/circular_buffer/base.hpp 2013-07-09 11:06:16 EDT (Tue, 09 Jul 2013) (r84991)
@@ -691,7 +691,7 @@
                         break;
                     }
                     if (is_uninitialized(dest)) {
- new (dest) value_type(this_type::move_if_noexcept(*src));
+ ::new (dest) value_type(this_type::move_if_noexcept(*src));
                         ++constructed;
                     } else {
                         value_type tmp = this_type::move_if_noexcept(*src);
@@ -876,7 +876,9 @@
     capacity_type capacity() const BOOST_NOEXCEPT { return m_end - m_buff; }
 
     //! Change the capacity of the <code>circular_buffer</code>.
- /*!
+ /*!
+ \pre If <code>T</code> is a move only type, then compiler shall support <code>noexcept</code> modifiers
+ and move constructor of <code>T</code> must be marked with it (must not throw exceptions).
         \post <code>capacity() == new_capacity \&\& size() \<= new_capacity</code><br><br>
               If the current number of elements stored in the <code>circular_buffer</code> is greater than the desired
               new capacity then number of <code>[size() - new_capacity]</code> <b>last</b> elements will be removed and
@@ -902,7 +904,7 @@
         iterator b = begin();
         BOOST_TRY {
             reset(buff,
- cb_details::uninitialized_copy_with_alloc(b, b + (std::min)(new_capacity, size()), buff, m_alloc),
+ cb_details::uninitialized_move_if_noexcept<value_type>(b, b + (std::min)(new_capacity, size()), buff),
                 new_capacity);
         } BOOST_CATCH(...) {
             deallocate(buff, new_capacity);
@@ -950,7 +952,9 @@
     }
 
     //! Change the capacity of the <code>circular_buffer</code>.
- /*!
+ /*!
+ \pre If <code>T</code> is a move only type, then compiler shall support <code>noexcept</code> modifiers
+ and move constructor of <code>T</code> must be marked with it (must not throw exceptions).
         \post <code>capacity() == new_capacity \&\& size() \<= new_capacity</code><br><br>
               If the current number of elements stored in the <code>circular_buffer</code> is greater than the desired
               new capacity then number of <code>[size() - new_capacity]</code> <b>first</b> elements will be removed
@@ -975,8 +979,8 @@
         pointer buff = allocate(new_capacity);
         iterator e = end();
         BOOST_TRY {
- reset(buff, cb_details::uninitialized_copy_with_alloc(e - (std::min)(new_capacity, size()),
- e, buff, m_alloc), new_capacity);
+ reset(buff, cb_details::uninitialized_move_if_noexcept<value_type>(e - (std::min)(new_capacity, size()),
+ e, buff), new_capacity);
         } BOOST_CATCH(...) {
             deallocate(buff, new_capacity);
             BOOST_RETHROW
@@ -1124,7 +1128,7 @@
         initialize_buffer(cb.capacity());
         m_first = m_buff;
         BOOST_TRY {
- m_last = cb_details::uninitialized_copy_with_alloc(cb.begin(), cb.end(), m_buff, m_alloc);
+ m_last = cb_details::uninitialized_copy<value_type>(cb.begin(), cb.end(), m_buff);
         } BOOST_CATCH(...) {
             deallocate(m_buff, cb.capacity());
             BOOST_RETHROW
@@ -1269,7 +1273,7 @@
             return *this;
         pointer buff = allocate(cb.capacity());
         BOOST_TRY {
- reset(buff, cb_details::uninitialized_copy_with_alloc(cb.begin(), cb.end(), buff, m_alloc), cb.capacity());
+ reset(buff, cb_details::uninitialized_copy<value_type>(cb.begin(), cb.end(), buff), cb.capacity());
         } BOOST_CATCH(...) {
             deallocate(buff, cb.capacity());
             BOOST_RETHROW
@@ -1465,7 +1469,7 @@
             increment(m_last);
             m_first = m_last;
         } else {
- new (m_last) value_type(static_cast<ValT>(item));
+ ::new (m_last) value_type(static_cast<ValT>(item));
             increment(m_last);
             ++m_size;
         }
@@ -1482,7 +1486,7 @@
                 m_last = m_first;
             } else {
                 decrement(m_first);
- new (m_first) value_type(static_cast<ValT>(item));
+ ::new (m_first) value_type(static_cast<ValT>(item));
                 ++m_size;
             }
         } BOOST_CATCH(...) {
@@ -2446,7 +2450,7 @@
     */
     void construct_or_replace(bool construct, pointer pos, param_value_type item) {
         if (construct)
- new (pos) value_type(item);
+ ::new (pos) value_type(item);
         else
             replace(pos, item);
     }
@@ -2458,7 +2462,7 @@
     */
     void construct_or_replace(bool construct, pointer pos, rvalue_type item) {
         if (construct)
- new (pos) value_type(boost::move(item));
+ ::new (pos) value_type(boost::move(item));
         else
             replace(pos, boost::move(item));
     }
@@ -2598,7 +2602,7 @@
         if (buffer_capacity == 0)
             return;
         while (first != last && !full()) {
- new (m_last) value_type(*first++);
+ ::new (m_last) value_type(*first++);
             increment(m_last);
             ++m_size;
         }
@@ -2634,7 +2638,7 @@
             m_size = distance;
         }
         BOOST_TRY {
- m_last = cb_details::uninitialized_copy_with_alloc(first, last, m_buff, m_alloc);
+ m_last = cb_details::uninitialized_copy<value_type>(first, last, m_buff);
         } BOOST_CATCH(...) {
             deallocate(m_buff, buffer_capacity);
             BOOST_RETHROW
@@ -2688,8 +2692,8 @@
         std::deque<value_type, allocator_type> tmp(first, last, m_alloc);
         size_type distance = tmp.size();
         assign_n(distance, distance,
- cb_details::assign_range<BOOST_DEDUCED_TYPENAME std::deque<value_type, allocator_type>::iterator,
- allocator_type>(tmp.begin(), tmp.end(), m_alloc));
+ cb_details::make_assign_range<value_type>
+ (boost::make_move_iterator(tmp.begin()), boost::make_move_iterator(tmp.end())));
     }
 
     //! Specialized assign method.
@@ -2697,7 +2701,7 @@
     void assign(ForwardIterator first, ForwardIterator last, const std::forward_iterator_tag&) {
         BOOST_CB_ASSERT(std::distance(first, last) >= 0); // check for wrong range
         size_type distance = std::distance(first, last);
- assign_n(distance, distance, cb_details::assign_range<ForwardIterator, allocator_type>(first, last, m_alloc));
+ assign_n(distance, distance, cb_details::make_assign_range<value_type>(first, last));
     }
 
     //! Specialized assign method.
@@ -2745,7 +2749,7 @@
             distance = new_capacity;
         }
         assign_n(new_capacity, distance,
- cb_details::assign_range<ForwardIterator, allocator_type>(first, last, m_alloc));
+ cb_details::make_assign_range<value_type>(first, last));
     }
 
     //! Helper assign method.
@@ -2836,7 +2840,7 @@
     void insert(iterator pos, InputIterator first, InputIterator last, const std::input_iterator_tag&) {
         if (!full() || pos != begin()) {
             for (;first != last; ++pos)
- pos = insert_item<param_value_type>(pos, *first++); // TODO: optimize for cases when InputIterator is move iterator
+ pos = insert(pos, *first++);
         }
     }
 
@@ -2868,7 +2872,7 @@
             pointer p = m_last;
             BOOST_TRY {
                 for (; ii < construct; ++ii, increment(p))
- new (p) value_type(*wrapper());
+ ::new (p) value_type(*wrapper());
                 for (;ii < n; ++ii, increment(p))
                     replace(p, *wrapper());
             } BOOST_CATCH(...) {
@@ -2962,7 +2966,7 @@
                 for (;ii > construct; --ii, increment(p))
                     replace(p, *wrapper());
                 for (; ii > 0; --ii, increment(p))
- new (p) value_type(*wrapper());
+ ::new (p) value_type(*wrapper());
             } BOOST_CATCH(...) {
                 size_type constructed = ii < construct ? construct - ii : 0;
                 m_last = add(m_last, constructed);

Modified: trunk/boost/circular_buffer/details.hpp
==============================================================================
--- trunk/boost/circular_buffer/details.hpp Tue Jul 9 09:50:24 2013 (r84990)
+++ trunk/boost/circular_buffer/details.hpp 2013-07-09 11:06:16 EDT (Tue, 09 Jul 2013) (r84991)
@@ -15,6 +15,8 @@
 
 #include <boost/iterator.hpp>
 #include <boost/throw_exception.hpp>
+#include <boost/move/move.hpp>
+#include <boost/type_traits/is_nothrow_move_constructible.hpp>
 #include <boost/detail/no_exceptions_support.hpp>
 #include <iterator>
 
@@ -36,9 +38,11 @@
 void uninitialized_fill_n_with_alloc(
     ForwardIterator first, Diff n, const T& item, Alloc& alloc);
 
-template<class InputIterator, class ForwardIterator, class Alloc>
-ForwardIterator uninitialized_copy_with_alloc(
- InputIterator first, InputIterator last, ForwardIterator dest, Alloc& alloc);
+template<class ValueType, class InputIterator, class ForwardIterator>
+ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest);
+
+template<class ValueType, class InputIterator, class ForwardIterator>
+ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest);
 
 /*!
     \struct const_traits
@@ -123,21 +127,25 @@
     \struct assign_range
     \brief Helper functor for assigning range of items.
 */
-template <class Iterator, class Alloc>
+template <class ValueType, class Iterator>
 struct assign_range {
- const Iterator& m_first;
- const Iterator& m_last;
- Alloc& m_alloc;
- assign_range(const Iterator& first, const Iterator& last, Alloc& alloc)
- : m_first(first), m_last(last), m_alloc(alloc) {}
+ Iterator m_first;
+ Iterator m_last;
+
+ assign_range(const Iterator& first, const Iterator& last) BOOST_NOEXCEPT
+ : m_first(first), m_last(last) {}
+
     template <class Pointer>
     void operator () (Pointer p) const {
- uninitialized_copy_with_alloc(m_first, m_last, p, m_alloc);
+ boost::cb_details::uninitialized_copy<ValueType>(m_first, m_last, p);
     }
-private:
- assign_range<Iterator, Alloc>& operator = (const assign_range<Iterator, Alloc>&); // do not generate
 };
 
+template <class ValueType, class Iterator>
+inline assign_range<ValueType, Iterator> make_assign_range(const Iterator& first, const Iterator& last) {
+ return assign_range<ValueType, Iterator>(first, last);
+}
+
 /*!
     \class capacity_control
     \brief Capacity controller of the space optimized circular buffer.
@@ -434,26 +442,53 @@
 #endif // #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_MSVC_STD_ITERATOR)
 
 /*!
- \fn ForwardIterator uninitialized_copy_with_alloc(InputIterator first, InputIterator last, ForwardIterator dest,
- Alloc& alloc)
- \brief Equivalent of <code>std::uninitialized_copy</code> with allocator.
-*/
-template<class InputIterator, class ForwardIterator, class Alloc>
-inline ForwardIterator uninitialized_copy_with_alloc(InputIterator first, InputIterator last, ForwardIterator dest,
- Alloc& alloc) {
+ \fn ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest)
+ \brief Equivalent of <code>std::uninitialized_copy</code> but with explicit specification of value type.
+*/
+template<class ValueType, class InputIterator, class ForwardIterator>
+inline ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest) {
+ typedef ValueType value_type;
+
+ // We do not use allocator.construct and allocator.destroy
+ // because C++03 requires to take parameter by const reference but
+ // Boost.move requires nonconst reference
     ForwardIterator next = dest;
     BOOST_TRY {
         for (; first != last; ++first, ++dest)
- alloc.construct(dest, *first);
+ ::new (dest) value_type(*first);
     } BOOST_CATCH(...) {
         for (; next != dest; ++next)
- alloc.destroy(next);
+ next->~value_type();
         BOOST_RETHROW
     }
     BOOST_CATCH_END
     return dest;
 }
 
+template<class ValueType, class InputIterator, class ForwardIterator>
+ForwardIterator uninitialized_move_if_noexcept_impl(InputIterator first, InputIterator last, ForwardIterator dest,
+ true_type) {
+ for (; first != last; ++first, ++dest)
+ ::new (dest) ValueType(boost::move(*first));
+ return dest;
+}
+
+template<class ValueType, class InputIterator, class ForwardIterator>
+ForwardIterator uninitialized_move_if_noexcept_impl(InputIterator first, InputIterator last, ForwardIterator dest,
+ false_type) {
+ return uninitialized_copy<ValueType>(first, last, dest);
+}
+
+/*!
+ \fn ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest)
+ \brief Equivalent of <code>std::uninitialized_copy</code> but with explicit specification of value type and moves elements if they have noexcept move constructors.
+*/
+template<class ValueType, class InputIterator, class ForwardIterator>
+ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest) {
+ typedef typename boost::is_nothrow_move_constructible<ValueType>::type tag_t;
+ return uninitialized_move_if_noexcept_impl<ValueType>(first, last, dest, tag_t());
+}
+
 /*!
     \fn void uninitialized_fill_n_with_alloc(ForwardIterator first, Diff n, const T& item, Alloc& alloc)
     \brief Equivalent of <code>std::uninitialized_fill_n</code> with allocator.

Modified: trunk/libs/circular_buffer/test/base_test.cpp
==============================================================================
--- trunk/libs/circular_buffer/test/base_test.cpp Tue Jul 9 09:50:24 2013 (r84990)
+++ trunk/libs/circular_buffer/test/base_test.cpp 2013-07-09 11:06:16 EDT (Tue, 09 Jul 2013) (r84991)
@@ -900,6 +900,54 @@
     BOOST_CHECK(!cb1[5].is_moved());
     BOOST_CHECK(!cb1[6].is_moved());
     BOOST_CHECK(!cb1[7].is_moved());
+
+#ifndef BOOST_NO_CXX11_NOEXCEPT
+ cb1.set_capacity(100);
+ BOOST_CHECK(!cb1[0].is_moved());
+ BOOST_CHECK(!cb1[1].is_moved());
+ BOOST_CHECK(!cb1[2].is_moved());
+ BOOST_CHECK(!cb1[3].is_moved());
+ BOOST_CHECK(!cb1[4].is_moved());
+ BOOST_CHECK(!cb1[5].is_moved());
+ BOOST_CHECK(!cb1[6].is_moved());
+ BOOST_CHECK(!cb1[7].is_moved());
+ BOOST_CHECK(cb1[0].value() == 6);
+ BOOST_CHECK(cb1[1].value() == 5);
+ BOOST_CHECK(cb1[2].value() == 4);
+ BOOST_CHECK(cb1[3].value() == 2);
+ BOOST_CHECK(cb1[4].value() == 1);
+ BOOST_CHECK(cb1[5].value() == 3);
+ BOOST_CHECK(cb1[6].value() == 8);
+ BOOST_CHECK(cb1[7].value() == 7);
+
+ cb1.rset_capacity(101);
+ BOOST_CHECK(!cb1[0].is_moved());
+ BOOST_CHECK(!cb1[1].is_moved());
+ BOOST_CHECK(!cb1[2].is_moved());
+ BOOST_CHECK(!cb1[3].is_moved());
+ BOOST_CHECK(!cb1[4].is_moved());
+ BOOST_CHECK(!cb1[5].is_moved());
+ BOOST_CHECK(!cb1[6].is_moved());
+ BOOST_CHECK(!cb1[7].is_moved());
+ BOOST_CHECK(cb1[0].value() == 6);
+ BOOST_CHECK(cb1[1].value() == 5);
+ BOOST_CHECK(cb1[2].value() == 4);
+ BOOST_CHECK(cb1[3].value() == 2);
+ BOOST_CHECK(cb1[4].value() == 1);
+ BOOST_CHECK(cb1[5].value() == 3);
+ BOOST_CHECK(cb1[6].value() == 8);
+ BOOST_CHECK(cb1[7].value() == 7);
+
+ cb1.set_capacity(2);
+ BOOST_CHECK(!cb1[0].is_moved());
+ BOOST_CHECK(!cb1[1].is_moved());
+ BOOST_CHECK(cb1[0].value() == 6);
+ BOOST_CHECK(cb1[1].value() == 5);
+
+ cb1.rset_capacity(1);
+ BOOST_CHECK(!cb1[0].is_moved());
+ BOOST_CHECK(cb1[0].value() == 5);
+#endif
 }
 
 void move_container_values_resetting() {


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk