1 | /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 |
2 | // test_diamond.cpp |
3 | |
4 | // (C) Copyright 2002-2009 Vladimir Prus and Robert Ramey. |
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 base class is saved multiple times |
34 | int load_count = 0; // used to detect when base class is loaded multiple times |
35 | |
36 | class base { |
37 | public: |
38 | base() : i(0) {} |
39 | base(int i) : i(i) |
40 | { |
41 | m[i] = "text" ; |
42 | } |
43 | |
44 | template<class Archive> |
45 | void save(Archive &ar, const unsigned int /* file_version */) const |
46 | { |
47 | std::cout << "Saving base\n" ; |
48 | ar << BOOST_SERIALIZATION_NVP(i); |
49 | ar << BOOST_SERIALIZATION_NVP(m); |
50 | ++save_count; |
51 | } |
52 | |
53 | template<class Archive> |
54 | void load(Archive & ar, const unsigned int /* file_version */) |
55 | { |
56 | std::cout << "Restoring base\n" ; |
57 | ar >> BOOST_SERIALIZATION_NVP(i); |
58 | ar >> BOOST_SERIALIZATION_NVP(m); |
59 | ++load_count; |
60 | } |
61 | |
62 | BOOST_SERIALIZATION_SPLIT_MEMBER() |
63 | |
64 | bool operator==(const base& another) const |
65 | { |
66 | return i == another.i && m == another.m; |
67 | } |
68 | // make polymorphic by marking at least one function virtual |
69 | virtual ~base() {}; |
70 | private: |
71 | int i; |
72 | std::map<int, std::string> m; |
73 | }; |
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 base object wouldn't normally be tracked. |
79 | // This would leave to multiple save/load operation of the data in |
80 | // this shared base class. This wouldn't cause an error, but it would |
81 | // be a waste of time. So set the tracking behavior trait of the base |
82 | // class to always track serialized objects of that class. This permits |
83 | // the system to detect and eliminate redundant save/load operations. |
84 | // (It is conceivable 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(base, track_always) |
88 | |
89 | class derived1 : virtual public base { |
90 | public: |
91 | template<class Archive> |
92 | void save(Archive &ar, const unsigned int /* file_version */) const |
93 | { |
94 | std::cout << "Saving derived1\n" ; |
95 | ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(base); |
96 | } |
97 | |
98 | template<class Archive> |
99 | void load(Archive & ar, const unsigned int /* file_version */) |
100 | { |
101 | std::cout << "Restoring derived1\n" ; |
102 | ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(base); |
103 | } |
104 | |
105 | BOOST_SERIALIZATION_SPLIT_MEMBER() |
106 | }; |
107 | |
108 | class derived2 : virtual public base { |
109 | public: |
110 | template<class Archive> |
111 | void save(Archive &ar, const unsigned int /* file_version */) const |
112 | { |
113 | std::cout << "Saving derived2\n" ; |
114 | ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(base); |
115 | } |
116 | |
117 | template<class Archive> |
118 | void load(Archive & ar, const unsigned int /* file_version */) |
119 | { |
120 | std::cout << "Restoring derived2\n" ; |
121 | ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(base); |
122 | } |
123 | |
124 | BOOST_SERIALIZATION_SPLIT_MEMBER() |
125 | }; |
126 | |
127 | class final : public derived1, public derived2 { |
128 | public: |
129 | final() {} |
130 | final(int i) : base(i) {} |
131 | |
132 | template<class Archive> |
133 | void save(Archive &ar, const unsigned int /* file_version */) const |
134 | { |
135 | std::cout << "Saving final\n" ; |
136 | ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(derived1); |
137 | ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(derived2); |
138 | } |
139 | |
140 | template<class Archive> |
141 | void load(Archive & ar, const unsigned int /* file_version */) |
142 | { |
143 | std::cout << "Restoring final\n" ; |
144 | ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(derived1); |
145 | ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(derived2); |
146 | } |
147 | |
148 | BOOST_SERIALIZATION_SPLIT_MEMBER() |
149 | }; |
150 | |
151 | BOOST_CLASS_EXPORT(final) |
152 | |
153 | int |
154 | test_main( int /* argc */, char* /* argv */[] ) |
155 | { |
156 | const char * testfile = boost::archive::tmpnam(NULL); |
157 | BOOST_REQUIRE(NULL != testfile); |
158 | |
159 | const final b(3); |
160 | { |
161 | test_ostream ofs(testfile, TEST_STREAM_FLAGS); |
162 | test_oarchive oa(ofs); |
163 | oa << boost::serialization::make_nvp(n: "b" , v: b); |
164 | } |
165 | |
166 | final b2; |
167 | { |
168 | test_istream ifs(testfile, TEST_STREAM_FLAGS); |
169 | test_iarchive ia(ifs); |
170 | ia >> boost::serialization::make_nvp(n: "b2" , v&: b2); |
171 | } |
172 | BOOST_CHECK(1 == save_count); |
173 | BOOST_CHECK(1 == load_count); |
174 | BOOST_CHECK(b2 == b); |
175 | std::remove(filename: testfile); |
176 | |
177 | // do the same test with pointers |
178 | testfile = boost::archive::tmpnam(NULL); |
179 | BOOST_REQUIRE(NULL != testfile); |
180 | |
181 | save_count = 0; |
182 | load_count = 0; |
183 | |
184 | const base* bp = new final( 3 ); |
185 | { |
186 | test_ostream ofs(testfile); |
187 | test_oarchive oa(ofs); |
188 | oa << BOOST_SERIALIZATION_NVP(bp); |
189 | } |
190 | |
191 | base* bp2; |
192 | { |
193 | test_istream ifs(testfile); |
194 | test_iarchive ia(ifs); |
195 | ia >> BOOST_SERIALIZATION_NVP(bp2); |
196 | } |
197 | |
198 | BOOST_CHECK(1 == save_count); |
199 | BOOST_CHECK(1 == load_count); |
200 | BOOST_CHECK(*bp2 == *bp); |
201 | delete bp; |
202 | std::remove(filename: testfile); |
203 | |
204 | return EXIT_SUCCESS; |
205 | } |
206 | |