Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r81293 - in trunk: boost/variant boost/variant/detail libs/variant/perf libs/variant/test
From: antoshkka_at_[hidden]
Date: 2012-11-11 03:05:00


Author: apolukhin
Date: 2012-11-11 03:04:55 EST (Sun, 11 Nov 2012)
New Revision: 81293
URL: http://svn.boost.org/trac/boost/changeset/81293

Log:
Added basic rvalue support and marked some functions with BOOST_NOEXCEPT (#refs #7620)
Added:
   trunk/libs/variant/perf/
   trunk/libs/variant/perf/Jamfile.v2 (contents, props changed)
   trunk/libs/variant/perf/move_perf.cpp (contents, props changed)
   trunk/libs/variant/test/rvalue_test.cpp (contents, props changed)
Text files modified:
   trunk/boost/variant/detail/backup_holder.hpp | 7
   trunk/boost/variant/detail/move.hpp | 8
   trunk/boost/variant/variant.hpp | 405 ++++++++++++++++++++++++++++++++++++++-
   trunk/libs/variant/test/Jamfile.v2 | 1
   4 files changed, 401 insertions(+), 20 deletions(-)

Modified: trunk/boost/variant/detail/backup_holder.hpp
==============================================================================
--- trunk/boost/variant/detail/backup_holder.hpp (original)
+++ trunk/boost/variant/detail/backup_holder.hpp 2012-11-11 03:04:55 EST (Sun, 11 Nov 2012)
@@ -13,6 +13,7 @@
 #ifndef BOOST_VARIANT_DETAIL_BACKUP_HOLDER_HPP
 #define BOOST_VARIANT_DETAIL_BACKUP_HOLDER_HPP
 
+#include "boost/config.hpp"
 #include "boost/assert.hpp"
 
 namespace boost {
@@ -32,7 +33,7 @@
         delete backup_;
     }
 
- explicit backup_holder(T* backup)
+ explicit backup_holder(T* backup) BOOST_NOEXCEPT
         : backup_(backup)
     {
     }
@@ -53,7 +54,7 @@
         return *this;
     }
 
- void swap(backup_holder& rhs)
+ void swap(backup_holder& rhs) BOOST_NOEXCEPT
     {
         T* tmp = rhs.backup_;
         rhs.backup_ = this->backup_;
@@ -83,7 +84,7 @@
 }
 
 template <typename T>
-void swap(backup_holder<T>& lhs, backup_holder<T>& rhs)
+void swap(backup_holder<T>& lhs, backup_holder<T>& rhs) BOOST_NOEXCEPT
 {
     lhs.swap(rhs);
 }

Modified: trunk/boost/variant/detail/move.hpp
==============================================================================
--- trunk/boost/variant/detail/move.hpp (original)
+++ trunk/boost/variant/detail/move.hpp 2012-11-11 03:04:55 EST (Sun, 11 Nov 2012)
@@ -82,6 +82,8 @@
 
 } // namespace detail
 
+#ifdef BOOST_NO_RVALUE_REFERENCES
+
 template <typename T>
 inline
     typename detail::move_type<T>::type
@@ -93,6 +95,12 @@
     return move_t(source);
 }
 
+#else
+
+using std::move;
+
+#endif
+
 //////////////////////////////////////////////////////////////////////////
 // class template return_t
 //

Modified: trunk/boost/variant/variant.hpp
==============================================================================
--- trunk/boost/variant/variant.hpp (original)
+++ trunk/boost/variant/variant.hpp 2012-11-11 03:04:55 EST (Sun, 11 Nov 2012)
@@ -51,7 +51,9 @@
 #include "boost/type_traits/has_nothrow_copy.hpp"
 #include "boost/type_traits/is_const.hpp"
 #include "boost/type_traits/is_same.hpp"
+#include "boost/type_traits/is_rvalue_reference.hpp"
 #include "boost/utility/enable_if.hpp"
+#include "boost/utility/declval.hpp"
 #include "boost/variant/recursive_wrapper_fwd.hpp"
 #include "boost/variant/static_visitor.hpp"
 
@@ -338,7 +340,7 @@
 
 public: // visitor interface
 
- T& operator()(T& operand) const
+ T& operator()(T& operand) const BOOST_NOEXCEPT
     {
         return operand;
     }
