test_diamond_complex.cpp 14 KB

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