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 for warning suppression
13 #include <boost/assert.hpp>
15 #include <cstddef> // NULL
17 #include <boost/limits.hpp>
19 // including this here to work around an ICC in intel 7.0
20 // normally this would be part of basic_oarchive.hpp below.
21 #define BOOST_ARCHIVE_SOURCE
22 // include this to prevent linker errors when the
23 // same modules are marked export and import.
24 #define BOOST_SERIALIZATION_SOURCE
25 #include <boost/serialization/config.hpp>
26 #include <boost/serialization/state_saver.hpp>
27 #include <boost/serialization/throw_exception.hpp>
28 #include <boost/serialization/extended_type_info.hpp>
30 #include <boost/archive/detail/decl.hpp>
31 #include <boost/archive/basic_archive.hpp>
32 #include <boost/archive/detail/basic_oserializer.hpp>
33 #include <boost/archive/detail/basic_pointer_oserializer.hpp>
34 #include <boost/archive/detail/basic_oarchive.hpp>
35 #include <boost/archive/archive_exception.hpp>
38 # pragma warning(push)
39 # pragma warning(disable : 4251 4231 4660 4275)
42 using namespace boost::serialization
;
48 class basic_oarchive_impl
{
49 friend class basic_oarchive
;
52 //////////////////////////////////////////////////////////////////////
53 // information about each serialized object saved
54 // keyed on address, class_id
58 class_id_type class_id
;
59 object_id_type object_id
;
61 bool operator<(const aobject
&rhs
) const
63 BOOST_ASSERT(NULL
!= address
);
64 BOOST_ASSERT(NULL
!= rhs
.address
);
65 if( address
< rhs
.address
)
67 if( address
> rhs
.address
)
69 return class_id
< rhs
.class_id
;
71 aobject
& operator=(const aobject
& rhs
)
73 address
= rhs
.address
;
74 class_id
= rhs
.class_id
;
75 object_id
= rhs
.object_id
;
80 class_id_type class_id_
,
81 object_id_type object_id_
87 aobject() : address(NULL
){}
89 // keyed on class_id, address
90 typedef std::set
<aobject
> object_set_type
;
91 object_set_type object_set
;
93 //////////////////////////////////////////////////////////////////////
94 // information about each serialized class saved
98 const basic_oserializer
* m_bos_ptr
;
99 const class_id_type m_class_id
;
102 std::size_t class_id
,
103 const basic_oserializer
& bos
106 m_class_id(class_id
),
109 cobject_type(const basic_oserializer
& bos
) :
114 const cobject_type
& rhs
116 m_bos_ptr(rhs
.m_bos_ptr
),
117 m_class_id(rhs
.m_class_id
),
118 m_initialized(rhs
.m_initialized
)
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 // use this only for lookup argument
124 cobject_type
& operator=(const cobject_type
&rhs
);
125 bool operator<(const cobject_type
&rhs
) const {
126 return *m_bos_ptr
< *(rhs
.m_bos_ptr
);
129 // keyed on type_info
130 typedef std::set
<cobject_type
> cobject_info_set_type
;
131 cobject_info_set_type cobject_info_set
;
133 // list of objects initially stored as pointers - used to detect errors
134 // keyed on object id
135 std::set
<object_id_type
> stored_pointers
;
137 // address of the most recent object serialized as a poiner
138 // whose data itself is now pending serialization
139 const void * pending_object
;
140 const basic_oserializer
* pending_bos
;
142 basic_oarchive_impl(unsigned int flags
) :
144 pending_object(NULL
),
149 find(const basic_oserializer
& bos
);
150 const basic_oserializer
*
151 find(const serialization::extended_type_info
&ti
) const;
155 register_type(const basic_oserializer
& bos
);
159 const basic_oserializer
& bos
164 const basic_pointer_oserializer
* bpos
168 //////////////////////////////////////////////////////////////////////
169 // basic_oarchive implementation functions
171 // given a type_info - find its bos
172 // return NULL if not found
173 inline const basic_oserializer
*
174 basic_oarchive_impl::find(const serialization::extended_type_info
& ti
) const {
176 # pragma warning(push)
177 # pragma warning(disable : 4511 4512)
180 public basic_oserializer
182 bool class_info() const {
186 // returns true if objects should be tracked
187 bool tracking(const unsigned int) const {
191 // returns class version
192 version_type
version() const {
194 return version_type(0);
196 // returns true if this class is polymorphic
197 bool is_polymorphic() const{
201 void save_object_data(
202 basic_oarchive
& /*ar*/, const void * /*x*/
207 bosarg(const serialization::extended_type_info
& eti
) :
208 boost::archive::detail::basic_oserializer(eti
)
215 cobject_info_set_type::const_iterator cit
216 = cobject_info_set
.find(cobject_type(bos
));
217 // it should already have been "registered" - see below
218 if(cit
== cobject_info_set
.end()){
219 // if an entry is not found in the table it is because a pointer
220 // of a derived class has been serialized through its base class
221 // but the derived class hasn't been "registered"
224 // return pointer to the real class
225 return cit
->m_bos_ptr
;
228 inline const basic_oarchive_impl::cobject_type
&
229 basic_oarchive_impl::find(const basic_oserializer
& bos
)
231 std::pair
<cobject_info_set_type::iterator
, bool> cresult
=
232 cobject_info_set
.insert(cobject_type(cobject_info_set
.size(), bos
));
233 return *(cresult
.first
);
236 inline const basic_oarchive_impl::cobject_type
&
237 basic_oarchive_impl::register_type(
238 const basic_oserializer
& bos
240 cobject_type
co(cobject_info_set
.size(), bos
);
241 std::pair
<cobject_info_set_type::const_iterator
, bool>
242 result
= cobject_info_set
.insert(co
);
243 return *(result
.first
);
247 basic_oarchive_impl::save_object(
250 const basic_oserializer
& bos
252 // if its been serialized through a pointer and the preamble's been done
253 if(t
== pending_object
&& pending_bos
== & bos
){
254 // just save the object data
256 (bos
.save_object_data
)(ar
, t
);
260 // get class information for this object
261 const cobject_type
& co
= register_type(bos
);
262 if(bos
.class_info()){
263 if( ! co
.m_initialized
){
264 ar
.vsave(class_id_optional_type(co
.m_class_id
));
265 ar
.vsave(tracking_type(bos
.tracking(m_flags
)));
266 ar
.vsave(version_type(bos
.version()));
267 (const_cast<cobject_type
&>(co
)).m_initialized
= true;
271 // we're not tracking this type of object
272 if(! bos
.tracking(m_flags
)){
273 // just windup the preamble - no object id to write
276 (bos
.save_object_data
)(ar
, t
);
280 // look for an existing object id
281 object_id_type
oid(object_set
.size());
282 // lookup to see if this object has already been written to the archive
283 basic_oarchive_impl::aobject
ao(t
, co
.m_class_id
, oid
);
284 std::pair
<basic_oarchive_impl::object_set_type::const_iterator
, bool>
285 aresult
= object_set
.insert(ao
);
286 oid
= aresult
.first
->object_id
;
288 // if its a new object
290 // write out the object id
294 (bos
.save_object_data
)(ar
, t
);
298 // check that it wasn't originally stored through a pointer
299 if(stored_pointers
.end() != stored_pointers
.find(oid
)){
300 // this has to be a user error. loading such an archive
301 // would create duplicate objects
302 boost::serialization::throw_exception(
303 archive_exception(archive_exception::pointer_conflict
)
306 // just save the object id
307 ar
.vsave(object_reference_type(oid
));
312 // save a pointer to an object instance
314 basic_oarchive_impl::save_pointer(
317 const basic_pointer_oserializer
* bpos_ptr
319 const basic_oserializer
& bos
= bpos_ptr
->get_basic_serializer();
320 std::size_t original_count
= cobject_info_set
.size();
321 const cobject_type
& co
= register_type(bos
);
322 if(! co
.m_initialized
){
323 ar
.vsave(co
.m_class_id
);
324 // if its a previously unregistered class
325 if((cobject_info_set
.size() > original_count
)){
326 if(bos
.is_polymorphic()){
327 const serialization::extended_type_info
*eti
= & bos
.get_eti();
328 const char * key
= NULL
;
330 key
= eti
->get_key();
332 // the following is required by IBM C++ compiler which
333 // makes a copy when passing a non-const to a const. This
334 // is permitted by the standard but rarely seen in practice
335 const class_name_type
cn(key
);
336 if(cn
.size() > (BOOST_SERIALIZATION_MAX_KEY_SIZE
- 1))
337 boost::serialization::throw_exception(
338 boost::archive::archive_exception(
339 boost::archive::archive_exception::
342 // write out the external class identifier
346 // without an external class name
347 // we won't be able to de-serialize it so bail now
348 boost::serialization::throw_exception(
349 archive_exception(archive_exception::unregistered_class
)
353 if(bos
.class_info()){
354 ar
.vsave(tracking_type(bos
.tracking(m_flags
)));
355 ar
.vsave(version_type(bos
.version()));
357 (const_cast<cobject_type
&>(co
)).m_initialized
= true;
360 ar
.vsave(class_id_reference_type(co
.m_class_id
));
363 // if we're not tracking
364 if(! bos
.tracking(m_flags
)){
365 // just save the data itself
367 serialization::state_saver
<const void *> x(pending_object
);
368 serialization::state_saver
<const basic_oserializer
*> y(pending_bos
);
370 pending_bos
= & bpos_ptr
->get_basic_serializer();
371 bpos_ptr
->save_object_ptr(ar
, t
);
375 object_id_type
oid(object_set
.size());
376 // lookup to see if this object has already been written to the archive
377 basic_oarchive_impl::aobject
ao(t
, co
.m_class_id
, oid
);
378 std::pair
<basic_oarchive_impl::object_set_type::const_iterator
, bool>
379 aresult
= object_set
.insert(ao
);
380 oid
= aresult
.first
->object_id
;
381 // if the saved object already exists
382 if(! aresult
.second
){
383 // append the object id to he preamble
384 ar
.vsave(object_reference_type(oid
));
390 // append id of this object to preamble
394 // and save the object itself
395 serialization::state_saver
<const void *> x(pending_object
);
396 serialization::state_saver
<const basic_oserializer
*> y(pending_bos
);
398 pending_bos
= & bpos_ptr
->get_basic_serializer();
399 bpos_ptr
->save_object_ptr(ar
, t
);
400 // add to the set of object initially stored through pointers
401 stored_pointers
.insert(oid
);
404 } // namespace detail
405 } // namespace archive
408 //////////////////////////////////////////////////////////////////////
409 // implementation of basic_oarchive functions
416 basic_oarchive::basic_oarchive(unsigned int flags
)
417 : pimpl(new basic_oarchive_impl(flags
))
421 basic_oarchive::~basic_oarchive()
424 BOOST_ARCHIVE_DECL
void
425 basic_oarchive::save_object(
427 const basic_oserializer
& bos
429 pimpl
->save_object(*this, x
, bos
);
432 BOOST_ARCHIVE_DECL
void
433 basic_oarchive::save_pointer(
435 const basic_pointer_oserializer
* bpos_ptr
437 pimpl
->save_pointer(*this, t
, bpos_ptr
);
440 BOOST_ARCHIVE_DECL
void
441 basic_oarchive::register_basic_serializer(const basic_oserializer
& bos
){
442 pimpl
->register_type(bos
);
445 BOOST_ARCHIVE_DECL library_version_type
446 basic_oarchive::get_library_version() const{
447 return BOOST_ARCHIVE_VERSION();
450 BOOST_ARCHIVE_DECL
unsigned int
451 basic_oarchive::get_flags() const{
452 return pimpl
->m_flags
;
455 BOOST_ARCHIVE_DECL
void
456 basic_oarchive::end_preamble(){
459 BOOST_ARCHIVE_DECL helper_collection
&
460 basic_oarchive::get_helper_collection(){
464 } // namespace detail
465 } // namespace archive