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) |
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: |
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() {}; |
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 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) |
101 | BOOST_CLASS_TRACKING(EX1Level1, track_always) |
102 | |
103 | class EX1Level2_A : virtual public EX1Level1 { |
104 | public: |
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 | |
122 | class EX1Level2_B : virtual public EX1Level1 { |
123 | public: |
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 | |
141 | class EX1Level3_A : public EX1Level2_A, public EX1Level2_B { |
142 | public: |
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 | |
166 | class EX1Level3_B : public EX1Level2_A, public EX1Level2_B { |
167 | public: |
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 | |
190 | class EX1Level4 : public EX1Level3_B { |
191 | public: |
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 | |
213 | class EX2Level1 { |
214 | public: |
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() {}; |
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 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) |
264 | BOOST_CLASS_TRACKING(EX2Level1, track_always) |
265 | |
266 | class EX2Level2_A : virtual public EX2Level1 { |
267 | public: |
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 | |
285 | class EX2Level2_B : virtual public EX2Level1 { |
286 | public: |
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 | |
304 | class EX2Level3_A : public EX2Level2_A, public EX2Level2_B { |
305 | public: |
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 | |
329 | class EX2Level3_B : public EX2Level2_A, public EX2Level2_B { |
330 | public: |
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 | |
353 | class EX2Level4 : public EX2Level3_B { |
354 | public: |
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 | |
375 | BOOST_CLASS_EXPORT(EX1Level4) |
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(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 | |