@@ -397,7 +399,7 @@
 
 public: // structors
 
- explicit copy_into(void* storage)
+ explicit copy_into(void* storage) BOOST_NOEXCEPT
         : storage_(storage)
     {
     }
@@ -431,6 +433,46 @@
 };
 
 ///////////////////////////////////////////////////////////////////////////////
+// (detail) class move_into
+//
+// Internal visitor that moves the value it visits into the given buffer.
+//
+#ifndef BOOST_NO_RVALUE_REFERENCES
+class move_into
+ : public static_visitor<>
+{
+private: // representation
+
+ void* storage_;
+
+public: // structors
+
+ explicit move_into(void* storage) BOOST_NOEXCEPT
+ : storage_(storage)
+ {
+ }
+
+public: // internal visitor interface
+
+ template <typename T>
+ BOOST_VARIANT_AUX_RETURN_VOID_TYPE
+ internal_visit(boost::detail::variant::backup_holder<T>& operand, long) const
+ {
+ new(storage_) T( ::boost::detail::variant::move(operand.get()) );
+ BOOST_VARIANT_AUX_RETURN_VOID;
+ }
+
+ template <typename T>
+ BOOST_VARIANT_AUX_RETURN_VOID_TYPE
+ internal_visit(T& operand, int) const BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(boost::declval<T>())))
+ {
+ new(storage_) T(::boost::detail::variant::move(operand));
+ BOOST_VARIANT_AUX_RETURN_VOID;
+ }
+};
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
 // (detail) class assign_storage
 //
 // Internal visitor that assigns the given storage (which must be a
@@ -445,7 +487,7 @@
 
 public: // structors
 
- explicit assign_storage(const void* rhs_storage)
+ explicit assign_storage(const void* rhs_storage) BOOST_NOEXCEPT
         : rhs_storage_(rhs_storage)
     {
     }
@@ -488,6 +530,63 @@
 };
 
 ///////////////////////////////////////////////////////////////////////////////
+// (detail) class move_storage
+//
+// Internal visitor that moves the given storage (which must be a
+// constructed value of the same type) to the value it visits.
+//
+struct move_storage
+ : public static_visitor<>
+{
+private: // representation
+
+ void* rhs_storage_;
+
+public: // structors
+
+ explicit move_storage(void* rhs_storage) BOOST_NOEXCEPT
+ : rhs_storage_(rhs_storage)
+ {
+ }
+
+public: // internal visitor interfaces
+
+ template <typename T>
+ BOOST_VARIANT_AUX_RETURN_VOID_TYPE
+ internal_visit(backup_holder<T>& lhs_content, long) const
+ {
+ lhs_content.get()
+ = ::boost::detail::variant::move(static_cast<backup_holder<T>* >(rhs_storage_)->get());
+ BOOST_VARIANT_AUX_RETURN_VOID;
+ }
+
+ template <typename T>
+ BOOST_VARIANT_AUX_RETURN_VOID_TYPE
+ internal_visit(const backup_holder<T>& lhs_content, long) const
+ {
+ lhs_content.get()
+ = ::boost::detail::variant::move(static_cast<backup_holder<T>* >(rhs_storage_)->get());
+ BOOST_VARIANT_AUX_RETURN_VOID;
+ }
+
+ template <typename T>
+ BOOST_VARIANT_AUX_RETURN_VOID_TYPE
+ internal_visit(T& lhs_content, int) const
+ {
+ // NOTE TO USER :
+ // Compile error here indicates one of variant's bounded types does
+ // not meet the requirements of the Assignable concept. Thus,
+ // variant is not Assignable.
+ //
+ // Hint: Are any of the bounded types const-qualified or references?
+ //
+ lhs_content = ::boost::detail::variant::move(*static_cast<T* >(rhs_storage_));
+ BOOST_VARIANT_AUX_RETURN_VOID;
+ }
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
 // (detail) class direct_assigner
 //
 // Generic static visitor that: if and only if the visited value is of the
@@ -504,7 +603,7 @@
 
 public: // structors
 
- explicit direct_assigner(const T& rhs)
+ explicit direct_assigner(const T& rhs) BOOST_NOEXCEPT
         : rhs_(rhs)
     {
     }
@@ -520,7 +619,7 @@
     }
 
     template <typename U>
