| 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 | |