|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r84984 - in trunk: boost/circular_buffer libs/circular_buffer/test
From: antoshkka_at_[hidden]
Date: 2013-07-08 09:41:58
Author: apolukhin
Date: 2013-07-08 09:41:58 EDT (Mon, 08 Jul 2013)
New Revision: 84984
URL: http://svn.boost.org/trac/boost/changeset/84984
Log:
Add basic rvalues move support for elements of circular_buffer (refs #7888). Patch uses Boost.Move to emulate rvalues in C++03
Text files modified:
trunk/boost/circular_buffer/base.hpp | 467 ++++++++++++++++++++++++++++++++-------
trunk/libs/circular_buffer/test/base_test.cpp | 164 +++++++++++++
2 files changed, 539 insertions(+), 92 deletions(-)
Modified: trunk/boost/circular_buffer/base.hpp
==============================================================================
--- trunk/boost/circular_buffer/base.hpp Mon Jul 8 09:12:18 2013 (r84983)
+++ trunk/boost/circular_buffer/base.hpp 2013-07-08 09:41:58 EDT (Mon, 08 Jul 2013) (r84984)
@@ -24,6 +24,9 @@
#include <boost/type_traits/is_stateless.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_scalar.hpp>
+#include <boost/type_traits/is_nothrow_move_constructible.hpp>
+#include <boost/type_traits/conditional.hpp>
+#include <boost/move/move.hpp>
#include <algorithm>
#include <utility>
#include <deque>
@@ -41,6 +44,8 @@
}
#endif
+
+
namespace boost {
/*!
@@ -77,7 +82,7 @@
{
// Requirements
- BOOST_CLASS_REQUIRE(T, boost, SGIAssignableConcept);
+ //BOOST_CLASS_REQUIRE(T, boost, SGIAssignableConcept);
//BOOST_CONCEPT_ASSERT((Assignable<T>));
@@ -90,6 +95,9 @@
public:
// Basic types
+
+ //! The type of this <code>circular_buffer</code>.
+ typedef circular_buffer<T, Alloc> this_type;
//! The type of elements stored in the <code>circular_buffer</code>.
typedef typename Alloc::value_type value_type;
@@ -165,12 +173,32 @@
// Helper types
// A type representing the "best" way to pass the value_type to a method.
- typedef typename call_traits<value_type>::param_type param_value_type;
+ //typedef typename call_traits<value_type>::param_type param_value_type;
+ typedef const value_type& param_value_type;
// A type representing the "best" way to return the value_type from a const method.
//typedef typename call_traits<value_type>::param_type return_value_type;
+ // A type representing rvalue from param type.
+ typedef BOOST_RV_REF(value_type) rvalue_type;
+
private:
+
+ // TODO: move to Boost.Move
+ // TODO: Improve!
+ template <class ValT>
+ static inline typename boost::conditional<
+ (boost::is_nothrow_move_constructible<ValT>::value /* || !boost::has_copy_constructor<T>::value*/)
+#ifdef BOOST_NO_CXX11_DELETED_FUNCTIONS
+ && has_move_emulation_enabled<T>::value
+#endif
+ ,
+ rvalue_type,
+ param_value_type
+ >::type move_if_noexcept(ValT& value) BOOST_NOEXCEPT {
+ return boost::move(value);
+ }
+
// Member variables
//! The internal buffer used for storing elements in the circular buffer.
@@ -662,12 +690,12 @@
break;
}
if (is_uninitialized(dest)) {
- m_alloc.construct(dest, *src);
+ new (dest) value_type(*src);
++constructed;
} else {
- value_type tmp = *src;
- replace(src, *dest);
- replace(dest, tmp);
+ value_type tmp = this_type::move_if_noexcept(*src);
+ replace(src, this_type::move_if_noexcept(*dest));
+ replace(dest, boost::move(tmp));
}
}
}
@@ -742,12 +770,12 @@
difference_type n = new_begin - begin();
if (m < n) {
for (; m > 0; --m) {
- push_front(back());
+ push_front(this_type::move_if_noexcept(back()));
pop_back();
}
} else {
for (; n > 0; --n) {
- push_back(front());
+ push_back(this_type::move_if_noexcept(front()));
pop_front();
}
}
@@ -1426,7 +1454,44 @@
}
// push and pop
+private:
+ template <class ValT>
+ void push_back_impl(ValT item) {
+ if (full()) {
+ if (empty())
+ return;
+ replace(m_last, static_cast<ValT>(item));
+ increment(m_last);
+ m_first = m_last;
+ } else {
+ new (m_last) value_type(static_cast<ValT>(item));
+ increment(m_last);
+ ++m_size;
+ }
+ }
+
+ template <class ValT>
+ void push_front_impl(ValT item) {
+ BOOST_TRY {
+ if (full()) {
+ if (empty())
+ return;
+ decrement(m_first);
+ replace(m_first, static_cast<ValT>(item));
+ m_last = m_first;
+ } else {
+ decrement(m_first);
+ new (m_first) value_type(static_cast<ValT>(item));
+ ++m_size;
+ }
+ } BOOST_CATCH(...) {
+ increment(m_first);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ }
+public:
//! Insert a new element at the end of the <code>circular_buffer</code>.
/*!
\post if <code>capacity() > 0</code> then <code>back() == item</code><br>
@@ -1444,18 +1509,51 @@
\sa <code>\link push_front() push_front(const_reference)\endlink</code>,
<code>pop_back()</code>, <code>pop_front()</code>
*/
- void push_back(param_value_type item = value_type()) {
- if (full()) {
- if (empty())
- return;
- replace(m_last, item);
- increment(m_last);
- m_first = m_last;
- } else {
- m_alloc.construct(m_last, item);
- increment(m_last);
- ++m_size;
- }
+ void push_back(param_value_type item) {
+ push_back_impl<param_value_type>(item);
+ }
+
+ //! Insert a new element at the end of the <code>circular_buffer</code> using rvalue references or rvalues references emulation.
+ /*!
+ \post if <code>capacity() > 0</code> then <code>back() == item</code><br>
+ If the <code>circular_buffer</code> is full, the first element will be removed. If the capacity is
+ <code>0</code>, nothing will be inserted.
+ \param item The element to be inserted.
+ \throws Whatever <code>T::T(T&&)</code> throws.
+ \throws Whatever <code>T::operator = (T&&)</code> throws.
+ \par Exception Safety
+ Basic; no-throw if the operation in the <i>Throws</i> section does not throw anything.
+ \par Iterator Invalidation
+ Does not invalidate any iterators with the exception of iterators pointing to the overwritten element.
+ \par Complexity
+ Constant (in the size of the <code>circular_buffer</code>).
+ \sa <code>\link push_front() push_front(const_reference)\endlink</code>,
+ <code>pop_back()</code>, <code>pop_front()</code>
+ */
+ void push_back(rvalue_type item) {
+ push_back_impl<rvalue_type>(boost::move(item));
+ }
+
+ //! Insert a new default-constructed element at the end of the <code>circular_buffer</code>.
+ /*!
+ \post if <code>capacity() > 0</code> then <code>back() == item</code><br>
+ If the <code>circular_buffer</code> is full, the first element will be removed. If the capacity is
+ <code>0</code>, nothing will be inserted.
+ \throws Whatever <code>T::T()</code> throws.
+ \throws Whatever <code>T::T(T&&)</code> throws.
+ \throws Whatever <code>T::operator = (T&&)</code> throws.
+ \par Exception Safety
+ Basic; no-throw if the operation in the <i>Throws</i> section does not throw anything.
+ \par Iterator Invalidation
+ Does not invalidate any iterators with the exception of iterators pointing to the overwritten element.
+ \par Complexity
+ Constant (in the size of the <code>circular_buffer</code>).
+ \sa <code>\link push_front() push_front(const_reference)\endlink</code>,
+ <code>pop_back()</code>, <code>pop_front()</code>
+ */
+ void push_back() {
+ value_type temp;
+ push_back(boost::move(temp));
}
//! Insert a new element at the beginning of the <code>circular_buffer</code>.
@@ -1475,24 +1573,51 @@
\sa <code>\link push_back() push_back(const_reference)\endlink</code>,
<code>pop_back()</code>, <code>pop_front()</code>
*/
- void push_front(param_value_type item = value_type()) {
- BOOST_TRY {
- if (full()) {
- if (empty())
- return;
- decrement(m_first);
- replace(m_first, item);
- m_last = m_first;
- } else {
- decrement(m_first);
- m_alloc.construct(m_first, item);
- ++m_size;
- }
- } BOOST_CATCH(...) {
- increment(m_first);
- BOOST_RETHROW
- }
- BOOST_CATCH_END
+ void push_front(param_value_type item) {
+ push_front_impl<param_value_type>(item);
+ }
+
+ //! Insert a new element at the beginning of the <code>circular_buffer</code> using rvalue references or rvalues references emulation.
+ /*!
+ \post if <code>capacity() > 0</code> then <code>front() == item</code><br>
+ If the <code>circular_buffer</code> is full, the last element will be removed. If the capacity is
+ <code>0</code>, nothing will be inserted.
+ \param item The element to be inserted.
+ \throws Whatever <code>T::T(T&&)</code> throws.
+ \throws Whatever <code>T::operator = (T&&)</code> throws.
+ \par Exception Safety
+ Basic; no-throw if the operation in the <i>Throws</i> section does not throw anything.
+ \par Iterator Invalidation
+ Does not invalidate any iterators with the exception of iterators pointing to the overwritten element.
+ \par Complexity
+ Constant (in the size of the <code>circular_buffer</code>).
+ \sa <code>\link push_back() push_back(const_reference)\endlink</code>,
+ <code>pop_back()</code>, <code>pop_front()</code>
+ */
+ void push_front(rvalue_type item) {
+ push_front_impl<rvalue_type>(boost::move(item));
+ }
+
+ //! Insert a new default-constructed element at the beginning of the <code>circular_buffer</code>.
+ /*!
+ \post if <code>capacity() > 0</code> then <code>front() == item</code><br>
+ If the <code>circular_buffer</code> is full, the last element will be removed. If the capacity is
+ <code>0</code>, nothing will be inserted.
+ \throws Whatever <code>T::T()</code> throws.
+ \throws Whatever <code>T::T(T&&)</code> throws.
+ \throws Whatever <code>T::operator = (T&&)</code> throws.
+ \par Exception Safety
+ Basic; no-throw if the operation in the <i>Throws</i> section does not throw anything.
+ \par Iterator Invalidation
+ Does not invalidate any iterators with the exception of iterators pointing to the overwritten element.
+ \par Complexity
+ Constant (in the size of the <code>circular_buffer</code>).
+ \sa <code>\link push_back() push_back(const_reference)\endlink</code>,
+ <code>pop_back()</code>, <code>pop_front()</code>
+ */
+ void push_front() {
+ value_type temp;
+ push_front(boost::move(temp));
}
//! Remove the last element from the <code>circular_buffer</code>.
@@ -1536,6 +1661,15 @@
increment(m_first);
--m_size;
}
+private:
+ template <class ValT>
+ iterator insert_impl(iterator pos, ValT item) {
+ BOOST_CB_ASSERT(pos.is_valid(this)); // check for uninitialized or invalidated iterator
+ iterator b = begin();
+ if (full() && pos == b)
+ return b;
+ return insert_item<ValT>(pos, static_cast<ValT>(item));
+ }
public:
// Insert
@@ -1569,12 +1703,76 @@
rinsert(iterator, size_type, value_type)\endlink</code>,
<code>rinsert(iterator, InputIterator, InputIterator)</code>
*/
- iterator insert(iterator pos, param_value_type item = value_type()) {
- BOOST_CB_ASSERT(pos.is_valid(this)); // check for uninitialized or invalidated iterator
- iterator b = begin();
- if (full() && pos == b)
- return b;
- return insert_item(pos, item);
+ iterator insert(iterator pos, param_value_type item) {
+ return insert_impl<param_value_type>(pos, item);
+ }
+
+ //! Insert an element at the specified position.
+ /*!
+ \pre <code>pos</code> is a valid iterator pointing to the <code>circular_buffer</code> or its end.
+ \post The <code>item</code> will be inserted at the position <code>pos</code>.<br>
+ If the <code>circular_buffer</code> is full, the first element will be overwritten. If the
+ <code>circular_buffer</code> is full and the <code>pos</code> points to <code>begin()</code>, then the
+ <code>item</code> will not be inserted. If the capacity is <code>0</code>, nothing will be inserted.
+ \param pos An iterator specifying the position where the <code>item</code> will be inserted.
+ \param item The element to be inserted.
+ \return Iterator to the inserted element or <code>begin()</code> if the <code>item</code> is not inserted. (See
+ the <i>Effect</i>.)
+ \throws Whatever <code>T::T(T&&)</code> throws.
+ \throws Whatever <code>T::operator = (T&&)</code> throws.
+ \par Exception Safety
+ Basic; no-throw if the operation in the <i>Throws</i> section does not throw anything.
+ \par Iterator Invalidation
+ Invalidates iterators pointing to the elements at the insertion point (including <code>pos</code>) and
+ iterators behind the insertion point (towards the end; except iterators equal to <code>end()</code>). It
+ also invalidates iterators pointing to the overwritten element.
+ \par Complexity
+ Linear (in <code>std::distance(pos, end())</code>).
+ \sa <code>\link insert(iterator, size_type, param_value_type)
+ insert(iterator, size_type, value_type)\endlink</code>,
+ <code>insert(iterator, InputIterator, InputIterator)</code>,
+ <code>\link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink</code>,
+ <code>\link rinsert(iterator, size_type, param_value_type)
+ rinsert(iterator, size_type, value_type)\endlink</code>,
+ <code>rinsert(iterator, InputIterator, InputIterator)</code>
+ */
+ iterator insert(iterator pos, rvalue_type item) {
+ return insert_impl<rvalue_type>(pos, boost::move(item));
+ }
+
+ //! Insert a default-constructed element at the specified position.
+ /*!
+ \pre <code>pos</code> is a valid iterator pointing to the <code>circular_buffer</code> or its end.
+ \post The <code>item</code> will be inserted at the position <code>pos</code>.<br>
+ If the <code>circular_buffer</code> is full, the first element will be overwritten. If the
+ <code>circular_buffer</code> is full and the <code>pos</code> points to <code>begin()</code>, then the
+ <code>item</code> will not be inserted. If the capacity is <code>0</code>, nothing will be inserted.
+ \param pos An iterator specifying the position where the <code>item</code> will be inserted.
+ \param item The element to be inserted.
+ \return Iterator to the inserted element or <code>begin()</code> if the <code>item</code> is not inserted. (See
+ the <i>Effect</i>.)
+ \throws Whatever <code>T::T()</code> throws.
+ \throws Whatever <code>T::T(T&&)</code> throws.
+ \throws Whatever <code>T::operator = (T&&)</code> throws.
+ \par Exception Safety
+ Basic; no-throw if the operation in the <i>Throws</i> section does not throw anything.
+ \par Iterator Invalidation
+ Invalidates iterators pointing to the elements at the insertion point (including <code>pos</code>) and
+ iterators behind the insertion point (towards the end; except iterators equal to <code>end()</code>). It
+ also invalidates iterators pointing to the overwritten element.
+ \par Complexity
+ Linear (in <code>std::distance(pos, end())</code>).
+ \sa <code>\link insert(iterator, size_type, param_value_type)
+ insert(iterator, size_type, value_type)\endlink</code>,
+ <code>insert(iterator, InputIterator, InputIterator)</code>,
+ <code>\link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink</code>,
+ <code>\link rinsert(iterator, size_type, param_value_type)
+ rinsert(iterator, size_type, value_type)\endlink</code>,
+ <code>rinsert(iterator, InputIterator, InputIterator)</code>
+ */
+ iterator insert(iterator pos) {
+ value_type temp;
+ return insert(pos, boost::move(temp));
}
//! Insert <code>n</code> copies of the <code>item</code> at the specified position.
@@ -1676,42 +1874,16 @@
insert(pos, first, last, is_integral<InputIterator>());
}
- //! Insert an element before the specified position.
- /*!
- \pre <code>pos</code> is a valid iterator pointing to the <code>circular_buffer</code> or its end.
- \post The <code>item</code> will be inserted before the position <code>pos</code>.<br>
- If the <code>circular_buffer</code> is full, the last element will be overwritten. If the
- <code>circular_buffer</code> is full and the <code>pos</code> points to <code>end()</code>, then the
- <code>item</code> will not be inserted. If the capacity is <code>0</code>, nothing will be inserted.
- \param pos An iterator specifying the position before which the <code>item</code> will be inserted.
- \param item The element to be inserted.
- \return Iterator to the inserted element or <code>end()</code> if the <code>item</code> is not inserted. (See
- the <i>Effect</i>.)
- \throws Whatever <code>T::T(const T&)</code> throws.
- \throws Whatever <code>T::operator = (const T&)</code> throws.
- \par Exception Safety
- Basic; no-throw if the operations in the <i>Throws</i> section do not throw anything.
- \par Iterator Invalidation
- Invalidates iterators pointing to the elements before the insertion point (towards the beginning and
- excluding <code>pos</code>). It also invalidates iterators pointing to the overwritten element.
- \par Complexity
- Linear (in <code>std::distance(begin(), pos)</code>).
- \sa <code>\link rinsert(iterator, size_type, param_value_type)
- rinsert(iterator, size_type, value_type)\endlink</code>,
- <code>rinsert(iterator, InputIterator, InputIterator)</code>,
- <code>\link insert(iterator, param_value_type) insert(iterator, value_type)\endlink</code>,
- <code>\link insert(iterator, size_type, param_value_type)
- insert(iterator, size_type, value_type)\endlink</code>,
- <code>insert(iterator, InputIterator, InputIterator)</code>
- */
- iterator rinsert(iterator pos, param_value_type item = value_type()) {
+private:
+ template <class ValT>
+ iterator rinsert_impl(iterator pos, ValT item) {
BOOST_CB_ASSERT(pos.is_valid(this)); // check for uninitialized or invalidated iterator
if (full() && pos.m_it == 0)
return end();
if (pos == begin()) {
BOOST_TRY {
decrement(m_first);
- construct_or_replace(!full(), m_first, item);
+ construct_or_replace(!full(), m_first, static_cast<ValT>(item));
} BOOST_CATCH(...) {
increment(m_first);
BOOST_RETHROW
@@ -1726,13 +1898,13 @@
bool construct = !full();
BOOST_TRY {
while (src != pos.m_it) {
- construct_or_replace(construct, dest, *src);
+ construct_or_replace(construct, dest, this_type::move_if_noexcept(*src));
increment(src);
increment(dest);
construct = false;
}
decrement(pos.m_it);
- replace(pos.m_it, item);
+ replace(pos.m_it, static_cast<ValT>(item));
} BOOST_CATCH(...) {
if (!construct && !full()) {
decrement(m_first);
@@ -1750,6 +1922,106 @@
return iterator(this, pos.m_it);
}
+public:
+
+ //! Insert an element before the specified position.
+ /*!
+ \pre <code>pos</code> is a valid iterator pointing to the <code>circular_buffer</code> or its end.
+ \post The <code>item</code> will be inserted before the position <code>pos</code>.<br>
+ If the <code>circular_buffer</code> is full, the last element will be overwritten. If the
+ <code>circular_buffer</code> is full and the <code>pos</code> points to <code>end()</code>, then the
+ <code>item</code> will not be inserted. If the capacity is <code>0</code>, nothing will be inserted.
+ \param pos An iterator specifying the position before which the <code>item</code> will be inserted.
+ \param item The element to be inserted.
+ \return Iterator to the inserted element or <code>end()</code> if the <code>item</code> is not inserted. (See
+ the <i>Effect</i>.)
+ \throws Whatever <code>T::T(const T&)</code> throws.
+ \throws Whatever <code>T::operator = (const T&)</code> throws.
+ \par Exception Safety
+ Basic; no-throw if the operations in the <i>Throws</i> section do not throw anything.
+ \par Iterator Invalidation
+ Invalidates iterators pointing to the elements before the insertion point (towards the beginning and
+ excluding <code>pos</code>). It also invalidates iterators pointing to the overwritten element.
+ \par Complexity
+ Linear (in <code>std::distance(begin(), pos)</code>).
+ \sa <code>\link rinsert(iterator, size_type, param_value_type)
+ rinsert(iterator, size_type, value_type)\endlink</code>,
+ <code>rinsert(iterator, InputIterator, InputIterator)</code>,
+ <code>\link insert(iterator, param_value_type) insert(iterator, value_type)\endlink</code>,
+ <code>\link insert(iterator, size_type, param_value_type)
+ insert(iterator, size_type, value_type)\endlink</code>,
+ <code>insert(iterator, InputIterator, InputIterator)</code>
+ */
+ iterator rinsert(iterator pos, param_value_type item) {
+ return rinsert_impl<param_value_type>(pos, item);
+ }
+
+ //! Insert an element before the specified position.
+ /*!
+ \pre <code>pos</code> is a valid iterator pointing to the <code>circular_buffer</code> or its end.
+ \post The <code>item</code> will be inserted before the position <code>pos</code>.<br>
+ If the <code>circular_buffer</code> is full, the last element will be overwritten. If the
+ <code>circular_buffer</code> is full and the <code>pos</code> points to <code>end()</code>, then the
+ <code>item</code> will not be inserted. If the capacity is <code>0</code>, nothing will be inserted.
+ \param pos An iterator specifying the position before which the <code>item</code> will be inserted.
+ \param item The element to be inserted.
+ \return Iterator to the inserted element or <code>end()</code> if the <code>item</code> is not inserted. (See
+ the <i>Effect</i>.)
+ \throws Whatever <code>T::T(T&&)</code> throws.
+ \throws Whatever <code>T::operator = (T&&)</code> throws.
+ \par Exception Safety
+ Basic; no-throw if the operations in the <i>Throws</i> section do not throw anything.
+ \par Iterator Invalidation
+ Invalidates iterators pointing to the elements before the insertion point (towards the beginning and
+ excluding <code>pos</code>). It also invalidates iterators pointing to the overwritten element.
+ \par Complexity
+ Linear (in <code>std::distance(begin(), pos)</code>).
+ \sa <code>\link rinsert(iterator, size_type, param_value_type)
+ rinsert(iterator, size_type, value_type)\endlink</code>,
+ <code>rinsert(iterator, InputIterator, InputIterator)</code>,
+ <code>\link insert(iterator, param_value_type) insert(iterator, value_type)\endlink</code>,
+ <code>\link insert(iterator, size_type, param_value_type)
+ insert(iterator, size_type, value_type)\endlink</code>,
+ <code>insert(iterator, InputIterator, InputIterator)</code>
+ */
+ iterator rinsert(iterator pos, rvalue_type item) {
+ return rinsert_impl<rvalue_type>(pos, boost::move(item));
+ }
+
+ //! Insert an element before the specified position.
+ /*!
+ \pre <code>pos</code> is a valid iterator pointing to the <code>circular_buffer</code> or its end.
+ \post The <code>item</code> will be inserted before the position <code>pos</code>.<br>
+ If the <code>circular_buffer</code> is full, the last element will be overwritten. If the
+ <code>circular_buffer</code> is full and the <code>pos</code> points to <code>end()</code>, then the
+ <code>item</code> will not be inserted. If the capacity is <code>0</code>, nothing will be inserted.
+ \param pos An iterator specifying the position before which the <code>item</code> will be inserted.
+ \param item The element to be inserted.
+ \return Iterator to the inserted element or <code>end()</code> if the <code>item</code> is not inserted. (See
+ the <i>Effect</i>.)
+ \throws Whatever <code>T::T()</code> throws.
+ \throws Whatever <code>T::T(T&&)</code> throws.
+ \throws Whatever <code>T::operator = (T&&)</code> throws.
+ \par Exception Safety
+ Basic; no-throw if the operations in the <i>Throws</i> section do not throw anything.
+ \par Iterator Invalidation
+ Invalidates iterators pointing to the elements before the insertion point (towards the beginning and
+ excluding <code>pos</code>). It also invalidates iterators pointing to the overwritten element.
+ \par Complexity
+ Linear (in <code>std::distance(begin(), pos)</code>).
+ \sa <code>\link rinsert(iterator, size_type, param_value_type)
+ rinsert(iterator, size_type, value_type)\endlink</code>,
+ <code>rinsert(iterator, InputIterator, InputIterator)</code>,
+ <code>\link insert(iterator, param_value_type) insert(iterator, value_type)\endlink</code>,
+ <code>\link insert(iterator, size_type, param_value_type)
+ insert(iterator, size_type, value_type)\endlink</code>,
+ <code>insert(iterator, InputIterator, InputIterator)</code>
+ */
+ iterator rinsert(iterator pos) {
+ value_type temp;
+ return rinsert(pos, boost::move(temp));
+ }
+
//! Insert <code>n</code> copies of the <code>item</code> before the specified position.
/*!
\pre <code>pos</code> is a valid iterator pointing to the <code>circular_buffer</code> or its end.
@@ -2146,7 +2418,7 @@
}
//! Does the pointer point to the uninitialized memory?
- bool is_uninitialized(const_pointer p) const {
+ bool is_uninitialized(const_pointer p) const BOOST_NOEXCEPT {
return p >= m_last && (m_first < m_last || p < m_first);
}
@@ -2158,6 +2430,14 @@
#endif
}
+ //! Replace an element.
+ void replace(pointer pos, rvalue_type item) {
+ *pos = boost::move(item);
+#if BOOST_CB_ENABLE_DEBUG
+ invalidate_iterators(iterator(this, pos));
+#endif
+ }
+
//! Construct or replace an element.
/*!
<code>construct</code> has to be set to <code>true</code> if and only if
@@ -2165,11 +2445,23 @@
*/
void construct_or_replace(bool construct, pointer pos, param_value_type item) {
if (construct)
- m_alloc.construct(pos, item);
+ new (pos) value_type(item);
else
replace(pos, item);
}
+ //! Construct or replace an element.
+ /*!
+ <code>construct</code> has to be set to <code>true</code> if and only if
+ <code>pos</code> points to an uninitialized memory.
+ */
+ void construct_or_replace(bool construct, pointer pos, rvalue_type item) {
+ if (construct)
+ new (pos) value_type(boost::move(item));
+ else
+ replace(pos, boost::move(item));
+ }
+
//! Destroy an item.
void destroy_item(pointer p) {
m_alloc.destroy(p);
@@ -2261,7 +2553,7 @@
// for containers
std::deque<value_type, allocator_type> tmp(first, last, m_alloc);
size_type distance = tmp.size();
- initialize(distance, tmp.begin(), tmp.end(), distance);
+ initialize(distance, boost::make_move_iterator(tmp.begin()), boost::make_move_iterator(tmp.end()), distance);
}
//! Specialized initialize method.
@@ -2305,7 +2597,7 @@
if (buffer_capacity == 0)
return;
while (first != last && !full()) {
- m_alloc.construct(m_last, *first++);
+ new (m_last) value_type(*first++);
increment(m_last);
++m_size;
}
@@ -2486,10 +2778,11 @@
}
//! Helper insert method.
- iterator insert_item(const iterator& pos, param_value_type item) {
+ template <class ValT>
+ iterator insert_item(const iterator& pos, ValT item) {
pointer p = pos.m_it;
if (p == 0) {
- construct_or_replace(!full(), m_last, item);
+ construct_or_replace(!full(), m_last, static_cast<ValT>(item));
p = m_last;
} else {
pointer src = m_last;
@@ -2498,11 +2791,11 @@
BOOST_TRY {
while (src != p) {
decrement(src);
- construct_or_replace(construct, dest, *src);
+ construct_or_replace(construct, dest, this_type::move_if_noexcept(*src));
decrement(dest);
construct = false;
}
- replace(p, item);
+ replace(p, static_cast<ValT>(item));
} BOOST_CATCH(...) {
if (!construct && !full()) {
increment(m_last);
@@ -2542,7 +2835,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(pos, *first++);
+ pos = insert_item<param_value_type>(pos, *first++); // TODO: optimize for cases when InputIterator is move iterator
}
}
@@ -2574,7 +2867,7 @@
pointer p = m_last;
BOOST_TRY {
for (; ii < construct; ++ii, increment(p))
- m_alloc.construct(p, *wrapper());
+ new (p) value_type(*wrapper());
for (;ii < n; ++ii, increment(p))
replace(p, *wrapper());
} BOOST_CATCH(...) {
@@ -2668,7 +2961,7 @@
for (;ii > construct; --ii, increment(p))
replace(p, *wrapper());
for (; ii > 0; --ii, increment(p))
- m_alloc.construct(p, *wrapper());
+ new (p) value_type(*wrapper());
} BOOST_CATCH(...) {
size_type constructed = ii < construct ? construct - ii : 0;
m_last = add(m_last, constructed);
Modified: trunk/libs/circular_buffer/test/base_test.cpp
==============================================================================
--- trunk/libs/circular_buffer/test/base_test.cpp Mon Jul 8 09:12:18 2013 (r84983)
+++ trunk/libs/circular_buffer/test/base_test.cpp 2013-07-08 09:41:58 EDT (Mon, 08 Jul 2013) (r84984)
@@ -740,7 +740,7 @@
void move_container_on_cpp11() {
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
- circular_buffer<MyInteger> cb1(10);
+ CB_CONTAINER<MyInteger> cb1(10);
cb1.push_back(1);
cb1.push_back(2);
cb1.push_back(3);
@@ -749,8 +749,8 @@
cb1.push_back(6);
// Checking move constructor
- circular_buffer<MyInteger> cb2(static_cast<circular_buffer<MyInteger>&& >(cb1));
- circular_buffer<MyInteger>::iterator it2 = cb2.begin() + 1;
+ CB_CONTAINER<MyInteger> cb2(static_cast<CB_CONTAINER<MyInteger>&& >(cb1));
+ CB_CONTAINER<MyInteger>::iterator it2 = cb2.begin() + 1;
BOOST_CHECK(cb1.empty());
BOOST_CHECK(!cb2.empty());
@@ -759,8 +759,8 @@
BOOST_CHECK(it2[2] == 4);
// Checking move assignment
- cb1 = static_cast<circular_buffer<MyInteger>&& >(cb2);
- circular_buffer<MyInteger>::iterator it1 = cb1.begin() + 1;
+ cb1 = static_cast<CB_CONTAINER<MyInteger>&& >(cb2);
+ CB_CONTAINER<MyInteger>::iterator it1 = cb1.begin() + 1;
BOOST_CHECK(!cb1.empty());
BOOST_CHECK(cb2.empty());
@@ -770,6 +770,158 @@
#endif
}
+
+struct noncopyable_movable_test_t {
+private:
+ BOOST_MOVABLE_BUT_NOT_COPYABLE(noncopyable_movable_test_t)
+ bool is_moved_;
+public:
+ explicit noncopyable_movable_test_t()
+ : is_moved_(false)
+ {}
+
+ noncopyable_movable_test_t(BOOST_RV_REF(noncopyable_movable_test_t) x) BOOST_NOEXCEPT {
+ is_moved_ = x.is_moved_;
+ x.is_moved_ = true;
+ }
+
+ noncopyable_movable_test_t& operator=(BOOST_RV_REF(noncopyable_movable_test_t) x) BOOST_NOEXCEPT {
+ is_moved_ = x.is_moved_;
+ x.is_moved_ = true;
+ return *this;
+ }
+
+ bool is_moved() const {
+ return is_moved_;
+ }
+
+ void reinit() { is_moved_ = false; }
+};
+
+// Required for C++03 compilers
+namespace boost {
+ template <>
+ struct is_nothrow_move_constructible<noncopyable_movable_test_t> {
+ BOOST_STATIC_CONSTANT(bool, value = true);
+ };
+} // namespace boost
+
+void move_container_values() {
+ CB_CONTAINER<noncopyable_movable_test_t> cb1(40);
+ noncopyable_movable_test_t var;
+ cb1.push_back(boost::move(var));
+ BOOST_CHECK(!cb1.back().is_moved());
+ BOOST_CHECK(var.is_moved());
+ BOOST_CHECK(cb1.size() == 1);
+
+ var.reinit();
+ cb1.push_front(boost::move(var));
+ BOOST_CHECK(!cb1.front().is_moved());
+ BOOST_CHECK(var.is_moved());
+ BOOST_CHECK(cb1.size() == 2);
+
+ cb1.push_back();
+ BOOST_CHECK(!cb1.back().is_moved());
+ BOOST_CHECK(cb1.size() == 3);
+
+ cb1.push_front();
+ BOOST_CHECK(!cb1.front().is_moved());
+ BOOST_CHECK(cb1.size() == 4);
+
+ cb1.insert(cb1.begin());
+ BOOST_CHECK(!cb1.front().is_moved());
+ BOOST_CHECK(cb1.size() == 5);
+
+ var.reinit();
+ cb1.insert(cb1.begin(), boost::move(var));
+ BOOST_CHECK(!cb1.front().is_moved());
+ BOOST_CHECK(cb1.size() == 6);
+
+ cb1.rinsert(cb1.begin());
+ BOOST_CHECK(!cb1.back().is_moved());
+ BOOST_CHECK(cb1.size() == 7);
+
+ var.reinit();
+ cb1.rinsert(cb1.begin(), boost::move(var));
+ BOOST_CHECK(!cb1.back().is_moved());
+ BOOST_CHECK(cb1.size() == 8);
+}
+
+void move_container_values_resetting() {
+ CB_CONTAINER<noncopyable_movable_test_t> cb1(1);
+ noncopyable_movable_test_t var;
+ cb1.push_back();
+
+ cb1.push_back(boost::move(var));
+ BOOST_CHECK(!cb1.back().is_moved());
+ BOOST_CHECK(var.is_moved());
+ BOOST_CHECK(cb1.size() == 1);
+ var = boost::move(cb1.back());
+ BOOST_CHECK(cb1.back().is_moved());
+
+ cb1.push_front(boost::move(var));
+ BOOST_CHECK(!cb1.front().is_moved());
+ BOOST_CHECK(var.is_moved());
+ BOOST_CHECK(cb1.size() == 1);
+ var = boost::move(cb1.back());
+ BOOST_CHECK(cb1.back().is_moved());
+
+ cb1.push_back();
+ BOOST_CHECK(!cb1.back().is_moved());
+ BOOST_CHECK(cb1.size() == 1);
+ var = boost::move(cb1.back());
+ BOOST_CHECK(cb1.back().is_moved());
+
+ cb1.push_front();
+ BOOST_CHECK(!cb1.front().is_moved());
+ BOOST_CHECK(cb1.size() == 1);
+ var = boost::move(cb1.back());
+ BOOST_CHECK(cb1.back().is_moved());
+
+
+ cb1.insert(cb1.begin());
+ // If the circular_buffer is full and the pos points to begin(),
+ // then the item will not be inserted.
+ BOOST_CHECK(cb1.front().is_moved());
+ BOOST_CHECK(cb1.size() == 1);
+ var = boost::move(cb1.back());
+ BOOST_CHECK(cb1.back().is_moved());
+
+ cb1.insert(cb1.begin(), boost::move(var));
+ // If the circular_buffer is full and the pos points to begin(),
+ // then the item will not be inserted.
+ BOOST_CHECK(cb1.front().is_moved());
+ BOOST_CHECK(cb1.size() == 1);
+ var = boost::move(cb1.back());
+ BOOST_CHECK(cb1.back().is_moved());
+
+ cb1.rinsert(cb1.begin());
+ BOOST_CHECK(!cb1.back().is_moved());
+ BOOST_CHECK(cb1.size() == 1);
+ var = boost::move(cb1.back());
+ BOOST_CHECK(cb1.back().is_moved());
+
+ var.reinit();
+ cb1.rinsert(cb1.begin(), boost::move(var));
+ BOOST_CHECK(!cb1.back().is_moved());
+ BOOST_CHECK(cb1.size() == 1);
+ var = boost::move(cb1.back());
+ BOOST_CHECK(cb1.back().is_moved());
+
+ cb1.rinsert(cb1.end());
+ BOOST_CHECK(cb1.back().is_moved());
+ BOOST_CHECK(cb1.size() == 1);
+ var = boost::move(cb1.back());
+ BOOST_CHECK(cb1.back().is_moved());
+
+ var.reinit();
+ cb1.rinsert(cb1.end(), boost::move(var));
+ BOOST_CHECK(cb1.back().is_moved());
+ BOOST_CHECK(cb1.size() == 1);
+ var = boost::move(cb1.back());
+ BOOST_CHECK(cb1.back().is_moved());
+}
+
// test main
test_suite* init_unit_test_suite(int /*argc*/, char* /*argv*/[]) {
@@ -788,6 +940,8 @@
tests->add(BOOST_TEST_CASE(&iterator_invalidation_test));
tests->add(BOOST_TEST_CASE(&exception_safety_test));
tests->add(BOOST_TEST_CASE(&move_container_on_cpp11));
+ tests->add(BOOST_TEST_CASE(&move_container_values));
+ tests->add(BOOST_TEST_CASE(&move_container_values_resetting));
return tests;
}
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