1 /*
2 Copyright (c) 2014, Randolph Voorhies, Shane Grant
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of cereal nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include "common.hpp"
28 #include <boost/test/unit_test.hpp>
29
30 struct PolyBase
31 {
PolyBasePolyBase32 PolyBase() {}
PolyBasePolyBase33 PolyBase( int xx, float yy ) : x(xx), y(yy) {}
34 int x;
35 float y;
36
37 template <class Archive>
serializePolyBase38 void serialize( Archive & ar )
39 {
40 ar( x, y );
41 }
42
43 virtual void foo() = 0;
44
operator ==PolyBase45 bool operator==( PolyBase const & other ) const
46 {
47 return x == other.x && std::abs(y - other.y) < 1e-5;
48 }
49 };
50
51 struct PolyDerived : PolyBase
52 {
PolyDerivedPolyDerived53 PolyDerived() {}
PolyDerivedPolyDerived54 PolyDerived( int xx, float yy, bool aa, double bb ) :
55 PolyBase( xx, yy ), a(aa), b(bb) {}
56
57 bool a;
58 double b;
59
60 template <class Archive>
serializePolyDerived61 void serialize( Archive & ar )
62 {
63 ar( cereal::base_class<PolyBase>( this ),
64 a, b );
65 }
66
operator ==PolyDerived67 bool operator==( PolyDerived const & other ) const
68 {
69 return PolyBase::operator==( other ) && a == other.a && std::abs(b - other.b) < 1e-5;
70 }
71
fooPolyDerived72 void foo() {}
73 };
74
75 struct PolyLA : std::enable_shared_from_this<PolyLA>
76 {
77 virtual void foo() = 0;
78 };
79
80 struct PolyDerivedLA : public PolyLA
81 {
PolyDerivedLAPolyDerivedLA82 PolyDerivedLA( int xx ) : x( xx ) { }
83
84 int x;
85 std::vector<std::shared_ptr<PolyLA>> vec;
86
87 template <class Archive>
serializePolyDerivedLA88 void serialize( Archive & ar )
89 {
90 ar( x );
91 ar( vec );
92 }
93
94 template <class Archive>
load_and_constructPolyDerivedLA95 static void load_and_construct( Archive & ar, cereal::construct<PolyDerivedLA> & construct )
96 {
97 int xx;
98 ar( xx );
99 construct( xx );
100 ar( construct->vec );
101 }
102
fooPolyDerivedLA103 void foo() {}
104
operator ==PolyDerivedLA105 bool operator==( PolyDerivedLA const & other ) const
106 {
107 if( x != other.x )
108 return false;
109 if( vec.size() != other.vec.size() )
110 return false;
111 for( size_t i = 0; i < vec.size(); ++i )
112 if( !(*std::dynamic_pointer_cast<PolyDerivedLA>(vec[i]) == *std::dynamic_pointer_cast<PolyDerivedLA>(other.vec[i])) )
113 return false;
114
115 return true;
116 }
117 };
118
operator <<(std::ostream & os,PolyDerivedLA const & s)119 std::ostream& operator<<(std::ostream& os, PolyDerivedLA const & s)
120 {
121 os << "[x: " << s.x << "] ";
122 for( auto const & v : s.vec )
123 os << " child: " << (*std::dynamic_pointer_cast<PolyDerivedLA>(v));
124 return os;
125 }
126
operator <<(std::ostream & os,PolyDerived const & s)127 std::ostream& operator<<(std::ostream& os, PolyDerived const & s)
128 {
129 os << "[x: " << s.x << " y: " << s.y << " a: " << s.a << " b: " << s.b << "]";
130 return os;
131 }
132
133 CEREAL_REGISTER_TYPE(PolyDerived)
CEREAL_REGISTER_TYPE(PolyDerivedLA)134 CEREAL_REGISTER_TYPE(PolyDerivedLA)
135
136 template <class IArchive, class OArchive>
137 void test_polymorphic()
138 {
139 std::random_device rd;
140 std::mt19937 gen(rd());
141
142 auto rngB = [&](){ return random_value<int>( gen ) % 2 == 0; };
143 auto rngI = [&](){ return random_value<int>( gen ); };
144 auto rngF = [&](){ return random_value<float>( gen ); };
145 auto rngD = [&](){ return random_value<double>( gen ); };
146
147 for(int ii=0; ii<100; ++ii)
148 {
149 std::shared_ptr<PolyBase> o_shared = std::make_shared<PolyDerived>( rngI(), rngF(), rngB(), rngD() );
150 std::weak_ptr<PolyBase> o_weak = o_shared;
151 std::unique_ptr<PolyBase> o_unique( new PolyDerived( rngI(), rngF(), rngB(), rngD() ) );
152
153 auto pda = std::make_shared<PolyDerivedLA>( rngI() );
154 pda->vec.emplace_back( std::make_shared<PolyDerivedLA>( rngI() ) );
155 std::shared_ptr<PolyLA> o_sharedLA = pda;
156
157 std::ostringstream os;
158 {
159 OArchive oar(os);
160
161 oar( o_shared, o_weak, o_unique );
162 oar( o_sharedLA );
163 }
164
165 decltype(o_shared) i_shared;
166 decltype(o_weak) i_weak;
167 decltype(o_unique) i_unique;
168 decltype(o_sharedLA) i_sharedLA;
169
170 std::istringstream is(os.str());
171 {
172 IArchive iar(is);
173
174 iar( i_shared, i_weak, i_unique );
175 iar( i_sharedLA );
176 }
177
178 auto i_locked = i_weak.lock();
179 auto o_locked = o_weak.lock();
180
181 auto i_sharedLA2 = i_sharedLA->shared_from_this();
182
183 BOOST_CHECK_EQUAL(i_shared.get(), i_locked.get());
184 BOOST_CHECK_EQUAL(*((PolyDerived*)i_shared.get()), *((PolyDerived*)o_shared.get()));
185 BOOST_CHECK_EQUAL(*((PolyDerived*)i_shared.get()), *((PolyDerived*)i_locked.get()));
186 BOOST_CHECK_EQUAL(*((PolyDerived*)i_locked.get()), *((PolyDerived*)o_locked.get()));
187 BOOST_CHECK_EQUAL(*((PolyDerived*)i_unique.get()), *((PolyDerived*)o_unique.get()));
188 BOOST_CHECK_EQUAL(*((PolyDerivedLA*)i_sharedLA.get()), *((PolyDerivedLA*)o_sharedLA.get()));
189 BOOST_CHECK_EQUAL(*((PolyDerivedLA*)i_sharedLA2.get()), *((PolyDerivedLA*)o_sharedLA.get()));
190 }
191 }
192
BOOST_AUTO_TEST_CASE(binary_polymorphic)193 BOOST_AUTO_TEST_CASE( binary_polymorphic )
194 {
195 test_polymorphic<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
196 }
197
BOOST_AUTO_TEST_CASE(portable_binary_polymorphic)198 BOOST_AUTO_TEST_CASE( portable_binary_polymorphic )
199 {
200 test_polymorphic<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
201 }
202
BOOST_AUTO_TEST_CASE(xml_polymorphic)203 BOOST_AUTO_TEST_CASE( xml_polymorphic )
204 {
205 test_polymorphic<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
206 }
207
BOOST_AUTO_TEST_CASE(json_polymorphic)208 BOOST_AUTO_TEST_CASE( json_polymorphic )
209 {
210 test_polymorphic<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
211 }
212
213