diff options
Diffstat (limited to '3rdParty/Boost/src/boost/variant/variant.hpp')
-rw-r--r-- | 3rdParty/Boost/src/boost/variant/variant.hpp | 784 |
1 files changed, 612 insertions, 172 deletions
diff --git a/3rdParty/Boost/src/boost/variant/variant.hpp b/3rdParty/Boost/src/boost/variant/variant.hpp index 6afd190..4ed5ad4 100644 --- a/3rdParty/Boost/src/boost/variant/variant.hpp +++ b/3rdParty/Boost/src/boost/variant/variant.hpp @@ -1,30 +1,31 @@ //----------------------------------------------------------------------------- // boost variant/variant.hpp header file // See http://www.boost.org for updates, documentation, and revision history. //----------------------------------------------------------------------------- // -// Copyright (c) 2002-2003 -// Eric Friedman, Itay Maman +// Copyright (c) 2002-2003 Eric Friedman, Itay Maman +// Copyright (c) 2012-2013 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) +// Thanks to Adam Romanek for providing patches for exception-disabled env. + #ifndef BOOST_VARIANT_VARIANT_HPP #define BOOST_VARIANT_VARIANT_HPP #include <cstddef> // for std::size_t #include <new> // for placement new #if !defined(BOOST_NO_TYPEID) #include <typeinfo> // for typeid, std::type_info #endif // BOOST_NO_TYPEID #include "boost/variant/detail/config.hpp" -#include "boost/mpl/aux_/config/eti.hpp" #include "boost/mpl/aux_/value_wknd.hpp" #include "boost/variant/variant_fwd.hpp" #include "boost/variant/detail/backup_holder.hpp" #include "boost/variant/detail/enable_recursive_fwd.hpp" #include "boost/variant/detail/forced_return.hpp" @@ -32,29 +33,32 @@ #include "boost/variant/detail/make_variant_list.hpp" #include "boost/variant/detail/over_sequence.hpp" #include "boost/variant/detail/visitation_impl.hpp" #include "boost/variant/detail/hash_variant.hpp" #include "boost/variant/detail/generic_result_type.hpp" -#include "boost/variant/detail/has_nothrow_move.hpp" #include "boost/variant/detail/move.hpp" +#include "boost/detail/no_exceptions_support.hpp" #include "boost/detail/reference_content.hpp" #include "boost/aligned_storage.hpp" #include "boost/blank.hpp" #include "boost/math/common_factor_ct.hpp" #include "boost/static_assert.hpp" #include "boost/preprocessor/cat.hpp" #include "boost/preprocessor/repeat.hpp" #include "boost/type_traits/alignment_of.hpp" #include "boost/type_traits/add_const.hpp" #include "boost/type_traits/has_nothrow_constructor.hpp" #include "boost/type_traits/has_nothrow_copy.hpp" +#include "boost/type_traits/is_nothrow_move_constructible.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" #include "boost/mpl/assert.hpp" #include "boost/mpl/begin_end.hpp" #include "boost/mpl/bool.hpp" @@ -211,21 +215,47 @@ public: // metafunction result > , mpl::identity< second_result_ > >::type type; }; -#if defined(BOOST_MPL_CFG_MSVC_60_ETI_BUG) - -template<> -struct find_fallback_type<int> -{ - typedef mpl::pair< no_fallback_type,no_fallback_type > type; +#ifndef BOOST_NO_CXX11_NOEXCEPT +/////////////////////////////////////////////////////////////////////////////// +// (detail) metafunction is_variant_move_noexcept_constructible +// +// Returns true_type if all the types are nothrow move constructible. +// +template <class Types> +struct is_variant_move_noexcept_constructible { + typedef typename boost::mpl::find_if< + Types, mpl::not_<boost::is_nothrow_move_constructible<boost::mpl::_1> > + >::type iterator_t; + + typedef typename boost::mpl::end<Types>::type end_t; + typedef typename boost::is_same< + iterator_t, end_t + >::type type; }; -#endif // BOOST_MPL_CFG_MSVC_60_ETI_BUG workaround +/////////////////////////////////////////////////////////////////////////////// +// (detail) metafunction is_variant_move_noexcept_assignable +// +// Returns true_type if all the types are nothrow move constructible. +// +template <class Types> +struct is_variant_move_noexcept_assignable { + typedef typename boost::mpl::find_if< + Types, mpl::not_<boost::is_nothrow_move_assignable<boost::mpl::_1> > + >::type iterator_t; + + typedef typename boost::mpl::end<Types>::type end_t; + typedef typename boost::is_same< + iterator_t, end_t + >::type type; +}; +#endif // BOOST_NO_CXX11_NOEXCEPT /////////////////////////////////////////////////////////////////////////////// // (detail) metafunction make_storage // // Provides an aligned storage type capable of holding any of the types // specified in the given type-sequence. @@ -262,58 +292,33 @@ private: // helpers, for metafunction result (below) typedef mpl::size_t< -1 > max_alignment; #endif // borland workaround public: // metafunction result -#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) - typedef ::boost::aligned_storage< BOOST_MPL_AUX_VALUE_WKND(max_size)::value , BOOST_MPL_AUX_VALUE_WKND(max_alignment)::value > type; - -#else // MSVC7 and below - - BOOST_STATIC_CONSTANT(std::size_t, msvc_max_size_c = max_size::value); - BOOST_STATIC_CONSTANT(std::size_t, msvc_max_alignment_c = max_alignment::value); - - typedef ::boost::aligned_storage< - msvc_max_size_c - , msvc_max_alignment_c - > type; - -#endif // MSVC workaround - }; -#if defined(BOOST_MPL_CFG_MSVC_60_ETI_BUG) - -template<> -struct make_storage<int,int> -{ - typedef int type; -}; - -#endif // BOOST_MPL_CFG_MSVC_60_ETI_BUG workaround - /////////////////////////////////////////////////////////////////////////////// // (detail) class destroyer // // Internal visitor that destroys the value it visits. // struct destroyer : public static_visitor<> { public: // visitor interfaces template <typename T> BOOST_VARIANT_AUX_RETURN_VOID_TYPE - internal_visit(T& operand, int) const + internal_visit(T& operand, int) const BOOST_NOEXCEPT { - operand.~T(); + operand.~T(); // must be noexcept #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0551)) || \ BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) operand; // suppresses warnings #endif @@ -331,59 +336,25 @@ public: // visitor interfaces // template <typename T> class known_get : public static_visitor<T&> { -#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) - public: // visitor interface - T& operator()(T& operand) const + T& operator()(T& operand) const BOOST_NOEXCEPT { return operand; } template <typename U> T& operator()(U&) const { // logical error to be here: see precondition above - BOOST_ASSERT(false); return ::boost::detail::variant::forced_return< T& >(); } - -#else // MSVC6 - -private: // helpers, for visitor interface (below) - - T& execute(T& operand, mpl::true_) const - { - return operand; - } - - template <typename U> - T& execute(U& operand, mpl::false_) const - { - // logical error to be here: see precondition above - BOOST_ASSERT(false); - return ::boost::detail::variant::forced_return< T& >(); - } - -public: // visitor interface - - template <typename U> - T& operator()(U& operand) const - { - typedef typename is_same< U,T >::type - U_is_T; - - return execute(operand, U_is_T()); - } - -#endif // MSVC6 workaround - }; /////////////////////////////////////////////////////////////////////////////// // (detail) class copy_into // // Internal visitor that copies the value it visits into the given buffer. @@ -394,13 +365,13 @@ class copy_into private: // representation void* storage_; public: // structors - explicit copy_into(void* storage) + explicit copy_into(void* storage) BOOST_NOEXCEPT : storage_(storage) { } public: // internal visitor interface @@ -428,12 +399,52 @@ public: // internal visitor interface BOOST_VARIANT_AUX_RETURN_VOID; } }; /////////////////////////////////////////////////////////////////////////////// +// (detail) class move_into +// +// Internal visitor that moves the value it visits into the given buffer. +// +#ifndef BOOST_NO_CXX11_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 // constructed value of the same type) to the value it visits. // struct assign_storage @@ -442,13 +453,13 @@ struct assign_storage private: // representation const void* rhs_storage_; public: // structors - explicit assign_storage(const void* rhs_storage) + explicit assign_storage(const void* rhs_storage) BOOST_NOEXCEPT : rhs_storage_(rhs_storage) { } public: // internal visitor interfaces @@ -485,12 +496,69 @@ public: // internal visitor interfaces BOOST_VARIANT_AUX_RETURN_VOID; } }; /////////////////////////////////////////////////////////////////////////////// +// (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 // specified type, assigns the given value to the visited value and returns // true; else returns false. // @@ -501,67 +569,82 @@ class direct_assigner private: // representation const T& rhs_; public: // structors - explicit direct_assigner(const T& rhs) + explicit direct_assigner(const T& rhs) BOOST_NOEXCEPT : rhs_(rhs) { } -#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) - public: // visitor interface bool operator()(T& lhs) { lhs = rhs_; return true; } template <typename U> - bool operator()(U&) + bool operator()(U&) BOOST_NOEXCEPT { return false; } -#else // MSVC6 +#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) +private: + // silence MSVC warning C4512: assignment operator could not be generated + direct_assigner& operator= (direct_assigner const&); +#endif +}; -private: // helpers, for visitor interface (below) +/////////////////////////////////////////////////////////////////////////////// +// (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 - bool execute(T& lhs, mpl::true_) - { - lhs = rhs_; - return true; - } + T& rhs_; - template <typename U> - bool execute(U&, mpl::false_) +public: // structors + + explicit direct_mover(T& rhs) BOOST_NOEXCEPT + : rhs_(rhs) { - return false; } public: // visitor interface - template <typename U> - bool operator()(U& lhs) + bool operator()(T& lhs) { - typedef typename is_same<U,T>::type U_is_T; - return execute(lhs, U_is_T()); + lhs = ::boost::detail::variant::move(rhs_); + return true; } -#endif // MSVC6 workaround + template <typename U> + bool operator()(U&) BOOST_NOEXCEPT + { + return false; + } #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) private: // silence MSVC warning C4512: assignment operator could not be generated - direct_assigner& operator= (direct_assigner const&); + direct_mover& operator= (direct_mover const&); #endif }; + /////////////////////////////////////////////////////////////////////////////// // (detail) class backup_assigner // // Internal visitor that "assigns" the given value to the visited value, // using backup to recover if the destroy-copy sequence fails. // @@ -598,73 +681,75 @@ private: // helpers, for visitor interface (below) new(addr) RhsT(*static_cast<const RhsT*>(obj)); } template <typename LhsT> void backup_assign_impl( LhsT& lhs_content - , mpl::true_// has_nothrow_move + , mpl::true_ // is_nothrow_move_constructible ) { // Move lhs content to backup... LhsT backup_lhs_content( ::boost::detail::variant::move(lhs_content) ); // nothrow // ...destroy lhs content... lhs_content.~LhsT(); // nothrow - try + BOOST_TRY { // ...and attempt to copy rhs content into lhs storage: copy_rhs_content_(lhs_.storage_.address(), rhs_content_); } - catch (...) + BOOST_CATCH (...) { // In case of failure, restore backup content to lhs storage... new(lhs_.storage_.address()) LhsT( ::boost::detail::variant::move(backup_lhs_content) ); // nothrow // ...and rethrow: - throw; + BOOST_RETHROW; } + BOOST_CATCH_END // In case of success, indicate new content type: lhs_.indicate_which(rhs_which_); // nothrow } template <typename LhsT> void backup_assign_impl( LhsT& lhs_content - , mpl::false_// has_nothrow_move + , mpl::false_ // is_nothrow_move_constructible ) { // Backup lhs content... LhsT* backup_lhs_ptr = new LhsT(lhs_content); // ...destroy lhs content... lhs_content.~LhsT(); // nothrow - try + BOOST_TRY { // ...and attempt to copy rhs content into lhs storage: copy_rhs_content_(lhs_.storage_.address(), rhs_content_); } - catch (...) + BOOST_CATCH (...) { // In case of failure, copy backup pointer to lhs storage... new(lhs_.storage_.address()) backup_holder<LhsT>( backup_lhs_ptr ); // nothrow // ...indicate now using backup... lhs_.indicate_backup_which( lhs_.which() ); // nothrow // ...and rethrow: - throw; + BOOST_RETHROW; } + BOOST_CATCH_END // In case of success, indicate new content type... lhs_.indicate_which(rhs_which_); // nothrow // ...and delete backup: delete backup_lhs_ptr; // nothrow @@ -673,13 +758,13 @@ private: // helpers, for visitor interface (below) public: // visitor interface template <typename LhsT> BOOST_VARIANT_AUX_RETURN_VOID_TYPE internal_visit(LhsT& lhs_content, int) { - typedef typename has_nothrow_move_constructor<LhsT>::type + typedef typename is_nothrow_move_constructible<LhsT>::type nothrow_move; backup_assign_impl( lhs_content, nothrow_move() ); BOOST_VARIANT_AUX_RETURN_VOID; } @@ -705,13 +790,13 @@ struct swap_with private: // representation Variant& toswap_; public: // structors - explicit swap_with(Variant& toswap) + explicit swap_with(Variant& toswap) BOOST_NOEXCEPT : toswap_(toswap) { } public: // internal visitor interfaces @@ -742,13 +827,13 @@ private: class reflect : public static_visitor<const std::type_info&> { 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); } }; @@ -769,13 +854,13 @@ class comparer private: // representation const Variant& lhs_; public: // structors - explicit comparer(const Variant& lhs) + explicit comparer(const Variant& lhs) BOOST_NOEXCEPT : lhs_(lhs) { } public: // visitor interfaces @@ -841,13 +926,13 @@ public: // visitor typedefs typedef typename Visitor::result_type result_type; public: // structors - explicit invoke_visitor(Visitor& visitor) + explicit invoke_visitor(Visitor& visitor) BOOST_NOEXCEPT : visitor_(visitor) { } #if !defined(BOOST_NO_VOID_RETURNS) @@ -1128,12 +1213,23 @@ private: // helpers, for representation (below) never_uses_backup_flag; typedef typename detail::variant::make_storage< internal_types, never_uses_backup_flag >::type storage_t; +#ifndef BOOST_NO_CXX11_NOEXCEPT + typedef typename detail::variant::is_variant_move_noexcept_constructible< + internal_types + > variant_move_noexcept_constructible; + + typedef typename detail::variant::is_variant_move_noexcept_assignable< + internal_types + > variant_move_noexcept_assignable; + +#endif + private: // helpers, for representation (below) // which_ on: // * [0, size<internal_types>) indicates stack content // * [-size<internal_types>, 0) indicates pointer to heap backup // if which_ >= 0: @@ -1167,32 +1263,32 @@ private: // helpers, for representation (below) public: #endif 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()) // ...then return adjusted which_: return -(which_ + 1); @@ -1206,34 +1302,42 @@ private: // helpers, for structors (below) : BOOST_VARIANT_AUX_INITIALIZER_T( recursive_enabled_types, recursive_enabled_T ) { }; - void destroy_content() + void destroy_content() BOOST_NOEXCEPT { detail::variant::destroyer visitor; this->internal_apply_visitor(visitor); } public: // structors - ~variant() + ~variant() BOOST_NOEXCEPT { destroy_content(); } - variant() + variant() BOOST_NOEXCEPT_IF(boost::has_nothrow_constructor<internal_T0>::value) { +#ifdef _MSC_VER +#pragma warning( push ) +// behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized +#pragma warning( disable : 4345 ) +#endif // NOTE TO USER : // Compile error from here indicates that the first bound // type is not default-constructible, and so variant cannot // support its own default-construction. // new( storage_.address() ) internal_T0(); indicate_which(0); // zero is the index of the first bounded type +#ifdef _MSC_VER +#pragma warning( pop ) +#endif } private: // helpers, for structors, cont. (below) class convert_copy_into : public static_visitor<int> @@ -1241,13 +1345,13 @@ private: // helpers, for structors, cont. (below) private: // representation void* storage_; public: // structors - explicit convert_copy_into(void* storage) + explicit convert_copy_into(void* storage) BOOST_NOEXCEPT : storage_(storage) { } public: // internal visitor interfaces (below) @@ -1307,12 +1411,80 @@ private: // helpers, for structors, cont. (below) } }; friend class convert_copy_into; +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + class convert_move_into + : public static_visitor<int> + { + private: // representation + + void* storage_; + + public: // structors + + explicit convert_move_into(void* storage) BOOST_NOEXCEPT + : storage_(storage) + { + } + + public: // internal visitor interfaces (below) + + template <typename T> + int internal_visit(T& operand, int) const + { + // NOTE TO USER : + // Compile error here indicates one of the source variant's types + // cannot be unambiguously converted to the destination variant's + // types (or that no conversion exists). + // + return initializer::initialize(storage_, detail::variant::move(operand) ); + } + + template <typename T> + int internal_visit(boost::detail::reference_content<T>& operand, long) const + { + return internal_visit( operand.get(), 1L ); + } + + template <typename T> + int internal_visit(const boost::detail::reference_content<T>& operand, long) const + { + return internal_visit( operand.get(), 1L ); + } + + template <typename T> + int internal_visit(boost::detail::variant::backup_holder<T>& operand, long) const + { + return internal_visit( operand.get(), 1L ); + } + + template <typename T> + int internal_visit(const boost::detail::variant::backup_holder<T>& operand, long) const + { + return internal_visit( operand.get(), 1L ); + } + + template <typename T> + int internal_visit(boost::recursive_wrapper<T>& operand, long) const + { + return internal_visit( operand.get(), 1L ); + } + + template <typename T> + int internal_visit(const boost::recursive_wrapper<T>& operand, long) const + { + return internal_visit( operand.get(), 1L ); + } + }; + + friend class convert_move_into; +#endif + private: // helpers, for structors, below template <typename T> void convert_construct( T& operand , int @@ -1329,12 +1501,34 @@ private: // helpers, for structors, below storage_.address() , operand ) ); } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template <typename T> + typename boost::enable_if<boost::is_rvalue_reference<T&&> >::type convert_construct( + T&& operand + , int + , mpl::false_ = mpl::false_() // is_foreign_variant + ) + { + // NOTE TO USER : + // Compile error here indicates that the given type is not + // unambiguously convertible to one of the variant's types + // (or that no conversion exists). + // + indicate_which( + initializer::initialize( + storage_.address() + , detail::variant::move(operand) + ) + ); + } +#endif + template <typename Variant> void convert_construct( Variant& operand , long , mpl::true_// is_foreign_variant ) @@ -1342,12 +1536,27 @@ private: // helpers, for structors, below convert_copy_into visitor(storage_.address()); indicate_which( operand.internal_apply_visitor(visitor) ); } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template <typename Variant> + typename boost::enable_if<boost::is_rvalue_reference<Variant&&> >::type convert_construct( + Variant&& operand + , long + , mpl::true_// is_foreign_variant + ) + { + convert_move_into visitor(storage_.address()); + indicate_which( + operand.internal_apply_visitor(visitor) + ); + } +#endif + template <typename Variant> void convert_construct_variant(Variant& operand) { // [Determine if the given variant is itself a bounded type, or if its // content needs to be converted (i.e., it is a 'foreign' variant):] // @@ -1369,12 +1578,41 @@ private: // helpers, for structors, below convert_construct( operand, 1L , is_foreign_variant() ); } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template <typename Variant> + typename boost::enable_if<boost::is_rvalue_reference<Variant&&> >::type convert_construct_variant(Variant&& operand) + { + // [Determine if the given variant is itself a bounded type, or if its + // content needs to be converted (i.e., it is a 'foreign' variant):] + // + + typedef typename mpl::find_if< + types + , is_same< + add_const<mpl::_1> + , const Variant + > + >::type found_it; + + typedef typename mpl::end<types>::type not_found; + typedef typename is_same< + found_it, not_found + >::type is_foreign_variant; + + // Convert move construct from operand: + convert_construct( + detail::variant::move(operand), 1L + , is_foreign_variant() + ); + } +#endif + template <BOOST_VARIANT_ENUM_PARAMS(typename U)> void convert_construct( boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)>& operand , long ) { @@ -1387,12 +1625,23 @@ private: // helpers, for structors, below , long ) { convert_construct_variant(operand); } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template <BOOST_VARIANT_ENUM_PARAMS(typename U)> + void convert_construct( + boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)>&& operand + , long + ) + { + convert_construct_variant( detail::variant::move(operand) ); + } +#endif + public: // structors, cont. #if !defined(BOOST_VARIANT_AUX_BROKEN_CONSTRUCTOR_TEMPLATE_ORDERING) template <typename T> variant(const T& operand) @@ -1436,14 +1685,22 @@ public: // structors, cont. template <typename T> variant(const T& operand) { convert_construct(operand, 1L); } - #endif // BOOST_VARIANT_AUX_BROKEN_CONSTRUCTOR_TEMPLATE_ORDERING workarounds + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template <class T> + variant(T&& operand, typename boost::enable_if<boost::is_rvalue_reference<T&&> >::type* = 0, + typename boost::disable_if<boost::is_const<T> >::type* = 0) + { + convert_construct( detail::variant::move(operand), 1L); + } +#endif public: // structors, cont. // [MSVC6 requires copy constructor appear after template constructors] variant(const variant& operand) { @@ -1451,12 +1708,24 @@ public: // structors, cont. detail::variant::copy_into visitor( storage_.address() ); operand.internal_apply_visitor(visitor); // ...and activate the *this's primary storage on success: indicate_which(operand.which()); } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + variant(variant&& operand) BOOST_NOEXCEPT_IF(variant_move_noexcept_constructible::type::value) + { + // 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) # if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template <typename Variant> friend class detail::variant::backup_assigner; @@ -1468,34 +1737,34 @@ private: // helpers, for modifiers (below) // by appropriate destruction and copy-construction. // class assigner : public static_visitor<> { - private: // representation + protected: // representation variant& lhs_; - int rhs_which_; + const int rhs_which_; public: // structors - assigner(variant& lhs, int rhs_which) + assigner(variant& lhs, int rhs_which) BOOST_NOEXCEPT : lhs_(lhs) , rhs_which_(rhs_which) { } - private: // helpers, for internal visitor interface (below) + protected: // helpers, for internal visitor interface (below) template <typename RhsT, typename B1, typename B2> void assign_impl( const RhsT& rhs_content - , mpl::true_// has_nothrow_copy - , B1// has_nothrow_move_constructor - , B2// has_fallback_type - ) + , mpl::true_ // has_nothrow_copy + , B1 // is_nothrow_move_constructible + , B2 // has_fallback_type + ) const BOOST_NOEXCEPT { // Destroy lhs's content... lhs_.destroy_content(); // nothrow // ...copy rhs content into lhs's storage... new(lhs_.storage_.address()) @@ -1505,16 +1774,16 @@ private: // helpers, for modifiers (below) lhs_.indicate_which(rhs_which_); // nothrow } template <typename RhsT, typename B> void assign_impl( const RhsT& rhs_content - , mpl::false_// has_nothrow_copy - , mpl::true_// has_nothrow_move_constructor - , B// has_fallback_type - ) + , mpl::false_ // has_nothrow_copy + , mpl::true_ // is_nothrow_move_constructible + , B // has_fallback_type + ) const { // Attempt to make a temporary copy (so as to move it below)... RhsT temp(rhs_content); // ...and upon success destroy lhs's content... lhs_.destroy_content(); // nothrow @@ -1524,72 +1793,77 @@ private: // helpers, for modifiers (below) RhsT( detail::variant::move(temp) ); // nothrow // ...and indicate new content type: lhs_.indicate_which(rhs_which_); // nothrow } + void construct_fallback() const BOOST_NOEXCEPT { + // 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 + } + template <typename RhsT> void assign_impl( const RhsT& rhs_content - , mpl::false_// has_nothrow_copy - , mpl::false_// has_nothrow_move_constructor - , mpl::true_// has_fallback_type - ) + , mpl::false_ // has_nothrow_copy + , mpl::false_ // is_nothrow_move_constructible + , mpl::true_ // has_fallback_type + ) const { // Destroy lhs's content... lhs_.destroy_content(); // nothrow - try + BOOST_TRY { // ...and attempt to copy rhs's content into lhs's storage: new(lhs_.storage_.address()) RhsT( rhs_content ); } - catch (...) + BOOST_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 + construct_fallback(); // ...and rethrow: - throw; + BOOST_RETHROW; } + BOOST_CATCH_END // 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 - ) + , mpl::false_ // has_nothrow_copy + , mpl::false_ // is_nothrow_move_constructible + , mpl::false_ // has_fallback_type + ) const { 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(const RhsT& rhs_content, int) + internal_visit(const RhsT& rhs_content, int) const { typedef typename has_nothrow_copy<RhsT>::type nothrow_copy; typedef typename mpl::or_< // reduces compile-time nothrow_copy - , detail::variant::has_nothrow_move_constructor<RhsT> + , is_nothrow_move_constructible<RhsT> >::type nothrow_move_constructor; assign_impl( rhs_content , nothrow_copy() , nothrow_move_constructor() @@ -1602,14 +1876,137 @@ private: // helpers, for modifiers (below) #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) private: // silence MSVC warning C4512: assignment operator could not be generated assigner& operator= (assigner const&); #endif }; - + friend class assigner; + +#ifndef BOOST_NO_CXX11_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 assigner + { + public: // structors + + move_assigner(variant& lhs, int rhs_which) BOOST_NOEXCEPT + : assigner(lhs, rhs_which) + { + } + + private: // helpers, for internal visitor interface (below) + + template <typename RhsT, typename B2> + void assign_impl( + RhsT& rhs_content + , mpl::true_ // has_nothrow_copy + , mpl::false_ // is_nothrow_move_constructible + , B2 // has_fallback_type + ) const BOOST_NOEXCEPT + { + assigner::assign_impl(rhs_content, mpl::true_(), mpl::false_(), B2()); + } + + template <typename RhsT, typename B, typename B2> + void assign_impl( + RhsT& rhs_content + , B // has_nothrow_copy + , mpl::true_ // is_nothrow_move_constructible + , B2 // has_fallback_type + ) const BOOST_NOEXCEPT + { + // ...destroy lhs's content... + assigner::lhs_.destroy_content(); // nothrow + + // ...move the rhs_content into lhs's storage... + new(assigner::lhs_.storage_.address()) + RhsT( detail::variant::move(rhs_content) ); // nothrow + + // ...and indicate new content type: + assigner::lhs_.indicate_which(assigner::rhs_which_); // nothrow + } + + template <typename RhsT> + void assign_impl( + RhsT& rhs_content + , mpl::false_ // has_nothrow_copy + , mpl::false_ // is_nothrow_move_constructible + , mpl::true_ // has_fallback_type + ) const + { + // Destroy lhs's content... + assigner::lhs_.destroy_content(); // nothrow + + BOOST_TRY + { + // ...and attempt to copy rhs's content into lhs's storage: + new(assigner::lhs_.storage_.address()) + RhsT( detail::variant::move(rhs_content) ); + } + BOOST_CATCH (...) + { + assigner::construct_fallback(); + + // ...and rethrow: + BOOST_RETHROW; + } + BOOST_CATCH_END + + // In the event of success, indicate new content type: + assigner::lhs_.indicate_which(assigner::rhs_which_); // nothrow + } + + template <typename RhsT> + void assign_impl( + RhsT& rhs_content + , mpl::false_ // has_nothrow_copy + , mpl::false_ // is_nothrow_move_constructible + , mpl::false_ // has_fallback_type + ) const + { + assigner::assign_impl(rhs_content, mpl::false_(), mpl::false_(), mpl::false_()); + } + + public: // internal visitor interfaces + + template <typename RhsT> + BOOST_VARIANT_AUX_RETURN_VOID_TYPE + internal_visit(RhsT& rhs_content, int) const + { + typedef typename is_nothrow_move_constructible<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_CXX11_RVALUE_REFERENCES void variant_assign(const variant& rhs) { // If the contained types are EXACTLY the same... if (which_ == rhs.which_) { @@ -1622,12 +2019,31 @@ private: // helpers, for modifiers (below) // Otherwise, perform general (copy-based) variant assignment: assigner visitor(*this, rhs.which()); rhs.internal_apply_visitor(visitor); } } +#ifndef BOOST_NO_CXX11_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_CXX11_RVALUE_REFERENCES + private: // helpers, for modifiers (below) template <typename T> void assign(const T& rhs) { // If direct T-to-T assignment is not possible... @@ -1642,14 +2058,44 @@ private: // helpers, for modifiers (below) // variant temp(rhs); variant_assign( detail::variant::move(temp) ); } } +#ifndef BOOST_NO_CXX11_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_CXX11_RVALUE_REFERENCES + public: // modifiers +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template <class T> + typename boost::enable_if_c<boost::is_rvalue_reference<T&&>::value && !boost::is_const<T>::value, variant& >::type + operator=(T&& rhs) + { + move_assign( detail::variant::move(rhs) ); + return *this; + } +#endif // BOOST_NO_CXX11_RVALUE_REFERENCES + template <typename T> variant& operator=(const T& rhs) { assign(rhs); return *this; } @@ -1658,12 +2104,23 @@ public: // modifiers variant& operator=(const variant& rhs) { variant_assign(rhs); return *this; } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + variant& operator=(variant&& rhs) +#if !defined(__GNUC__) || (__GNUC__ != 4) || (__GNUC_MINOR__ > 6) + BOOST_NOEXCEPT_IF(variant_move_noexcept_constructible::type::value && variant_move_noexcept_assignable::type::value) +#endif + { + variant_assign( detail::variant::move(rhs) ); + return *this; + } +#endif // BOOST_NO_CXX11_RVALUE_REFERENCES + void swap(variant& rhs) { // If the contained types are the same... if (which() == rhs.which()) { // ...then swap the values directly: @@ -1682,13 +2139,13 @@ public: // modifiers public: // queries // // NOTE: member which() defined above. // - bool empty() const + bool empty() const BOOST_NOEXCEPT { return false; } #if !defined(BOOST_NO_TYPEID) const std::type_info& type() const @@ -1697,39 +2154,24 @@ public: // queries return this->apply_visitor(visitor); } #endif public: // prevent comparison with foreign types -#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) - +// Obsolete. Remove. # define BOOST_VARIANT_AUX_FAIL_COMPARISON_RETURN_TYPE \ void -#else // MSVC7 - - // - // MSVC7 gives error about return types for above being different than - // the true comparison operator overloads: - // - -# define BOOST_VARIANT_AUX_FAIL_COMPARISON_RETURN_TYPE \ - bool - -#endif // MSVC7 workaround - template <typename U> - BOOST_VARIANT_AUX_FAIL_COMPARISON_RETURN_TYPE - operator==(const U&) const + void operator==(const U&) const { BOOST_STATIC_ASSERT( false && sizeof(U) ); } template <typename U> - BOOST_VARIANT_AUX_FAIL_COMPARISON_RETURN_TYPE - operator<(const U&) const + void operator<(const U&) const { BOOST_STATIC_ASSERT( false && sizeof(U) ); } public: // comparison operators @@ -1856,15 +2298,13 @@ public: // visitation support // template <typename Types> struct make_variant_over { private: // precondition assertions -#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) BOOST_STATIC_ASSERT(( ::boost::mpl::is_sequence<Types>::value )); -#endif public: // metafunction result typedef variant< detail::variant::over_sequence< Types > > type; |