]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/serialization/src/basic_iarchive.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / serialization / src / basic_iarchive.cpp
1 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2 // basic_archive.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 // See http://www.boost.org for updates, documentation, and revision history.
10
11 #include <boost/config.hpp> // msvc 6.0 needs this to suppress warnings
12
13 #include <boost/assert.hpp>
14 #include <set>
15 #include <list>
16 #include <vector>
17 #include <cstddef> // size_t, NULL
18
19 #include <boost/config.hpp>
20 #if defined(BOOST_NO_STDC_NAMESPACE)
21 namespace std{
22 using ::size_t;
23 } // namespace std
24 #endif
25
26 #include <boost/integer_traits.hpp>
27
28 #define BOOST_ARCHIVE_SOURCE
29 // include this to prevent linker errors when the
30 // same modules are marked export and import.
31 #define BOOST_SERIALIZATION_SOURCE
32 #include <boost/serialization/config.hpp>
33
34 #include <boost/serialization/state_saver.hpp>
35 #include <boost/serialization/throw_exception.hpp>
36 #include <boost/serialization/tracking.hpp>
37
38 #include <boost/archive/archive_exception.hpp>
39 #include <boost/archive/detail/decl.hpp>
40 #include <boost/archive/basic_archive.hpp>
41 #include <boost/archive/detail/basic_iserializer.hpp>
42 #include <boost/archive/detail/basic_pointer_iserializer.hpp>
43 #include <boost/archive/detail/basic_iarchive.hpp>
44
45 #include <boost/archive/detail/auto_link_archive.hpp>
46
47 using namespace boost::serialization;
48
49 namespace boost {
50 namespace archive {
51 namespace detail {
52
53 class basic_iarchive_impl {
54 friend class basic_iarchive;
55 library_version_type m_archive_library_version;
56 unsigned int m_flags;
57
58 //////////////////////////////////////////////////////////////////////
59 // information about each serialized object loaded
60 // indexed on object_id
61 struct aobject
62 {
63 void * address;
64 bool loaded_as_pointer;
65 class_id_type class_id;
66 aobject(
67 void *a,
68 class_id_type class_id_
69 ) :
70 address(a),
71 loaded_as_pointer(false),
72 class_id(class_id_)
73 {}
74 aobject() :
75 address(NULL),
76 loaded_as_pointer(false),
77 class_id(-2)
78 {}
79 };
80 typedef std::vector<aobject> object_id_vector_type;
81 object_id_vector_type object_id_vector;
82
83 //////////////////////////////////////////////////////////////////////
84 // used to implement the reset_object_address operation.
85 struct moveable_objects {
86 object_id_type start;
87 object_id_type end;
88 object_id_type recent;
89 bool is_pointer;
90 moveable_objects() :
91 start(0),
92 end(0),
93 recent(0),
94 is_pointer(false)
95 {}
96 } m_moveable_objects;
97
98 void reset_object_address(
99 const void * new_address,
100 const void *old_address
101 );
102
103 //////////////////////////////////////////////////////////////////////
104 // used by load object to look up class id given basic_serializer
105 struct cobject_type
106 {
107 const basic_iserializer * m_bis;
108 const class_id_type m_class_id;
109 cobject_type(
110 std::size_t class_id,
111 const basic_iserializer & bis
112 ) :
113 m_bis(& bis),
114 m_class_id(class_id)
115 {}
116 cobject_type(const cobject_type & rhs) :
117 m_bis(rhs.m_bis),
118 m_class_id(rhs.m_class_id)
119 {}
120 // the following cannot be defined because of the const
121 // member. This will generate a link error if an attempt
122 // is made to assign. This should never be necessary
123 cobject_type & operator=(const cobject_type & rhs);
124 bool operator<(const cobject_type &rhs) const
125 {
126 return *m_bis < *(rhs.m_bis);
127 }
128 };
129 typedef std::set<cobject_type> cobject_info_set_type;
130 cobject_info_set_type cobject_info_set;
131
132 //////////////////////////////////////////////////////////////////////
133 // information about each serialized class indexed on class_id
134 class cobject_id
135 {
136 public:
137 cobject_id & operator=(const cobject_id & rhs){
138 bis_ptr = rhs.bis_ptr;
139 bpis_ptr = rhs.bpis_ptr;
140 file_version = rhs.file_version;
141 tracking_level = rhs.tracking_level;
142 initialized = rhs.initialized;
143 return *this;
144 }
145 const basic_iserializer * bis_ptr;
146 const basic_pointer_iserializer * bpis_ptr;
147 version_type file_version;
148 tracking_type tracking_level;
149 bool initialized;
150
151 cobject_id(const basic_iserializer & bis_) :
152 bis_ptr(& bis_),
153 bpis_ptr(NULL),
154 file_version(0),
155 tracking_level(track_never),
156 initialized(false)
157 {}
158 cobject_id(const cobject_id &rhs):
159 bis_ptr(rhs.bis_ptr),
160 bpis_ptr(rhs.bpis_ptr),
161 file_version(rhs.file_version),
162 tracking_level(rhs.tracking_level),
163 initialized(rhs.initialized)
164 {}
165 };
166 typedef std::vector<cobject_id> cobject_id_vector_type;
167 cobject_id_vector_type cobject_id_vector;
168
169 //////////////////////////////////////////////////////////////////////
170 // address of the most recent object serialized as a poiner
171 // whose data itself is now pending serialization
172 struct pending {
173 void * object;
174 const basic_iserializer * bis;
175 version_type version;
176 pending() :
177 object(NULL),
178 bis(NULL),
179 version(0)
180 {}
181 } m_pending;
182
183 basic_iarchive_impl(unsigned int flags) :
184 m_archive_library_version(BOOST_ARCHIVE_VERSION()),
185 m_flags(flags)
186 {}
187 void set_library_version(library_version_type archive_library_version){
188 m_archive_library_version = archive_library_version;
189 }
190 bool
191 track(
192 basic_iarchive & ar,
193 void * & t
194 );
195 void
196 load_preamble(
197 basic_iarchive & ar,
198 cobject_id & co
199 );
200 class_id_type register_type(
201 const basic_iserializer & bis
202 );
203
204 // redirect through virtual functions to load functions for this archive
205 template<class T>
206 void load(basic_iarchive & ar, T & t){
207 ar.vload(t);
208 }
209
210 //public:
211 void
212 next_object_pointer(void * t){
213 m_pending.object = t;
214 }
215 void delete_created_pointers();
216 class_id_type register_type(
217 const basic_pointer_iserializer & bpis
218 );
219 void load_object(
220 basic_iarchive & ar,
221 void * t,
222 const basic_iserializer & bis
223 );
224 const basic_pointer_iserializer * load_pointer(
225 basic_iarchive & ar,
226 void * & t,
227 const basic_pointer_iserializer * bpis,
228 const basic_pointer_iserializer * (*finder)(
229 const boost::serialization::extended_type_info & type
230 )
231 );
232 };
233
234 inline void
235 basic_iarchive_impl::reset_object_address(
236 void const * const new_address,
237 void const * const old_address
238 ){
239 if(m_moveable_objects.is_pointer)
240 return;
241
242 // this code handles a couple of situations.
243 // a) where reset_object_address is applied to an untracked object.
244 // In such a case the call is really superfluous and its really an
245 // an error. But we don't have access to the types here so we can't
246 // know that. However, this code will effectively turn this situation
247 // into a no-op and every thing will work fine - albeat with a small
248 // execution time penalty.
249 // b) where the call to reset_object_address doesn't immediatly follow
250 // the << operator to which it corresponds. This would be a bad idea
251 // but the code may work anyway. Naturally, a bad practice on the part
252 // of the programmer but we can't detect it - as above. So maybe we
253 // can save a few more people from themselves as above.
254 object_id_type i = m_moveable_objects.recent;
255 for(; i < m_moveable_objects.end; ++i){
256 if(old_address == object_id_vector[i].address)
257 break;
258 }
259 for(; i < m_moveable_objects.end; ++i){
260 void const * const this_address = object_id_vector[i].address;
261 // calculate displacement from this level
262 // warning - pointer arithmetic on void * is in herently non-portable
263 // but expected to work on all platforms in current usage
264 if(this_address > old_address){
265 std::size_t member_displacement
266 = reinterpret_cast<std::size_t>(this_address)
267 - reinterpret_cast<std::size_t>(old_address);
268 object_id_vector[i].address = reinterpret_cast<void *>(
269 reinterpret_cast<std::size_t>(new_address) + member_displacement
270 );
271 }
272 else{
273 std::size_t member_displacement
274 = reinterpret_cast<std::size_t>(old_address)
275 - reinterpret_cast<std::size_t>(this_address);
276 object_id_vector[i].address = reinterpret_cast<void *>(
277 reinterpret_cast<std::size_t>(new_address) - member_displacement
278 );
279 }
280 }
281 }
282
283 inline void
284 basic_iarchive_impl::delete_created_pointers()
285 {
286 object_id_vector_type::iterator i;
287 for(
288 i = object_id_vector.begin();
289 i != object_id_vector.end();
290 ++i
291 ){
292 if(i->loaded_as_pointer){
293 // borland complains without this minor hack
294 const int j = i->class_id;
295 const cobject_id & co = cobject_id_vector[j];
296 //const cobject_id & co = cobject_id_vector[i->class_id];
297 // with the appropriate input serializer,
298 // delete the indicated object
299 co.bis_ptr->destroy(i->address);
300 }
301 }
302 }
303
304 inline class_id_type
305 basic_iarchive_impl::register_type(
306 const basic_iserializer & bis
307 ){
308 class_id_type cid(cobject_info_set.size());
309 cobject_type co(cid, bis);
310 std::pair<cobject_info_set_type::const_iterator, bool>
311 result = cobject_info_set.insert(co);
312
313 if(result.second){
314 cobject_id_vector.push_back(cobject_id(bis));
315 BOOST_ASSERT(cobject_info_set.size() == cobject_id_vector.size());
316 }
317 cid = result.first->m_class_id;
318 // borland complains without this minor hack
319 const int tid = cid;
320 cobject_id & coid = cobject_id_vector[tid];
321 coid.bpis_ptr = bis.get_bpis_ptr();
322 return cid;
323 }
324
325 void
326 basic_iarchive_impl::load_preamble(
327 basic_iarchive & ar,
328 cobject_id & co
329 ){
330 if(! co.initialized){
331 if(co.bis_ptr->class_info()){
332 class_id_optional_type cid(class_id_type(0));
333 load(ar, cid); // to be thrown away
334 load(ar, co.tracking_level);
335 load(ar, co.file_version);
336 }
337 else{
338 // override tracking with indicator from class information
339 co.tracking_level = co.bis_ptr->tracking(m_flags);
340 co.file_version = version_type(
341 co.bis_ptr->version()
342 );
343 }
344 co.initialized = true;
345 }
346 }
347
348 bool
349 basic_iarchive_impl::track(
350 basic_iarchive & ar,
351 void * & t
352 ){
353 object_id_type oid;
354 load(ar, oid);
355
356 // if its a reference to a old object
357 if(object_id_type(object_id_vector.size()) > oid){
358 // we're done
359 t = object_id_vector[oid].address;
360 return false;
361 }
362 return true;
363 }
364
365 inline void
366 basic_iarchive_impl::load_object(
367 basic_iarchive & ar,
368 void * t,
369 const basic_iserializer & bis
370 ){
371 m_moveable_objects.is_pointer = false;
372 serialization::state_saver<bool> ss_is_pointer(m_moveable_objects.is_pointer);
373 // if its been serialized through a pointer and the preamble's been done
374 if(t == m_pending.object && & bis == m_pending.bis){
375 // read data
376 (bis.load_object_data)(ar, t, m_pending.version);
377 return;
378 }
379
380 const class_id_type cid = register_type(bis);
381 const int i = cid;
382 cobject_id & co = cobject_id_vector[i];
383
384 load_preamble(ar, co);
385
386 // save the current move stack position in case we want to truncate it
387 boost::serialization::state_saver<object_id_type> ss_start(m_moveable_objects.start);
388
389 // note: extra line used to evade borland issue
390 const bool tracking = co.tracking_level;
391
392 object_id_type this_id;
393 m_moveable_objects.start =
394 this_id = object_id_type(object_id_vector.size());
395
396 // if we tracked this object when the archive was saved
397 if(tracking){
398 // if it was already read
399 if(!track(ar, t))
400 // we're done
401 return;
402 // add a new enty into the tracking list
403 object_id_vector.push_back(aobject(t, cid));
404 // and add an entry for this object
405 m_moveable_objects.end = object_id_type(object_id_vector.size());
406 }
407 // read data
408 (bis.load_object_data)(ar, t, co.file_version);
409 m_moveable_objects.recent = this_id;
410 }
411
412 inline const basic_pointer_iserializer *
413 basic_iarchive_impl::load_pointer(
414 basic_iarchive &ar,
415 void * & t,
416 const basic_pointer_iserializer * bpis_ptr,
417 const basic_pointer_iserializer * (*finder)(
418 const boost::serialization::extended_type_info & type_
419 )
420 ){
421 m_moveable_objects.is_pointer = true;
422 serialization::state_saver<bool> w(m_moveable_objects.is_pointer);
423
424 class_id_type cid;
425 load(ar, cid);
426
427 if(NULL_POINTER_TAG == cid){
428 t = NULL;
429 return bpis_ptr;
430 }
431
432 // if its a new class type - i.e. never been registered
433 if(class_id_type(cobject_info_set.size()) <= cid){
434 // if its either abstract
435 if(NULL == bpis_ptr
436 // or polymorphic
437 || bpis_ptr->get_basic_serializer().is_polymorphic()){
438 // is must have been exported
439 char key[BOOST_SERIALIZATION_MAX_KEY_SIZE];
440 class_name_type class_name(key);
441 load(ar, class_name);
442 // if it has a class name
443 const serialization::extended_type_info *eti = NULL;
444 if(0 != key[0])
445 eti = serialization::extended_type_info::find(key);
446 if(NULL == eti)
447 boost::serialization::throw_exception(
448 archive_exception(archive_exception::unregistered_class)
449 );
450 bpis_ptr = (*finder)(*eti);
451 }
452 BOOST_ASSERT(NULL != bpis_ptr);
453 // class_id_type new_cid = register_type(bpis_ptr->get_basic_serializer());
454 BOOST_VERIFY(register_type(bpis_ptr->get_basic_serializer()) == cid);
455 int i = cid;
456 cobject_id_vector[i].bpis_ptr = bpis_ptr;
457 }
458 int i = cid;
459 cobject_id & co = cobject_id_vector[i];
460 bpis_ptr = co.bpis_ptr;
461
462 if (bpis_ptr == NULL) {
463 boost::serialization::throw_exception(
464 archive_exception(archive_exception::unregistered_class)
465 );
466 }
467
468 load_preamble(ar, co);
469
470 // extra line to evade borland issue
471 const bool tracking = co.tracking_level;
472 // if we're tracking and the pointer has already been read
473 if(tracking && ! track(ar, t))
474 // we're done
475 return bpis_ptr;
476
477 // save state
478 serialization::state_saver<object_id_type> w_start(m_moveable_objects.start);
479
480 // allocate space on the heap for the object - to be constructed later
481 t = bpis_ptr->heap_allocation();
482 BOOST_ASSERT(NULL != t);
483
484 if(! tracking){
485 bpis_ptr->load_object_ptr(ar, t, co.file_version);
486 }
487 else{
488 serialization::state_saver<void *> x(m_pending.object);
489 serialization::state_saver<const basic_iserializer *> y(m_pending.bis);
490 serialization::state_saver<version_type> z(m_pending.version);
491
492 m_pending.bis = & bpis_ptr->get_basic_serializer();
493 m_pending.version = co.file_version;
494
495 // predict next object id to be created
496 const size_t ui = object_id_vector.size();
497
498 serialization::state_saver<object_id_type> w_end(m_moveable_objects.end);
499
500
501 // add to list of serialized objects so that we can properly handle
502 // cyclic strucures
503 object_id_vector.push_back(aobject(t, cid));
504
505 // remember that that the address of these elements could change
506 // when we make another call so don't use the address
507 bpis_ptr->load_object_ptr(
508 ar,
509 t,
510 m_pending.version
511 );
512 object_id_vector[ui].loaded_as_pointer = true;
513 }
514
515 return bpis_ptr;
516 }
517
518 } // namespace detail
519 } // namespace archive
520 } // namespace boost
521
522 //////////////////////////////////////////////////////////////////////
523 // implementation of basic_iarchive functions
524 namespace boost {
525 namespace archive {
526 namespace detail {
527
528 BOOST_ARCHIVE_DECL void
529 basic_iarchive::next_object_pointer(void *t){
530 pimpl->next_object_pointer(t);
531 }
532
533 BOOST_ARCHIVE_DECL
534 basic_iarchive::basic_iarchive(unsigned int flags) :
535 pimpl(new basic_iarchive_impl(flags))
536 {}
537
538 BOOST_ARCHIVE_DECL
539 basic_iarchive::~basic_iarchive()
540 {}
541
542 BOOST_ARCHIVE_DECL void
543 basic_iarchive::set_library_version(library_version_type archive_library_version){
544 pimpl->set_library_version(archive_library_version);
545 }
546
547 BOOST_ARCHIVE_DECL void
548 basic_iarchive::reset_object_address(
549 const void * new_address,
550 const void * old_address
551 ){
552 pimpl->reset_object_address(new_address, old_address);
553 }
554
555 BOOST_ARCHIVE_DECL void
556 basic_iarchive::load_object(
557 void *t,
558 const basic_iserializer & bis
559 ){
560 pimpl->load_object(*this, t, bis);
561 }
562
563 // load a pointer object
564 BOOST_ARCHIVE_DECL const basic_pointer_iserializer *
565 basic_iarchive::load_pointer(
566 void * &t,
567 const basic_pointer_iserializer * bpis_ptr,
568 const basic_pointer_iserializer * (*finder)(
569 const boost::serialization::extended_type_info & type_
570 )
571
572 ){
573 return pimpl->load_pointer(*this, t, bpis_ptr, finder);
574 }
575
576 BOOST_ARCHIVE_DECL void
577 basic_iarchive::register_basic_serializer(const basic_iserializer & bis){
578 pimpl->register_type(bis);
579 }
580
581 BOOST_ARCHIVE_DECL void
582 basic_iarchive::delete_created_pointers()
583 {
584 pimpl->delete_created_pointers();
585 }
586
587 BOOST_ARCHIVE_DECL boost::archive::library_version_type
588 basic_iarchive::get_library_version() const{
589 return pimpl->m_archive_library_version;
590 }
591
592 BOOST_ARCHIVE_DECL unsigned int
593 basic_iarchive::get_flags() const{
594 return pimpl->m_flags;
595 }
596
597 } // namespace detail
598 } // namespace archive
599 } // namespace boost