]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/archive/detail/iserializer.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / archive / detail / iserializer.hpp
1 #ifndef BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP
2 #define BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP
3
4 // MS compatible compilers support #pragma once
5 #if defined(_MSC_VER)
6 # pragma once
7 #pragma inline_depth(511)
8 #pragma inline_recursion(on)
9 #endif
10
11 #if defined(__MWERKS__)
12 #pragma inline_depth(511)
13 #endif
14
15 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
16 // iserializer.hpp: interface for serialization system.
17
18 // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
19 // Use, modification and distribution is subject to the Boost Software
20 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
21 // http://www.boost.org/LICENSE_1_0.txt)
22
23 // See http://www.boost.org for updates, documentation, and revision history.
24
25 #include <new> // for placement new
26 #include <cstddef> // size_t, NULL
27
28 #include <boost/config.hpp>
29 #include <boost/detail/workaround.hpp>
30 #if defined(BOOST_NO_STDC_NAMESPACE)
31 namespace std{
32 using ::size_t;
33 } // namespace std
34 #endif
35
36 #include <boost/static_assert.hpp>
37
38 #include <boost/mpl/eval_if.hpp>
39 #include <boost/mpl/identity.hpp>
40 #include <boost/mpl/greater_equal.hpp>
41 #include <boost/mpl/equal_to.hpp>
42 #include <boost/core/no_exceptions_support.hpp>
43
44 #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO
45 #include <boost/serialization/extended_type_info_typeid.hpp>
46 #endif
47 #include <boost/serialization/throw_exception.hpp>
48 #include <boost/serialization/smart_cast.hpp>
49 #include <boost/serialization/static_warning.hpp>
50
51 #include <boost/type_traits/is_pointer.hpp>
52 #include <boost/type_traits/is_enum.hpp>
53 #include <boost/type_traits/is_const.hpp>
54 #include <boost/type_traits/remove_const.hpp>
55 #include <boost/type_traits/remove_extent.hpp>
56 #include <boost/type_traits/is_polymorphic.hpp>
57
58 #include <boost/serialization/assume_abstract.hpp>
59
60 #if !defined(BOOST_MSVC) && \
61 (BOOST_WORKAROUND(__IBMCPP__, < 1210) || \
62 defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x590))
63 #define DONT_USE_HAS_NEW_OPERATOR 1
64 #else
65 #define DONT_USE_HAS_NEW_OPERATOR 0
66 #endif
67
68 #if ! DONT_USE_HAS_NEW_OPERATOR
69 #include <boost/type_traits/has_new_operator.hpp>
70 #endif
71
72 #include <boost/serialization/serialization.hpp>
73 #include <boost/serialization/version.hpp>
74 #include <boost/serialization/level.hpp>
75 #include <boost/serialization/tracking.hpp>
76 #include <boost/serialization/type_info_implementation.hpp>
77 #include <boost/serialization/nvp.hpp>
78 #include <boost/serialization/void_cast.hpp>
79 #include <boost/serialization/collection_size_type.hpp>
80 #include <boost/serialization/singleton.hpp>
81 #include <boost/serialization/wrapper.hpp>
82 #include <boost/serialization/array_wrapper.hpp>
83
84 // the following is need only for dynamic cast of polymorphic pointers
85 #include <boost/archive/archive_exception.hpp>
86 #include <boost/archive/detail/basic_iarchive.hpp>
87 #include <boost/archive/detail/basic_iserializer.hpp>
88 #include <boost/archive/detail/basic_pointer_iserializer.hpp>
89 #include <boost/archive/detail/archive_serializer_map.hpp>
90 #include <boost/archive/detail/check.hpp>
91
92 #include <boost/core/addressof.hpp>
93
94 namespace boost {
95
96 namespace serialization {
97 class extended_type_info;
98 } // namespace serialization
99
100 namespace archive {
101
102 // an accessor to permit friend access to archives. Needed because
103 // some compilers don't handle friend templates completely
104 class load_access {
105 public:
106 template<class Archive, class T>
107 static void load_primitive(Archive &ar, T &t){
108 ar.load(t);
109 }
110 };
111
112 namespace detail {
113
114 #ifdef BOOST_MSVC
115 # pragma warning(push)
116 # pragma warning(disable : 4511 4512)
117 #endif
118
119 template<class Archive, class T>
120 class iserializer : public basic_iserializer
121 {
122 private:
123 virtual void destroy(/*const*/ void *address) const {
124 boost::serialization::access::destroy(static_cast<T *>(address));
125 }
126 protected:
127 // protected constructor since it's always created by singleton
128 explicit iserializer() :
129 basic_iserializer(
130 boost::serialization::singleton<
131 typename
132 boost::serialization::type_info_implementation< T >::type
133 >::get_const_instance()
134 )
135 {}
136 public:
137 virtual BOOST_DLLEXPORT void load_object_data(
138 basic_iarchive & ar,
139 void *x,
140 const unsigned int file_version
141 ) const BOOST_USED;
142 virtual bool class_info() const {
143 return boost::serialization::implementation_level< T >::value
144 >= boost::serialization::object_class_info;
145 }
146 virtual bool tracking(const unsigned int /* flags */) const {
147 return boost::serialization::tracking_level< T >::value
148 == boost::serialization::track_always
149 || ( boost::serialization::tracking_level< T >::value
150 == boost::serialization::track_selectively
151 && serialized_as_pointer());
152 }
153 virtual version_type version() const {
154 return version_type(::boost::serialization::version< T >::value);
155 }
156 virtual bool is_polymorphic() const {
157 return boost::is_polymorphic< T >::value;
158 }
159 virtual ~iserializer(){};
160 };
161
162 #ifdef BOOST_MSVC
163 # pragma warning(pop)
164 #endif
165
166 template<class Archive, class T>
167 BOOST_DLLEXPORT void iserializer<Archive, T>::load_object_data(
168 basic_iarchive & ar,
169 void *x,
170 const unsigned int file_version
171 ) const {
172 // note: we now comment this out. Before we permited archive
173 // version # to be very large. Now we don't. To permit
174 // readers of these old archives, we have to suppress this
175 // code. Perhaps in the future we might re-enable it but
176 // permit its suppression with a runtime switch.
177 #if 0
178 // trap case where the program cannot handle the current version
179 if(file_version > static_cast<const unsigned int>(version()))
180 boost::serialization::throw_exception(
181 archive::archive_exception(
182 boost::archive::archive_exception::unsupported_class_version,
183 get_debug_info()
184 )
185 );
186 #endif
187 // make sure call is routed through the higest interface that might
188 // be specialized by the user.
189 boost::serialization::serialize_adl(
190 boost::serialization::smart_cast_reference<Archive &>(ar),
191 * static_cast<T *>(x),
192 file_version
193 );
194 }
195
196 #ifdef BOOST_MSVC
197 # pragma warning(push)
198 # pragma warning(disable : 4511 4512)
199 #endif
200
201 // the purpose of this code is to allocate memory for an object
202 // without requiring the constructor to be called. Presumably
203 // the allocated object will be subsequently initialized with
204 // "placement new".
205 // note: we have the boost type trait has_new_operator but we
206 // have no corresponding has_delete_operator. So we presume
207 // that the former being true would imply that the a delete
208 // operator is also defined for the class T.
209
210 template<class T>
211 struct heap_allocation {
212 // boost::has_new_operator< T > doesn't work on these compilers
213 #if DONT_USE_HAS_NEW_OPERATOR
214 // This doesn't handle operator new overload for class T
215 static T * invoke_new(){
216 return static_cast<T *>(operator new(sizeof(T)));
217 }
218 static void invoke_delete(T *t){
219 (operator delete(t));
220 }
221 #else
222 // note: we presume that a true value for has_new_operator
223 // implies the existence of a class specific delete operator as well
224 // as a class specific new operator.
225 struct has_new_operator {
226 static T * invoke_new() {
227 return static_cast<T *>((T::operator new)(sizeof(T)));
228 }
229 static void invoke_delete(T * t) {
230 // if compilation fails here, the likely cause that the class
231 // T has a class specific new operator but no class specific
232 // delete operator which matches the following signature.
233 // note that this solution addresses the issue that two
234 // possible signatures. But it doesn't address the possibility
235 // that the class might have class specific new with NO
236 // class specific delete at all. Patches (compatible with
237 // C++03) welcome!
238 (operator delete)(t);
239 }
240 };
241 struct doesnt_have_new_operator {
242 static T* invoke_new() {
243 return static_cast<T *>(operator new(sizeof(T)));
244 }
245 static void invoke_delete(T * t) {
246 // Note: I'm reliance upon automatic conversion from T * to void * here
247 (operator delete)(t);
248 }
249 };
250 static T * invoke_new() {
251 typedef typename
252 mpl::eval_if<
253 boost::has_new_operator< T >,
254 mpl::identity<has_new_operator >,
255 mpl::identity<doesnt_have_new_operator >
256 >::type typex;
257 return typex::invoke_new();
258 }
259 static void invoke_delete(T *t) {
260 typedef typename
261 mpl::eval_if<
262 boost::has_new_operator< T >,
263 mpl::identity<has_new_operator >,
264 mpl::identity<doesnt_have_new_operator >
265 >::type typex;
266 typex::invoke_delete(t);
267 }
268 #endif
269 explicit heap_allocation(){
270 m_p = invoke_new();
271 }
272 ~heap_allocation(){
273 if (0 != m_p)
274 invoke_delete(m_p);
275 }
276 T* get() const {
277 return m_p;
278 }
279
280 T* release() {
281 T* p = m_p;
282 m_p = 0;
283 return p;
284 }
285 private:
286 T* m_p;
287 };
288
289 template<class Archive, class T>
290 class pointer_iserializer :
291 public basic_pointer_iserializer
292 {
293 private:
294 virtual void * heap_allocation() const {
295 detail::heap_allocation<T> h;
296 T * t = h.get();
297 h.release();
298 return t;
299 }
300 virtual const basic_iserializer & get_basic_serializer() const {
301 return boost::serialization::singleton<
302 iserializer<Archive, T>
303 >::get_const_instance();
304 }
305 BOOST_DLLEXPORT virtual void load_object_ptr(
306 basic_iarchive & ar,
307 void * x,
308 const unsigned int file_version
309 ) const BOOST_USED;
310 protected:
311 // this should alway be a singleton so make the constructor protected
312 pointer_iserializer();
313 ~pointer_iserializer();
314 };
315
316 #ifdef BOOST_MSVC
317 # pragma warning(pop)
318 #endif
319
320 // note: BOOST_DLLEXPORT is so that code for polymorphic class
321 // serialized only through base class won't get optimized out
322 template<class Archive, class T>
323 BOOST_DLLEXPORT void pointer_iserializer<Archive, T>::load_object_ptr(
324 basic_iarchive & ar,
325 void * t,
326 const unsigned int file_version
327 ) const
328 {
329 Archive & ar_impl =
330 boost::serialization::smart_cast_reference<Archive &>(ar);
331
332 // note that the above will throw std::bad_alloc if the allocation
333 // fails so we don't have to address this contingency here.
334
335 // catch exception during load_construct_data so that we don't
336 // automatically delete the t which is most likely not fully
337 // constructed
338 BOOST_TRY {
339 // this addresses an obscure situation that occurs when
340 // load_constructor de-serializes something through a pointer.
341 ar.next_object_pointer(t);
342 boost::serialization::load_construct_data_adl<Archive, T>(
343 ar_impl,
344 static_cast<T *>(t),
345 file_version
346 );
347 }
348 BOOST_CATCH(...){
349 // if we get here the load_construct failed. The heap_allocation
350 // will be automatically deleted so we don't have to do anything
351 // special here.
352 BOOST_RETHROW;
353 }
354 BOOST_CATCH_END
355
356 ar_impl >> boost::serialization::make_nvp(NULL, * static_cast<T *>(t));
357 }
358
359 template<class Archive, class T>
360 pointer_iserializer<Archive, T>::pointer_iserializer() :
361 basic_pointer_iserializer(
362 boost::serialization::singleton<
363 typename
364 boost::serialization::type_info_implementation< T >::type
365 >::get_const_instance()
366 )
367 {
368 boost::serialization::singleton<
369 iserializer<Archive, T>
370 >::get_mutable_instance().set_bpis(this);
371 archive_serializer_map<Archive>::insert(this);
372 }
373
374 template<class Archive, class T>
375 pointer_iserializer<Archive, T>::~pointer_iserializer(){
376 archive_serializer_map<Archive>::erase(this);
377 }
378
379 template<class Archive>
380 struct load_non_pointer_type {
381 // note this bounces the call right back to the archive
382 // with no runtime overhead
383 struct load_primitive {
384 template<class T>
385 static void invoke(Archive & ar, T & t){
386 load_access::load_primitive(ar, t);
387 }
388 };
389 // note this bounces the call right back to the archive
390 // with no runtime overhead
391 struct load_only {
392 template<class T>
393 static void invoke(Archive & ar, const T & t){
394 // short cut to user's serializer
395 // make sure call is routed through the higest interface that might
396 // be specialized by the user.
397 boost::serialization::serialize_adl(
398 ar,
399 const_cast<T &>(t),
400 boost::serialization::version< T >::value
401 );
402 }
403 };
404
405 // note this save class information including version
406 // and serialization level to the archive
407 struct load_standard {
408 template<class T>
409 static void invoke(Archive &ar, const T & t){
410 void * x = boost::addressof(const_cast<T &>(t));
411 ar.load_object(
412 x,
413 boost::serialization::singleton<
414 iserializer<Archive, T>
415 >::get_const_instance()
416 );
417 }
418 };
419
420 struct load_conditional {
421 template<class T>
422 static void invoke(Archive &ar, T &t){
423 //if(0 == (ar.get_flags() & no_tracking))
424 load_standard::invoke(ar, t);
425 //else
426 // load_only::invoke(ar, t);
427 }
428 };
429
430 template<class T>
431 static void invoke(Archive & ar, T &t){
432 typedef typename mpl::eval_if<
433 // if its primitive
434 mpl::equal_to<
435 boost::serialization::implementation_level< T >,
436 mpl::int_<boost::serialization::primitive_type>
437 >,
438 mpl::identity<load_primitive>,
439 // else
440 typename mpl::eval_if<
441 // class info / version
442 mpl::greater_equal<
443 boost::serialization::implementation_level< T >,
444 mpl::int_<boost::serialization::object_class_info>
445 >,
446 // do standard load
447 mpl::identity<load_standard>,
448 // else
449 typename mpl::eval_if<
450 // no tracking
451 mpl::equal_to<
452 boost::serialization::tracking_level< T >,
453 mpl::int_<boost::serialization::track_never>
454 >,
455 // do a fast load
456 mpl::identity<load_only>,
457 // else
458 // do a fast load only tracking is turned off
459 mpl::identity<load_conditional>
460 > > >::type typex;
461 check_object_versioning< T >();
462 check_object_level< T >();
463 typex::invoke(ar, t);
464 }
465 };
466
467 template<class Archive>
468 struct load_pointer_type {
469 struct abstract
470 {
471 template<class T>
472 static const basic_pointer_iserializer * register_type(Archive & /* ar */){
473 // it has? to be polymorphic
474 BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value);
475 return static_cast<basic_pointer_iserializer *>(NULL);
476 }
477 };
478
479 struct non_abstract
480 {
481 template<class T>
482 static const basic_pointer_iserializer * register_type(Archive & ar){
483 return ar.register_type(static_cast<T *>(NULL));
484 }
485 };
486
487 template<class T>
488 static const basic_pointer_iserializer * register_type(Archive &ar, const T* const /*t*/){
489 // there should never be any need to load an abstract polymorphic
490 // class pointer. Inhibiting code generation for this
491 // permits abstract base classes to be used - note: exception
492 // virtual serialize functions used for plug-ins
493 typedef typename
494 mpl::eval_if<
495 boost::serialization::is_abstract<const T>,
496 boost::mpl::identity<abstract>,
497 boost::mpl::identity<non_abstract>
498 >::type typex;
499 return typex::template register_type< T >(ar);
500 }
501
502 template<class T>
503 static T * pointer_tweak(
504 const boost::serialization::extended_type_info & eti,
505 void const * const t,
506 const T &
507 ) {
508 // tweak the pointer back to the base class
509 void * upcast = const_cast<void *>(
510 boost::serialization::void_upcast(
511 eti,
512 boost::serialization::singleton<
513 typename
514 boost::serialization::type_info_implementation< T >::type
515 >::get_const_instance(),
516 t
517 )
518 );
519 if(NULL == upcast)
520 boost::serialization::throw_exception(
521 archive_exception(archive_exception::unregistered_class)
522 );
523 return static_cast<T *>(upcast);
524 }
525
526 template<class T>
527 static void check_load(T * const /* t */){
528 check_pointer_level< T >();
529 check_pointer_tracking< T >();
530 }
531
532 static const basic_pointer_iserializer *
533 find(const boost::serialization::extended_type_info & type){
534 return static_cast<const basic_pointer_iserializer *>(
535 archive_serializer_map<Archive>::find(type)
536 );
537 }
538
539 template<class Tptr>
540 static void invoke(Archive & ar, Tptr & t){
541 check_load(t);
542 const basic_pointer_iserializer * bpis_ptr = register_type(ar, t);
543 const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer(
544 // note major hack here !!!
545 // I tried every way to convert Tptr &t (where Tptr might
546 // include const) to void * &. This is the only way
547 // I could make it work. RR
548 (void * & )t,
549 bpis_ptr,
550 find
551 );
552 // if the pointer isn't that of the base class
553 if(newbpis_ptr != bpis_ptr){
554 t = pointer_tweak(newbpis_ptr->get_eti(), t, *t);
555 }
556 }
557 };
558
559 template<class Archive>
560 struct load_enum_type {
561 template<class T>
562 static void invoke(Archive &ar, T &t){
563 // convert integers to correct enum to load
564 int i;
565 ar >> boost::serialization::make_nvp(NULL, i);
566 t = static_cast< T >(i);
567 }
568 };
569
570 template<class Archive>
571 struct load_array_type {
572 template<class T>
573 static void invoke(Archive &ar, T &t){
574 typedef typename remove_extent< T >::type value_type;
575
576 // convert integers to correct enum to load
577 // determine number of elements in the array. Consider the
578 // fact that some machines will align elements on boundries
579 // other than characters.
580 std::size_t current_count = sizeof(t) / (
581 static_cast<char *>(static_cast<void *>(&t[1]))
582 - static_cast<char *>(static_cast<void *>(&t[0]))
583 );
584 boost::serialization::collection_size_type count;
585 ar >> BOOST_SERIALIZATION_NVP(count);
586 if(static_cast<std::size_t>(count) > current_count)
587 boost::serialization::throw_exception(
588 archive::archive_exception(
589 boost::archive::archive_exception::array_size_too_short
590 )
591 );
592 // explict template arguments to pass intel C++ compiler
593 ar >> serialization::make_array<
594 value_type,
595 boost::serialization::collection_size_type
596 >(
597 static_cast<value_type *>(&t[0]),
598 count
599 );
600 }
601 };
602
603 } // detail
604
605 template<class Archive, class T>
606 inline void load(Archive & ar, T &t){
607 // if this assertion trips. It means we're trying to load a
608 // const object with a compiler that doesn't have correct
609 // function template ordering. On other compilers, this is
610 // handled below.
611 detail::check_const_loading< T >();
612 typedef
613 typename mpl::eval_if<is_pointer< T >,
614 mpl::identity<detail::load_pointer_type<Archive> >
615 ,//else
616 typename mpl::eval_if<is_array< T >,
617 mpl::identity<detail::load_array_type<Archive> >
618 ,//else
619 typename mpl::eval_if<is_enum< T >,
620 mpl::identity<detail::load_enum_type<Archive> >
621 ,//else
622 mpl::identity<detail::load_non_pointer_type<Archive> >
623 >
624 >
625 >::type typex;
626 typex::invoke(ar, t);
627 }
628
629 } // namespace archive
630 } // namespace boost
631
632 #endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP