Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r82176 - in sandbox/static_vector: boost/container boost/container/detail test
From: adam.wulkiewicz_at_[hidden]
Date: 2012-12-22 18:51:07


Author: awulkiew
Date: 2012-12-22 18:51:06 EST (Sat, 22 Dec 2012)
New Revision: 82176
URL: http://svn.boost.org/trac/boost/changeset/82176

Log:
Implemented second, safer versions of move ctor, assign and swap added. Choosing between versions may be done with traits.
Unsafe method moves values directly e.g. by memcpy, is nothrowing and is probably faster. If some members of Value class stores addresses relative to the Value object address, using of this version will cause an error.
Safer method uses move ctors and assigns if possible or copies, is throwing, provides basic or strong safety and is probably slower.
Text files modified:
   sandbox/static_vector/boost/container/detail/static_vector_util.hpp | 109 +++++++++++++---------
   sandbox/static_vector/boost/container/static_vector.hpp | 186 ++++++++++++++++++++++++++-------------
   sandbox/static_vector/test/static_vector.cpp | 3
   3 files changed, 188 insertions(+), 110 deletions(-)

Modified: sandbox/static_vector/boost/container/detail/static_vector_util.hpp
==============================================================================
--- sandbox/static_vector/boost/container/detail/static_vector_util.hpp (original)
+++ sandbox/static_vector/boost/container/detail/static_vector_util.hpp 2012-12-22 18:51:06 EST (Sat, 22 Dec 2012)
@@ -136,6 +136,51 @@
>
 {};
 
+// destroy(I, I)
+
+template <typename I>
+void destroy_dispatch(I /*first*/, I /*last*/,
+ boost::true_type const& /*has_trivial_destructor*/)
+{}
+
+template <typename I>
+void destroy_dispatch(I first, I last,
+ boost::false_type const& /*has_trivial_destructor*/)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ for ( ; first != last ; ++first )
+ first->~value_type();
+}
+
+template <typename I>
+void destroy(I first, I last)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ destroy_dispatch(first, last, has_trivial_destructor<value_type>());
+}
+
+// destroy(I)
+
+template <typename I>
+void destroy_dispatch(I /*pos*/,
+ boost::true_type const& /*has_trivial_destructor*/)
+{}
+
+template <typename I>
+void destroy_dispatch(I pos,
+ boost::false_type const& /*has_trivial_destructor*/)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ pos->~value_type();
+}
+
+template <typename I>
+void destroy(I pos)
+{
+ typedef typename boost::iterator_value<I>::type value_type;
+ destroy_dispatch(pos, has_trivial_destructor<value_type>());
+}
+
 // copy(I, I, O)
 
 template <typename I, typename O>
@@ -250,7 +295,20 @@
 O uninitialized_move_dispatch(I first, I last, O dst,
                               boost::mpl::bool_<false> const& /*use_memcpy*/)
 {
- return boost::uninitialized_move(first, last, dst); // may throw
+ //return boost::uninitialized_move(first, last, dst); // may throw
+
+ O o = dst;
+ try
+ {
+ typedef typename std::iterator_traits<O>::value_type value_type;
+ for (; first != last; ++first, ++o )
+ new (boost::addressof(*o)) value_type(boost::move(*first));
+ }
+ catch (...)
+ {
+ destroy(dst, o);
+ }
+ return dst;
 }
 
 template <typename I, typename O>
@@ -268,6 +326,8 @@
     return uninitialized_move_dispatch(first, last, dst, use_memcpy()); // may throw
 }
 
+// TODO - move uses memmove - implement 2nd version using memcpy?
+
 // move(I, I, O)
 
 template <typename I, typename O>
@@ -303,6 +363,8 @@
     return move_dispatch(first, last, dst, use_memmove()); // may throw
 }
 
+// TODO - move_backward uses memmove - implement 2nd version using memcpy?
+
 // move_backward(BDI, BDI, BDO)
 
 template <typename BDI, typename BDO>
@@ -368,51 +430,6 @@
     fill_dispatch(pos, v, use_memcpy()); // may throw
 }
 
