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 inheritance 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)
18namespace 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
33int save_count = 0; // used to detect when EXnLevel1 class is saved multiple times
34int 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
50class EX1Level1 {
51public:
52 EX1Level1() : i(0) {}
53 EX1Level1(int i) : i(i)
54 {
55 m[i] = "text";
56 }
57
58 template<class Archive>
59 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>
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
83 virtual ~EX1Level1() {};
84private:
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 eliminate redundant save/load operations.
98// (It is conceivable 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)
101BOOST_CLASS_TRACKING(EX1Level1, track_always)
102
103class EX1Level2_A : virtual public EX1Level1 {
104public:
105 template<class Archive>
106 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>
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
122class EX1Level2_B : virtual public EX1Level1 {
123public:
124 template<class Archive>
125 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>
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
141class EX1Level3_A : public EX1Level2_A, public EX1Level2_B {
142public:
143 EX1Level3_A() {}
144 EX1Level3_A(int i) : EX1Level1(i) {}
145
146 template<class Archive>
147 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>
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
166class EX1Level3_B : public EX1Level2_A, public EX1Level2_B {
167public:
168 EX1Level3_B() {}
169 EX1Level3_B(int) {}
170
171 template<class Archive>
172 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>
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
190class EX1Level4 : public EX1Level3_B {
191public:
192 EX1Level4() {}
193 EX1Level4(int i) : EX1Level1(i) {}
194
195 template<class Archive>
196 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>
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
213class EX2Level1 {
214public:
215 EX2Level1() : i(0) {}
216 EX2Level1(int i) : i(i)
217 {
218 m[i] = "text";
219 }
220
221 template<class Archive>
222 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>
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
246 virtual ~EX2Level1() {};
247private:
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 eliminate redundant save/load operations.
261// (It is conceivable 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)
264BOOST_CLASS_TRACKING(EX2Level1, track_always)
265
266class EX2Level2_A : virtual public EX2Level1 {
267public:
268 template<class Archive>
269 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>
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
285class EX2Level2_B : virtual public EX2Level1 {
286public:
287 template<class Archive>
288 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>
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
304class EX2Level3_A : public EX2Level2_A, public EX2Level2_B {
305public:
306 EX2Level3_A() {}
307 EX2Level3_A(int i) : EX2Level1(i) {}
308
309 template<class Archive>
310 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>
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
329class EX2Level3_B : public EX2Level2_A, public EX2Level2_B {
330public:
331 EX2Level3_B() {}
332 EX2Level3_B(int i) : EX2Level1(i) {}
333
334 template<class Archive>
335 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>
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
353class EX2Level4 : public EX2Level3_B {
354public:
355 EX2Level4() {}
356 EX2Level4(int i) : EX2Level1(i) {}
357
358 template<class Archive>
359 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>
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
375BOOST_CLASS_EXPORT(EX1Level4)
376BOOST_CLASS_EXPORT(EX1Level3_A)
377
378BOOST_CLASS_EXPORT(EX2Level3_A)
379BOOST_CLASS_EXPORT(EX2Level4)
380
381int
382test_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(n: "ex1L1_save", v&: 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(n: "ex1L1_load", v&: 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(filename: 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(n: "ex1L1_save", v&: 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(n: "ex1L1_load", v&: 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(filename: 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(n: "ex2L1_save", v&: 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(n: "ex2L1_load", v&: 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(filename: 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(n: "ex2L1_save", v&: 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(n: "ex2L1_load", v&: 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(filename: testfile);
478 }
479 return EXIT_SUCCESS;
480}
481

source code of boost/libs/serialization/test/test_diamond_complex.cpp