1 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2 // test_reset_object_address.cpp
3
4 // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
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 #include <sstream>
10 #include <cassert>
11 #include <cstdlib> // for rand()
12 #include <cstddef> // size_t
13
14 #include <boost/config.hpp>
15 #if defined(BOOST_NO_STDC_NAMESPACE)
16 namespace std{
17 using ::rand;
18 using ::size_t;
19 }
20 #endif
21
22 #include "test_tools.hpp"
23
24 #include <boost/archive/text_oarchive.hpp>
25 #include <boost/archive/text_iarchive.hpp>
26 #include <boost/archive/polymorphic_text_oarchive.hpp>
27 #include <boost/archive/polymorphic_text_iarchive.hpp>
28
29 #include <boost/serialization/list.hpp>
30 #include <boost/serialization/access.hpp>
31
32 // Someday, maybe all tests will be converted to the unit test framework.
33 // but for now use the text execution monitor to be consistent with all
34 // the other tests.
35
36 // simple test of untracked value
37 #include "A.hpp"
38 #include "A.ipp"
39
test1()40 void test1(){
41 std::stringstream ss;
42 const A a;
43 {
44 boost::archive::text_oarchive oa(ss);
45 oa << a;
46 }
47 A a1;
48 {
49 boost::archive::text_iarchive ia(ss);
50 // load to temporary
51 A a2;
52 ia >> a2;
53 BOOST_CHECK_EQUAL(a, a2);
54 // move to final destination
55 a1 = a2;
56 ia.reset_object_address(& a1, & a2);
57 }
58 BOOST_CHECK_EQUAL(a, a1);
59 }
60
61 // simple test of tracked value
62 class B {
63 friend class boost::serialization::access;
64 int m_i;
65 template<class Archive>
serialize(Archive & ar,const unsigned int)66 void serialize(Archive &ar, const unsigned int /*file_version*/){
67 ar & m_i;
68 }
69 public:
operator ==(const B & rhs) const70 bool operator==(const B & rhs) const {
71 return m_i == rhs.m_i;
72 }
B()73 B() :
74 m_i(std::rand())
75 {}
76 };
77
78 //BOOST_TEST_DONT_PRINT_LOG_VALUE( B )
79
test2()80 void test2(){
81 std::stringstream ss;
82 B const b;
83 B const * const b_ptr = & b;
84 BOOST_CHECK_EQUAL(& b, b_ptr);
85 {
86 boost::archive::text_oarchive oa(ss);
87 oa << b;
88 oa << b_ptr;
89 }
90 B b1;
91 B * b1_ptr;
92 {
93 boost::archive::text_iarchive ia(ss);
94 // load to temporary
95 B b2;
96 ia >> b2;
97 BOOST_CHECK_EQUAL(b, b2);
98 // move to final destination
99 b1 = b2;
100 ia.reset_object_address(& b1, & b2);
101 ia >> b1_ptr;
102 }
103 BOOST_CHECK_EQUAL(b, b1);
104 BOOST_CHECK_EQUAL(& b1, b1_ptr);
105 }
106
107 // check that nested member values are properly moved
108 class D {
109 friend class boost::serialization::access;
110 template<class Archive>
serialize(Archive & ar,const unsigned int)111 void serialize(Archive &ar, const unsigned int /*file_version*/){
112 ar & m_b;
113 }
114 public:
115 B m_b;
operator ==(const D & rhs) const116 bool operator==(const D & rhs) const {
117 return m_b == rhs.m_b;
118 }
D()119 D(){}
120 };
121
122 //BOOST_TEST_DONT_PRINT_LOG_VALUE( D )
123
test3()124 void test3(){
125 std::stringstream ss;
126 D const d;
127 B const * const b_ptr = & d.m_b;
128 {
129 boost::archive::text_oarchive oa(ss);
130 oa << d;
131 oa << b_ptr;
132 }
133 D d1;
134 B * b1_ptr;
135 {
136 boost::archive::text_iarchive ia(ss);
137 D d2;
138 ia >> d2;
139 d1 = d2;
140 ia.reset_object_address(& d1, & d2);
141 ia >> b1_ptr;
142 }
143 BOOST_CHECK_EQUAL(d, d1);
144 BOOST_CHECK_EQUAL(* b_ptr, * b1_ptr);
145 }
146
147 // check that data pointed to by pointer members is NOT moved
148 class E {
149 int m_i;
150 friend class boost::serialization::access;
151 template<class Archive>
serialize(Archive & ar,const unsigned int)152 void serialize(Archive &ar, const unsigned int /*file_version*/){
153 ar & m_i;
154 }
155 public:
operator ==(const E & rhs) const156 bool operator==(const E &rhs) const {
157 return m_i == rhs.m_i;
158 }
E()159 E() :
160 m_i(std::rand())
161 {}
E(const E & rhs)162 E(const E & rhs) :
163 m_i(rhs.m_i)
164 {}
165 };
166 //BOOST_TEST_DONT_PRINT_LOG_VALUE( E )
167
168 // check that moves don't move stuff pointed to
169 class F {
170 friend class boost::serialization::access;
171 E * m_eptr;
172 template<class Archive>
serialize(Archive & ar,const unsigned int)173 void serialize(Archive &ar, const unsigned int /*file_version*/){
174 ar & m_eptr;
175 }
176 public:
operator ==(const F & rhs) const177 bool operator==(const F &rhs) const {
178 return *m_eptr == *rhs.m_eptr;
179 }
operator =(const F & rhs)180 F & operator=(const F & rhs) {
181 * m_eptr = * rhs.m_eptr;
182 return *this;
183 }
F()184 F(){
185 m_eptr = new E;
186 }
F(const F & rhs)187 F(const F & rhs){
188 *this = rhs;
189 }
~F()190 ~F(){
191 delete m_eptr;
192 }
193 };
194
195 //BOOST_TEST_DONT_PRINT_LOG_VALUE( F )
196
test4()197 void test4(){
198 std::stringstream ss;
199 const F f;
200 {
201 boost::archive::text_oarchive oa(ss);
202 oa << f;
203 }
204 F f1;
205 {
206 boost::archive::text_iarchive ia(ss);
207 F f2;
208 ia >> f2;
209 f1 = f2;
210 ia.reset_object_address(& f1, & f2);
211 }
212 BOOST_CHECK_EQUAL(f, f1);
213 }
214
215 // check that multiple moves keep track of the correct target
216 class G {
217 friend class boost::serialization::access;
218 A m_a1;
219 A m_a2;
220 A *m_pa2;
221 template<class Archive>
save(Archive & ar,const unsigned int) const222 void save(Archive &ar, const unsigned int /*file_version*/) const {
223 ar << m_a1;
224 ar << m_a2;
225 ar << m_pa2;
226 }
227 template<class Archive>
load(Archive & ar,const unsigned int)228 void load(Archive &ar, const unsigned int /*file_version*/){
229 A a; // temporary A
230 ar >> a;
231 m_a1 = a;
232 ar.reset_object_address(& m_a1, & a);
233 ar >> a;
234 m_a2 = a;
235 ar.reset_object_address(& m_a2, & a);
236 ar & m_pa2;
237 }
238 BOOST_SERIALIZATION_SPLIT_MEMBER()
239 public:
operator ==(const G & rhs) const240 bool operator==(const G &rhs) const {
241 return
242 m_a1 == rhs.m_a1
243 && m_a2 == rhs.m_a2
244 && *m_pa2 == *rhs.m_pa2;
245 }
operator =(const G & rhs)246 G & operator=(const G & rhs) {
247 m_a1 = rhs.m_a1;
248 m_a2 = rhs.m_a2;
249 m_pa2 = & m_a2;
250 return *this;
251 }
G()252 G(){
253 m_pa2 = & m_a2;
254 }
G(const G & rhs)255 G(const G & rhs){
256 *this = rhs;
257 }
~G()258 ~G(){}
259 };
260
261 //BOOST_TEST_DONT_PRINT_LOG_VALUE( G )
262
test5()263 void test5(){
264 std::stringstream ss;
265 const G g;
266 {
267 boost::archive::text_oarchive oa(ss);
268 oa << g;
269 }
270 G g1;
271 {
272 boost::archive::text_iarchive ia(ss);
273 ia >> g1;
274 }
275 BOOST_CHECK_EQUAL(g, g1);
276 }
277
278 // joaquin's test - this tests the case where rest_object_address
279 // is applied to an item which in fact is not tracked so that
280 // the call is in fact superfluous.
281 struct foo
282 {
283 int x;
284
285 private:
286 friend class boost::serialization::access;
287
288 template<class Archive>
serializefoo289 void serialize(Archive &,const unsigned int)
290 {
291 }
292 };
293
294 struct bar
295 {
296 foo f[2];
297 foo* pf[2];
298
299 private:
300 friend class boost::serialization::access;
BOOST_SERIALIZATION_SPLIT_MEMBERbar301 BOOST_SERIALIZATION_SPLIT_MEMBER()
302
303 template<class Archive>
304 void save(Archive& ar,const unsigned int)const
305 {
306 for(int i=0;i<2;++i){
307 ar<<f[i].x;
308 ar<<f[i];
309 }
310 for(int j=0;j<2;++j){
311 ar<<pf[j];
312 }
313 }
314
315 template<class Archive>
loadbar316 void load(Archive& ar,const unsigned int)
317 {
318 for(int i=0;i<2;++i){
319 int x;
320 ar>>x;
321 f[i].x=x;
322 ar.reset_object_address(&f[i].x,&x);
323 ar>>f[i];
324 }
325 for(int j=0;j<2;++j){
326 ar>>pf[j];
327 }
328 }
329 };
330
test6()331 int test6()
332 {
333 bar b;
334 b.f[0].x=0;
335 b.f[1].x=1;
336 b.pf[0]=&b.f[0];
337 b.pf[1]=&b.f[1];
338
339 std::ostringstream oss;
340 {
341 boost::archive::text_oarchive oa(oss);
342 oa<<const_cast<const bar&>(b);
343 }
344
345 bar b1;
346 b1.pf[0]=0;
347 b1.pf[1]=0;
348
349 std::istringstream iss(oss.str());
350 boost::archive::text_iarchive ia(iss);
351 ia>>b1;
352 BOOST_CHECK(b1.pf[0]==&b1.f[0]&&b1.pf[1]==&b1.f[1]);
353
354 return 0;
355 }
356
357 // test one of the collections
test7()358 void test7(){
359 std::stringstream ss;
360 B const b;
361 B const * const b_ptr = & b;
362 BOOST_CHECK_EQUAL(& b, b_ptr);
363 {
364 std::list<const B *> l;
365 l.push_back(b_ptr);
366 boost::archive::text_oarchive oa(ss);
367 oa << const_cast<const std::list<const B *> &>(l);
368 }
369 B b1;
370 {
371 std::list<B *> l;
372 boost::archive::text_iarchive ia(ss);
373 ia >> l;
374 delete l.front(); // prevent memory leak
375 }
376 }
377
378 // test one of the collections with polymorphic archive
test8()379 void test8(){
380 std::stringstream ss;
381 B const b;
382 B const * const b_ptr = & b;
383 BOOST_CHECK_EQUAL(& b, b_ptr);
384 {
385 std::list<const B *> l;
386 l.push_back(b_ptr);
387 boost::archive::polymorphic_text_oarchive oa(ss);
388 boost::archive::polymorphic_oarchive & poa = oa;
389 poa << const_cast<const std::list<const B *> &>(l);
390 }
391 B b1;
392 {
393 std::list<B *> l;
394 boost::archive::polymorphic_text_iarchive ia(ss);
395 boost::archive::polymorphic_iarchive & pia = ia;
396 pia >> l;
397 delete l.front(); // prevent memory leak
398 }
399 }
400
test_main(int,char * [])401 int test_main(int /* argc */, char * /* argv */[])
402 {
403 test1();
404 test2();
405 test3();
406 test4();
407 test5();
408 test6();
409 test7();
410 test8();
411 return EXIT_SUCCESS;
412 }
413