1 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
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)
9 // See http://www.boost.org for updates, documentation, and revision history.
11 #include <boost/config.hpp> // msvc 6.0 needs this to suppress warnings
13 #include <boost/assert.hpp>
17 #include <cstddef> // size_t, NULL
19 #include <boost/config.hpp>
20 #if defined(BOOST_NO_STDC_NAMESPACE)
26 #include <boost/integer_traits.hpp>
27 #include <boost/serialization/state_saver.hpp>
28 #include <boost/serialization/throw_exception.hpp>
29 #include <boost/serialization/tracking.hpp>
31 #define BOOST_ARCHIVE_SOURCE
32 // include this to prevent linker errors when the
33 // same modules are marked export and import.
34 #define BOOST_SERIALIZATION_SOURCE
36 #include <boost/archive/archive_exception.hpp>
38 #include <boost/archive/detail/decl.hpp>
39 #include <boost/archive/basic_archive.hpp>
40 #include <boost/archive/detail/basic_iserializer.hpp>
41 #include <boost/archive/detail/basic_pointer_iserializer.hpp>
42 #include <boost/archive/detail/basic_iarchive.hpp>
44 #include <boost/archive/detail/auto_link_archive.hpp>
46 using namespace boost::serialization;
52 class basic_iarchive_impl {
53 friend class basic_iarchive;
54 library_version_type m_archive_library_version;
57 //////////////////////////////////////////////////////////////////////
58 // information about each serialized object loaded
59 // indexed on object_id
63 bool loaded_as_pointer;
64 class_id_type class_id;
67 class_id_type class_id_
70 loaded_as_pointer(false),
75 loaded_as_pointer(false),
79 typedef std::vector<aobject> object_id_vector_type;
80 object_id_vector_type object_id_vector;
82 //////////////////////////////////////////////////////////////////////
83 // used to implement the reset_object_address operation.
84 struct moveable_objects {
87 object_id_type recent;
97 void reset_object_address(
98 const void * new_address,
99 const void *old_address
102 //////////////////////////////////////////////////////////////////////
103 // used by load object to look up class id given basic_serializer
106 const basic_iserializer * m_bis;
107 const class_id_type m_class_id;
109 std::size_t class_id,
110 const basic_iserializer & bis
115 cobject_type(const cobject_type & rhs) :
117 m_class_id(rhs.m_class_id)
119 // the following cannot be defined because of the const
120 // member. This will generate a link error if an attempt
121 // is made to assign. This should never be necessary
122 cobject_type & operator=(const cobject_type & rhs);
123 bool operator<(const cobject_type &rhs) const
125 return *m_bis < *(rhs.m_bis);
128 typedef std::set<cobject_type> cobject_info_set_type;
129 cobject_info_set_type cobject_info_set;
131 //////////////////////////////////////////////////////////////////////
132 // information about each serialized class indexed on class_id
136 cobject_id & operator=(const cobject_id & rhs){
137 bis_ptr = rhs.bis_ptr;
138 bpis_ptr = rhs.bpis_ptr;
139 file_version = rhs.file_version;
140 tracking_level = rhs.tracking_level;
141 initialized = rhs.initialized;
144 const basic_iserializer * bis_ptr;
145 const basic_pointer_iserializer * bpis_ptr;
146 version_type file_version;
147 tracking_type tracking_level;
150 cobject_id(const basic_iserializer & bis_) :
154 tracking_level(track_never),
157 cobject_id(const cobject_id &rhs):
158 bis_ptr(rhs.bis_ptr),
159 bpis_ptr(rhs.bpis_ptr),
160 file_version(rhs.file_version),
161 tracking_level(rhs.tracking_level),
162 initialized(rhs.initialized)
165 typedef std::vector<cobject_id> cobject_id_vector_type;
166 cobject_id_vector_type cobject_id_vector;
168 //////////////////////////////////////////////////////////////////////
169 // address of the most recent object serialized as a poiner
170 // whose data itself is now pending serialization
173 const basic_iserializer * bis;
174 version_type version;
182 basic_iarchive_impl(unsigned int flags) :
183 m_archive_library_version(BOOST_ARCHIVE_VERSION()),
186 ~basic_iarchive_impl(){}
187 void set_library_version(library_version_type archive_library_version){
188 m_archive_library_version = archive_library_version;
200 class_id_type register_type(
201 const basic_iserializer & bis
204 // redirect through virtual functions to load functions for this archive
206 void load(basic_iarchive & ar, T & t){
212 next_object_pointer(void * t){
213 m_pending.object = t;
215 void delete_created_pointers();
216 class_id_type register_type(
217 const basic_pointer_iserializer & bpis
222 const basic_iserializer & bis
224 const basic_pointer_iserializer * load_pointer(
227 const basic_pointer_iserializer * bpis,
228 const basic_pointer_iserializer * (*finder)(
229 const boost::serialization::extended_type_info & type
236 basic_iarchive_impl::reset_object_address(
237 void const * const new_address,
238 void const * const old_address
240 if(m_moveable_objects.is_pointer)
243 // this code handles a couple of situations.
244 // a) where reset_object_address is applied to an untracked object.
245 // In such a case the call is really superfluous and its really an
246 // an error. But we don't have access to the types here so we can't
247 // know that. However, this code will effectively turn this situation
248 // into a no-op and every thing will work fine - albeat with a small
249 // execution time penalty.
250 // b) where the call to reset_object_address doesn't immediatly follow
251 // the << operator to which it corresponds. This would be a bad idea
252 // but the code may work anyway. Naturally, a bad practice on the part
253 // of the programmer but we can't detect it - as above. So maybe we
254 // can save a few more people from themselves as above.
256 for(i = m_moveable_objects.recent; i < m_moveable_objects.end; ++i){
257 if(old_address == object_id_vector[i].address)
260 for(; i < m_moveable_objects.end; ++i){
261 void const * const this_address = object_id_vector[i].address;
262 // calculate displacement from this level
263 // warning - pointer arithmetic on void * is in herently non-portable
264 // but expected to work on all platforms in current usage
265 if(this_address > old_address){
266 std::size_t member_displacement
267 = reinterpret_cast<std::size_t>(this_address)
268 - reinterpret_cast<std::size_t>(old_address);
269 object_id_vector[i].address = reinterpret_cast<void *>(
270 reinterpret_cast<std::size_t>(new_address) + member_displacement
274 std::size_t member_displacement
275 = reinterpret_cast<std::size_t>(old_address)
276 - reinterpret_cast<std::size_t>(this_address);
277 object_id_vector[i].address = reinterpret_cast<void *>(
278 reinterpret_cast<std::size_t>(new_address) - member_displacement
285 basic_iarchive_impl::delete_created_pointers()
287 object_id_vector_type::iterator i;
289 i = object_id_vector.begin();
290 i != object_id_vector.end();
293 if(i->loaded_as_pointer){
294 // borland complains without this minor hack
295 const int j = i->class_id;
296 const cobject_id & co = cobject_id_vector[j];
297 //const cobject_id & co = cobject_id_vector[i->class_id];
298 // with the appropriate input serializer,
299 // delete the indicated object
300 co.bis_ptr->destroy(i->address);
306 basic_iarchive_impl::register_type(
307 const basic_iserializer & bis
309 class_id_type cid(cobject_info_set.size());
310 cobject_type co(cid, bis);
311 std::pair<cobject_info_set_type::const_iterator, bool>
312 result = cobject_info_set.insert(co);
315 cobject_id_vector.push_back(cobject_id(bis));
316 BOOST_ASSERT(cobject_info_set.size() == cobject_id_vector.size());
318 cid = result.first->m_class_id;
319 // borland complains without this minor hack
321 cobject_id & coid = cobject_id_vector[tid];
322 coid.bpis_ptr = bis.get_bpis_ptr();
327 basic_iarchive_impl::load_preamble(
331 if(! co.initialized){
332 if(co.bis_ptr->class_info()){
333 class_id_optional_type cid(class_id_type(0));
334 load(ar, cid); // to be thrown away
335 load(ar, co.tracking_level);
336 load(ar, co.file_version);
339 // override tracking with indicator from class information
340 co.tracking_level = co.bis_ptr->tracking(m_flags);
341 co.file_version = version_type(
342 co.bis_ptr->version()
345 co.initialized = true;
350 basic_iarchive_impl::track(
357 // if its a reference to a old object
358 if(object_id_type(object_id_vector.size()) > oid){
360 t = object_id_vector[oid].address;
367 basic_iarchive_impl::load_object(
370 const basic_iserializer & bis
372 m_moveable_objects.is_pointer = false;
373 serialization::state_saver<bool> ss_is_pointer(m_moveable_objects.is_pointer);
374 // if its been serialized through a pointer and the preamble's been done
375 if(t == m_pending.object && & bis == m_pending.bis){
377 (bis.load_object_data)(ar, t, m_pending.version);
381 const class_id_type cid = register_type(bis);
383 cobject_id & co = cobject_id_vector[i];
385 load_preamble(ar, co);
387 // save the current move stack position in case we want to truncate it
388 boost::serialization::state_saver<object_id_type> ss_start(m_moveable_objects.start);
390 // note: extra line used to evade borland issue
391 const bool tracking = co.tracking_level;
393 object_id_type this_id;
394 m_moveable_objects.start =
395 this_id = object_id_type(object_id_vector.size());
397 // if we tracked this object when the archive was saved
399 // if it was already read
403 // add a new enty into the tracking list
404 object_id_vector.push_back(aobject(t, cid));
405 // and add an entry for this object
406 m_moveable_objects.end = object_id_type(object_id_vector.size());
409 (bis.load_object_data)(ar, t, co.file_version);
410 m_moveable_objects.recent = this_id;
413 inline const basic_pointer_iserializer *
414 basic_iarchive_impl::load_pointer(
417 const basic_pointer_iserializer * bpis_ptr,
418 const basic_pointer_iserializer * (*finder)(
419 const boost::serialization::extended_type_info & type_
422 m_moveable_objects.is_pointer = true;
423 serialization::state_saver<bool> w(m_moveable_objects.is_pointer);
428 if(NULL_POINTER_TAG == cid){
433 // if its a new class type - i.e. never been registered
434 if(class_id_type(cobject_info_set.size()) <= cid){
435 // if its either abstract
438 || bpis_ptr->get_basic_serializer().is_polymorphic()){
439 // is must have been exported
440 char key[BOOST_SERIALIZATION_MAX_KEY_SIZE];
441 class_name_type class_name(key);
442 load(ar, class_name);
443 // if it has a class name
444 const serialization::extended_type_info *eti = NULL;
446 eti = serialization::extended_type_info::find(key);
448 boost::serialization::throw_exception(
449 archive_exception(archive_exception::unregistered_class)
451 bpis_ptr = (*finder)(*eti);
453 BOOST_ASSERT(NULL != bpis_ptr);
454 // class_id_type new_cid = register_type(bpis_ptr->get_basic_serializer());
455 BOOST_VERIFY(register_type(bpis_ptr->get_basic_serializer()) == cid);
457 cobject_id_vector[i].bpis_ptr = bpis_ptr;
460 cobject_id & co = cobject_id_vector[i];
461 bpis_ptr = co.bpis_ptr;
463 load_preamble(ar, co);
465 // extra line to evade borland issue
466 const bool tracking = co.tracking_level;
467 // if we're tracking and the pointer has already been read
468 if(tracking && ! track(ar, t))
473 serialization::state_saver<object_id_type> w_start(m_moveable_objects.start);
475 // allocate space on the heap for the object - to be constructed later
476 t = bpis_ptr->heap_allocation();
477 BOOST_ASSERT(NULL != t);
480 bpis_ptr->load_object_ptr(ar, t, co.file_version);
483 serialization::state_saver<void *> x(m_pending.object);
484 serialization::state_saver<const basic_iserializer *> y(m_pending.bis);
485 serialization::state_saver<version_type> z(m_pending.version);
487 m_pending.bis = & bpis_ptr->get_basic_serializer();
488 m_pending.version = co.file_version;
490 // predict next object id to be created
491 const unsigned int ui = object_id_vector.size();
493 serialization::state_saver<object_id_type> w_end(m_moveable_objects.end);
496 // add to list of serialized objects so that we can properly handle
498 object_id_vector.push_back(aobject(t, cid));
500 // remember that that the address of these elements could change
501 // when we make another call so don't use the address
502 bpis_ptr->load_object_ptr(
507 object_id_vector[ui].loaded_as_pointer = true;
513 } // namespace detail
514 } // namespace archive
517 //////////////////////////////////////////////////////////////////////
518 // implementation of basic_iarchive functions
523 BOOST_ARCHIVE_DECL(void)
524 basic_iarchive::next_object_pointer(void *t){
525 pimpl->next_object_pointer(t);
528 BOOST_ARCHIVE_DECL(BOOST_PP_EMPTY())
529 basic_iarchive::basic_iarchive(unsigned int flags) :
530 pimpl(new basic_iarchive_impl(flags))
533 BOOST_ARCHIVE_DECL(BOOST_PP_EMPTY())
534 basic_iarchive::~basic_iarchive()
539 BOOST_ARCHIVE_DECL(void)
540 basic_iarchive::set_library_version(library_version_type archive_library_version){
541 pimpl->set_library_version(archive_library_version);
544 BOOST_ARCHIVE_DECL(void)
545 basic_iarchive::reset_object_address(
546 const void * new_address,
547 const void * old_address
549 pimpl->reset_object_address(new_address, old_address);
552 BOOST_ARCHIVE_DECL(void)
553 basic_iarchive::load_object(
555 const basic_iserializer & bis
557 pimpl->load_object(*this, t, bis);
560 // load a pointer object
561 BOOST_ARCHIVE_DECL(const basic_pointer_iserializer *)
562 basic_iarchive::load_pointer(
564 const basic_pointer_iserializer * bpis_ptr,
565 const basic_pointer_iserializer * (*finder)(
566 const boost::serialization::extended_type_info & type_
570 return pimpl->load_pointer(*this, t, bpis_ptr, finder);
573 BOOST_ARCHIVE_DECL(void)
574 basic_iarchive::register_basic_serializer(const basic_iserializer & bis){
575 pimpl->register_type(bis);
578 BOOST_ARCHIVE_DECL(void)
579 basic_iarchive::delete_created_pointers()
581 pimpl->delete_created_pointers();
584 BOOST_ARCHIVE_DECL(boost::archive::library_version_type)
585 basic_iarchive::get_library_version() const{
586 return pimpl->m_archive_library_version;
589 BOOST_ARCHIVE_DECL(unsigned int)
590 basic_iarchive::get_flags() const{
591 return pimpl->m_flags;
594 } // namespace detail
595 } // namespace archive