summaryrefslogtreecommitdiff
path: root/libs/variant/test
diff options
context:
space:
mode:
Diffstat (limited to 'libs/variant/test')
-rw-r--r--libs/variant/test/Jamfile.v23
-rw-r--r--libs/variant/test/auto_visitors.cpp321
-rw-r--r--libs/variant/test/recursive_variant_test.cpp67
-rw-r--r--libs/variant/test/rvalue_test.cpp17
-rw-r--r--libs/variant/test/test8.cpp8
-rw-r--r--libs/variant/test/variant_comparison_test.cpp35
-rw-r--r--libs/variant/test/variant_get_test.cpp323
-rw-r--r--libs/variant/test/variant_multivisit_test.cpp49
-rw-r--r--libs/variant/test/variant_nonempty_check.cpp474
-rw-r--r--libs/variant/test/variant_polymorphic_get_test.cpp29
10 files changed, 1309 insertions, 17 deletions
diff --git a/libs/variant/test/Jamfile.v2 b/libs/variant/test/Jamfile.v2
index 91b30595e..c861ac94f 100644
--- a/libs/variant/test/Jamfile.v2
+++ b/libs/variant/test/Jamfile.v2
@@ -28,10 +28,12 @@ test-suite variant
[ run variant_reference_test.cpp ]
[ run variant_comparison_test.cpp ]
[ run variant_visit_test.cpp ]
+ [ run variant_get_test.cpp ]
[ run variant_polymorphic_get_test.cpp ]
[ run variant_multivisit_test.cpp ]
[ run hash_variant_test.cpp ]
[ run rvalue_test.cpp ]
+ [ run variant_nonempty_check.cpp ]
[ run recursive_variant_test.cpp : : : <define>BOOST_NO_EXCEPTIONS
<toolset>gcc-4.3:<cxxflags>-fno-exceptions
<toolset>gcc-4.4:<cxxflags>-fno-exceptions
@@ -44,6 +46,7 @@ test-suite variant
]
[ run recursive_variant_test.cpp : : : <rtti>off <define>BOOST_NO_RTTI <define>BOOST_NO_TYPEID : variant_no_rtti_test ]
[ run variant_swap_test.cpp ]
+ [ run auto_visitors.cpp ]
;
diff --git a/libs/variant/test/auto_visitors.cpp b/libs/variant/test/auto_visitors.cpp
new file mode 100644
index 000000000..84c91c9d2
--- /dev/null
+++ b/libs/variant/test/auto_visitors.cpp
@@ -0,0 +1,321 @@
+//-----------------------------------------------------------------------------
+// boost-libs variant/test/auto_visitors.cpp source file
+// See http://www.boost.org for updates, documentation, and revision history.
+//-----------------------------------------------------------------------------
+//
+// Copyright (c) 2014-2015 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/variant/multivisitors.hpp"
+#include "boost/lexical_cast.hpp"
+
+struct lex_streamer_explicit: boost::static_visitor<std::string> {
+ template <class T>
+ const char* operator()(const T& ) {
+ return "10";
+ }
+
+ template <class T1, class T2>
+ const char* operator()(const T1& , const T2& ) {
+ return "100";
+ }
+};
+
+
+void run_explicit()
+{
+ typedef boost::variant<int, std::string, double> variant_type;
+ variant_type v2("10"), v1("100");
+
+ lex_streamer_explicit visitor_ref;
+
+ // Must return instance of std::string
+ BOOST_CHECK(boost::apply_visitor(visitor_ref, v2).c_str() == std::string("10"));
+ BOOST_CHECK(boost::apply_visitor(visitor_ref, v2, v1).c_str() == std::string("100"));
+}
+
+
+// Most part of tests from this file require decltype(auto)
+
+#ifdef BOOST_NO_CXX14_DECLTYPE_AUTO
+
+void run()
+{
+ BOOST_CHECK(true);
+}
+
+void run2()
+{
+ BOOST_CHECK(true);
+}
+
+
+void run3()
+{
+ BOOST_CHECK(true);
+}
+
+#else
+
+#include <iostream>
+
+struct lex_streamer {
+ template <class T>
+ std::string operator()(const T& val) const {
+ return boost::lexical_cast<std::string>(val);
+ }
+};
+
+struct lex_streamer_void {
+ template <class T>
+ void operator()(const T& val) const {
+ std::cout << val << std::endl;
+ }
+
+
+ template <class T1, class T2>
+ void operator()(const T1& val, const T2& val2) const {
+ std::cout << val << '+' << val2 << std::endl;
+ }
+
+
+ template <class T1, class T2, class T3>
+ void operator()(const T1& val, const T2& val2, const T3& val3) const {
+ std::cout << val << '+' << val2 << '+' << val3 << std::endl;
+ }
+};
+
+
+struct lex_streamer2 {
+ std::string res;
+
+ template <class T>
+ const char* operator()(const T& val) const {
+ return "fail";
+ }
+
+ template <class T1, class T2>
+ const char* operator()(const T1& v1, const T2& v2) const {
+ return "fail2";
+ }
+
+
+ template <class T1, class T2, class T3>
+ const char* operator()(const T1& v1, const T2& v2, const T3& v3) const {
+ return "fail3";
+ }
+
+ template <class T>
+ std::string& operator()(const T& val) {
+ res = boost::lexical_cast<std::string>(val);
+ return res;
+ }
+
+
+ template <class T1, class T2>
+ std::string& operator()(const T1& v1, const T2& v2) {
+ res = boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2);
+ return res;
+ }
+
+
+ template <class T1, class T2, class T3>
+ std::string& operator()(const T1& v1, const T2& v2, const T3& v3) {
+ res = boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2)
+ + "+" + boost::lexical_cast<std::string>(v3);
+ return res;
+ }
+};
+
+#ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
+# define BOOST_CHECK_IF_HAS_VARIADIC(x) BOOST_CHECK(x)
+#else
+# define BOOST_CHECK_IF_HAS_VARIADIC(x) /**/
+#endif
+
+void run()
+{
+ typedef boost::variant<int, std::string, double> variant_type;
+ variant_type v1(1), v2("10"), v3(100.0);
+ lex_streamer lex_streamer_visitor;
+
+ BOOST_CHECK(boost::apply_visitor(lex_streamer(), v1) == "1");
+ BOOST_CHECK_IF_HAS_VARIADIC(boost::apply_visitor(lex_streamer_visitor)(v1) == "1");
+ BOOST_CHECK(boost::apply_visitor(lex_streamer(), v2) == "10");
+ BOOST_CHECK_IF_HAS_VARIADIC(boost::apply_visitor(lex_streamer_visitor)(v2) == "10");
+
+ #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS
+ BOOST_CHECK(boost::apply_visitor([](auto v) { return boost::lexical_cast<std::string>(v); }, v1) == "1");
+ BOOST_CHECK(boost::apply_visitor([](auto v) { return boost::lexical_cast<std::string>(v); }, v2) == "10");
+
+ // Retun type must be the same in all instances, so this code does not compile
+ //boost::variant<int, short, unsigned> v_diff_types(1);
+ //BOOST_CHECK(boost::apply_visitor([](auto v) { return v; }, v_diff_types) == 1);
+
+ boost::apply_visitor([](auto v) { std::cout << v << std::endl; }, v1);
+ boost::apply_visitor([](auto v) { std::cout << v << std::endl; }, v2);
+ #endif
+
+ lex_streamer2 visitor_ref;
+ BOOST_CHECK(boost::apply_visitor(visitor_ref, v1) == "1");
+ BOOST_CHECK(boost::apply_visitor(visitor_ref, v2) == "10");
+#ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
+ std::string& ref_to_string = boost::apply_visitor(visitor_ref, v1);
+ BOOST_CHECK(ref_to_string == "1");
+#endif
+ lex_streamer_void lex_streamer_void_visitor;
+ boost::apply_visitor(lex_streamer_void(), v1);
+ boost::apply_visitor(lex_streamer_void(), v2);
+#ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
+ boost::apply_visitor(lex_streamer_void_visitor)(v2);
+#endif
+}
+
+
+struct lex_combine {
+ template <class T1, class T2>
+ std::string operator()(const T1& v1, const T2& v2) const {
+ return boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2);
+ }
+
+
+ template <class T1, class T2, class T3>
+ std::string operator()(const T1& v1, const T2& v2, const T3& v3) const {
+ return boost::lexical_cast<std::string>(v1) + "+"
+ + boost::lexical_cast<std::string>(v2) + '+'
+ + boost::lexical_cast<std::string>(v3);
+ }
+};
+
+void run2()
+{
+ typedef boost::variant<int, std::string, double> variant_type;
+ variant_type v1(1), v2("10"), v3(100.0);
+ lex_combine lex_combine_visitor;
+
+ BOOST_CHECK(boost::apply_visitor(lex_combine(), v1, v2) == "1+10");
+ BOOST_CHECK(boost::apply_visitor(lex_combine(), v2, v1) == "10+1");
+ BOOST_CHECK_IF_HAS_VARIADIC(boost::apply_visitor(lex_combine_visitor)(v2, v1) == "10+1");
+
+
+ #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS
+ BOOST_CHECK(
+ boost::apply_visitor(
+ [](auto v1, auto v2) {
+ return boost::lexical_cast<std::string>(v1) + "+"
+ + boost::lexical_cast<std::string>(v2);
+ }
+ , v1
+ , v2
+ ) == "1+10"
+ );
+ BOOST_CHECK(
+ boost::apply_visitor(
+ [](auto v1, auto v2) {
+ return boost::lexical_cast<std::string>(v1) + "+"
+ + boost::lexical_cast<std::string>(v2);
+ }
+ , v2
+ , v1
+ ) == "10+1"
+ );
+
+ boost::apply_visitor([](auto v1, auto v2) { std::cout << v1 << '+' << v2 << std::endl; }, v1, v2);
+ boost::apply_visitor([](auto v1, auto v2) { std::cout << v1 << '+' << v2 << std::endl; }, v2, v1);
+ #endif
+
+
+ lex_streamer2 visitor_ref;
+ BOOST_CHECK(boost::apply_visitor(visitor_ref, v1, v2) == "1+10");
+ BOOST_CHECK(boost::apply_visitor(visitor_ref, v2, v1) == "10+1");
+#ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
+ std::string& ref_to_string = boost::apply_visitor(visitor_ref)(v1, v2);
+ BOOST_CHECK(ref_to_string == "1+10");
+#endif
+
+ boost::apply_visitor(lex_streamer_void(), v1, v2);
+ boost::apply_visitor(lex_streamer_void(), v2, v1);
+}
+
+#undef BOOST_CHECK_IF_HAS_VARIADIC
+
+void run3()
+{
+#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
+ typedef boost::variant<int, std::string, double> variant_type;
+ variant_type v1(1), v2("10"), v3(100);
+ lex_combine lex_combine_visitor;
+
+ BOOST_CHECK(boost::apply_visitor(lex_combine(), v1, v2, v3) == "1+10+100");
+ BOOST_CHECK(boost::apply_visitor(lex_combine(), v2, v1, v3) == "10+1+100");
+ BOOST_CHECK(boost::apply_visitor(lex_combine_visitor)(v2, v1, v3) == "10+1+100");
+
+
+ #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS
+ BOOST_CHECK(
+ boost::apply_visitor(
+ [](auto v1, auto v2, auto v3) {
+ return boost::lexical_cast<std::string>(v1) + "+"
+ + boost::lexical_cast<std::string>(v2) + "+"
+ + boost::lexical_cast<std::string>(v3);
+ }
+ , v1
+ , v2
+ , v3
+ ) == "1+10+100"
+ );
+ BOOST_CHECK(
+ boost::apply_visitor(
+ [](auto v1, auto v2, auto v3) {
+ return boost::lexical_cast<std::string>(v1) + "+"
+ + boost::lexical_cast<std::string>(v2) + "+"
+ + boost::lexical_cast<std::string>(v3);
+ }
+ , v3
+ , v1
+ , v3
+ ) == "100+1+100"
+ );
+
+ boost::apply_visitor(
+ [](auto v1, auto v2, auto v3) { std::cout << v1 << '+' << v2 << '+' << v3 << std::endl; },
+ v1, v2, v3
+ );
+ boost::apply_visitor(
+ [](auto v1, auto v2, auto v3) { std::cout << v1 << '+' << v2 << '+' << v3 << std::endl; },
+ v2, v1, v3
+ );
+ #endif
+
+
+ lex_streamer2 visitor_ref;
+ BOOST_CHECK(boost::apply_visitor(visitor_ref, v1, v2) == "1+10");
+ BOOST_CHECK(boost::apply_visitor(visitor_ref)(v2, v1) == "10+1");
+ std::string& ref_to_string = boost::apply_visitor(visitor_ref, v1, v2);
+ BOOST_CHECK(ref_to_string == "1+10");
+
+ lex_streamer_void lex_streamer_void_visitor;
+ boost::apply_visitor(lex_streamer_void(), v1, v2, v1);
+ boost::apply_visitor(lex_streamer_void(), v2, v1, v1);
+ boost::apply_visitor(lex_streamer_void_visitor)(v2, v1, v1);
+#endif // !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
+}
+#endif
+
+
+int test_main(int , char* [])
+{
+ run_explicit();
+ run();
+ run2();
+ run3();
+
+ return 0;
+}
diff --git a/libs/variant/test/recursive_variant_test.cpp b/libs/variant/test/recursive_variant_test.cpp
index 8b6434801..fc9eaf2a5 100644
--- a/libs/variant/test/recursive_variant_test.cpp
+++ b/libs/variant/test/recursive_variant_test.cpp
@@ -129,6 +129,43 @@ void test_recursive_variant()
std::cout << "result1: " << result1 << '\n';
BOOST_CHECK(result1 == "( 3 5 ( 3 5 ) 7 ) ");
+ std::vector<var1_t> vec1_copy = vec1;
+ vec1_copy.erase(vec1_copy.begin() + 2);
+ vec1_copy.insert(vec1_copy.begin() + 2, vec1_copy);
+ var1 = vec1_copy;
+ result1 = printer()(var1);
+ std::cout << "result1+: " << result1 << '\n';
+ BOOST_CHECK(result1 == "( 3 5 ( 3 5 7 ) 7 ) ");
+
+ // Uses move construction on compilers with rvalue references support
+ result1 = printer()(
+ var1_t(
+ std::vector<var1_t>(vec1_copy)
+ )
+ );
+ std::cout << "result1++: " << result1 << '\n';
+ BOOST_CHECK(result1 == "( 3 5 ( 3 5 7 ) 7 ) ");
+
+
+ var1_t vec1_another_copy(vec1_copy);
+ vec1_copy[2].swap(vec1_another_copy);
+ result1 = printer()(
+ var1_t(vec1_copy)
+ );
+ std::cout << "result1+++1: " << result1 << '\n';
+ BOOST_CHECK(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) ");
+
+ result1 = printer()(vec1_another_copy);
+ std::cout << "result1++2: " << result1 << '\n';
+ BOOST_CHECK(result1 == "( 3 5 7 ) ");
+
+ vec1_copy[2].swap(vec1_copy[2]);
+ result1 = printer()(
+ var1_t(vec1_copy)
+ );
+ std::cout << "result1.2: " << result1 << '\n';
+ BOOST_CHECK(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) ");
+
typedef boost::make_recursive_variant<
boost::variant<int, double>
, std::vector<boost::recursive_variant_>
@@ -231,6 +268,36 @@ void test_recursive_variant_over()
std::cout << "result1: " << result1 << '\n';
BOOST_CHECK(result1 == "( 3 5 ( 3 5 ) 7 ) ");
+ std::vector<var1_t> vec1_copy = vec1;
+ vec1_copy.erase(vec1_copy.begin() + 2);
+ vec1_copy.insert(vec1_copy.begin() + 2, vec1_copy);
+ var1 = vec1_copy;
+ result1 = printer()(var1);
+ std::cout << "result1+: " << result1 << '\n';
+ BOOST_CHECK(result1 == "( 3 5 ( 3 5 7 ) 7 ) ");
+
+ // Uses move construction on compilers with rvalue references support
+ result1 = printer()(
+ var1_t(
+ std::vector<var1_t>(vec1_copy)
+ )
+ );
+ std::cout << "result1++: " << result1 << '\n';
+ BOOST_CHECK(result1 == "( 3 5 ( 3 5 7 ) 7 ) ");
+
+
+ var1_t vec1_another_copy(vec1_copy);
+ vec1_copy[2].swap(vec1_another_copy);
+ result1 = printer()(
+ var1_t(vec1_copy)
+ );
+ std::cout << "result1+++1: " << result1 << '\n';
+ BOOST_CHECK(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) ");
+
+ result1 = printer()(vec1_another_copy);
+ std::cout << "result1++2: " << result1 << '\n';
+ BOOST_CHECK(result1 == "( 3 5 7 ) ");
+
typedef boost::make_recursive_variant_over<
boost::mpl::vector<
boost::make_variant_over<boost::mpl::vector<int, double> >::type
diff --git a/libs/variant/test/rvalue_test.cpp b/libs/variant/test/rvalue_test.cpp
index d2d849a55..8ef9d3971 100644
--- a/libs/variant/test/rvalue_test.cpp
+++ b/libs/variant/test/rvalue_test.cpp
@@ -16,8 +16,22 @@
#include "boost/type_traits/is_nothrow_move_assignable.hpp"
#include "boost/mpl/bool.hpp"
-// Most part of tests from this file require rvalue references support
+#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:
@@ -288,6 +302,7 @@ void run_is_container_compilation_test()
int test_main(int , char* [])
{
+ swap_ambiguouty_test_ns::swap_ambiguouty_test();
run();
run1();
run_move_only();
diff --git a/libs/variant/test/test8.cpp b/libs/variant/test/test8.cpp
index 0e64ba0d7..d228b4c6b 100644
--- a/libs/variant/test/test8.cpp
+++ b/libs/variant/test/test8.cpp
@@ -58,17 +58,17 @@ T& check_pass(Variant& v, T value)
template <typename T, typename Variant>
void check_fail(Variant& v)
{
- BOOST_CHECK(!get<T>(&v));
+ BOOST_CHECK(!relaxed_get<T>(&v));
try
{
- T& r = get<T>(v);
+ T& r = relaxed_get<T>(v);
(void)r; // suppress warning about r not being used
BOOST_CHECK(false && &r); // should never reach
}
- catch(boost::bad_get&)
+ catch(const boost::bad_get& e)
{
- // (do nothing here)
+ BOOST_CHECK(!!e.what()); // make sure that what() is const qualified and returnes something
}
}
diff --git a/libs/variant/test/variant_comparison_test.cpp b/libs/variant/test/variant_comparison_test.cpp
index f04d2575c..3f6cc4176 100644
--- a/libs/variant/test/variant_comparison_test.cpp
+++ b/libs/variant/test/variant_comparison_test.cpp
@@ -3,8 +3,8 @@
// See http://www.boost.org for updates, documentation, and revision history.
//-----------------------------------------------------------------------------
//
-// Copyright (c) 2003
-// Eric Friedman, Itay Maman
+// Copyright (c) 2003 Eric Friedman, Itay Maman
+// Copyright (c) 2014 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -34,6 +34,9 @@ void assert_equality_comparable(
BOOST_CHECK( !(&x == &y) || (x == y) );
BOOST_CHECK( !(&x == &z) || (x == z) );
BOOST_CHECK( !(&y == &z) || (y == z) );
+ BOOST_CHECK( !(&x == &y) || !(x != y) );
+ BOOST_CHECK( !(&x == &z) || !(x != z) );
+ BOOST_CHECK( !(&y == &z) || !(y != z) );
// reflexivity check
BOOST_CHECK( (x == x) );
@@ -43,12 +46,18 @@ void assert_equality_comparable(
// symmetry check
BOOST_CHECK( !(x == y) || (y == x) );
BOOST_CHECK( !(y == x) || (x == y) );
+ BOOST_CHECK( (x != y) || (y == x) );
+ BOOST_CHECK( (y != x) || (x == y) );
BOOST_CHECK( !(x == z) || (z == x) );
BOOST_CHECK( !(z == x) || (x == z) );
+ BOOST_CHECK( (x != z) || (z == x) );
+ BOOST_CHECK( (z != x) || (x == z) );
BOOST_CHECK( !(y == z) || (z == y) );
BOOST_CHECK( !(z == y) || (y == z) );
+ BOOST_CHECK( (y != z) || (z == y) );
+ BOOST_CHECK( (z != y) || (y == z) );
// transitivity check
BOOST_CHECK( !(x == y && y == z) || (x == z) );
@@ -65,12 +74,34 @@ void assert_less_than_comparable(
BOOST_CHECK( !(x < x) );
BOOST_CHECK( !(y < y) );
BOOST_CHECK( !(z < z) );
+ BOOST_CHECK( !(x > x) );
+ BOOST_CHECK( !(y > y) );
+ BOOST_CHECK( !(z > z) );
+
+ BOOST_CHECK( (x <= x) );
+ BOOST_CHECK( (y <= y) );
+ BOOST_CHECK( (z <= z) );
+ BOOST_CHECK( (x >= x) );
+ BOOST_CHECK( (y >= y) );
+ BOOST_CHECK( (z >= z) );
// transitivity check
BOOST_CHECK( (x < y) );
BOOST_CHECK( (y < z) );
BOOST_CHECK( (x < z) );
+ BOOST_CHECK( (x <= y) );
+ BOOST_CHECK( (y <= z) );
+ BOOST_CHECK( (x <= z) );
+
+ BOOST_CHECK( (z > y) );
+ BOOST_CHECK( (y > x) );
+ BOOST_CHECK( (z > x) );
+
+ BOOST_CHECK( (z >= y) );
+ BOOST_CHECK( (y >= x) );
+ BOOST_CHECK( (z >= x) );
+
// antisymmetry check
BOOST_CHECK( !(y < x) );
BOOST_CHECK( !(z < y) );
diff --git a/libs/variant/test/variant_get_test.cpp b/libs/variant/test/variant_get_test.cpp
new file mode 100644
index 000000000..69b613729
--- /dev/null
+++ b/libs/variant/test/variant_get_test.cpp
@@ -0,0 +1,323 @@
+//-----------------------------------------------------------------------------
+// boost-libs variant/test/variant_get_test.cpp source file
+// See http://www.boost.org for updates, documentation, and revision history.
+//-----------------------------------------------------------------------------
+//
+// Copyright (c) 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/variant/variant.hpp"
+#include "boost/variant/get.hpp"
+#include "boost/variant/polymorphic_get.hpp"
+#include "boost/variant/recursive_wrapper.hpp"
+#include "boost/test/minimal.hpp"
+
+struct base {
+ int trash;
+
+ base() : trash(123) {}
+ base(const base& b) : trash(b.trash) { int i = 100; (void)i; }
+ const base& operator=(const base& b) {
+ trash = b.trash;
+ int i = 100; (void)i;
+
+ return *this;
+ }
+
+ virtual ~base(){}
+};
+
+struct derived1 : base{};
+struct derived2 : base{};
+
+struct vbase { short trash; virtual ~vbase(){} virtual int foo() const { return 0; } };
+struct vderived1 : virtual vbase{ virtual int foo() const { return 1; } };
+struct vderived2 : virtual vbase{ virtual int foo() const { return 3; } };
+struct vderived3 : vderived1, vderived2 { virtual int foo() const { return 3; } };
+
+typedef boost::variant<int, base, derived1, derived2, std::string> var_t;
+typedef boost::variant<int, derived1, derived2, std::string> var_t_shortened;
+typedef boost::variant<base, derived1, derived2> var_t_no_fallback;
+typedef boost::variant<int&, base&, derived1&, derived2&, std::string&> var_ref_t;
+typedef boost::variant<const int&, const base&, const derived1&, const derived2&, const std::string&> var_cref_t;
+
+struct recursive_structure;
+typedef boost::variant<
+ int, base, derived1, derived2, std::string, boost::recursive_wrapper<recursive_structure>
+> var_req_t;
+struct recursive_structure { var_req_t var; };
+
+template <class T, class V, class TestType>
+inline void check_polymorphic_get_on_types_impl_single_type(V* v)
+{
+ if (!!boost::is_same<T, TestType>::value) {
+ BOOST_CHECK(boost::polymorphic_get<TestType>(v));
+ BOOST_CHECK(boost::polymorphic_get<const TestType>(v));
+ BOOST_CHECK(boost::polymorphic_strict_get<TestType>(v));
+ BOOST_CHECK(boost::polymorphic_strict_get<const TestType>(v));
+ BOOST_CHECK(boost::polymorphic_relaxed_get<TestType>(v));
+ BOOST_CHECK(boost::polymorphic_relaxed_get<const TestType>(v));
+ } else {
+ BOOST_CHECK(!boost::polymorphic_get<TestType>(v));
+ BOOST_CHECK(!boost::polymorphic_get<const TestType>(v));
+ BOOST_CHECK(!boost::polymorphic_strict_get<TestType>(v));
+ BOOST_CHECK(!boost::polymorphic_strict_get<const TestType>(v));
+ BOOST_CHECK(!boost::polymorphic_relaxed_get<TestType>(v));
+ BOOST_CHECK(!boost::polymorphic_relaxed_get<const TestType>(v));
+ }
+}
+
+template <class T, class V, class TestType>
+inline void check_get_on_types_impl_single_type(V* v)
+{
+ if (!!boost::is_same<T, TestType>::value) {
+ BOOST_CHECK(boost::get<TestType>(v));
+ BOOST_CHECK(boost::get<const TestType>(v));
+ BOOST_CHECK(boost::strict_get<TestType>(v));
+ BOOST_CHECK(boost::strict_get<const TestType>(v));
+ BOOST_CHECK(boost::relaxed_get<TestType>(v));
+ BOOST_CHECK(boost::relaxed_get<const TestType>(v));
+ } else {
+ BOOST_CHECK(!boost::get<TestType>(v));
+ BOOST_CHECK(!boost::get<const TestType>(v));
+ BOOST_CHECK(!boost::strict_get<TestType>(v));
+ BOOST_CHECK(!boost::strict_get<const TestType>(v));
+ BOOST_CHECK(!boost::relaxed_get<TestType>(v));
+ BOOST_CHECK(!boost::relaxed_get<const TestType>(v));
+ }
+}
+
+template <class T, class V>
+inline void check_get_on_types_impl(V* v)
+{
+ check_get_on_types_impl_single_type<T, V, int>(v);
+ check_polymorphic_get_on_types_impl_single_type<T, V, int>(v);
+
+ check_get_on_types_impl_single_type<T, V, base>(v);
+
+ check_get_on_types_impl_single_type<T, V, derived1>(v);
+ check_polymorphic_get_on_types_impl_single_type<T, V, derived1>(v);
+
+ check_get_on_types_impl_single_type<T, V, derived2>(v);
+ check_polymorphic_get_on_types_impl_single_type<T, V, derived2>(v);
+
+ check_get_on_types_impl_single_type<T, V, std::string>(v);
+ check_polymorphic_get_on_types_impl_single_type<T, V, std::string>(v);
+
+ // Never exist in here
+ BOOST_CHECK(!boost::relaxed_get<short>(v));
+ BOOST_CHECK(!boost::relaxed_get<const short>(v));
+ BOOST_CHECK(!boost::relaxed_get<char>(v));
+ BOOST_CHECK(!boost::relaxed_get<char*>(v));
+ BOOST_CHECK(!boost::relaxed_get<bool>(v));
+ BOOST_CHECK(!boost::relaxed_get<const bool>(v));
+
+ BOOST_CHECK(!boost::polymorphic_relaxed_get<short>(v));
+ BOOST_CHECK(!boost::polymorphic_relaxed_get<const short>(v));
+ BOOST_CHECK(!boost::polymorphic_relaxed_get<char>(v));
+ BOOST_CHECK(!boost::polymorphic_relaxed_get<char*>(v));
+ BOOST_CHECK(!boost::polymorphic_relaxed_get<bool>(v));
+ BOOST_CHECK(!boost::polymorphic_relaxed_get<const bool>(v));
+
+ boost::get<T>(*v); // Must compile
+ boost::get<const T>(*v); // Must compile
+ boost::strict_get<T>(*v); // Must compile
+ boost::strict_get<const T>(*v); // Must compile
+
+ boost::polymorphic_get<T>(*v); // Must compile
+ boost::polymorphic_get<const T>(*v); // Must compile
+ boost::polymorphic_strict_get<T>(*v); // Must compile
+ boost::polymorphic_strict_get<const T>(*v); // Must compile
+}
+
+template <class T, class V>
+inline void check_get_on_types(V* v)
+{
+ check_get_on_types_impl<T, V>(v);
+ check_get_on_types_impl<T, const V>(v);
+}
+
+inline void get_test()
+{
+ var_t v;
+ check_get_on_types<int>(&v);
+
+ var_t(base()).swap(v);
+ check_get_on_types<base>(&v);
+
+ var_t(derived1()).swap(v);
+ check_get_on_types<derived1>(&v);
+
+ var_t(derived2()).swap(v);
+ check_get_on_types<derived2>(&v);
+
+ var_t(std::string("Hello")).swap(v);
+ check_get_on_types<std::string>(&v);
+
+ var_t_shortened vs = derived2();
+ check_polymorphic_get_on_types_impl_single_type<derived2, var_t_shortened, int>(&vs);
+ check_polymorphic_get_on_types_impl_single_type<derived2, const var_t_shortened, int>(&vs);
+ // Checking that Base is really determinated
+ check_polymorphic_get_on_types_impl_single_type<base, var_t_shortened, base>(&vs);
+ check_polymorphic_get_on_types_impl_single_type<base, const var_t_shortened, base>(&vs);
+
+ vs = derived1();
+ check_polymorphic_get_on_types_impl_single_type<derived2, var_t_shortened, int>(&vs);
+ check_polymorphic_get_on_types_impl_single_type<derived2, const var_t_shortened, int>(&vs);
+ // Checking that Base is really determinated
+ check_polymorphic_get_on_types_impl_single_type<base, var_t_shortened, base>(&vs);
+ check_polymorphic_get_on_types_impl_single_type<base, const var_t_shortened, base>(&vs);
+}
+
+inline void get_test_no_fallback()
+{
+ var_t_no_fallback v;
+ var_t_no_fallback(base()).swap(v);
+ check_polymorphic_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v);
+ check_polymorphic_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v);
+ check_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v);
+ check_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v);
+
+ var_t_no_fallback(derived1()).swap(v);
+ check_polymorphic_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v);
+ check_polymorphic_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v);
+ check_get_on_types_impl_single_type<derived1, var_t_no_fallback, derived1>(&v);
+ check_get_on_types_impl_single_type<derived1, const var_t_no_fallback, derived1>(&v);
+
+ var_t_no_fallback(derived2()).swap(v);
+ check_polymorphic_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v);
+ check_polymorphic_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v);
+ check_get_on_types_impl_single_type<derived2, var_t_no_fallback, derived2>(&v);
+ check_get_on_types_impl_single_type<derived2, const var_t_no_fallback, derived2>(&v);
+}
+
+inline void get_ref_test()
+{
+ int i = 0;
+ var_ref_t v(i);
+ check_get_on_types<int>(&v);
+
+ base b;
+ var_ref_t v1(b);
+ check_get_on_types<base>(&v1);
+
+ derived1 d1;
+ var_ref_t v2(d1);
+ check_get_on_types<derived1>(&v2);
+
+ derived2 d2;
+ var_ref_t v3(d2);
+ check_get_on_types<derived2>(&v3);
+
+ std::string s("Hello");
+ var_ref_t v4(s);
+ check_get_on_types<std::string>(&v4);
+}
+
+
+inline void get_cref_test()
+{
+ int i = 0;
+ var_cref_t v(i);
+ BOOST_CHECK(boost::get<const int>(&v));
+ BOOST_CHECK(!boost::get<const base>(&v));
+
+ base b;
+ var_cref_t v1(b);
+ BOOST_CHECK(boost::get<const base>(&v1));
+ BOOST_CHECK(!boost::get<const derived1>(&v1));
+ BOOST_CHECK(!boost::get<const int>(&v1));
+
+ std::string s("Hello");
+ const var_cref_t v4 = s;
+ BOOST_CHECK(boost::get<const std::string>(&v4));
+ BOOST_CHECK(!boost::get<const int>(&v4));
+}
+
+inline void get_recursive_test()
+{
+ var_req_t v;
+ check_get_on_types<int>(&v);
+
+ var_req_t(base()).swap(v);
+ check_get_on_types<base>(&v);
+
+ var_req_t(derived1()).swap(v);
+ check_get_on_types<derived1>(&v);
+
+ var_req_t(derived2()).swap(v);
+ check_get_on_types<derived2>(&v);
+
+ var_req_t(std::string("Hello")).swap(v);
+ check_get_on_types<std::string>(&v);
+
+ recursive_structure s = { v }; // copying "v"
+ v = s;
+ check_get_on_types<recursive_structure>(&v);
+}
+
+template <class T>
+inline void check_that_does_not_exist_impl()
+{
+ using namespace boost::detail::variant;
+
+ BOOST_CHECK((holds_element<T, const int>::value));
+ BOOST_CHECK((!holds_element<T, short>::value));
+ BOOST_CHECK((!holds_element<T, short>::value));
+ BOOST_CHECK((!holds_element<T, const short>::value));
+ BOOST_CHECK((!holds_element<T, char*>::value));
+ BOOST_CHECK((!holds_element<T, const char*>::value));
+ BOOST_CHECK((!holds_element<T, char[5]>::value));
+ BOOST_CHECK((!holds_element<T, const char[5]>::value));
+ BOOST_CHECK((!holds_element<T, bool>::value));
+ BOOST_CHECK((!holds_element<T, const bool>::value));
+
+ BOOST_CHECK((!holds_element<T, boost::recursive_wrapper<int> >::value));
+ BOOST_CHECK((!holds_element<T, boost::recursive_wrapper<short> >::value));
+ BOOST_CHECK((!holds_element<T, boost::detail::reference_content<short> >::value));
+
+
+ BOOST_CHECK((holds_element_polymorphic<T, const int>::value));
+ BOOST_CHECK((!holds_element_polymorphic<T, short>::value));
+ BOOST_CHECK((!holds_element_polymorphic<T, short>::value));
+ BOOST_CHECK((!holds_element_polymorphic<T, const short>::value));
+ BOOST_CHECK((!holds_element_polymorphic<T, char*>::value));
+ BOOST_CHECK((!holds_element_polymorphic<T, const char*>::value));
+ BOOST_CHECK((!holds_element_polymorphic<T, char[5]>::value));
+ BOOST_CHECK((!holds_element_polymorphic<T, const char[5]>::value));
+ BOOST_CHECK((!holds_element_polymorphic<T, bool>::value));
+ BOOST_CHECK((!holds_element_polymorphic<T, const bool>::value));
+
+ BOOST_CHECK((!holds_element_polymorphic<T, boost::recursive_wrapper<int> >::value));
+ BOOST_CHECK((!holds_element_polymorphic<T, boost::recursive_wrapper<short> >::value));
+ BOOST_CHECK((!holds_element_polymorphic<T, boost::detail::reference_content<short> >::value));
+}
+
+inline void check_that_does_not_exist()
+{
+ using namespace boost::detail::variant;
+
+ BOOST_CHECK((holds_element<var_t, int>::value));
+ BOOST_CHECK((holds_element<var_ref_t, int>::value));
+ BOOST_CHECK((!holds_element<var_cref_t, int>::value));
+
+ check_that_does_not_exist_impl<var_t>();
+ check_that_does_not_exist_impl<var_ref_t>();
+ check_that_does_not_exist_impl<var_cref_t>();
+ check_that_does_not_exist_impl<var_req_t>();
+}
+
+int test_main(int , char* [])
+{
+ get_test();
+ get_test_no_fallback();
+ get_ref_test();
+ get_cref_test();
+ get_recursive_test();
+ check_that_does_not_exist();
+
+ return boost::exit_success;
+}
diff --git a/libs/variant/test/variant_multivisit_test.cpp b/libs/variant/test/variant_multivisit_test.cpp
index ddcbe02da..8fc3ebe82 100644
--- a/libs/variant/test/variant_multivisit_test.cpp
+++ b/libs/variant/test/variant_multivisit_test.cpp
@@ -3,37 +3,46 @@
// See http://www.boost.org for updates, documentation, and revision history.
//-----------------------------------------------------------------------------
//
-// Copyright (c) 2013
-// Antony Polukhin
+// Copyright (c) 2013-2015 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/noncopyable.hpp"
#define BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS 5
#include "boost/variant/multivisitors.hpp"
+#include "boost/variant.hpp"
#include "boost/test/minimal.hpp"
+struct my_noncopyable : boost::noncopyable {
+ my_noncopyable(){}
+ ~my_noncopyable(){}
+};
+
+typedef boost::variant<my_noncopyable, int> variant_noncopy_t;
+
+
typedef boost::variant<char, unsigned char, signed char, unsigned short, int, unsigned int> variant6_t;
struct test_visitor: boost::static_visitor<> {
// operators that shall not be called
template <class T1, class T2, class T3>
- void operator()(T1, T2, T3) const
+ void operator()(T1&, T2&, T3&) const
{
BOOST_CHECK(false);
}
template <class T1, class T2, class T3, class T4>
- void operator()(T1, T2, T3, T4) const
+ void operator()(T1&, T2&, T3&, T4&) const
{
BOOST_CHECK(false);
}
template <class T1, class T2, class T3, class T4, class T5>
- void operator()(T1, T2, T3, T4, T5) const
+ void operator()(T1&, T2&, T3&, T4&, T5&) const
{
BOOST_CHECK(false);
}
@@ -62,6 +71,21 @@ struct test_visitor: boost::static_visitor<> {
BOOST_CHECK(v3 == 3);
BOOST_CHECK(v4 == 4);
}
+
+
+ // Noncopyables
+ void operator()(my_noncopyable&, my_noncopyable&, my_noncopyable&) const {
+ BOOST_CHECK(true);
+ }
+ void operator()(my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&) const {
+ BOOST_CHECK(true);
+ }
+ void operator()(my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&) const {
+ BOOST_CHECK(true);
+ }
+ void operator()(my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&) const {
+ BOOST_CHECK(true);
+ }
};
typedef boost::variant<int, double, bool> bool_like_t;
@@ -112,13 +136,24 @@ int test_main(int , char* [])
arithmetics_t(true)
);
- /* Delayed multi visitation is not implemented
+#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES)
if_visitor if_vis;
BOOST_CHECK(
boost::apply_visitor(if_vis)(v0, v1, v2)
==
arithmetics_t(true)
);
- */
+#endif
+
+
+ variant_noncopy_t vnonc[6];
+ boost::apply_visitor(v, vnonc[0], vnonc[1], vnonc[2]);
+ boost::apply_visitor(test_visitor(), vnonc[0], vnonc[1], vnonc[2], vnonc[3]);
+
+#ifdef BOOST_VARIANT_MULTIVISITORS_TEST_VERY_EXTREME
+ boost::apply_visitor(v, vnonc[0], vnonc[1], vnonc[2], vnonc[3], vnonc[4]);
+ boost::apply_visitor(test_visitor(), vnonc[0], vnonc[1], vnonc[2], vnonc[3], vnonc[4], vnonc[5]);
+#endif
+
return boost::exit_success;
}
diff --git a/libs/variant/test/variant_nonempty_check.cpp b/libs/variant/test/variant_nonempty_check.cpp
new file mode 100644
index 000000000..de643b862
--- /dev/null
+++ b/libs/variant/test/variant_nonempty_check.cpp
@@ -0,0 +1,474 @@
+//-----------------------------------------------------------------------------
+// boost-libs variant/test/variant_nonempty_check.cpp source file
+// See http://www.boost.org for updates, documentation, and revision history.
+//-----------------------------------------------------------------------------
+//
+// Copyright (c) 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)
+
+
+// In this file we are making tests to ensure that variant guarantees nonemptiness.
+//
+// For that purpose we create a `throwing_class`, that throws exception at a specified
+// assignment attempt. If exception was thrown during move/assignemnt operation we make sure
+// that data in variant is same as before move/assignemnt operation or that a fallback type is
+// stored in variant.
+//
+// Different nonthrowing_class'es are used to tests different variant internal policies:
+// with/without fallback type + throw/nothrow copyable + throw/nothrow movable
+
+
+#include "boost/variant/variant.hpp"
+#include "boost/variant/get.hpp"
+#include "boost/test/minimal.hpp"
+#include <stdexcept>
+
+struct exception_on_assignment : std::exception {};
+struct exception_on_move_assignment : exception_on_assignment {};
+
+void prevent_compiler_noexcept_detection() {
+ char* p = new char;
+ *p = '\0';
+ delete p;
+}
+
+
+struct throwing_class {
+ int trash;
+ enum helper_enum {
+ do_not_throw = 780,
+ throw_after_5,
+ throw_after_4,
+ throw_after_3,
+ throw_after_2,
+ throw_after_1
+ };
+
+ bool is_throw() {
+ if (trash < do_not_throw) {
+ return true;
+ }
+
+ if (trash > do_not_throw && trash <= throw_after_1) {
+ ++ trash;
+ return false;
+ }
+
+ return trash != do_not_throw;
+ }
+
+ throwing_class(int value = 123) BOOST_NOEXCEPT_IF(false) : trash(value) {
+ prevent_compiler_noexcept_detection();
+ }
+
+ throwing_class(const throwing_class& b) BOOST_NOEXCEPT_IF(false) : trash(b.trash) {
+ if (is_throw()) {
+ throw exception_on_assignment();
+ }
+ }
+
+ const throwing_class& operator=(const throwing_class& b) BOOST_NOEXCEPT_IF(false) {
+ trash = b.trash;
+ if (is_throw()) {
+ throw exception_on_assignment();
+ }
+
+ return *this;
+ }
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+ throwing_class(throwing_class&& b) BOOST_NOEXCEPT_IF(false) : trash(b.trash) {
+ if (is_throw()) {
+ throw exception_on_move_assignment();
+ }
+ }
+
+ const throwing_class& operator=(throwing_class&& b) BOOST_NOEXCEPT_IF(false) {
+ trash = b.trash;
+ if (is_throw()) {
+ throw exception_on_move_assignment();
+ }
+
+ return *this;
+ }
+#endif
+
+ virtual ~throwing_class() {}
+};
+
+struct nonthrowing_class {
+ int trash;
+
+ nonthrowing_class() BOOST_NOEXCEPT_IF(false) : trash(123) {
+ prevent_compiler_noexcept_detection();
+ }
+
+ nonthrowing_class(const nonthrowing_class&) BOOST_NOEXCEPT_IF(false) {
+ prevent_compiler_noexcept_detection();
+ }
+
+ const nonthrowing_class& operator=(const nonthrowing_class&) BOOST_NOEXCEPT_IF(false) {
+ prevent_compiler_noexcept_detection();
+ return *this;
+ }
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+ nonthrowing_class(nonthrowing_class&&) BOOST_NOEXCEPT_IF(false) {
+ prevent_compiler_noexcept_detection();
+ }
+
+ const nonthrowing_class& operator=(nonthrowing_class&&) BOOST_NOEXCEPT_IF(false) {
+ prevent_compiler_noexcept_detection();
+ return *this;
+ }
+#endif
+};
+
+struct nonthrowing_class2 {
+ int trash;
+
+ nonthrowing_class2() BOOST_NOEXCEPT_IF(false) : trash(123) {
+ prevent_compiler_noexcept_detection();
+ }
+};
+
+struct nonthrowing_class3 {
+ int trash;
+
+ nonthrowing_class3() BOOST_NOEXCEPT_IF(true) : trash(123) {}
+
+ nonthrowing_class3(const nonthrowing_class3&) BOOST_NOEXCEPT_IF(false) {
+ prevent_compiler_noexcept_detection();
+ }
+
+ const nonthrowing_class3& operator=(const nonthrowing_class3&) BOOST_NOEXCEPT_IF(false) {
+ prevent_compiler_noexcept_detection();
+ return *this;
+ }
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+ nonthrowing_class3(nonthrowing_class3&&) BOOST_NOEXCEPT_IF(false) {
+ prevent_compiler_noexcept_detection();
+ }
+
+ const nonthrowing_class3& operator=(nonthrowing_class3&&) BOOST_NOEXCEPT_IF(false) {
+ prevent_compiler_noexcept_detection();
+ return *this;
+ }
+#endif
+};
+
+struct nonthrowing_class4 {
+ int trash;
+
+ nonthrowing_class4() BOOST_NOEXCEPT_IF(false) : trash(123) {
+ prevent_compiler_noexcept_detection();
+ }
+
+ nonthrowing_class4(const nonthrowing_class4&) BOOST_NOEXCEPT_IF(false) {
+ prevent_compiler_noexcept_detection();
+ }
+
+ const nonthrowing_class4& operator=(const nonthrowing_class4&) BOOST_NOEXCEPT_IF(false) {
+ prevent_compiler_noexcept_detection();
+ return *this;
+ }
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+ nonthrowing_class4(nonthrowing_class4&&) BOOST_NOEXCEPT_IF(true) {
+ }
+
+ const nonthrowing_class4& operator=(nonthrowing_class4&&) BOOST_NOEXCEPT_IF(true) {
+ return *this;
+ }
+#endif
+};
+
+
+// Tests /////////////////////////////////////////////////////////////////////////////////////
+
+
+template <class Nonthrowing>
+inline void check_1_impl(int helper)
+{
+ boost::variant<throwing_class, Nonthrowing> v;
+ try {
+ v = throwing_class(helper);
+ BOOST_CHECK(!v.which());
+ BOOST_CHECK(boost::get<throwing_class>(&v));
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(!v.which());
+ BOOST_CHECK(boost::get<throwing_class>(&v));
+ }
+
+ try {
+ throwing_class tc(helper);
+ v = tc;
+ BOOST_CHECK(!v.which());
+ BOOST_CHECK(boost::get<throwing_class>(&v));
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(!v.which());
+ BOOST_CHECK(boost::get<throwing_class>(&v));
+ }
+}
+
+inline void check_1(int helper = 1)
+{
+ check_1_impl<nonthrowing_class>(helper);
+ check_1_impl<nonthrowing_class2>(helper);
+ check_1_impl<nonthrowing_class3>(helper);
+ check_1_impl<nonthrowing_class4>(helper);
+ check_1_impl<boost::blank>(helper);
+}
+
+template <class Nonthrowing>
+inline void check_2_impl(int helper)
+{
+ boost::variant<Nonthrowing, throwing_class> v;
+ try {
+ v = throwing_class(helper);
+ BOOST_CHECK(v.which() == 1);
+ BOOST_CHECK(boost::get<throwing_class>(&v));
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(!v.which());
+ BOOST_CHECK(boost::get<Nonthrowing>(&v));
+ }
+
+ try {
+ throwing_class cl(helper);
+ v = cl;
+ BOOST_CHECK(v.which() == 1);
+ BOOST_CHECK(boost::get<throwing_class>(&v));
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(!v.which());
+ BOOST_CHECK(boost::get<Nonthrowing>(&v));
+ }
+}
+
+inline void check_2(int helper = 1)
+{
+ check_2_impl<nonthrowing_class>(helper);
+ check_2_impl<nonthrowing_class2>(helper);
+ check_2_impl<nonthrowing_class3>(helper);
+ check_2_impl<nonthrowing_class4>(helper);
+ check_2_impl<boost::blank>(helper);
+}
+
+template <class Nonthrowing>
+inline void check_3_impl(int helper)
+{
+ boost::variant<Nonthrowing, throwing_class> v1, v2;
+
+ swap(v1, v2);
+ try {
+ v1 = throwing_class(helper);
+ BOOST_CHECK(v1.which() == 1);
+ BOOST_CHECK(boost::get<throwing_class>(&v1));
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(!v1.which());
+ BOOST_CHECK(boost::get<Nonthrowing>(&v1));
+ }
+
+
+ try {
+ v2 = throwing_class(helper);
+ BOOST_CHECK(v2.which() == 1);
+ BOOST_CHECK(boost::get<throwing_class>(&v2));
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(!v2.which());
+ BOOST_CHECK(boost::get<Nonthrowing>(&v2));
+ }
+
+
+ if (!v1.which() && !v2.which()) {
+ swap(v1, v2); // Make sure that two backup holders swap well
+ BOOST_CHECK(!v1.which());
+ BOOST_CHECK(boost::get<Nonthrowing>(&v1));
+ BOOST_CHECK(!v2.which());
+ BOOST_CHECK(boost::get<Nonthrowing>(&v2));
+
+ v1 = v2;
+ }
+}
+
+inline void check_3(int helper = 1)
+{
+ check_3_impl<nonthrowing_class>(helper);
+ check_3_impl<nonthrowing_class2>(helper);
+ check_3_impl<nonthrowing_class3>(helper);
+ check_3_impl<nonthrowing_class4>(helper);
+ check_3_impl<boost::blank>(helper);
+}
+
+inline void check_4(int helper = 1)
+{
+ // This one has a fallback
+ boost::variant<int, throwing_class> v1, v2;
+
+ swap(v1, v2);
+ try {
+ v1 = throwing_class(helper);
+ BOOST_CHECK(v1.which() == 1);
+ BOOST_CHECK(boost::get<throwing_class>(&v1));
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(!v1.which());
+ BOOST_CHECK(boost::get<int>(&v1));
+ }
+
+
+ try {
+ v2 = throwing_class(helper);
+ BOOST_CHECK(v2.which() == 1);
+ BOOST_CHECK(boost::get<throwing_class>(&v2));
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(!v2.which());
+ BOOST_CHECK(boost::get<int>(&v2));
+ }
+
+ if (!v1.which() && !v2.which()) {
+ swap(v1, v2);
+ BOOST_CHECK(!v1.which());
+ BOOST_CHECK(boost::get<int>(&v1));
+ BOOST_CHECK(!v2.which());
+ BOOST_CHECK(boost::get<int>(&v2));
+
+ v1 = v2;
+ }
+}
+
+template <class Nonthrowing>
+inline void check_5_impl(int helper)
+{
+ boost::variant<Nonthrowing, throwing_class> v1, v2;
+ throwing_class throw_not_now;
+ throw_not_now.trash = throwing_class::do_not_throw;
+ v1 = throw_not_now;
+ v2 = throw_not_now;
+
+ boost::get<throwing_class>(v1).trash = 1;
+ boost::get<throwing_class>(v2).trash = 1;
+
+ try {
+ v1 = throwing_class(helper);
+ BOOST_CHECK(v1.which() == 1);
+ BOOST_CHECK(boost::get<throwing_class>(&v1));
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(v1.which() == 1);
+ BOOST_CHECK(boost::get<throwing_class>(&v1));
+ }
+
+ boost::get<throwing_class>(v1).trash = throwing_class::do_not_throw;
+ boost::get<throwing_class>(v2).trash = throwing_class::do_not_throw;
+ v1 = Nonthrowing();
+ v2 = Nonthrowing();
+ try {
+ v1 = throwing_class(helper);
+ BOOST_CHECK(v1.which() == 1);
+ BOOST_CHECK(boost::get<throwing_class>(&v1));
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(v1.which() == 0);
+ BOOST_CHECK(boost::get<Nonthrowing>(&v1));
+ }
+
+ int v1_type = v1.which();
+ int v2_type = v2.which();
+ try {
+ swap(v1, v2); // Make sure that backup holders swap well
+ BOOST_CHECK(v1.which() == v2_type);
+ BOOST_CHECK(v2.which() == v1_type);
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(v1.which() == v1_type);
+ BOOST_CHECK(v2.which() == v2_type);
+ }
+}
+
+
+inline void check_5(int helper = 1)
+{
+ check_5_impl<nonthrowing_class>(helper);
+ check_5_impl<nonthrowing_class2>(helper);
+ check_5_impl<nonthrowing_class3>(helper);
+ check_5_impl<nonthrowing_class4>(helper);
+ check_5_impl<boost::blank>(helper);
+}
+
+template <class Nonthrowing>
+inline void check_6_impl(int helper)
+{
+ boost::variant<Nonthrowing, throwing_class> v1, v2;
+ throwing_class throw_not_now;
+ throw_not_now.trash = throwing_class::do_not_throw;
+ v1 = throw_not_now;
+ v2 = throw_not_now;
+
+ v1 = throw_not_now;
+ v2 = throw_not_now;
+ swap(v1, v2);
+ boost::get<throwing_class>(v1).trash = 1;
+ boost::get<throwing_class>(v2).trash = 1;
+
+ v1 = throwing_class(throw_not_now);
+ v2 = v1;
+
+ v1 = Nonthrowing();
+ try {
+ throwing_class tc;
+ tc.trash = helper;
+ v1 = tc;
+ BOOST_CHECK(v1.which() == 1);
+ BOOST_CHECK(boost::get<throwing_class>(&v1));
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(v1.which() == 0);
+ }
+
+ v2 = Nonthrowing();
+ try {
+ v2 = 2;
+ BOOST_CHECK(false);
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(v2.which() == 0);
+ }
+
+ // Probably the most significant test:
+ // unsuccessful swap must preserve old values of vaiant
+ v1 = throw_not_now;
+ boost::get<throwing_class>(v1).trash = helper;
+ try {
+ swap(v1, v2);
+ } catch (const exception_on_assignment& /*e*/) {
+ BOOST_CHECK(v1.which() == 1);
+ BOOST_CHECK(v2.which() == 0);
+ BOOST_CHECK(boost::get<throwing_class>(v1).trash == helper);
+ }
+}
+
+
+inline void check_6(int helper = 1)
+{
+ check_6_impl<nonthrowing_class>(helper);
+ check_6_impl<nonthrowing_class2>(helper);
+ check_6_impl<nonthrowing_class3>(helper);
+ check_6_impl<nonthrowing_class4>(helper);
+ check_6_impl<boost::blank>(helper);
+}
+
+int test_main(int , char* [])
+{
+ // throwing_class::throw_after_1 + 1 => throw on first assignment/construction
+ // throwing_class::throw_after_1 => throw on second assignment/construction
+ // throwing_class::throw_after_2 => throw on third assignment/construction
+ // ...
+ for (int i = throwing_class::throw_after_1 + 1; i != throwing_class::do_not_throw; --i) {
+ check_1(i);
+ check_2(i);
+ check_3(i);
+ check_4(i);
+ check_5(i);
+ check_6(i);
+ }
+
+ return boost::exit_success;
+}
diff --git a/libs/variant/test/variant_polymorphic_get_test.cpp b/libs/variant/test/variant_polymorphic_get_test.cpp
index d4e6fe4a9..43fc7b6b9 100644
--- a/libs/variant/test/variant_polymorphic_get_test.cpp
+++ b/libs/variant/test/variant_polymorphic_get_test.cpp
@@ -1,10 +1,10 @@
//-----------------------------------------------------------------------------
-// boost-libs variant/test/variant_visit_test.cpp source file
+// boost-libs variant/test/variant_plymorphic_get_test.cpp source file
// See http://www.boost.org for updates, documentation, and revision history.
//-----------------------------------------------------------------------------
//
-// Copyright (c) 2003
-// Eric Friedman
+// Copyright (c) 2003 Eric Friedman
+// Copyright (c) 2013-2014 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -25,24 +25,44 @@ struct vderived1 : virtual vbase{ virtual int foo() const { return 1; } };
struct vderived2 : virtual vbase{ virtual int foo() const { return 3; } };
struct vderived3 : vderived1, vderived2 { virtual int foo() const { return 3; } };
+template <class T, class Variant>
+inline void check_throws(Variant& v) {
+ try {
+ boost::polymorphic_get<T>(v);
+ BOOST_CHECK(false);
+ } catch (const boost::bad_polymorphic_get& e) {
+ BOOST_CHECK(!!e.what());
+ BOOST_CHECK(std::string(e.what()) != boost::bad_get().what());
+ }
+}
+
int test_main(int , char* [])
{
typedef boost::variant<int, base, derived1, derived2> var_t;
var_t var1;
BOOST_CHECK(!boost::polymorphic_get<base>(&var1));
+ check_throws<base>(var1);
+ BOOST_CHECK(!boost::polymorphic_get<const base>(&var1));
+ check_throws<base, const var_t>(var1);
var1 = derived1();
BOOST_CHECK(boost::polymorphic_get<base>(&var1));
+ BOOST_CHECK(boost::polymorphic_get<const base>(&var1));
derived2 d;
d.trash = 777;
var_t var2 = d;
BOOST_CHECK(boost::polymorphic_get<base>(var2).trash == 777);
+ BOOST_CHECK(boost::polymorphic_get<const base>(var2).trash == 777);
var2 = 777;
BOOST_CHECK(!boost::polymorphic_get<base>(&var2));
+ check_throws<base>(var2);
+ BOOST_CHECK(!boost::polymorphic_get<const base>(&var2));
+ check_throws<base, const var_t>(var2);
BOOST_CHECK(boost::polymorphic_get<int>(var2) == 777);
+ BOOST_CHECK(boost::polymorphic_get<const int>(var2) == 777);
typedef boost::variant<int, vbase, vderived1, vderived2, vderived3> vvar_t;
@@ -50,9 +70,12 @@ int test_main(int , char* [])
boost::polymorphic_get<vderived3>(v).trash = 777;
const vvar_t& cv = v;
BOOST_CHECK(boost::polymorphic_get<vbase>(cv).trash == 777);
+ BOOST_CHECK(boost::polymorphic_get<const vbase>(cv).trash == 777);
BOOST_CHECK(boost::polymorphic_get<vbase>(cv).foo() == 3);
BOOST_CHECK(boost::polymorphic_get<vbase>(v).foo() == 3);
+ BOOST_CHECK(boost::polymorphic_get<const vbase>(cv).foo() == 3);
+ BOOST_CHECK(boost::polymorphic_get<const vbase>(v).foo() == 3);
return boost::exit_success;
}