- bool operator()(U&)
+ bool operator()(U&) BOOST_NOEXCEPT
     {
         return false;
     }
@@ -560,6 +659,65 @@
 };
 
 ///////////////////////////////////////////////////////////////////////////////
+// (detail) class direct_mover
+//
+// Generic static visitor that: if and only if the visited value is of the
+// specified type, move assigns the given value to the visited value and returns
+// true; else returns false.
+//
+template <typename T>
+class direct_mover
+ : public static_visitor<bool>
+{
+private: // representation
+
+ T& rhs_;
+
+public: // structors
+
+ explicit direct_mover(T& rhs) BOOST_NOEXCEPT
+ : rhs_(rhs)
+ {
+ }
+
+#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
+
+public: // visitor interface
+
+ bool operator()(T& lhs)
+ {
+ lhs = ::boost::detail::variant::move(rhs_);
+ return true;
+ }
+
+ template <typename U>
+ bool operator()(U&) BOOST_NOEXCEPT
+ {
+ return false;
+ }
+
+#else // MSVC6
+
+public: // visitor interface
+
+ template <typename U>
+ bool operator()(U& lhs)
+ {
+ // MSVC6 can not use direct_mover class
+ return direct_assigner(rhs_)(lhs);
+ }
+
+#endif // MSVC6 workaround
+
+#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
+private:
+ // silence MSVC warning C4512: assignment operator could not be generated
+ direct_mover& operator= (direct_mover const&);
+#endif
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
 // (detail) class backup_assigner
 //
 // Internal visitor that "assigns" the given value to the visited value,
@@ -745,7 +903,7 @@
 public: // visitor interfaces
 
     template <typename T>
- const std::type_info& operator()(const T&) const
+ const std::type_info& operator()(const T&) const BOOST_NOEXCEPT
     {
         return typeid(T);
     }
@@ -772,7 +930,7 @@
 
 public: // structors
 
- explicit comparer(const Variant& lhs)
+ explicit comparer(const Variant& lhs) BOOST_NOEXCEPT
         : lhs_(lhs)
     {
     }
@@ -844,7 +1002,7 @@
 
 public: // structors
 
- explicit invoke_visitor(Visitor& visitor)
+ explicit invoke_visitor(Visitor& visitor) BOOST_NOEXCEPT
         : visitor_(visitor)
     {
     }
@@ -1170,26 +1328,26 @@
     which_t which_;
     storage_t storage_;
 
- void indicate_which(int which_arg)
+ void indicate_which(int which_arg) BOOST_NOEXCEPT
     {
         which_ = static_cast<which_t>( which_arg );
     }
 
- void indicate_backup_which(int which_arg)
+ void indicate_backup_which(int which_arg) BOOST_NOEXCEPT
     {
         which_ = static_cast<which_t>( -(which_arg + 1) );
     }
 
 private: // helpers, for queries (below)
 
- bool using_backup() const
+ bool using_backup() const BOOST_NOEXCEPT
     {
         return which_ < 0;
     }
 
 public: // queries
 
- int which() const
+ int which() const BOOST_NOEXCEPT
     {
         // If using heap backup...
         if (using_backup())
@@ -1222,7 +1380,7 @@
         destroy_content();
     }
 
- variant()
+ variant() BOOST_NOEXCEPT_IF(boost::has_nothrow_constructor<internal_T0>::type::value)
     {
         // NOTE TO USER :
         // Compile error from here indicates that the first bound
@@ -1244,7 +1402,7 @@
 
     public: // structors
 
- explicit convert_copy_into(void* storage)
+ explicit convert_copy_into(void* storage) BOOST_NOEXCEPT
             : storage_(storage)
         {
         }
@@ -1454,6 +1612,18 @@
         // ...and activate the *this's primary storage on success:
         indicate_which(operand.which());
     }
+
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ variant(variant&& operand)
+ {
+ // Move the value of operand into *this...
+ detail::variant::move_into visitor( storage_.address() );
+ operand.internal_apply_visitor(visitor);
+
+ // ...and activate the *this's primary storage on success:
+ indicate_which(operand.which());
+ }
+#endif
 
 private: // helpers, for modifiers (below)
 
@@ -1478,7 +1648,7 @@
 
     public: // structors
 
- assigner(variant& lhs, int rhs_which)
+ assigner(variant& lhs, int rhs_which) BOOST_NOEXCEPT
             : lhs_(lhs)
             , rhs_which_(rhs_which)
         {
@@ -1605,8 +1775,153 @@
         assigner& operator= (assigner const&);
 #endif
     };
-
+
     friend class assigner;
+
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ // class move_assigner
+ //
+ // Internal visitor that "move assigns" the visited value to the given variant
+ // by appropriate destruction and move-construction.
+ //
+
+ class move_assigner
+ : public static_visitor<>
+ {
+ private: // representation
+
+ variant& lhs_;
+ int rhs_which_;
+
+ public: // structors
+
+ move_assigner(variant& lhs, int rhs_which) BOOST_NOEXCEPT
+ : lhs_(lhs)
+ , rhs_which_(rhs_which)
+ {
+ }
+
+ private: // helpers, for internal visitor interface (below)
+
+ template <typename RhsT, typename B1, typename B2>
+ void assign_impl(
+ RhsT& rhs_content
+ , mpl::true_// has_nothrow_copy
+ , mpl::false_// has_nothrow_move_constructor
+ , B2// has_fallback_type
+ )
+ {
+ // Destroy lhs's content...
+ lhs_.destroy_content(); // nothrow
+
+ // ...copy rhs content into lhs's storage...
+ new(lhs_.storage_.address())
+ RhsT( rhs_content ); // nothrow
+
+ // ...and indicate new content type:
+ lhs_.indicate_which(rhs_which_); // nothrow
+ }
+
+ template <typename RhsT, typename B>
+ void assign_impl(
+ RhsT& rhs_content
+ , mpl::true_// has_nothrow_copy
+ , mpl::true_// has_nothrow_move_constructor
+ , B// has_fallback_type
+ )
+ {
+ // ...destroy lhs's content...
+ lhs_.destroy_content(); // nothrow
+
+ // ...move the rhs_content into lhs's storage...
+ new(lhs_.storage_.address())
+ RhsT( detail::variant::move(rhs_content) ); // nothrow
+
+ // ...and indicate new content type:
+ lhs_.indicate_which(rhs_which_); // nothrow
+ }
+
+ template <typename RhsT>
+ void assign_impl(
+ RhsT& rhs_content
+ , mpl::false_// has_nothrow_copy
+ , mpl::false_// has_nothrow_move_constructor
+ , mpl::true_// has_fallback_type
+ )
+ {
+ // Destroy lhs's content...
+ lhs_.destroy_content(); // nothrow
+
+ try
+ {
+ // ...and attempt to copy rhs's content into lhs's storage:
+ new(lhs_.storage_.address())
+ RhsT( detail::variant::move(rhs_content) );
+ }
+ catch (...)
+ {
+ // In case of failure, default-construct fallback type in lhs's storage...
+ new (lhs_.storage_.address())
+ fallback_type_; // nothrow
+
+ // ...indicate construction of fallback type...
+ lhs_.indicate_which(
+ BOOST_MPL_AUX_VALUE_WKND(fallback_type_index_)::value
+ ); // nothrow
+
+ // ...and rethrow:
+ throw;
+ }
+
+ // In the event of success, indicate new content type:
+ lhs_.indicate_which(rhs_which_); // nothrow
+ }
+
+ template <typename RhsT>
+ void assign_impl(
+ const RhsT& rhs_content
+ , mpl::false_// has_nothrow_copy
+ , mpl::false_// has_nothrow_move_constructor
+ , mpl::false_// has_fallback_type
+ )
+ {
+ detail::variant::backup_assigner<wknd_self_t>
+ visitor(lhs_, rhs_which_, rhs_content);
+ lhs_.internal_apply_visitor(visitor);
+ }
+
+ public: // internal visitor interfaces
+
+ template <typename RhsT>
+ BOOST_VARIANT_AUX_RETURN_VOID_TYPE
+ internal_visit(RhsT& rhs_content, int)
+ {
+ typedef typename detail::variant::has_nothrow_move_constructor<RhsT>::type
+ nothrow_move_constructor;
+ typedef typename mpl::or_< // reduces compile-time
+ nothrow_move_constructor
+ , has_nothrow_copy<RhsT>
+ >::type nothrow_copy;
+
+ assign_impl(
+ rhs_content
+ , nothrow_copy()
+ , nothrow_move_constructor()
+ , has_fallback_type_()
+ );
+
+ BOOST_VARIANT_AUX_RETURN_VOID;
+ }
+
+#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
+ private:
+ // silence MSVC warning C4512: assignment operator could not be generated
+ move_assigner& operator= (move_assigner const&);
+#endif
+ };
+
+ friend class move_assigner;
+#endif // BOOST_NO_RVALUE_REFERENCES
 
     void variant_assign(const variant& rhs)
     {
@@ -1625,6 +1940,25 @@
         }
     }
 
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ void variant_assign(variant&& rhs)
+ {
+ // If the contained types are EXACTLY the same...
+ if (which_ == rhs.which_)
+ {
+ // ...then move rhs's storage to lhs's content:
+ detail::variant::move_storage visitor(rhs.storage_.address());
+ this->internal_apply_visitor(visitor);
+ }
+ else
+ {
+ // Otherwise, perform general (move-based) variant assignment:
+ move_assigner visitor(*this, rhs.which());
+ rhs.internal_apply_visitor(visitor);
+ }
+ }
+#endif // BOOST_NO_RVALUE_REFERENCES
+
 private: // helpers, for modifiers (below)
 
     template <typename T>
