]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/serialization/src/basic_oarchive.cpp
update sources to v12.2.3
[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
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;
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 {
182 bool class_info() const {
183 BOOST_ASSERT(false);
184 return false;
185 }
186 // returns true if objects should be tracked
187 bool tracking(const unsigned int) const {
188 BOOST_ASSERT(false);
189 return false;
190 }
191 // returns class version
192 version_type version() const {
193 BOOST_ASSERT(false);
194 return version_type(0);
195 }
196 // returns true if this class is polymorphic
197 bool is_polymorphic() const{
198 BOOST_ASSERT(false);
199 return false;
200 }
201 void save_object_data(
202 basic_oarchive & /*ar*/, const void * /*x*/
203 ) const {
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();
309 return;
310}
311
312// save a pointer to an object instance
313inline void
314basic_oarchive_impl::save_pointer(
315 basic_oarchive & ar,
316 const void * t,
317 const basic_pointer_oserializer * bpos_ptr
318){
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;
329 if(NULL != eti)
330 key = eti->get_key();
331 if(NULL != 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::
340 invalid_class_name)
341 );
342 // write out the external class identifier
343 ar.vsave(cn);
344 }
345 else
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)
350 );
351 }
352 }
353 if(bos.class_info()){
354 ar.vsave(tracking_type(bos.tracking(m_flags)));
355 ar.vsave(version_type(bos.version()));
356 }
357 (const_cast<cobject_type &>(co)).m_initialized = true;
358 }
359 else{
360 ar.vsave(class_id_reference_type(co.m_class_id));
361 }
362
363 // if we're not tracking
364 if(! bos.tracking(m_flags)){
365 // just save the data itself
366 ar.end_preamble();
367 serialization::state_saver<const void *> x(pending_object);
368 serialization::state_saver<const basic_oserializer *> y(pending_bos);
369 pending_object = t;
370 pending_bos = & bpos_ptr->get_basic_serializer();
371 bpos_ptr->save_object_ptr(ar, t);
372 return;
373 }
374
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));
385 // and windup.
386 ar.end_preamble();
387 return;
388 }
389
390 // append id of this object to preamble
391 ar.vsave(oid);
392 ar.end_preamble();
393
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);
397 pending_object = t;
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);
402}
403
404} // namespace detail
405} // namespace archive
406} // namespace boost
407
408//////////////////////////////////////////////////////////////////////
409// implementation of basic_oarchive functions
410
411namespace boost {
412namespace archive {
413namespace detail {
414
415BOOST_ARCHIVE_DECL
416basic_oarchive::basic_oarchive(unsigned int flags)
417 : pimpl(new basic_oarchive_impl(flags))
418{}
419
420BOOST_ARCHIVE_DECL
421basic_oarchive::~basic_oarchive()
422{}
423
424BOOST_ARCHIVE_DECL void
425basic_oarchive::save_object(
426 const void *x,
427 const basic_oserializer & bos
428){
429 pimpl->save_object(*this, x, bos);
430}
431
432BOOST_ARCHIVE_DECL void
433basic_oarchive::save_pointer(
434 const void * t,
435 const basic_pointer_oserializer * bpos_ptr
436){
437 pimpl->save_pointer(*this, t, bpos_ptr);
438}
439
440BOOST_ARCHIVE_DECL void
441basic_oarchive::register_basic_serializer(const basic_oserializer & bos){
442 pimpl->register_type(bos);
443}
444
445BOOST_ARCHIVE_DECL library_version_type
446basic_oarchive::get_library_version() const{
447 return BOOST_ARCHIVE_VERSION();
448}
449
450BOOST_ARCHIVE_DECL unsigned int
451basic_oarchive::get_flags() const{
452 return pimpl->m_flags;
453}
454
455BOOST_ARCHIVE_DECL void
456basic_oarchive::end_preamble(){
457}
458
459BOOST_ARCHIVE_DECL helper_collection &
460basic_oarchive::get_helper_collection(){
461 return *this;
462}
463
464} // namespace detail
465} // namespace archive
466} // namespace boost
467
468#ifdef BOOST_MSVC
469#pragma warning(pop)
470#endif