mirror of
https://github.com/boostorg/variant.git
synced 2026-02-02 21:32:11 +00:00
Merge from trunk: added basic rvalue support and marked some functions with BOOST_NOEXCEPT (fixes #7620)
[SVN r81455]
This commit is contained in:
@@ -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 @@ public: // structors
|
||||
delete backup_;
|
||||
}
|
||||
|
||||
explicit backup_holder(T* backup)
|
||||
explicit backup_holder(T* backup) BOOST_NOEXCEPT
|
||||
: backup_(backup)
|
||||
{
|
||||
}
|
||||
@@ -53,7 +54,7 @@ public: // modifiers
|
||||
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 @@ backup_holder<T>::backup_holder(const backup_holder&)
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -82,6 +82,8 @@ public: // metafunction result
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#ifdef BOOST_NO_RVALUE_REFERENCES
|
||||
|
||||
template <typename T>
|
||||
inline
|
||||
typename detail::move_type<T>::type
|
||||
@@ -93,6 +95,12 @@ move(T& source)
|
||||
return move_t(source);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
using std::move;
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// class template return_t
|
||||
//
|
||||
|
||||
@@ -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 @@ class known_get
|
||||
|
||||
public: // visitor interface
|
||||
|
||||
T& operator()(T& operand) const
|
||||
T& operator()(T& operand) const BOOST_NOEXCEPT
|
||||
{
|
||||
return operand;
|
||||
}
|
||||
@@ -397,7 +399,7 @@ private: // representation
|
||||
|
||||
public: // structors
|
||||
|
||||
explicit copy_into(void* storage)
|
||||
explicit copy_into(void* storage) BOOST_NOEXCEPT
|
||||
: storage_(storage)
|
||||
{
|
||||
}
|
||||
@@ -430,6 +432,46 @@ public: // internal visitor interface
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// (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
|
||||
//
|
||||
@@ -445,7 +487,7 @@ private: // representation
|
||||
|
||||
public: // structors
|
||||
|
||||
explicit assign_storage(const void* rhs_storage)
|
||||
explicit assign_storage(const void* rhs_storage) BOOST_NOEXCEPT
|
||||
: rhs_storage_(rhs_storage)
|
||||
{
|
||||
}
|
||||
@@ -487,6 +529,63 @@ public: // internal visitor interfaces
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// (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
|
||||
//
|
||||
@@ -504,7 +603,7 @@ private: // representation
|
||||
|
||||
public: // structors
|
||||
|
||||
explicit direct_assigner(const T& rhs)
|
||||
explicit direct_assigner(const T& rhs) BOOST_NOEXCEPT
|
||||
: rhs_(rhs)
|
||||
{
|
||||
}
|
||||
@@ -520,7 +619,7 @@ public: // visitor interface
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
bool operator()(U&)
|
||||
bool operator()(U&) BOOST_NOEXCEPT
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -559,6 +658,65 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// (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
|
||||
//
|
||||
@@ -745,7 +903,7 @@ class reflect
|
||||
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 @@ private: // representation
|
||||
|
||||
public: // structors
|
||||
|
||||
explicit comparer(const Variant& lhs)
|
||||
explicit comparer(const Variant& lhs) BOOST_NOEXCEPT
|
||||
: lhs_(lhs)
|
||||
{
|
||||
}
|
||||
@@ -844,7 +1002,7 @@ public: // visitor typedefs
|
||||
|
||||
public: // structors
|
||||
|
||||
explicit invoke_visitor(Visitor& visitor)
|
||||
explicit invoke_visitor(Visitor& visitor) BOOST_NOEXCEPT
|
||||
: visitor_(visitor)
|
||||
{
|
||||
}
|
||||
@@ -1170,26 +1328,26 @@ private: // helpers, for representation (below)
|
||||
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 @@ public: // structors
|
||||
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 @@ private: // helpers, for structors, cont. (below)
|
||||
|
||||
public: // structors
|
||||
|
||||
explicit convert_copy_into(void* storage)
|
||||
explicit convert_copy_into(void* storage) BOOST_NOEXCEPT
|
||||
: storage_(storage)
|
||||
{
|
||||
}
|
||||
@@ -1454,6 +1612,18 @@ public: // structors, cont.
|
||||
// ...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 @@ private: // helpers, for modifiers (below)
|
||||
|
||||
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 @@ private: // helpers, for modifiers (below)
|
||||
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 @@ private: // helpers, for modifiers (below)
|
||||
}
|
||||
}
|
||||
|
||||
#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 @@ private: // helpers, for modifiers (below)
|
||||
}
|
||||
}
|
||||
|
||||
#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 @@ public: // modifiers
|
||||
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 @@ public: // queries
|
||||
// NOTE: member which() defined above.
|
||||
//
|
||||
|
||||
bool empty() const
|
||||
bool empty() const BOOST_NOEXCEPT
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ test-suite variant
|
||||
[ run variant_comparison_test.cpp ]
|
||||
[ run variant_visit_test.cpp ]
|
||||
[ run hash_variant_test.cpp ]
|
||||
[ run rvalue_test.cpp ]
|
||||
;
|
||||
|
||||
|
||||
|
||||
137
test/rvalue_test.cpp
Normal file
137
test/rvalue_test.cpp
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user