1 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2 // test_diamond.cpp
3
4 // (C) Copyright 2002-2009 Vladimir Prus, Robert Ramey and Takatoshi Kondo.
5 // Use, modification and distribution is subject to the Boost Software
6 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8
9 // test of serialization library for diamond inheritence situations
10
11 #include <cstddef> // NULL
12 #include <fstream>
13 #include <iostream>
14
15 #include <boost/config.hpp>
16 #include <cstdio> // remove
17 #if defined(BOOST_NO_STDC_NAMESPACE)
18 namespace std{
19 using ::remove;
20 }
21 #endif
22
23 #include "test_tools.hpp"
24
25 #include <boost/serialization/map.hpp>
26 #include <boost/serialization/utility.hpp>
27 #include <boost/serialization/split_member.hpp>
28 #include <boost/serialization/tracking.hpp>
29 #include <boost/serialization/base_object.hpp>
30 #include <boost/serialization/nvp.hpp>
31 #include <boost/serialization/export.hpp>
32
33 int save_count = 0; // used to detect when EXnLevel1 class is saved multiple times
34 int load_count = 0; // used to detect when EXnLevel1 class is loaded multiple times
35
36 // inheritance structure
37 //
38 // EX1Level1<-+-EX1Level2_A<-+-+-EX1Level3_A
39 // | | |
40 // +-EX1Level2_B<-+ +-EX1Level3_B<--EX1Level4
41 //
42 // EXPORT Sequence EX1Level3_A, EX1Level4
43 //---------------------------------------------------------
44 // EX2Level1<-+-EX2Level2_A<-+-+-EX2Level3_A
45 // | | |
46 // +-EX2Level2_B<-+ +-EX2Level3_B<--EX2Level4
47 //
48 // EXPORT Sequence EX2Level4, EX2Level3_A
49
50 class EX1Level1 {
51 public:
EX1Level1()52 EX1Level1() : i(0) {}
EX1Level1(int i)53 EX1Level1(int i) : i(i)
54 {
55 m[i] = "text";
56 }
57
58 template<class Archive>
save(Archive & ar,const unsigned int) const59 void save(Archive &ar, const unsigned int /* file_version */) const
60 {
61 std::cout << "Saving EX1Level1\n";
62 ar << BOOST_SERIALIZATION_NVP(i);
63 ar << BOOST_SERIALIZATION_NVP(m);
64 ++save_count;
65 }
66
67 template<class Archive>
load(Archive & ar,const unsigned int)68 void load(Archive & ar, const unsigned int /* file_version */)
69 {
70 std::cout << "Restoring EX1Level1\n";
71 ar >> BOOST_SERIALIZATION_NVP(i);
72 ar >> BOOST_SERIALIZATION_NVP(m);
73 ++load_count;
74 }
75
76 BOOST_SERIALIZATION_SPLIT_MEMBER()
77
78 bool operator==(const EX1Level1& another) const
79 {
80 return i == another.i && m == another.m;
81 }
82 // make polymorphic by marking at least one function virtual
~EX1Level1()83 virtual ~EX1Level1() {};
84 private:
85 int i;
86 std::map<int, std::string> m;
87 };
88
89 // note: the default is for object tracking to be performed if and only
90 // if and object of the corresponding class is anywhere serialized
91 // through a pointer. In this example, that doesn't occur so
92 // by default, the shared EX1Level1 object wouldn't normally be tracked.
93 // This would leave to multiple save/load operation of the data in
94 // this shared EX1Level1 class. This wouldn't cause an error, but it would
95 // be a waste of time. So set the tracking behavior trait of the EX1Level1
96 // class to always track serialized objects of that class. This permits
97 // the system to detect and elminate redundent save/load operations.
98 // (It is concievable that this might someday be detected automatically
99 // but for now, this is not done so we have to rely on the programmer
100 // to specify this trait)
101 BOOST_CLASS_TRACKING(EX1Level1, track_always)
102
103 class EX1Level2_A : virtual public EX1Level1 {
104 public:
105 template<class Archive>
save(Archive & ar,const unsigned int) const106 void save(Archive &ar, const unsigned int /* file_version */) const
107 {
108 std::cout << "Saving EX1Level2_A\n";
109 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level1);
110 }
111
112 template<class Archive>
load(Archive & ar,const unsigned int)113 void load(Archive & ar, const unsigned int /* file_version */)
114 {
115 std::cout << "Restoring EX1Level2_A\n";
116 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level1);
117 }
118
119 BOOST_SERIALIZATION_SPLIT_MEMBER()
120 };
121
122 class EX1Level2_B : virtual public EX1Level1 {
123 public:
124 template<class Archive>
save(Archive & ar,const unsigned int) const125 void save(Archive &ar, const unsigned int /* file_version */) const
126 {
127 std::cout << "Saving EX1Level2_B\n";
128 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level1);
129 }
130
131 template<class Archive>
load(Archive & ar,const unsigned int)132 void load(Archive & ar, const unsigned int /* file_version */)
133 {
134 std::cout << "Restoring EX1Level2_B\n";
135 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level1);
136 }
137
138 BOOST_SERIALIZATION_SPLIT_MEMBER()
139 };
140
141 class EX1Level3_A : public EX1Level2_A, public EX1Level2_B {
142 public:
EX1Level3_A()143 EX1Level3_A() {}
EX1Level3_A(int i)144 EX1Level3_A(int i) : EX1Level1(i) {}
145
146 template<class Archive>
save(Archive & ar,const unsigned int) const147 void save(Archive &ar, const unsigned int /* file_version */) const
148 {
149 std::cout << "Saving EX1Level3_A\n";
150 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level2_A);
151 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level2_B);
152 }
153
154 template<class Archive>
load(Archive & ar,const unsigned int)155 void load(Archive & ar, const unsigned int /* file_version */)
156 {
157 std::cout << "Restoring EX1Level3_A\n";
158 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level2_A);
159 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level2_B);
160 }
161
162 BOOST_SERIALIZATION_SPLIT_MEMBER()
163 };
164
165
166 class EX1Level3_B : public EX1Level2_A, public EX1Level2_B {
167 public:
EX1Level3_B()168 EX1Level3_B() {}
EX1Level3_B(int)169 EX1Level3_B(int) {}
170
171 template<class Archive>
save(Archive & ar,const unsigned int) const172 void save(Archive &ar, const unsigned int /* file_version */) const
173 {
174 std::cout << "Saving EX1Level3_B\n";
175 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level2_A);
176 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level2_B);
177 }
178
179 template<class Archive>
load(Archive & ar,const unsigned int)180 void load(Archive & ar, const unsigned int /* file_version */)
181 {
182 std::cout << "Restoring EX1Level3_B\n";
183 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level2_A);
184 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level2_B);
185 }
186
187 BOOST_SERIALIZATION_SPLIT_MEMBER()
188 };
189
190 class EX1Level4 : public EX1Level3_B {
191 public:
EX1Level4()192 EX1Level4() {}
EX1Level4(int i)193 EX1Level4(int i) : EX1Level1(i) {}
194
195 template<class Archive>
save(Archive & ar,const unsigned int) const196 void save(Archive &ar, const unsigned int /* file_version */) const
197 {
198 std::cout << "Saving EX1Level4\n";
199 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level3_B);
200 }
201
202 template<class Archive>
load(Archive & ar,const unsigned int)203 void load(Archive & ar, const unsigned int /* file_version */)
204 {
205 std::cout << "Restoring EX1Level4\n";
206 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX1Level3_B);
207 }
208
209 BOOST_SERIALIZATION_SPLIT_MEMBER()
210 };
211
212
213 class EX2Level1 {
214 public:
EX2Level1()215 EX2Level1() : i(0) {}
EX2Level1(int i)216 EX2Level1(int i) : i(i)
217 {
218 m[i] = "text";
219 }
220
221 template<class Archive>
save(Archive & ar,const unsigned int) const222 void save(Archive &ar, const unsigned int /* file_version */) const
223 {
224 std::cout << "Saving EX2Level1\n";
225 ar << BOOST_SERIALIZATION_NVP(i);
226 ar << BOOST_SERIALIZATION_NVP(m);
227 ++save_count;
228 }
229
230 template<class Archive>
load(Archive & ar,const unsigned int)231 void load(Archive & ar, const unsigned int /* file_version */)
232 {
233 std::cout << "Restoring EX2Level1\n";
234 ar >> BOOST_SERIALIZATION_NVP(i);
235 ar >> BOOST_SERIALIZATION_NVP(m);
236 ++load_count;
237 }
238
239 BOOST_SERIALIZATION_SPLIT_MEMBER()
240
241 bool operator==(const EX2Level1& another) const
242 {
243 return i == another.i && m == another.m;
244 }
245 // make polymorphic by marking at least one function virtual
~EX2Level1()246 virtual ~EX2Level1() {};
247 private:
248 int i;
249 std::map<int, std::string> m;
250 };
251
252 // note: the default is for object tracking to be performed if and only
253 // if and object of the corresponding class is anywhere serialized
254 // through a pointer. In this example, that doesn't occur so
255 // by default, the shared EX2Level1 object wouldn't normally be tracked.
256 // This would leave to multiple save/load operation of the data in
257 // this shared EX2Level1 class. This wouldn't cause an error, but it would
258 // be a waste of time. So set the tracking behavior trait of the EX2Level1
259 // class to always track serialized objects of that class. This permits
260 // the system to detect and elminate redundent save/load operations.
261 // (It is concievable that this might someday be detected automatically
262 // but for now, this is not done so we have to rely on the programmer
263 // to specify this trait)
264 BOOST_CLASS_TRACKING(EX2Level1, track_always)
265
266 class EX2Level2_A : virtual public EX2Level1 {
267 public:
268 template<class Archive>
save(Archive & ar,const unsigned int) const269 void save(Archive &ar, const unsigned int /* file_version */) const
270 {
271 std::cout << "Saving EX2Level2_A\n";
272 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level1);
273 }
274
275 template<class Archive>
load(Archive & ar,const unsigned int)276 void load(Archive & ar, const unsigned int /* file_version */)
277 {
278 std::cout << "Restoring EX2Level2_A\n";
279 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level1);
280 }
281
282 BOOST_SERIALIZATION_SPLIT_MEMBER()
283 };
284
285 class EX2Level2_B : virtual public EX2Level1 {
286 public:
287 template<class Archive>
save(Archive & ar,const unsigned int) const288 void save(Archive &ar, const unsigned int /* file_version */) const
289 {
290 std::cout << "Saving EX2Level2_B\n";
291 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level1);
292 }
293
294 template<class Archive>
load(Archive & ar,const unsigned int)295 void load(Archive & ar, const unsigned int /* file_version */)
296 {
297 std::cout << "Restoring EX2Level2_B\n";
298 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level1);
299 }
300
301 BOOST_SERIALIZATION_SPLIT_MEMBER()
302 };
303
304 class EX2Level3_A : public EX2Level2_A, public EX2Level2_B {
305 public:
EX2Level3_A()306 EX2Level3_A() {}
EX2Level3_A(int i)307 EX2Level3_A(int i) : EX2Level1(i) {}
308
309 template<class Archive>
save(Archive & ar,const unsigned int) const310 void save(Archive &ar, const unsigned int /* file_version */) const
311 {
312 std::cout << "Saving EX2Level3_A\n";
313 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level2_A);
314 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level2_B);
315 }
316
317 template<class Archive>
load(Archive & ar,const unsigned int)318 void load(Archive & ar, const unsigned int /* file_version */)
319 {
320 std::cout << "Restoring EX2Level3_A\n";
321 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level2_A);
322 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level2_B);
323 }
324
325 BOOST_SERIALIZATION_SPLIT_MEMBER()
326 };
327
328
329 class EX2Level3_B : public EX2Level2_A, public EX2Level2_B {
330 public:
EX2Level3_B()331 EX2Level3_B() {}
EX2Level3_B(int i)332 EX2Level3_B(int i) : EX2Level1(i) {}
333
334 template<class Archive>
save(Archive & ar,const unsigned int) const335 void save(Archive &ar, const unsigned int /* file_version */) const
336 {
337 std::cout << "Saving EX2Level3_B\n";
338 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level2_A);
339 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level2_B);
340 }
341
342 template<class Archive>
load(Archive & ar,const unsigned int)343 void load(Archive & ar, const unsigned int /* file_version */)
344 {
345 std::cout << "Restoring EX2Level3_B\n";
346 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level2_A);
347 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level2_B);
348 }
349
350 BOOST_SERIALIZATION_SPLIT_MEMBER()
351 };
352
353 class EX2Level4 : public EX2Level3_B {
354 public:
EX2Level4()355 EX2Level4() {}
EX2Level4(int i)356 EX2Level4(int i) : EX2Level1(i) {}
357
358 template<class Archive>
save(Archive & ar,const unsigned int) const359 void save(Archive &ar, const unsigned int /* file_version */) const
360 {
361 std::cout << "Saving EX2Level4\n";
362 ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level3_B);
363 }
364
365 template<class Archive>
load(Archive & ar,const unsigned int)366 void load(Archive & ar, const unsigned int /* file_version */)
367 {
368 std::cout << "Restoring EX2Level4\n";
369 ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(EX2Level3_B);
370 }
371
372 BOOST_SERIALIZATION_SPLIT_MEMBER()
373 };
374
375 BOOST_CLASS_EXPORT(EX1Level4)
BOOST_CLASS_EXPORT(EX1Level3_A)376 BOOST_CLASS_EXPORT(EX1Level3_A)
377
378 BOOST_CLASS_EXPORT(EX2Level3_A)
379 BOOST_CLASS_EXPORT(EX2Level4)
380
381 int
382 test_main( int /* argc */, char* /* argv */[] )
383 {
384 const char * testfile = boost::archive::tmpnam(NULL);
385 BOOST_REQUIRE(NULL != testfile);
386
387 {
388 save_count = 0;
389 load_count = 0;
390
391 const EX1Level3_A ex1L3a_save(3);
392 const EX1Level1 *ex1L1_save = &ex1L3a_save;
393 {
394 test_ostream ofs(testfile, TEST_STREAM_FLAGS);
395 test_oarchive oa(ofs);
396 oa << boost::serialization::make_nvp("ex1L1_save", ex1L1_save);
397 }
398
399 EX1Level1 *ex1L1_load;
400 {
401 test_istream ifs(testfile, TEST_STREAM_FLAGS);
402 test_iarchive ia(ifs);
403 ia >> boost::serialization::make_nvp("ex1L1_load", ex1L1_load);
404 }
405 BOOST_CHECK(1 == save_count);
406 BOOST_CHECK(1 == load_count);
407 BOOST_CHECK(*ex1L1_save == *ex1L1_load);
408 std::remove(testfile);
409 }
410 {
411 save_count = 0;
412 load_count = 0;
413
414 const EX1Level4 ex1L4_save(3);
415 const EX1Level1 *ex1L1_save = &ex1L4_save;
416 {
417 test_ostream ofs(testfile, TEST_STREAM_FLAGS);
418 test_oarchive oa(ofs);
419 oa << boost::serialization::make_nvp("ex1L1_save", ex1L1_save);
420 }
421
422 EX1Level1 *ex1L1_load;
423 {
424 test_istream ifs(testfile, TEST_STREAM_FLAGS);
425 test_iarchive ia(ifs);
426 ia >> boost::serialization::make_nvp("ex1L1_load", ex1L1_load);
427 }
428 BOOST_CHECK(1 == save_count);
429 BOOST_CHECK(1 == load_count);
430 BOOST_CHECK(*ex1L1_save == *ex1L1_load);
431 std::remove(testfile);
432 }
433 {
434 save_count = 0;
435 load_count = 0;
436
437 const EX2Level3_A ex2L3a_save(3);
438 const EX2Level1 *ex2L1_save = &ex2L3a_save;
439 {
440 test_ostream ofs(testfile, TEST_STREAM_FLAGS);
441 test_oarchive oa(ofs);
442 oa << boost::serialization::make_nvp("ex2L1_save", ex2L1_save);
443 }
444
445 EX2Level1 *ex2L1_load;
446 {
447 test_istream ifs(testfile, TEST_STREAM_FLAGS);
448 test_iarchive ia(ifs);
449 ia >> boost::serialization::make_nvp("ex2L1_load", ex2L1_load);
450 }
451 BOOST_CHECK(1 == save_count);
452 BOOST_CHECK(1 == load_count);
453 BOOST_CHECK(*ex2L1_save == *ex2L1_load);
454 std::remove(testfile);
455 }
456 {
457 save_count = 0;
458 load_count = 0;
459
460 const EX2Level4 ex2L4_save(3);
461 const EX2Level1 *ex2L1_save = &ex2L4_save;
462 {
463 test_ostream ofs(testfile, TEST_STREAM_FLAGS);
464 test_oarchive oa(ofs);
465 oa << boost::serialization::make_nvp("ex2L1_save", ex2L1_save);
466 }
467
468 EX2Level1 *ex2L1_load;
469 {
470 test_istream ifs(testfile, TEST_STREAM_FLAGS);
471 test_iarchive ia(ifs);
472 ia >> boost::serialization::make_nvp("ex2L1_load", ex2L1_load);
473 }
474 BOOST_CHECK(1 == save_count);
475 BOOST_CHECK(1 == load_count);
476 BOOST_CHECK(*ex2L1_save == *ex2L1_load);
477 std::remove(testfile);
478 }
479 return EXIT_SUCCESS;
480 }
481