123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- //-----------------------------------------------------------------------------
- // boost-libs variant/test/rvalue_test.cpp source file
- // See http://www.boost.org for updates, documentation, and revision history.
- //-----------------------------------------------------------------------------
- //
- // Copyright (c) 2012-2019 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/core/lightweight_test.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_TEST(true);
- }
- void run_move_only()
- {
- BOOST_TEST(true);
- }
- void run_moves_are_noexcept()
- {
- BOOST_TEST(true);
- }
- void run_const_rvalues()
- {
- BOOST_TEST(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_TEST(move_copy_conting_class::copy_count == 0);
- BOOST_TEST(move_copy_conting_class::moves_count == 0);
-
- v1 = move_copy_conting_class();
- // Assuring that `move_copy_conting_class` was moved at least once
- BOOST_TEST(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_TEST(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_TEST(move_copy_conting_class::moves_count != 0);
- BOOST_TEST(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_TEST(move_copy_conting_class::moves_count != 0);
- BOOST_TEST(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_TEST(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_TEST(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_TEST(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_TEST(move_copy_conting_class::moves_count != 0);
- BOOST_TEST(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_TEST(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_TEST(move_copy_conting_class::copy_count == 0);
- BOOST_TEST(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_TEST(vi.which() == 0);
- BOOST_TEST(vi2.which() == 1);
- vi = 10;
- vi2 = 10;
- BOOST_TEST(vi.which() == 0);
- BOOST_TEST(vi2.which() == 0);
- vi = static_cast<move_only_structure&&>(mo);
- vi2 = static_cast<move_only_structure&&>(mo);
- BOOST_TEST(vi.which() == 1);
- boost::variant<move_only_structure, int > rvi (1);
- BOOST_TEST(rvi.which() == 1);
- rvi = static_cast<move_only_structure&&>(mo);
- BOOST_TEST(rvi.which() == 0);
- rvi = 1;
- BOOST_TEST(rvi.which() == 1);
- rvi = static_cast<boost::variant<int, move_only_structure >&&>(vi2);
- BOOST_TEST(rvi.which() == 0);
- move_only_structure from_visitor = boost::apply_visitor(visitor_returning_move_only_type(), vi);
- (void)from_visitor;
- }
- void run_moves_are_noexcept() {
- #if !defined(BOOST_NO_CXX11_NOEXCEPT) && (!defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || __GNUC_MINOR__ >= 8)
- typedef boost::variant<int, short, double> variant_noexcept_t;
- BOOST_TEST(boost::is_nothrow_move_assignable<variant_noexcept_t>::value);
- BOOST_TEST(boost::is_nothrow_move_constructible<variant_noexcept_t>::value);
- typedef boost::variant<int, short, double, move_only_structure> variant_except_t;
- BOOST_TEST(!boost::is_nothrow_move_assignable<variant_except_t>::value);
- BOOST_TEST(!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_TEST((!is_container<boost::variant<double, int> >::value));
- BOOST_TEST((!is_container<boost::variant<double, int, char> >::value));
- BOOST_TEST((!is_container<boost::variant<double, int, char, float> >::value));
- }
- int main()
- {
- 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_TEST(false &&
- "Something wrong with macro definitions. GCC-4.7+ is known to work with variadic templates"
- );
- # endif
- #endif
- return boost::report_errors();
- }
|