-// destroy(I, I)
-
-template <typename I>
-void destroy_dispatch(I /*first*/, I /*last*/,
- boost::true_type const& /*has_trivial_destructor*/)
-{}
-
-template <typename I>
-void destroy_dispatch(I first, I last,
- boost::false_type const& /*has_trivial_destructor*/)
-{
- typedef typename boost::iterator_value<I>::type value_type;
- for ( ; first != last ; ++first )
- first->~value_type();
-}
-
-template <typename I>
-void destroy(I first, I last)
-{
- typedef typename boost::iterator_value<I>::type value_type;
- destroy_dispatch(first, last, has_trivial_destructor<value_type>());
-}
-
-// destroy(I)
-
-template <typename I>
-void destroy_dispatch(I /*pos*/,
- boost::true_type const& /*has_trivial_destructor*/)
-{}
-
-template <typename I>
-void destroy_dispatch(I pos,
- boost::false_type const& /*has_trivial_destructor*/)
-{
- typedef typename boost::iterator_value<I>::type value_type;
- pos->~value_type();
-}
-
-template <typename I>
-void destroy(I pos)
-{
- typedef typename boost::iterator_value<I>::type value_type;
- destroy_dispatch(pos, has_trivial_destructor<value_type>());
-}
-
 // construct
 
 template <typename I>

Modified: sandbox/static_vector/boost/container/static_vector.hpp
==============================================================================
--- sandbox/static_vector/boost/container/static_vector.hpp (original)
+++ sandbox/static_vector/boost/container/static_vector.hpp 2012-12-22 18:51:06 EST (Sat, 22 Dec 2012)
@@ -30,6 +30,33 @@
 // or boost/detail/iterator.hpp ?
 #include <boost/iterator/reverse_iterator.hpp>
 
+#if defined(BOOST_NO_RVALUE_REFERENCES)
+
+#define BOOST_CONTAINER_STATIC_VECTOR_ASSIGN_REF(V, C, S) boost::rv< static_vector<V, C, S> > const&
+#define BOOST_CONTAINER_STATIC_VECTOR_RV_REF(V, C, S) boost::rv< static_vector<V, C, S> > &
+
+#define BOOST_CONTAINER_STATIC_VECTOR_COPYABLE_AND_MOVABLE() \
+BOOST_COPYABLE_AND_MOVABLE(static_vector) \
+public: \
+ template <std::size_t C, typename S> \
+ static_vector & operator=(static_vector<Value, C, S> & t) \
+ { \
+ typedef static_vector<Value, C, S> O; \
+ this->operator=(static_cast<const ::boost::rv<O> &>(const_cast<const O &>(t))); \
+ return *this; \
+ } \
+private:
+
+#else
+
+#define BOOST_CONTAINER_STATIC_VECTOR_ASSIGN_REF(V, C, S) static_vector<V, C, S> const&
+#define BOOST_CONTAINER_STATIC_VECTOR_RV_REF(V, C, S) static_vector<V, C, S> &&
+
+#define BOOST_CONTAINER_STATIC_VECTOR_COPYABLE_AND_MOVABLE() \
+BOOST_COPYABLE_AND_MOVABLE(static_vector)
+
+#endif
+
 namespace boost { namespace container {
 
 // Forward declaration
@@ -91,7 +118,8 @@
 struct static_vector_traits
 {
     typedef typename Strategy::size_type size_type;
- typedef boost::true_type use_nonthrowing_swap;
+ typedef boost::true_type use_memop_in_swap_and_move;
+ typedef boost::false_type use_optimized_swap;
     typedef Strategy strategy;
 };
 
@@ -122,22 +150,11 @@
         Value, Capacity, Strategy
>::strategy errh;
 
- BOOST_COPYABLE_AND_MOVABLE(static_vector)
-
-#if defined(BOOST_NO_RVALUE_REFERENCES)
-public:
- template <std::size_t C, typename S>
- static_vector & operator=(static_vector<Value, C, S> & t)
- {
- typedef static_vector<Value, C, S> O;
- this->operator=(static_cast<const ::boost::rv<O> &>(const_cast<const O &>(t)));
- return *this;
- }
-#endif
-
     template <typename V, std::size_t C, typename S>
     friend class static_vector;
 
+ BOOST_CONTAINER_STATIC_VECTOR_COPYABLE_AND_MOVABLE()
+
 public:
     typedef Value value_type;
     typedef stored_size_type size_type;
@@ -179,8 +196,6 @@
         this->assign(first, last); // may throw
     }
 
- // Copy constructors
-
     // strong
     static_vector(static_vector const& other)
         : m_size(other.size())
@@ -200,8 +215,6 @@
         sv::uninitialized_copy(other.begin(), other.end(), this->begin()); // may throw
     }
 
