Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r83901 - in trunk: boost libs/any/test
From: antoshkka_at_[hidden]
Date: 2013-04-14 14:16:29


Author: apolukhin
Date: 2013-04-14 14:16:26 EDT (Sun, 14 Apr 2013)
New Revision: 83901
URL: http://svn.boost.org/trac/boost/changeset/83901

Log:
Added rvalue references support via Boost.Move to Boost.Any (refs #6999)
Added:
   trunk/libs/any/test/any_test_rv.cpp (contents, props changed)
Text files modified:
   trunk/boost/any.hpp | 126 +++++++++++++++++++++++++++++++++++----
   trunk/libs/any/test/Jamfile.v2 | 1
   2 files changed, 112 insertions(+), 15 deletions(-)

Modified: trunk/boost/any.hpp
==============================================================================
--- trunk/boost/any.hpp (original)
+++ trunk/boost/any.hpp 2013-04-14 14:16:26 EDT (Sun, 14 Apr 2013)
@@ -3,12 +3,16 @@
 #ifndef BOOST_ANY_INCLUDED
 #define BOOST_ANY_INCLUDED
 
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
 // what: variant type boost::any
 // who: contributed by Kevlin Henney,
 // with features contributed and bugs found by
-// Ed Brey, Mark Rodgers, Peter Dimov, and James Curran
-// when: July 2001
-// where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95
+// Antony Polukhin, Ed Brey, Mark Rodgers,
+// Peter Dimov, and James Curran
+// when: July 2001, Aplril 2013
 
 #include <algorithm>
 #include <typeinfo>
@@ -18,6 +22,7 @@
 #include <boost/type_traits/is_reference.hpp>
 #include <boost/throw_exception.hpp>
 #include <boost/static_assert.hpp>
+#include <boost/move/move.hpp>
 
 // See boost/python/type_id.hpp
 // TODO: add BOOST_TYPEID_COMPARE_BY_NAME to config.hpp
@@ -30,27 +35,80 @@
 #include <cstring>
 # endif
 
+#ifdef BOOST_MSVC
+#pragma warning (push)
+#pragma warning (disable : 4521 ) // multiple copy constructors specified
+#pragma warning (disable : 4522 ) // multiple assignment operators specified
+#endif
+
 namespace boost
 {
     class any
     {
+ private:
+ // Mark this class copyable and movable
+ BOOST_COPYABLE_AND_MOVABLE(any)
     public: // structors
 
- any()
+ any() BOOST_NOEXCEPT
           : content(0)
         {
         }
+
+ any(const any & other)
+ : content(other.content ? other.content->clone() : 0)
+ {
+ }
+
+ //Move constructor
+ any(BOOST_RV_REF(any) other) BOOST_NOEXCEPT
+ : content(other.content)
+ {
+ other.content = 0;
+ }
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+ any(any & other)
+ : content(other.content ? other.content->clone() : 0)
+ {
+ }
+
+ template<typename ValueType>
+ any(ValueType&& value)
+ : content(new holder< BOOST_DEDUCED_TYPENAME remove_reference<ValueType>::type >(
+ ::boost::forward<ValueType>(value)
+ ))
+ {
+ }
+#else
+ any(const ::boost::rv<any>& other)
+ : content(other.content ? other.content->clone() : 0)
+ {
+ }
 
         template<typename ValueType>
         any(const ValueType & value)
           : content(new holder<ValueType>(value))
         {
+ BOOST_STATIC_ASSERT_MSG(!boost::move_detail::is_rv<ValueType>::value,
+ "You compiler can not deal with emulated move semantics."
+ "Please remove moves of non boost::any types to boost::any container."
+ );
+ }
+#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+ template<typename ValueType>
+ any(const ::boost::rv<ValueType> & value)
+ : content(new holder<ValueType>(value))
+ {
         }
 
- any(const any & other)
- : content(other.content ? other.content->clone() : 0)
+ template<typename ValueType>
+ any(::boost::rv<ValueType> & value)
+ : content(new holder<ValueType>(value))
         {
         }
+#endif
+#endif // BOOST_NO_CXX11_RVALUE_REFERENCES
 
         ~any()
         {
@@ -59,12 +117,40 @@
 
     public: // modifiers
 
- any & swap(any & rhs)
+ any & swap(any & rhs) BOOST_NOEXCEPT
         {
             std::swap(content, rhs.content);
             return *this;
         }
+
+ any & operator=(BOOST_COPY_ASSIGN_REF(any) rhs)
+ {
+ any(rhs).swap(*this);
+ return *this;
+ }
 
+ any & operator=(BOOST_RV_REF(any) rhs) BOOST_NOEXCEPT
+ {
+ rhs.swap(*this); // noexcept
+ any().swap(rhs); // noexcept
+ return *this;
+ }
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+ any & operator=(any& rhs)
+ {
+ any(rhs).swap(*this);
+ return *this;
+ }
+
+ template<typename ValueType>
+ any & operator=(ValueType&& rhs)
+ {
+ any( ::boost::forward<ValueType>(rhs) )
+ .swap(*this);
+ return *this;
+ }
+#else
         template<typename ValueType>
         any & operator=(const ValueType & rhs)
         {
@@ -72,15 +158,17 @@
             return *this;
         }
 
- any & operator=(any rhs)
+ template<typename ValueType>
+ any & operator=(ValueType & rhs)
         {
- rhs.swap(*this);
+ any(rhs).swap(*this);
             return *this;
         }
+#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
 
     public: // queries
 
- bool empty() const
+ bool empty() const BOOST_NOEXCEPT
         {
             return !content;
         }
@@ -122,6 +210,10 @@
             {
             }
 
+ holder(BOOST_RV_REF(ValueType) value)
+ : held( boost::move(value) )
+ {
+ }
         public: // queries
 
             virtual const std::type_info & type() const
@@ -147,7 +239,7 @@
     private: // representation
 
         template<typename ValueType>
- friend ValueType * any_cast(any *);
+ friend ValueType * any_cast(any *) BOOST_NOEXCEPT;
 
         template<typename ValueType>
         friend ValueType * unsafe_any_cast(any *);
@@ -162,7 +254,7 @@
 
     };
 
- inline void swap(any & lhs, any & rhs)
+ inline void swap(any & lhs, any & rhs) BOOST_NOEXCEPT
     {
         lhs.swap(rhs);
     }
@@ -178,7 +270,7 @@
     };
 
     template<typename ValueType>
- ValueType * any_cast(any * operand)
+ ValueType * any_cast(any * operand) BOOST_NOEXCEPT
     {
         return operand &&
 #ifdef BOOST_AUX_ANY_TYPE_ID_NAME
@@ -191,7 +283,7 @@
     }
 
     template<typename ValueType>
- inline const ValueType * any_cast(const any * operand)
+ inline const ValueType * any_cast(const any * operand) BOOST_NOEXCEPT
     {
         return any_cast<ValueType>(const_cast<any *>(operand));
     }
@@ -247,7 +339,11 @@
     {
         return unsafe_any_cast<ValueType>(const_cast<any *>(operand));
     }
-}
+} // namespace boost
+
+#ifdef BOOST_MSVC
+#pragma warning (pop)
+#endif
 
 // Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
 //

