blob: 8ef9d3971b5a0ebc4c77d531d6bf1ba7f39983c7 [file] [log] [blame]
//-----------------------------------------------------------------------------
// boost-libs variant/test/rvalue_test.cpp source file
// See http://www.boost.org for updates, documentation, and revision history.
//-----------------------------------------------------------------------------
//
// Copyright (c) 2012-2014 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"
#include "boost/type_traits/is_nothrow_move_assignable.hpp"
#include "boost/mpl/bool.hpp"
#include <boost/blank.hpp>
#include <boost/swap.hpp>
namespace swap_ambiguouty_test_ns {
struct A {};
struct B {};
void swap_ambiguouty_test() {
// If boost::blank is not used, then it compiles.
typedef boost::variant<boost::blank, A, B> Variant;
Variant v1, v2;
swap(v1, v2);
}
} // namespace swap_ambiguouty_test_ns
// Most part of tests from this file require rvalue references support
class 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) ) {
++ moves_count;
}
move_copy_conting_class& operator=(BOOST_RV_REF(move_copy_conting_class) ) {
++ 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) ) {
++ copy_count;
return *this;
}
};
unsigned int move_copy_conting_class::moves_count = 0;
unsigned int move_copy_conting_class::copy_count = 0;
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
void run()
{
// Making sure that internals of Boost.Move do not interfere with
// internals of Boost.Variant and in case of C++03 or C++98 compilation
// is still possible.
typedef boost::variant<int, move_copy_conting_class> variant_I_type;
variant_I_type v1, v2;
v1 = move_copy_conting_class();
v2 = v1;
v2 = boost::move(v1);
v1.swap(v2);
move_copy_conting_class val;
v2 = boost::move(val);
v2 = 10;
variant_I_type v3(boost::move(val));
variant_I_type v4(boost::move(v1));
}
void run1()
{
BOOST_CHECK(true);
}
void run_move_only()
{
BOOST_CHECK(true);
}
void run_moves_are_noexcept()
{
BOOST_CHECK(true);
}
void run_const_rvalues()
{
BOOST_CHECK(true);
}
#else
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 = boost::move(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 = boost::move(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 = boost::move(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 = boost::move(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(boost::move(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);
}
void run1()
{
move_copy_conting_class::moves_count = 0;
move_copy_conting_class::copy_count = 0;
move_copy_conting_class c1;
typedef boost::variant<int, move_copy_conting_class> variant_I_type;
variant_I_type v1(boost::move(c1));
// Assuring that `move_copy_conting_class` was not copyied
BOOST_CHECK(move_copy_conting_class::copy_count == 0);
BOOST_CHECK(move_copy_conting_class::moves_count > 0);
}
struct move_only_structure {
move_only_structure(){}
move_only_structure(move_only_structure&&){}
move_only_structure& operator=(move_only_structure&&) { return *this; }
private:
move_only_structure(const move_only_structure&);
move_only_structure& operator=(const move_only_structure&);
};
struct visitor_returning_move_only_type: boost::static_visitor<move_only_structure> {
template <class T>
move_only_structure operator()(const T&) const {
return move_only_structure();
}
};
void run_move_only()
{
move_only_structure mo;
boost::variant<int, move_only_structure > vi, vi2(static_cast<move_only_structure&&>(mo));
BOOST_CHECK(vi.which() == 0);
BOOST_CHECK(vi2.which() == 1);
vi = 10;
vi2 = 10;
BOOST_CHECK(vi.which() == 0);
BOOST_CHECK(vi2.which() == 0);
vi = static_cast<move_only_structure&&>(mo);
vi2 = static_cast<move_only_structure&&>(mo);
BOOST_CHECK(vi.which() == 1);
move_only_structure from_visitor = boost::apply_visitor(visitor_returning_move_only_type(), vi);
(void)from_visitor;
}
void run_moves_are_noexcept() {
#ifndef BOOST_NO_CXX11_NOEXCEPT
typedef boost::variant<int, short, double> variant_noexcept_t;
//BOOST_CHECK(boost::is_nothrow_move_assignable<variant_noexcept_t>::value);
BOOST_CHECK(boost::is_nothrow_move_constructible<variant_noexcept_t>::value);
typedef boost::variant<int, short, double, move_only_structure> variant_except_t;
//BOOST_CHECK(!boost::is_nothrow_move_assignable<variant_except_t>::value);
BOOST_CHECK(!boost::is_nothrow_move_constructible<variant_except_t>::value);
#endif
}
inline const std::string get_string() { return "test"; }
inline const boost::variant<int, std::string> get_variant() { return std::string("test"); }
inline const boost::variant<std::string, int> get_variant2() { return std::string("test"); }
void run_const_rvalues()
{
typedef boost::variant<int, std::string> variant_t;
const variant_t v1(get_string());
const variant_t v2(get_variant());
const variant_t v3(get_variant2());
variant_t v4, v5, v6, v7;
v4 = get_string();
v5 = get_variant();
v6 = get_variant2();
v7 = boost::move(v1);
}
#endif
struct nothrow_copyable_throw_movable {
nothrow_copyable_throw_movable(){}
nothrow_copyable_throw_movable(const nothrow_copyable_throw_movable&) BOOST_NOEXCEPT {}
nothrow_copyable_throw_movable& operator=(const nothrow_copyable_throw_movable&) BOOST_NOEXCEPT { return *this; }
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
nothrow_copyable_throw_movable(nothrow_copyable_throw_movable&&) BOOST_NOEXCEPT_IF(false) {}
nothrow_copyable_throw_movable& operator=(nothrow_copyable_throw_movable&&) BOOST_NOEXCEPT_IF(false) { return *this; }
#endif
};
// This test is created to cover the following situation:
// https://svn.boost.org/trac/boost/ticket/8772
void run_tricky_compilation_test()
{
boost::variant<int, nothrow_copyable_throw_movable> v;
v = nothrow_copyable_throw_movable();
}
template <typename T>
struct is_container : boost::mpl::false_ {};
template <typename T>
struct is_container<boost::variant<T> > : is_container<T> {};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct is_container<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
: boost::mpl::bool_<is_container<T0>::value
|| is_container<boost::variant<BOOST_VARIANT_ENUM_SHIFTED_PARAMS(T)> >::value>
{};
void run_is_container_compilation_test()
{
BOOST_CHECK((!is_container<boost::variant<double, int> >::value));
BOOST_CHECK((!is_container<boost::variant<double, int, char> >::value));
BOOST_CHECK((!is_container<boost::variant<double, int, char, float> >::value));
}
int test_main(int , char* [])
{
swap_ambiguouty_test_ns::swap_ambiguouty_test();
run();
run1();
run_move_only();
run_moves_are_noexcept();
run_tricky_compilation_test();
run_const_rvalues();
run_is_container_compilation_test();
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ > 6)
# ifdef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
BOOST_CHECK(false &&
"Something wrong with macro definitions. GCC-4.7+ is known to work with variadic templates"
);
# endif
#endif
return 0;
}