- // Copy assignments
-
     // basic
     static_vector & operator=(BOOST_COPY_ASSIGN_REF(static_vector) other)
     {
@@ -212,71 +225,68 @@
 
     // basic
     template <std::size_t C, typename S>
-#if defined(BOOST_NO_RVALUE_REFERENCES)
- static_vector & operator=(boost::rv< static_vector<value_type, C, S> > const& other)
-#else
- static_vector & operator=(static_vector<value_type, C, S> const& other)
-#endif
+ static_vector & operator=(BOOST_CONTAINER_STATIC_VECTOR_ASSIGN_REF(value_type, C, S) other)
     {
         this->assign(other.begin(), other.end()); // may throw
 
         return *this;
     }
 
- // Move constructors
-
- // nothrow
+ // nothrow or strong (based on traits, default nothrow)
     // (note: linear complexity)
     static_vector(BOOST_RV_REF(static_vector) other)
- : m_size(other.m_size)
     {
- ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size);
- other.m_size = 0;
+ typedef typename
+ static_vector_detail::static_vector_traits<
+ Value, Capacity, Strategy
+ >::use_memop_in_swap_and_move use_memop_in_swap_and_move;
+
+ this->move_ctor_dispatch(other, use_memop_in_swap_and_move());
     }
 
- // nothrow or strong (depends on stragety)
+ // nothrow or strong (based on traits, default nothrow)
     // (note: linear complexity)
     template <std::size_t C, typename S>
-#if defined(BOOST_NO_RVALUE_REFERENCES)
- static_vector(boost::rv< static_vector<value_type, C, S> > & other)
-#else
- static_vector(static_vector<value_type, C, S> && other)
-#endif
+ static_vector(BOOST_CONTAINER_STATIC_VECTOR_RV_REF(value_type, C, S) other)
         : m_size(other.m_size)
     {
         errh::check_capacity(*this, other.size()); // may throw
 
- ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size);
- other.m_size = 0;
- }
+ typedef typename
+ static_vector_detail::static_vector_traits<
+ Value, Capacity, Strategy
+ >::use_memop_in_swap_and_move use_memop_in_swap_and_move;
 
- // Move assignments
+ this->move_ctor_dispatch(other, use_memop_in_swap_and_move());
+ }
 
- // nothrow
+ // nothrow or basic (based on traits, default nothrow)
+ // (note: linear complexity)
     static_vector & operator=(BOOST_RV_REF(static_vector) other)
     {
- this->clear();
+ typedef typename
+ static_vector_detail::static_vector_traits<
+ Value, Capacity, Strategy
+ >::use_memop_in_swap_and_move use_memop_in_swap_and_move;
 
- ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size);
- boost::swap(m_size, other.m_size);
+ this->move_assign_dispatch(other, use_memop_in_swap_and_move());
 
         return *this;
     }
 
- // nothrow or strong (depends on stragety)
+ // nothrow or basic (based on traits, default nothrow)
+ // (note: linear complexity)
     template <std::size_t C, typename S>
-#if defined(BOOST_NO_RVALUE_REFERENCES)
- static_vector & operator=(boost::rv< static_vector<value_type, C, S> > & other)
-#else
- static_vector & operator=(static_vector<value_type, C, S> && other)
-#endif
+ static_vector & operator=(BOOST_CONTAINER_STATIC_VECTOR_RV_REF(value_type, C, S) other)
     {
         errh::check_capacity(*this, other.size()); // may throw
 
- this->clear();
+ typedef typename
+ static_vector_detail::static_vector_traits<
+ Value, Capacity, Strategy
+ >::use_memop_in_swap_and_move use_memop_in_swap_and_move;
 
- ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size);
- boost::swap(m_size, other.m_size);
+ this->move_assign_dispatch(other, use_memop_in_swap_and_move());
 
         return *this;
     }
@@ -288,16 +298,16 @@
         sv::destroy(this->begin(), this->end());
     }
 
- // nothrow or basic (depends on traits)
+ // nothrow or basic (depends on traits, default nothrow)
     // swap (note: linear complexity)
     void swap(static_vector & other)
     {
         typedef typename
         static_vector_detail::static_vector_traits<
             Value, Capacity, Strategy
- >::use_nonthrowing_swap use_nonthrowing_swap;
+ >::use_optimized_swap use_optimized_swap;
 
- this->swap_dispatch(other, use_nonthrowing_swap());
+ this->swap_dispatch(other, use_optimized_swap());
     }
 
     // nothrow, strong or basic (depends on traits and strategy)
