1 | /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 |
2 | // test_variant.cpp |
3 | // test of non-intrusive serialization of variant types |
4 | // |
5 | // copyright (c) 2005 |
6 | // troy d. straszheim <troy@resophonic.com> |
7 | // http://www.resophonic.com |
8 | // |
9 | // copyright (c) 2023 |
10 | // Robert Ramey <ramey@rrsd.com> |
11 | // http://www.rrsd.com |
12 | // |
13 | // Use, modification and distribution is subject to the Boost Software |
14 | // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
15 | // http://www.boost.org/LICENSE_1_0.txt) |
16 | // |
17 | // See http://www.boost.org for updates, documentation, and revision history. |
18 | // |
19 | // thanks to Robert Ramey and Peter Dimov. |
20 | // |
21 | |
22 | #include <cstddef> // NULL |
23 | #include <cstdio> // remove |
24 | #include <fstream> |
25 | |
26 | #include <boost/config.hpp> |
27 | #if BOOST_CXX_VERSION > 199711L // only include floating point if C++ version >= C++11 |
28 | #include <boost/math/special_functions/next.hpp> |
29 | #endif |
30 | |
31 | #if defined(BOOST_NO_STDC_NAMESPACE) |
32 | namespace std { |
33 | using ::remove; |
34 | } |
35 | #endif |
36 | |
37 | #include <boost/type_traits/is_same.hpp> |
38 | #include <boost/mpl/eval_if.hpp> |
39 | #include <boost/mpl/identity.hpp> |
40 | |
41 | #if defined(_MSC_VER) && (_MSC_VER <= 1020) |
42 | # pragma warning (disable : 4786) // too long name, harmless warning |
43 | #endif |
44 | |
45 | #include "test_tools.hpp" |
46 | |
47 | #include <boost/archive/archive_exception.hpp> |
48 | #include <boost/serialization/nvp.hpp> |
49 | #include <boost/serialization/throw_exception.hpp> |
50 | |
51 | #include <boost/variant/static_visitor.hpp> |
52 | |
53 | namespace boost { |
54 | template<typename ResultType> class static_visitor; |
55 | } |
56 | |
57 | #include "A.hpp" |
58 | #include "A.ipp" |
59 | |
60 | class are_equal |
61 | : public boost::static_visitor<bool> |
62 | { |
63 | public: |
64 | typedef bool result_type; |
65 | // note extra rigamarole for compilers which don't support |
66 | // partial function template ordering - specifically msvc 6.x |
67 | struct same { |
68 | template<class T, class U> |
69 | static bool invoke(const T & t, const U & u){ |
70 | return t == u; |
71 | } |
72 | }; |
73 | |
74 | struct not_same { |
75 | template<class T, class U> |
76 | static bool invoke(const T &, const U &){ |
77 | return false; |
78 | } |
79 | }; |
80 | |
81 | template <class T, class U> |
82 | bool operator()( const T & t, const U & u) const |
83 | { |
84 | typedef typename boost::mpl::eval_if<boost::is_same<T, U>, |
85 | boost::mpl::identity<same>, |
86 | boost::mpl::identity<not_same> |
87 | >::type type; |
88 | return type::invoke(t, u); |
89 | } |
90 | |
91 | template <class T, class U> |
92 | bool operator()(T * const & t, U * const & u) const |
93 | { |
94 | return this->operator()(*t, *u); |
95 | } |
96 | |
97 | bool operator()( const float & lhs, const float & rhs ) const |
98 | { |
99 | #if BOOST_CXX_VERSION > 199711L // only include floating point if C++ version >= C++11 |
100 | return std::abs( x: boost::math::float_distance(a: lhs, b: rhs) ) < 2; |
101 | #else |
102 | return true; |
103 | #endif |
104 | } |
105 | bool operator()( const double & lhs, const double & rhs ) const |
106 | { |
107 | #if BOOST_CXX_VERSION > 199711L // only include floating point if C++ version >= C++11 |
108 | return std::abs( x: boost::math::float_distance(a: lhs, b: rhs) ) < 2; |
109 | #else |
110 | return true; |
111 | #endif |
112 | } |
113 | }; |
114 | |
115 | template<class Variant> |
116 | bool test_type(const Variant & v){ |
117 | const char * testfile = boost::archive::tmpnam(NULL); |
118 | BOOST_REQUIRE(testfile != NULL); |
119 | { |
120 | test_ostream os(testfile, TEST_STREAM_FLAGS); |
121 | test_oarchive oa(os, TEST_ARCHIVE_FLAGS); |
122 | oa << boost::serialization::make_nvp("written" , v); |
123 | } |
124 | |
125 | Variant vx; |
126 | { |
127 | test_istream is(testfile, TEST_STREAM_FLAGS); |
128 | test_iarchive ia(is, TEST_ARCHIVE_FLAGS); |
129 | BOOST_TRY { |
130 | ia >> boost::serialization::make_nvp("written" , vx); |
131 | BOOST_CHECK(visit(are_equal(), v, vx)); |
132 | } |
133 | BOOST_CATCH(boost::archive::archive_exception const& e) { |
134 | return false; |
135 | } |
136 | BOOST_CATCH_END |
137 | } |
138 | std::remove(filename: testfile); |
139 | return true; |
140 | } |
141 | |
142 | template<class Variant> |
143 | void test(Variant & v) |
144 | { |
145 | // uninitialized |
146 | test_type(v); |
147 | v = false; |
148 | test_type(v); |
149 | v = 1; |
150 | test_type(v); |
151 | v = (float) 2.3; |
152 | test_type(v); |
153 | v = (double) 6.4; |
154 | test_type(v); |
155 | v = A(); |
156 | test_type(v); |
157 | v = std::string("we can't stop here, this is Bat Country" ); |
158 | test_type(v); |
159 | } |
160 | |
161 | #include <boost/serialization/variant.hpp> |
162 | |
163 | int test_main( int /* argc */, char* /* argv */[] ){ |
164 | |
165 | // boost::variant - compatible with C++03 |
166 | { |
167 | boost::variant<bool, int, float, double, A, std::string> v; |
168 | test(v); |
169 | const A a; |
170 | boost::variant<bool, int, float, double, const A *, std::string> v1 = & a; |
171 | test_type(v: v1); |
172 | } |
173 | |
174 | // boost::variant2/variant requires C++ 11 |
175 | #if BOOST_CXX_VERSION >= 201103L |
176 | { |
177 | boost::variant2::variant<bool, int, float, double, A, std::string> v; |
178 | test(v); |
179 | const A a; |
180 | boost::variant2::variant<bool, int, float, double, const A *, std::string> v1 = & a; |
181 | test_type(v: v1); |
182 | } |
183 | #endif |
184 | |
185 | // std::variant reqires C++ 17 or more |
186 | #ifndef BOOST_NO_CXX17_HDR_VARIANT |
187 | { |
188 | std::variant<bool, int, float, double, A, std::string> v; |
189 | test(v); |
190 | const A a; |
191 | std::variant<bool, int, float, double, const A *, std::string> v1 = & a; |
192 | test_type(v: v1); |
193 | } |
194 | #endif |
195 | |
196 | return EXIT_SUCCESS; |
197 | } |
198 | |
199 | // EOF |
200 | |