• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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