@@ -1645,8 +1979,37 @@
         }
     }
 
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ template <typename T>
+ void move_assign(T&& rhs)
+ {
+ // If direct T-to-T move assignment is not possible...
+ detail::variant::direct_mover<T> direct_move(rhs);
+ if (this->apply_visitor(direct_move) == false)
+ {
+ // ...then convert rhs to variant and assign:
+ //
+ // While potentially inefficient, the following construction of a
+ // variant allows T as any type convertible to one of the bounded
+ // types without excessive code redundancy.
+ //
+ variant temp( detail::variant::move(rhs) );
+ variant_assign( detail::variant::move(temp) );
+ }
+ }
+#endif // BOOST_NO_RVALUE_REFERENCES
+
 public: // modifiers
 
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ template <class T>
+ typename boost::enable_if<boost::is_rvalue_reference<T&&>, variant& >::type operator=(T&& rhs)
+ {
+ move_assign( detail::variant::move(rhs) );
+ return *this;
+ }
+#endif // BOOST_NO_RVALUE_REFERENCES
+
     template <typename T>
     variant& operator=(const T& rhs)
     {
@@ -1661,6 +2024,14 @@
         return *this;
     }
 
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ variant& operator=(variant&& rhs)
+ {
+ variant_assign( detail::variant::move(rhs) );
+ return *this;
+ }
+#endif // BOOST_NO_RVALUE_REFERENCES
+
     void swap(variant& rhs)
     {
         // If the contained types are the same...
@@ -1685,7 +2056,7 @@
     // NOTE: member which() defined above.
     //
 
- bool empty() const
+ bool empty() const BOOST_NOEXCEPT
     {
         return false;
     }

Added: trunk/libs/variant/perf/Jamfile.v2
==============================================================================
--- (empty file)
+++ trunk/libs/variant/perf/Jamfile.v2 2012-11-11 03:04:55 EST (Sun, 11 Nov 2012)
@@ -0,0 +1,29 @@
+#==============================================================================
+# Copyright (c) 2012 Antony Polukhin
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#==============================================================================
+
+# performance tests
+import testing ;
+import path ;
+
+path-constant TEST_DIR : . ;
+
+project performance/test
+ : source-location ./
+ : requirements
+# <library>/boost/chrono//boost_chrono
+# <library>/boost/system//boost_system
+ <link>static
+ <target-os>freebsd:<linkflags>"-lrt"
+ <target-os>linux:<linkflags>"-lrt"
+ <toolset>gcc:<cxxflags>-fvisibility=hidden
+ <toolset>intel-linux:<cxxflags>-fvisibility=hidden
+ <toolset>sun:<cxxflags>-xldscope=hidden
+ : default-build release
+ ;
+
+run move_perf.cpp : $(TEST_DIR) ;
+

Added: trunk/libs/variant/perf/move_perf.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/variant/perf/move_perf.cpp 2012-11-11 03:04:55 EST (Sun, 11 Nov 2012)
@@ -0,0 +1,229 @@
+// (C) Copyright Antony Polukhin 2012.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/config for most recent version.
+
+//
+// Testing variant performance rvalue copy/assign performance
+//
+
+#define BOOST_ERROR_CODE_HEADER_ONLY
+#define BOOST_CHRONO_HEADER_ONLY
+#include <boost/chrono.hpp>
+
+#include <boost/variant.hpp>
+#include <string>
+#include <vector>
+
+ struct scope {
+ typedef boost::chrono::steady_clock test_clock;
+ typedef boost::chrono::milliseconds duration_t;
+ test_clock::time_point start_;
+ const char* const message_;
+
+ explicit scope(const char* const message)
+ : start_(test_clock::now())
+ , message_(message)
+ {}
+
+ ~scope() {
+ std::cout << message_ << " " << boost::chrono::duration_cast<duration_t>(test_clock::now() - start_) << std::endl;
+ }
+ };
+
+
+
+static void do_test(bool do_count_cleanup_time = false) {
+ BOOST_STATIC_CONSTANT(std::size_t, c_run_count = 5000000);
+ typedef std::vector<char> str_t;
+ typedef boost::variant<int, str_t, float> var_t;
+
+ const char hello1_c[] = "hello long word";
+ const str_t hello1(hello1_c, hello1_c + sizeof(hello1_c));
+
+ const char hello2_c[] = "Helllloooooooooooooooooooooooooooooooo!!!!!!!!!!!!!";
+ const str_t hello2(hello2_c, hello2_c + sizeof(hello2_c));
+
+ if (do_count_cleanup_time) {
+ std::cout << "#############################################\n";
+ std::cout << "#############################################\n";
+ std::cout << "NOW TIMES WITH DATA DESTRUCTION\n";
+ std::cout << "#############################################\n";
+ }
+
+ std::vector<var_t> data_from, data_to;
+ data_from.resize(c_run_count, hello1);
+ data_to.reserve(c_run_count);
+ {
+ scope sc("boost::variant(const variant&) copying speed");
+ for (std::size_t i = 0; i < c_run_count; ++i) {
+ data_to.push_back(data_from[i]);
+
+ }
+
+ if (do_count_cleanup_time) {
+ data_to.clear();
+ data_from.clear();
+ }
+ }
+
+ data_from.resize(c_run_count, hello1);
+ data_to.clear();
+ data_to.reserve(c_run_count);
+ {
+ scope sc("boost::variant(variant&&) moving speed");
+ for (std::size_t i = 0; i < c_run_count; ++i) {
+ data_to.push_back(std::move(data_from[i]));
+ }
+
+ if (do_count_cleanup_time) {
+ data_to.clear();
+ data_from.clear();
+ }
+ }
+
+ std::cout << "#############################################\n";
+
+ data_from.clear();
+ data_from.resize(c_run_count, hello2);
+ data_to.clear();
+ data_to.resize(c_run_count, hello2);
+ {
+ scope sc("boost::variant=(const variant&) copying speed on same types");
+ for (std::size_t i = 0; i < c_run_count; ++i) {
+ data_to[i] = data_from[i];
+ }
+
+ if (do_count_cleanup_time) {
+ data_to.clear();
+ data_from.clear();
+ }
+ }
+
+ data_from.resize(c_run_count, hello2);
+ data_to.clear();
+ data_to.resize(c_run_count, hello2);
+ {
+ scope sc("boost::variant=(variant&&) moving speed on same types");
+ for (std::size_t i = 0; i < c_run_count; ++i) {
+ data_to[i] = std::move(data_from[i]);
+ }
+
+ if (do_count_cleanup_time) {
+ data_to.clear();
+ data_from.clear();
+ }
+ }
+
+ std::cout << "#############################################\n";
+
+ data_from.clear();
+ data_from.resize(c_run_count, hello2);
+
+ data_to.clear();
+ data_to.resize(c_run_count, var_t(0));
+ {
+ scope sc("boost::variant=(const variant&) copying speed on different types");
+ for (std::size_t i = 0; i < c_run_count; ++i) {
+ data_to[i] = data_from[i];
+ }
+
+ if (do_count_cleanup_time) {
+ data_to.clear();
+ data_from.clear();
+ }
+ }
+
+ data_from.resize(c_run_count, hello2);
+ data_to.clear();
+ data_to.resize(c_run_count, var_t(0));
+ {
+ scope sc("boost::variant=(variant&&) moving speed on different types");
+ for (std::size_t i = 0; i < c_run_count; ++i) {
+ data_to[i] = std::move(data_from[i]);
+ }
+
+ if (do_count_cleanup_time) {
+ data_to.clear();
+ data_from.clear();
+ }
+ }
+
+ std::cout << "#############################################\n";
+
+ data_from.clear();
+ data_from.resize(c_run_count, var_t(0));
+
+ data_to.clear();
+ data_to.resize(c_run_count, hello2);
+ {
+ scope sc("boost::variant=(const variant&) copying speed on different types II");
+ for (std::size_t i = 0; i < c_run_count; ++i) {
+ data_to[i] = data_from[i];
+ }
+
+ if (do_count_cleanup_time) {
+ data_to.clear();
+ data_from.clear();
+ }
+ }
+
+ data_from.resize(c_run_count, var_t(0));
+ data_to.clear();
+ data_to.resize(c_run_count, hello2);
+ {
+ scope sc("boost::variant=(variant&&) moving speed on different types II");
+ for (std::size_t i = 0; i < c_run_count; ++i) {
+ data_to[i] = std::move(data_from[i]);
+ }
+
+ if (do_count_cleanup_time) {
+ data_to.clear();
+ data_from.clear();
+ }
+ }
+
+
+ std::cout << "#############################################\n";
+
+ std::vector<str_t> s1(c_run_count, hello2);
+ data_to.clear();
+ data_to.resize(c_run_count, var_t(0));
+
+ {
+ scope sc("boost::variant=(const T&) copying speed");
+ for (std::size_t i = 0; i < c_run_count; ++i) {
+ data_to[i] = s1[i];
+ }
+
+ if (do_count_cleanup_time) {
+ data_to.clear();
+ s1.clear();
+ }
+ }
+
+ std::vector<str_t> s2(c_run_count, hello2);
+ data_to.clear();
+ data_to.resize(c_run_count, var_t(0));
+ {
+ scope sc("boost::variant=(T&&) moving speed");
+ for (std::size_t i = 0; i < c_run_count; ++i) {
+ data_to[i] = std::move(s2[i]);
+ }
+
+ if (do_count_cleanup_time) {
+ data_to.clear();
+ s2.clear();
+ }
+ }
+}
+
+
+int main () {
+ do_test(false);
+ do_test(true);
+}
+
+

Modified: trunk/libs/variant/test/Jamfile.v2
==============================================================================
--- trunk/libs/variant/test/Jamfile.v2 (original)
+++ trunk/libs/variant/test/Jamfile.v2 2012-11-11 03:04:55 EST (Sun, 11 Nov 2012)
@@ -33,6 +33,7 @@
     [ run variant_comparison_test.cpp ]
     [ run variant_visit_test.cpp ]
     [ run hash_variant_test.cpp ]
+ [ run rvalue_test.cpp ]
    ;
 
 

Added: trunk/libs/variant/test/rvalue_test.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/variant/test/rvalue_test.cpp 2012-11-11 03:04:55 EST (Sun, 11 Nov 2012)
@@ -0,0 +1,137 @@
+//-----------------------------------------------------------------------------
+// boost-libs variant/test/rvalue_test.cpp source file
+// See http://www.boost.org for updates, documentation, and revision history.
+//-----------------------------------------------------------------------------
+//
+// Copyright (c) 2012
+// Antony Polukhin
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "boost/config.hpp"
+
+#include "boost/test/minimal.hpp"
+#include "boost/variant.hpp"
+
+// This test requires BOOST_HAS_RVALUE_REFS
+
+#ifndef BOOST_HAS_RVALUE_REFS
+
+void run()
+{
+ BOOST_CHECK(true);
+}
+
+#else
+
+class move_copy_conting_class {
+public:
+ static unsigned int moves_count;
+ static unsigned int copy_count;
+
+ move_copy_conting_class(){}
+ move_copy_conting_class(move_copy_conting_class&&) {
+ ++ moves_count;
+ }
+
+ move_copy_conting_class& operator=(move_copy_conting_class&&) {
+ ++ moves_count;
+ return *this;
+ }
+
+ move_copy_conting_class(const move_copy_conting_class&) {
+ ++ copy_count;
+ }
+ move_copy_conting_class& operator=(const move_copy_conting_class&) {
+ ++ copy_count;
+ return *this;
+ }
+};
+
+unsigned int move_copy_conting_class::moves_count = 0;
+unsigned int move_copy_conting_class::copy_count = 0;
+
+void run()
+{
+ typedef boost::variant<int, move_copy_conting_class> variant_I_type;
+ variant_I_type v1, v2;
+
+ // Assuring that `move_copy_conting_class` was not created
+ BOOST_CHECK(move_copy_conting_class::copy_count == 0);
+ BOOST_CHECK(move_copy_conting_class::moves_count == 0);
+
+ v1 = move_copy_conting_class();
+ // Assuring that `move_copy_conting_class` was moved at least once
+ BOOST_CHECK(move_copy_conting_class::moves_count != 0);
+
+ unsigned int total_count = move_copy_conting_class::moves_count + move_copy_conting_class::copy_count;
+ move_copy_conting_class var;
+ v1 = 0;
+ move_copy_conting_class::moves_count = 0;
+ move_copy_conting_class::copy_count = 0;
+ v1 = var;
+ // Assuring that move assignment operator moves/copyes value not more times than copy assignment operator
+ BOOST_CHECK(total_count <= move_copy_conting_class::moves_count + move_copy_conting_class::copy_count);
+
+ move_copy_conting_class::moves_count = 0;
+ move_copy_conting_class::copy_count = 0;
+ v2 = static_cast<variant_I_type&&>(v1);
+ // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied
+ BOOST_CHECK(move_copy_conting_class::moves_count != 0);
+ BOOST_CHECK(move_copy_conting_class::copy_count == 0);
+
+ v1 = move_copy_conting_class();
+ move_copy_conting_class::moves_count = 0;
+ move_copy_conting_class::copy_count = 0;
+ v2 = static_cast<variant_I_type&&>(v1);
+ // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied
+ BOOST_CHECK(move_copy_conting_class::moves_count != 0);
+ BOOST_CHECK(move_copy_conting_class::copy_count == 0);
+ total_count = move_copy_conting_class::moves_count + move_copy_conting_class::copy_count;
+ move_copy_conting_class::moves_count = 0;
+ move_copy_conting_class::copy_count = 0;
+ v1 = v2;
+ // Assuring that move assignment operator moves/copyes value not more times than copy assignment operator
+ BOOST_CHECK(total_count <= move_copy_conting_class::moves_count + move_copy_conting_class::copy_count);
+
+
+ typedef boost::variant<move_copy_conting_class, int> variant_II_type;
+ variant_II_type v3;
+ move_copy_conting_class::moves_count = 0;
+ move_copy_conting_class::copy_count = 0;
+ v1 = static_cast<variant_II_type&&>(v3);
+ // Assuring that `move_copy_conting_class` in v3 was moved at least once (v1 and v3 have different types)
+ BOOST_CHECK(move_copy_conting_class::moves_count != 0);
+
+ move_copy_conting_class::moves_count = 0;
+ move_copy_conting_class::copy_count = 0;
+ v2 = static_cast<variant_I_type&&>(v1);
+ // Assuring that `move_copy_conting_class` in v1 was moved at least once (v1 and v3 have different types)
+ BOOST_CHECK(move_copy_conting_class::moves_count != 0);
+
+ move_copy_conting_class::moves_count = 0;
+ move_copy_conting_class::copy_count = 0;
+ variant_I_type v5(static_cast<variant_I_type&&>(v1));
+ // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied
+ BOOST_CHECK(move_copy_conting_class::moves_count != 0);
+ BOOST_CHECK(move_copy_conting_class::copy_count == 0);
+
+ total_count = move_copy_conting_class::moves_count + move_copy_conting_class::copy_count;
+ move_copy_conting_class::moves_count = 0;
+ move_copy_conting_class::copy_count = 0;
+ variant_I_type v6(v1);
+ // Assuring that move constructor moves/copyes value not more times than copy constructor
+ BOOST_CHECK(total_count <= move_copy_conting_class::moves_count + move_copy_conting_class::copy_count);
+}
+
+
+#endif
+
+
+int test_main(int , char* [])
+{
+ run();
+ return 0;
+}
\ No newline at end of file


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