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>
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>
34 #include <boost/serialization/state_saver.hpp>
35 #include <boost/serialization/throw_exception.hpp>
36 #include <boost/serialization/tracking.hpp>
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>
45 #include <boost/archive/detail/auto_link_archive.hpp>
47 using namespace boost::serialization
;
53 class basic_iarchive_impl
{
54 friend class basic_iarchive
;
55 library_version_type m_archive_library_version
;
58 //////////////////////////////////////////////////////////////////////
59 // information about each serialized object loaded
60 // indexed on object_id
64 bool loaded_as_pointer
;
65 class_id_type class_id
;
68 class_id_type class_id_
71 loaded_as_pointer(false),
76 loaded_as_pointer(false),
80 typedef std::vector
<aobject
> object_id_vector_type
;
81 object_id_vector_type object_id_vector
;
83 //////////////////////////////////////////////////////////////////////
84 // used to implement the reset_object_address operation.
85 struct moveable_objects
{
88 object_id_type recent
;
98 void reset_object_address(
99 const void * new_address
,
100 const void *old_address
103 //////////////////////////////////////////////////////////////////////
104 // used by load object to look up class id given basic_serializer
107 const basic_iserializer
* m_bis
;
108 const class_id_type m_class_id
;
110 std::size_t class_id
,
111 const basic_iserializer
& bis
116 cobject_type(const cobject_type
& rhs
) :
118 m_class_id(rhs
.m_class_id
)
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
126 return *m_bis
< *(rhs
.m_bis
);
129 typedef std::set
<cobject_type
> cobject_info_set_type
;
130 cobject_info_set_type cobject_info_set
;
132 //////////////////////////////////////////////////////////////////////
133 // information about each serialized class indexed on class_id
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
;
145 const basic_iserializer
* bis_ptr
;
146 const basic_pointer_iserializer
* bpis_ptr
;
147 version_type file_version
;
148 tracking_type tracking_level
;
151 cobject_id(const basic_iserializer
& bis_
) :
155 tracking_level(track_never
),
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
)
166 typedef std::vector
<cobject_id
> cobject_id_vector_type
;
167 cobject_id_vector_type cobject_id_vector
;
169 //////////////////////////////////////////////////////////////////////
170 // address of the most recent object serialized as a poiner
171 // whose data itself is now pending serialization
174 const basic_iserializer
* bis
;
175 version_type version
;
183 basic_iarchive_impl(unsigned int flags
) :
184 m_archive_library_version(BOOST_ARCHIVE_VERSION()),
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
235 basic_iarchive_impl::reset_object_address(
236 void const * const new_address
,
237 void const * const old_address
239 if(m_moveable_objects
.is_pointer
)
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
)
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
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
284 basic_iarchive_impl::delete_created_pointers()
286 object_id_vector_type::iterator i
;
288 i
= object_id_vector
.begin();
289 i
!= object_id_vector
.end();
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
);
305 basic_iarchive_impl::register_type(
306 const basic_iserializer
& bis
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
);
314 cobject_id_vector
.push_back(cobject_id(bis
));
315 BOOST_ASSERT(cobject_info_set
.size() == cobject_id_vector
.size());
317 cid
= result
.first
->m_class_id
;
318 // borland complains without this minor hack
320 cobject_id
& coid
= cobject_id_vector
[tid
];
321 coid
.bpis_ptr
= bis
.get_bpis_ptr();
326 basic_iarchive_impl::load_preamble(
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
);
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()
344 co
.initialized
= true;
349 basic_iarchive_impl::track(
356 // if its a reference to a old object
357 if(object_id_type(object_id_vector
.size()) > oid
){
359 t
= object_id_vector
[oid
].address
;
366 basic_iarchive_impl::load_object(
369 const basic_iserializer
& bis
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
){
376 (bis
.load_object_data
)(ar
, t
, m_pending
.version
);
380 const class_id_type cid
= register_type(bis
);
382 cobject_id
& co
= cobject_id_vector
[i
];
384 load_preamble(ar
, co
);
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
);
389 // note: extra line used to evade borland issue
390 const bool tracking
= co
.tracking_level
;
392 object_id_type this_id
;
393 m_moveable_objects
.start
=
394 this_id
= object_id_type(object_id_vector
.size());
396 // if we tracked this object when the archive was saved
398 // if it was already read
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());
408 (bis
.load_object_data
)(ar
, t
, co
.file_version
);
409 m_moveable_objects
.recent
= this_id
;
412 inline const basic_pointer_iserializer
*
413 basic_iarchive_impl::load_pointer(
416 const basic_pointer_iserializer
* bpis_ptr
,
417 const basic_pointer_iserializer
* (*finder
)(
418 const boost::serialization::extended_type_info
& type_
421 m_moveable_objects
.is_pointer
= true;
422 serialization::state_saver
<bool> w(m_moveable_objects
.is_pointer
);
427 if(NULL_POINTER_TAG
== cid
){
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
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
;
445 eti
= serialization::extended_type_info::find(key
);
447 boost::serialization::throw_exception(
448 archive_exception(archive_exception::unregistered_class
)
450 bpis_ptr
= (*finder
)(*eti
);
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
);
456 cobject_id_vector
[i
].bpis_ptr
= bpis_ptr
;
459 cobject_id
& co
= cobject_id_vector
[i
];
460 bpis_ptr
= co
.bpis_ptr
;
462 if (bpis_ptr
== NULL
) {
463 boost::serialization::throw_exception(
464 archive_exception(archive_exception::unregistered_class
)
468 load_preamble(ar
, co
);
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
))
478 serialization::state_saver
<object_id_type
> w_start(m_moveable_objects
.start
);
480 // allocate space on the heap for the object - to be constructed later
481 t
= bpis_ptr
->heap_allocation();
482 BOOST_ASSERT(NULL
!= t
);
485 bpis_ptr
->load_object_ptr(ar
, t
, co
.file_version
);
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
);
492 m_pending
.bis
= & bpis_ptr
->get_basic_serializer();
493 m_pending
.version
= co
.file_version
;
495 // predict next object id to be created
496 const size_t ui
= object_id_vector
.size();
498 serialization::state_saver
<object_id_type
> w_end(m_moveable_objects
.end
);
501 // add to list of serialized objects so that we can properly handle
503 object_id_vector
.push_back(aobject(t
, cid
));
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(
512 object_id_vector
[ui
].loaded_as_pointer
= true;
518 } // namespace detail
519 } // namespace archive
522 //////////////////////////////////////////////////////////////////////
523 // implementation of basic_iarchive functions
528 BOOST_ARCHIVE_DECL
void
529 basic_iarchive::next_object_pointer(void *t
){
530 pimpl
->next_object_pointer(t
);
534 basic_iarchive::basic_iarchive(unsigned int flags
) :
535 pimpl(new basic_iarchive_impl(flags
))
539 basic_iarchive::~basic_iarchive()
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
);
547 BOOST_ARCHIVE_DECL
void
548 basic_iarchive::reset_object_address(
549 const void * new_address
,
550 const void * old_address
552 pimpl
->reset_object_address(new_address
, old_address
);
555 BOOST_ARCHIVE_DECL
void
556 basic_iarchive::load_object(
558 const basic_iserializer
& bis
560 pimpl
->load_object(*this, t
, bis
);
563 // load a pointer object
564 BOOST_ARCHIVE_DECL
const basic_pointer_iserializer
*
565 basic_iarchive::load_pointer(
567 const basic_pointer_iserializer
* bpis_ptr
,
568 const basic_pointer_iserializer
* (*finder
)(
569 const boost::serialization::extended_type_info
& type_
573 return pimpl
->load_pointer(*this, t
, bpis_ptr
, finder
);
576 BOOST_ARCHIVE_DECL
void
577 basic_iarchive::register_basic_serializer(const basic_iserializer
& bis
){
578 pimpl
->register_type(bis
);
581 BOOST_ARCHIVE_DECL
void
582 basic_iarchive::delete_created_pointers()
584 pimpl
->delete_created_pointers();
587 BOOST_ARCHIVE_DECL
boost::archive::library_version_type
588 basic_iarchive::get_library_version() const{
589 return pimpl
->m_archive_library_version
;
592 BOOST_ARCHIVE_DECL
unsigned int
593 basic_iarchive::get_flags() const{
594 return pimpl
->m_flags
;
597 } // namespace detail
598 } // namespace archive