|
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