@@ -311,9 +321,9 @@
         typedef typename
         static_vector_detail::static_vector_traits<
             Value, Capacity, Strategy
- >::use_nonthrowing_swap use_nonthrowing_swap;
+ >::use_optimized_swap use_optimized_swap;
 
- this->swap_dispatch(other, use_nonthrowing_swap());
+ this->swap_dispatch(other, use_optimized_swap());
     }
 
     // strong
@@ -613,10 +623,54 @@
 
 private:
 
- // swap
+ // nothrow
+ // linear complexity
+ template <std::size_t C, typename S>
+ void move_ctor_dispatch(static_vector<value_type, C, S> & other, boost::true_type /*use_memop*/)
+ {
+ ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size);
+ m_size = other.m_size;
+ other.m_size = 0;
+ }
+
+ // strong
+ // linear complexity
+ template <std::size_t C, typename S>
+ void move_ctor_dispatch(static_vector<value_type, C, S> & other, boost::false_type /*use_memop*/)
+ {
+ namespace sv = static_vector_detail;
+ sv::uninitialized_move(other.begin(), other.end(), this->begin());
+ m_size = other.m_size;
+ sv::destroy(other.begin(), other.end());
+ other.m_size = 0;
+ }
+
+ // nothrow
+ // linear complexity
+ template <std::size_t C, typename S>
+ void move_assign_dispatch(static_vector<value_type, C, S> & other, boost::true_type /*use_memop*/)
+ {
+ this->clear();
+
+ ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size);
+ boost::swap(m_size, other.m_size);
+ }
+
+ // basic
+ // linear complexity
+ template <std::size_t C, typename S>
+ void move_assign_dispatch(static_vector<value_type, C, S> & other, boost::false_type /*use_memop*/)
+ {
+ // TODO - use move iterators or implement moving
+
+ this->assign(other.begin(), other.end());
+ other.clear();
+ }
 
+ // nothrow
+ // linear complexity
     template <std::size_t C, typename S>
- void swap_dispatch(static_vector<value_type, C, S> & other, boost::true_type const& /*nonthrowing_version*/)
+ void swap_dispatch(static_vector<value_type, C, S> & other, boost::true_type const& /*use_optimized_swap*/)
     {
         typedef typename
         boost::mpl::if_c<
@@ -636,8 +690,10 @@
         boost::swap(m_size, other.m_size);
     }
 
+ // basic
+ // linear complexity
     template <std::size_t C, typename S>
- void swap_dispatch(static_vector<value_type, C, S> & other, boost::false_type const& /*throwing_version*/)
+ void swap_dispatch(static_vector<value_type, C, S> & other, boost::false_type const& /*use_optimized_swap*/)
     {
         namespace sv = static_vector_detail;
 
@@ -648,17 +704,17 @@
         boost::swap(m_size, other.m_size);
     }
 
+ // basic
+ // linear complexity
     template <typename ItSm, typename ItLa>
     void swap_dispatch_impl(ItSm first_sm, ItSm last_sm, ItLa first_la, ItLa last_la)
     {
         //BOOST_ASSERT_MSG(std::distance(first_sm, last_sm) <= std::distance(first_la, last_la));
 
- // TODO - use move instead of copy
-
         namespace sv = static_vector_detail;
         for (; first_sm != last_sm ; ++first_sm, ++first_la)
         {
- //boost::swap(*first_sm, *first_la); // may throw
+ //boost::swap(*first_sm, *first_la); // may throw
             value_type temp(boost::move(*first_sm)); // may throw
             *first_sm = boost::move(*first_la); // may throw
             *first_la = boost::move(temp); // may throw
@@ -1124,4 +1180,8 @@
 
 }} // namespace boost::container
 
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
+#pragma warning(pop)
+#endif
+
 #endif // BOOST_CONTAINER_STATIC_VECTOR_HPP

Modified: sandbox/static_vector/test/static_vector.cpp
==============================================================================
--- sandbox/static_vector/test/static_vector.cpp (original)
+++ sandbox/static_vector/test/static_vector.cpp 2012-12-22 18:51:06 EST (Sat, 22 Dec 2012)
@@ -519,7 +519,8 @@
 struct static_vector_traits<Value, Capacity, bad_alloc_strategy>
 {
     typedef std::size_t size_type;
- typedef boost::false_type use_nonthrowing_swap;
+ typedef boost::false_type use_memop_in_swap_and_move;
+ typedef boost::false_type use_optimized_swap;
     typedef bad_alloc_strategy strategy;
 };
 


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