Modified: trunk/libs/any/test/Jamfile.v2
==============================================================================
--- trunk/libs/any/test/Jamfile.v2 (original)
+++ trunk/libs/any/test/Jamfile.v2 2013-04-14 14:16:26 EDT (Sun, 14 Apr 2013)
@@ -8,6 +8,7 @@
 
 test-suite any :
     [ run ../any_test.cpp ]
+ [ run any_test_rv.cpp ]
     [ compile-fail any_cast_cv_failed.cpp ]
     ;
 

Added: trunk/libs/any/test/any_test_rv.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/any/test/any_test_rv.cpp 2013-04-14 14:16:26 EDT (Sun, 14 Apr 2013)
@@ -0,0 +1,266 @@
+// Unit test for boost::any.
+//
+// See http://www.boost.org for most recent version, including documentation.
+//
+// Copyright Antony Polukhin, 2013.
+//
+// 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 <cstdlib>
+#include <string>
+#include <utility>
+
+#include "boost/any.hpp"
+#include "../test.hpp"
+
+namespace any_tests
+{
+ typedef test<const char *, void (*)()> test_case;
+ typedef const test_case * test_case_iterator;
+
+ extern const test_case_iterator begin, end;
+}
+
+int main()
+{
+ using namespace any_tests;
+ tester<test_case_iterator> test_suite(begin, end);
+ return test_suite() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+namespace any_tests // test suite
+{
+ void test_move_construction();
+ void test_move_assignment();
+ void test_copy_construction();
+ void test_copy_assignment();
+
+ void test_move_construction_from_value();
+ void test_move_assignment_from_value();
+ void test_copy_construction_from_value();
+ void test_copy_assignment_from_value();
+
+
+ const test_case test_cases[] =
+ {
+ { "move construction of any", test_move_construction },
+ { "move assignment of any", test_move_assignment },
+ { "copy construction of any", test_copy_construction },
+ { "copy assignment of any", test_copy_assignment },
+
+ { "move construction from value", test_move_construction_from_value },
+ { "move assignment from value", test_move_assignment_from_value },
+ { "copy construction from value", test_copy_construction_from_value },
+ { "copy assignment from value", test_copy_assignment_from_value }
+ };
+
+ const test_case_iterator begin = test_cases;
+ const test_case_iterator end =
+ test_cases + (sizeof test_cases / sizeof *test_cases);
+
+
+ class move_copy_conting_class {
+ BOOST_COPYABLE_AND_MOVABLE(move_copy_conting_class)
+ public:
+ static unsigned int moves_count;
+ static unsigned int copy_count;
+
+ move_copy_conting_class(){}
+ move_copy_conting_class(BOOST_RV_REF(move_copy_conting_class) /*param*/) {
+ ++ moves_count;
+ }
+
+ move_copy_conting_class& operator=(BOOST_RV_REF(move_copy_conting_class) /*param*/) {
+ ++ moves_count;
+ return *this;
+ }
+
+ move_copy_conting_class(const move_copy_conting_class&) {
+ ++ copy_count;
+ }
+ move_copy_conting_class& operator=(BOOST_COPY_ASSIGN_REF(move_copy_conting_class) /*param*/) {
+ ++ copy_count;
+ return *this;
+ }
+ };
+
+ unsigned int move_copy_conting_class::moves_count = 0;
+ unsigned int move_copy_conting_class::copy_count = 0;
+}
+
+namespace any_tests // test definitions
+{
+ using namespace boost;
+
+ void test_move_construction()
+ {
+ any value0 = move_copy_conting_class();
+ move_copy_conting_class::copy_count = 0;
+ move_copy_conting_class::moves_count = 0;
+ any value(boost::move(value0));
+
+ check(value0.empty(), "moved away value is empty");
+ check_false(value.empty(), "empty");
+ check_equal(value.type(), typeid(move_copy_conting_class), "type");
+ check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
+ check_equal(
+ move_copy_conting_class::copy_count, 0u,
+ "checking copy counts");
+ check_equal(
+ move_copy_conting_class::moves_count, 0u,
+ "checking move counts");
+ }
+
+ void test_move_assignment()
+ {
+ any value0 = move_copy_conting_class();
+ any value = move_copy_conting_class();
+ move_copy_conting_class::copy_count = 0;
+ move_copy_conting_class::moves_count = 0;
+ value = boost::move(value0);
+
+ check(value0.empty(), "moved away is empty");
+ check_false(value.empty(), "empty");
+ check_equal(value.type(), typeid(move_copy_conting_class), "type");
+ check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
+ check_equal(
+ move_copy_conting_class::copy_count, 0u,
+ "checking copy counts");
+ check_equal(
+ move_copy_conting_class::moves_count, 0u,
+ "checking move counts");
+ }
+
+ void test_copy_construction()
+ {
+ any value0 = move_copy_conting_class();
+ move_copy_conting_class::copy_count = 0;
+ move_copy_conting_class::moves_count = 0;
+ any value(value0);
+
+ check_false(value0.empty(), "copyed value is not empty");
+ check_false(value.empty(), "empty");
+ check_equal(value.type(), typeid(move_copy_conting_class), "type");
+ check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
+ check_equal(
+ move_copy_conting_class::copy_count, 1u,
+ "checking copy counts");
+ check_equal(
+ move_copy_conting_class::moves_count, 0u,
+ "checking move counts");
+ }
+
+ void test_copy_assignment()
+ {
+ any value0 = move_copy_conting_class();
+ any value = move_copy_conting_class();
+ move_copy_conting_class::copy_count = 0;
+ move_copy_conting_class::moves_count = 0;
+ value = value0;
+
+ check_false(value0.empty(), "copyied value is not empty");
+ check_false(value.empty(), "empty");
+ check_equal(value.type(), typeid(move_copy_conting_class), "type");
+ check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
+ check_equal(
+ move_copy_conting_class::copy_count, 1u,
+ "checking copy counts");
+ check_equal(
+ move_copy_conting_class::moves_count, 0u,
+ "checking move counts");
+ }
+
+ void test_move_construction_from_value()
+ {
+ move_copy_conting_class value0;
+ move_copy_conting_class::copy_count = 0;
+ move_copy_conting_class::moves_count = 0;
+#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+ any value(boost::move(value0));
+#else
+ any value(value0);
+#endif
+
+ check_false(value.empty(), "empty");
+ check_equal(value.type(), typeid(move_copy_conting_class), "type");
+ check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
+
+#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+ check_equal(
+ move_copy_conting_class::copy_count, 0u,
+ "checking copy counts");
+ check_equal(
+ move_copy_conting_class::moves_count, 1u,
+ "checking move counts");
+#endif
+
+ }
+
+ void test_move_assignment_from_value()
+ {
+ move_copy_conting_class value0;
+ any value;
+ move_copy_conting_class::copy_count = 0;
+ move_copy_conting_class::moves_count = 0;
+#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+ value = boost::move(value0);
+#else
+ value = value0;
+#endif
+
+ check_false(value.empty(), "empty");
+ check_equal(value.type(), typeid(move_copy_conting_class), "type");
+ check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
+
+#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+ check_equal(
+ move_copy_conting_class::copy_count, 0u,
+ "checking copy counts");
+ check_equal(
+ move_copy_conting_class::moves_count, 1u,
+ "checking move counts");
+#endif
+
+ }
+
+ void test_copy_construction_from_value()
+ {
+ move_copy_conting_class value0;
+ move_copy_conting_class::copy_count = 0;
+ move_copy_conting_class::moves_count = 0;
+ any value(value0);
+
+ check_false(value.empty(), "empty");
+ check_equal(value.type(), typeid(move_copy_conting_class), "type");
+ check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
+
+ check_equal(
+ move_copy_conting_class::copy_count, 1u,
+ "checking copy counts");
+ check_equal(
+ move_copy_conting_class::moves_count, 0u,
+ "checking move counts");
+ }
+
+ void test_copy_assignment_from_value()
+ {
+ move_copy_conting_class value0;
+ any value;
+ move_copy_conting_class::copy_count = 0;
+ move_copy_conting_class::moves_count = 0;
+ value = value0;
+
+ check_false(value.empty(), "empty");
+ check_equal(value.type(), typeid(move_copy_conting_class), "type");
+ check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
+
+ check_equal(
+ move_copy_conting_class::copy_count, 1u,
+ "checking copy counts");
+ check_equal(
+ move_copy_conting_class::moves_count, 0u,
+ "checking move counts");
+ }
+}


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