]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/serialization/src/basic_oarchive.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / serialization / src / basic_oarchive.cpp
CommitLineData
7c673cae
FG
1/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2// basic_oarchive.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 for warning suppression
12
13#include <boost/assert.hpp>
14#include <set>
15#include <cstddef> // NULL
16
17#include <boost/limits.hpp>
18
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>
29
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>
36
37#ifdef BOOST_MSVC
38# pragma warning(push)
39# pragma warning(disable : 4251 4231 4660 4275)
40#endif
41
42using namespace boost::serialization;
43
44namespace boost {
45namespace archive {
46namespace detail {
47
48class basic_oarchive_impl {
49 friend class basic_oarchive;
50 unsigned int m_flags;
51
52 //////////////////////////////////////////////////////////////////////
53 // information about each serialized object saved
54 // keyed on address, class_id
55 struct aobject
56 {
57 const void * address;
58 class_id_type class_id;
59 object_id_type object_id;
60
61 bool operator<(const aobject &rhs) const
62 {
63 BOOST_ASSERT(NULL != address);
64 BOOST_ASSERT(NULL != rhs.address);
65 if( address < rhs.address )
66 return true;
67 if( address > rhs.address )
68 return false;
69 return class_id < rhs.class_id;
70 }
71 aobject & operator=(const aobject & rhs)
72 {
73 address = rhs.address;
74 class_id = rhs.class_id;
75 object_id = rhs.object_id;
76 return *this;
77 }
78 aobject(
79 const void *a,
80 class_id_type class_id_,
81 object_id_type object_id_
82 ) :
83 address(a),
84 class_id(class_id_),
85 object_id(object_id_)
86 {}
87 aobject() : address(NULL){}
88 };
89 // keyed on class_id, address
90 typedef std::set<aobject> object_set_type;
91 object_set_type object_set;
92
93 //////////////////////////////////////////////////////////////////////
94 // information about each serialized class saved
95 // keyed on type_info
96 struct cobject_type
97 {
98 const basic_oserializer * m_bos_ptr;
99 const class_id_type m_class_id;
100 bool m_initialized;
101 cobject_type(
102 std::size_t class_id,
103 const basic_oserializer & bos
104 ) :
105 m_bos_ptr(& bos),
106 m_class_id(class_id),
107 m_initialized(false)
108 {}
b32b8144
FG
109 cobject_type(const basic_oserializer & bos) :
110 m_bos_ptr(& bos),
111 m_initialized(false)
7c673cae
FG
112 {}
113 cobject_type(
114 const cobject_type & rhs
115 ) :
116 m_bos_ptr(rhs.m_bos_ptr),
117 m_class_id(rhs.m_class_id),
118 m_initialized(rhs.m_initialized)
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 // 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);
127 }
128 };
129 // keyed on type_info
130 typedef std::set<cobject_type> cobject_info_set_type;
131 cobject_info_set_type cobject_info_set;
132
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;
136
20effc67 137 // address of the most recent object serialized as a pointer
7c673cae
FG
138 // whose data itself is now pending serialization
139 const void * pending_object;
140 const basic_oserializer * pending_bos;
141
142 basic_oarchive_impl(unsigned int flags) :
143 m_flags(flags),
144 pending_object(NULL),
145 pending_bos(NULL)
146 {}
147
148 const cobject_type &
149 find(const basic_oserializer & bos);
150 const basic_oserializer *
151 find(const serialization::extended_type_info &ti) const;
152
153//public:
154 const cobject_type &
155 register_type(const basic_oserializer & bos);
156 void save_object(
157 basic_oarchive & ar,
158 const void *t,
159 const basic_oserializer & bos
160 );
161 void save_pointer(
162 basic_oarchive & ar,
163 const void * t,
164 const basic_pointer_oserializer * bpos
165 );
166};
167
168//////////////////////////////////////////////////////////////////////
169// basic_oarchive implementation functions
170
171// given a type_info - find its bos
172// return NULL if not found
173inline const basic_oserializer *
174basic_oarchive_impl::find(const serialization::extended_type_info & ti) const {
175 #ifdef BOOST_MSVC
176 # pragma warning(push)
177 # pragma warning(disable : 4511 4512)
178 #endif
179 class bosarg :
180 public basic_oserializer
181 {
20effc67 182 bool class_info() const BOOST_OVERRIDE {
7c673cae
FG
183 BOOST_ASSERT(false);
184 return false;
185 }
186 // returns true if objects should be tracked
20effc67 187 bool tracking(const unsigned int) const BOOST_OVERRIDE {
7c673cae
FG
188 BOOST_ASSERT(false);
189 return false;
190 }
191 // returns class version
20effc67 192 version_type version() const BOOST_OVERRIDE {
7c673cae
FG
193 BOOST_ASSERT(false);
194 return version_type(0);
195 }
196 // returns true if this class is polymorphic
20effc67 197 bool is_polymorphic() const BOOST_OVERRIDE {
7c673cae
FG
198 BOOST_ASSERT(false);
199 return false;
200 }
201 void save_object_data(
202 basic_oarchive & /*ar*/, const void * /*x*/
20effc67 203 ) const BOOST_OVERRIDE {
7c673cae
FG
204 BOOST_ASSERT(false);
205 }
206 public:
207 bosarg(const serialization::extended_type_info & eti) :
208 boost::archive::detail::basic_oserializer(eti)
209 {}
210 };
211 #ifdef BOOST_MSVC
212 #pragma warning(pop)
213 #endif
214 bosarg bos(ti);
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"
222 return NULL;
223 }
224 // return pointer to the real class
225 return cit->m_bos_ptr;
226}
227
228inline const basic_oarchive_impl::cobject_type &
229basic_oarchive_impl::find(const basic_oserializer & bos)
230{
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);
234}
235
236inline const basic_oarchive_impl::cobject_type &
237basic_oarchive_impl::register_type(
238 const basic_oserializer & bos
239){
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);
244}
245
246inline void
247basic_oarchive_impl::save_object(
248 basic_oarchive & ar,
249 const void *t,
250 const basic_oserializer & bos
251){
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
255 ar.end_preamble();
256 (bos.save_object_data)(ar, t);
257 return;
258 }
259
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;
268 }
269 }
270
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
274 ar.end_preamble();
275 // and save the data
276 (bos.save_object_data)(ar, t);
277 return;
278 }
279
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;
287
288 // if its a new object
289 if(aresult.second){
290 // write out the object id
291 ar.vsave(oid);
292 ar.end_preamble();
293 // and data
294 (bos.save_object_data)(ar, t);
295 return;
296 }
297
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)
304 );
305 }
306 // just save the object id
307 ar.vsave(object_reference_type(oid));
308 ar.end_preamble();
7c673cae
FG
309}
310
f67539c2 311// colle
7c673cae
FG
312inline void
313basic_oarchive_impl::save_pointer(
314 basic_oarchive & ar,
315 const void * t,
316 const basic_pointer_oserializer * bpos_ptr
317){
318 const basic_oserializer & bos = bpos_ptr->get_basic_serializer();
319 std::size_t original_count = cobject_info_set.size();
320 const cobject_type & co = register_type(bos);
321 if(! co.m_initialized){
322 ar.vsave(co.m_class_id);
323 // if its a previously unregistered class
324 if((cobject_info_set.size() > original_count)){
325 if(bos.is_polymorphic()){
326 const serialization::extended_type_info *eti = & bos.get_eti();
327 const char * key = NULL;
328 if(NULL != eti)
329 key = eti->get_key();
330 if(NULL != key){
331 // the following is required by IBM C++ compiler which
332 // makes a copy when passing a non-const to a const. This
333 // is permitted by the standard but rarely seen in practice
334 const class_name_type cn(key);
335 if(cn.size() > (BOOST_SERIALIZATION_MAX_KEY_SIZE - 1))
336 boost::serialization::throw_exception(
337 boost::archive::archive_exception(
338 boost::archive::archive_exception::
339 invalid_class_name)
340 );
341 // write out the external class identifier
342 ar.vsave(cn);
343 }
344 else
345 // without an external class name
346 // we won't be able to de-serialize it so bail now
347 boost::serialization::throw_exception(
348 archive_exception(archive_exception::unregistered_class)
349 );
350 }
351 }
352 if(bos.class_info()){
353 ar.vsave(tracking_type(bos.tracking(m_flags)));
354 ar.vsave(version_type(bos.version()));
355 }
356 (const_cast<cobject_type &>(co)).m_initialized = true;
357 }
358 else{
359 ar.vsave(class_id_reference_type(co.m_class_id));
360 }
361
362 // if we're not tracking
363 if(! bos.tracking(m_flags)){
364 // just save the data itself
365 ar.end_preamble();
366 serialization::state_saver<const void *> x(pending_object);
367 serialization::state_saver<const basic_oserializer *> y(pending_bos);
368 pending_object = t;
369 pending_bos = & bpos_ptr->get_basic_serializer();
370 bpos_ptr->save_object_ptr(ar, t);
371 return;
372 }
373
374 object_id_type oid(object_set.size());
375 // lookup to see if this object has already been written to the archive
376 basic_oarchive_impl::aobject ao(t, co.m_class_id, oid);
377 std::pair<basic_oarchive_impl::object_set_type::const_iterator, bool>
378 aresult = object_set.insert(ao);
379 oid = aresult.first->object_id;
380 // if the saved object already exists
381 if(! aresult.second){
382 // append the object id to he preamble
383 ar.vsave(object_reference_type(oid));
384 // and windup.
385 ar.end_preamble();
386 return;
387 }
388
389 // append id of this object to preamble
390 ar.vsave(oid);
391 ar.end_preamble();
392
393 // and save the object itself
394 serialization::state_saver<const void *> x(pending_object);
395 serialization::state_saver<const basic_oserializer *> y(pending_bos);
396 pending_object = t;
397 pending_bos = & bpos_ptr->get_basic_serializer();
398 bpos_ptr->save_object_ptr(ar, t);
399 // add to the set of object initially stored through pointers
400 stored_pointers.insert(oid);
401}
402
403} // namespace detail
404} // namespace archive
405} // namespace boost
406
407//////////////////////////////////////////////////////////////////////
408// implementation of basic_oarchive functions
409
410namespace boost {
411namespace archive {
412namespace detail {
413
414BOOST_ARCHIVE_DECL
415basic_oarchive::basic_oarchive(unsigned int flags)
416 : pimpl(new basic_oarchive_impl(flags))
417{}
418
419BOOST_ARCHIVE_DECL
420basic_oarchive::~basic_oarchive()
421{}
422
423BOOST_ARCHIVE_DECL void
424basic_oarchive::save_object(
425 const void *x,
426 const basic_oserializer & bos
427){
428 pimpl->save_object(*this, x, bos);
429}
430
431BOOST_ARCHIVE_DECL void
432basic_oarchive::save_pointer(
433 const void * t,
434 const basic_pointer_oserializer * bpos_ptr
435){
436 pimpl->save_pointer(*this, t, bpos_ptr);
437}
438
439BOOST_ARCHIVE_DECL void
440basic_oarchive::register_basic_serializer(const basic_oserializer & bos){
441 pimpl->register_type(bos);
442}
443
444BOOST_ARCHIVE_DECL library_version_type
445basic_oarchive::get_library_version() const{
446 return BOOST_ARCHIVE_VERSION();
447}
448
449BOOST_ARCHIVE_DECL unsigned int
450basic_oarchive::get_flags() const{
451 return pimpl->m_flags;
452}
453
454BOOST_ARCHIVE_DECL void
455basic_oarchive::end_preamble(){
456}
457
458BOOST_ARCHIVE_DECL helper_collection &
459basic_oarchive::get_helper_collection(){
460 return *this;
461}
462
463} // namespace detail
464} // namespace archive
465} // namespace boost
466
467#ifdef BOOST_MSVC
468#pragma warning(pop)
469#endif