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 BOOST_SERIALIZATION_DONT_USE_HAS_NEW_OPERATOR 1
64 #else
65 #define BOOST_SERIALIZATION_DONT_USE_HAS_NEW_OPERATOR 0
66 #endif
67
68 #if ! BOOST_SERIALIZATION_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>
load_primitive(Archive & ar,T & 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:
destroy(void * address) const123 void destroy(/*const*/ void *address) const BOOST_OVERRIDE {
124 boost::serialization::access::destroy(static_cast<T *>(address));
125 }
126 public:
iserializer()127 explicit iserializer() :
128 basic_iserializer(
129 boost::serialization::singleton<
130 typename
131 boost::serialization::type_info_implementation< T >::type
132 >::get_const_instance()
133 )
134 {}
135 BOOST_DLLEXPORT void load_object_data(
136 basic_iarchive & ar,
137 void *x,
138 const unsigned int file_version
139 ) const BOOST_OVERRIDE BOOST_USED;
class_info() const140 bool class_info() const BOOST_OVERRIDE {
141 return boost::serialization::implementation_level< T >::value
142 >= boost::serialization::object_class_info;
143 }
tracking(const unsigned int) const144 bool tracking(const unsigned int /* flags */) const BOOST_OVERRIDE {
145 return boost::serialization::tracking_level< T >::value
146 == boost::serialization::track_always
147 || ( boost::serialization::tracking_level< T >::value
148 == boost::serialization::track_selectively
149 && serialized_as_pointer());
150 }
version() const151 version_type version() const BOOST_OVERRIDE {
152 return version_type(::boost::serialization::version< T >::value);
153 }
is_polymorphic() const154 bool is_polymorphic() const BOOST_OVERRIDE {
155 return boost::is_polymorphic< T >::value;
156 }
~iserializer()157 ~iserializer() BOOST_OVERRIDE {}
158 };
159
160 #ifdef BOOST_MSVC
161 # pragma warning(pop)
162 #endif
163
164 template<class Archive, class T>
load_object_data(basic_iarchive & ar,void * x,const unsigned int file_version) const165 BOOST_DLLEXPORT void iserializer<Archive, T>::load_object_data(
166 basic_iarchive & ar,
167 void *x,
168 const unsigned int file_version
169 ) const {
170 // note: we now comment this out. Before we permited archive
171 // version # to be very large. Now we don't. To permit
172 // readers of these old archives, we have to suppress this
173 // code. Perhaps in the future we might re-enable it but
174 // permit its suppression with a runtime switch.
175 #if 0
176 // trap case where the program cannot handle the current version
177 if(file_version > static_cast<const unsigned int>(version()))
178 boost::serialization::throw_exception(
179 archive::archive_exception(
180 boost::archive::archive_exception::unsupported_class_version,
181 get_debug_info()
182 )
183 );
184 #endif
185 // make sure call is routed through the higest interface that might
186 // be specialized by the user.
187 boost::serialization::serialize_adl(
188 boost::serialization::smart_cast_reference<Archive &>(ar),
189 * static_cast<T *>(x),
190 file_version
191 );
192 }
193
194 #ifdef BOOST_MSVC
195 # pragma warning(push)
196 # pragma warning(disable : 4511 4512)
197 #endif
198
199 // the purpose of this code is to allocate memory for an object
200 // without requiring the constructor to be called. Presumably
201 // the allocated object will be subsequently initialized with
202 // "placement new".
203 // note: we have the boost type trait has_new_operator but we
204 // have no corresponding has_delete_operator. So we presume
205 // that the former being true would imply that the a delete
206 // operator is also defined for the class T.
207
208 template<class T>
209 struct heap_allocation {
210 // boost::has_new_operator< T > doesn't work on these compilers
211 #if BOOST_SERIALIZATION_DONT_USE_HAS_NEW_OPERATOR
212 // This doesn't handle operator new overload for class T
invoke_newboost::archive::detail::heap_allocation213 static T * invoke_new(){
214 return static_cast<T *>(operator new(sizeof(T)));
215 }
invoke_deleteboost::archive::detail::heap_allocation216 static void invoke_delete(T *t){
217 (operator delete(t));
218 }
219 #else
220 // note: we presume that a true value for has_new_operator
221 // implies the existence of a class specific delete operator as well
222 // as a class specific new operator.
223 struct has_new_operator {
224 static T * invoke_new() {
225 return static_cast<T *>((T::operator new)(sizeof(T)));
226 }
227 static void invoke_delete(T * t) {
228 // if compilation fails here, the likely cause that the class
229 // T has a class specific new operator but no class specific
230 // delete operator which matches the following signature.
231 // note that this solution addresses the issue that two
232 // possible signatures. But it doesn't address the possibility
233 // that the class might have class specific new with NO
234 // class specific delete at all. Patches (compatible with
235 // C++03) welcome!
236 (operator delete)(t);
237 }
238 };
239 struct doesnt_have_new_operator {
240 static T* invoke_new() {
241 return static_cast<T *>(operator new(sizeof(T)));
242 }
243 static void invoke_delete(T * t) {
244 // Note: I'm reliance upon automatic conversion from T * to void * here
245 (operator delete)(t);
246 }
247 };
248 static T * invoke_new() {
249 typedef typename
250 mpl::eval_if<
251 boost::has_new_operator< T >,
252 mpl::identity<has_new_operator >,
253 mpl::identity<doesnt_have_new_operator >
254 >::type typex;
255 return typex::invoke_new();
256 }
257 static void invoke_delete(T *t) {
258 typedef typename
259 mpl::eval_if<
260 boost::has_new_operator< T >,
261 mpl::identity<has_new_operator >,
262 mpl::identity<doesnt_have_new_operator >
263 >::type typex;
264 typex::invoke_delete(t);
265 }
266 #endif
heap_allocationboost::archive::detail::heap_allocation267 explicit heap_allocation(){
268 m_p = invoke_new();
269 }
~heap_allocationboost::archive::detail::heap_allocation270 ~heap_allocation(){
271 if (0 != m_p)
272 invoke_delete(m_p);
273 }
getboost::archive::detail::heap_allocation274 T* get() const {
275 return m_p;
276 }
277
releaseboost::archive::detail::heap_allocation278 T* release() {
279 T* p = m_p;
280 m_p = 0;
281 return p;
282 }
283 private:
284 T* m_p;
285 };
286
287 template<class Archive, class T>
288 class pointer_iserializer :
289 public basic_pointer_iserializer
290 {
291 private:
heap_allocation() const292 void * heap_allocation() const BOOST_OVERRIDE {
293 detail::heap_allocation<T> h;
294 T * t = h.get();
295 h.release();
296 return t;
297 }
get_basic_serializer() const298 const basic_iserializer & get_basic_serializer() const BOOST_OVERRIDE {
299 return boost::serialization::singleton<
300 iserializer<Archive, T>
301 >::get_const_instance();
302 }
303 BOOST_DLLEXPORT void load_object_ptr(
304 basic_iarchive & ar,
305 void * x,
306 const unsigned int file_version
307 ) const BOOST_OVERRIDE BOOST_USED;
308 public:
309 // this should alway be a singleton so make the constructor protected
310 pointer_iserializer();
311 ~pointer_iserializer() BOOST_OVERRIDE;
312 };
313
314 #ifdef BOOST_MSVC
315 # pragma warning(pop)
316 #endif
317
318 // note: BOOST_DLLEXPORT is so that code for polymorphic class
319 // serialized only through base class won't get optimized out
320 template<class Archive, class T>
load_object_ptr(basic_iarchive & ar,void * t,const unsigned int file_version) const321 BOOST_DLLEXPORT void pointer_iserializer<Archive, T>::load_object_ptr(
322 basic_iarchive & ar,
323 void * t,
324 const unsigned int file_version
325 ) const
326 {
327 Archive & ar_impl =
328 boost::serialization::smart_cast_reference<Archive &>(ar);
329
330 // note that the above will throw std::bad_alloc if the allocation
331 // fails so we don't have to address this contingency here.
332
333 // catch exception during load_construct_data so that we don't
334 // automatically delete the t which is most likely not fully
335 // constructed
336 BOOST_TRY {
337 // this addresses an obscure situation that occurs when
338 // load_constructor de-serializes something through a pointer.
339 ar.next_object_pointer(t);
340 boost::serialization::load_construct_data_adl<Archive, T>(
341 ar_impl,
342 static_cast<T *>(t),
343 file_version
344 );
345 }
346 BOOST_CATCH(...){
347 // if we get here the load_construct failed. The heap_allocation
348 // will be automatically deleted so we don't have to do anything
349 // special here.
350 BOOST_RETHROW;
351 }
352 BOOST_CATCH_END
353
354 ar_impl >> boost::serialization::make_nvp(NULL, * static_cast<T *>(t));
355 }
356
357 template<class Archive, class T>
pointer_iserializer()358 pointer_iserializer<Archive, T>::pointer_iserializer() :
359 basic_pointer_iserializer(
360 boost::serialization::singleton<
361 typename
362 boost::serialization::type_info_implementation< T >::type
363 >::get_const_instance()
364 )
365 {
366 boost::serialization::singleton<
367 iserializer<Archive, T>
368 >::get_mutable_instance().set_bpis(this);
369 archive_serializer_map<Archive>::insert(this);
370 }
371
372 template<class Archive, class T>
~pointer_iserializer()373 pointer_iserializer<Archive, T>::~pointer_iserializer(){
374 archive_serializer_map<Archive>::erase(this);
375 }
376
377 template<class Archive>
378 struct load_non_pointer_type {
379 // note this bounces the call right back to the archive
380 // with no runtime overhead
381 struct load_primitive {
382 template<class T>
invokeboost::archive::detail::load_non_pointer_type::load_primitive383 static void invoke(Archive & ar, T & t){
384 load_access::load_primitive(ar, t);
385 }
386 };
387 // note this bounces the call right back to the archive
388 // with no runtime overhead
389 struct load_only {
390 template<class T>
invokeboost::archive::detail::load_non_pointer_type::load_only391 static void invoke(Archive & ar, const T & t){
392 // short cut to user's serializer
393 // make sure call is routed through the higest interface that might
394 // be specialized by the user.
395 boost::serialization::serialize_adl(
396 ar,
397 const_cast<T &>(t),
398 boost::serialization::version< T >::value
399 );
400 }
401 };
402
403 // note this save class information including version
404 // and serialization level to the archive
405 struct load_standard {
406 template<class T>
invokeboost::archive::detail::load_non_pointer_type::load_standard407 static void invoke(Archive &ar, const T & t){
408 void * x = boost::addressof(const_cast<T &>(t));
409 ar.load_object(
410 x,
411 boost::serialization::singleton<
412 iserializer<Archive, T>
413 >::get_const_instance()
414 );
415 }
416 };
417
418 struct load_conditional {
419 template<class T>
invokeboost::archive::detail::load_non_pointer_type::load_conditional420 static void invoke(Archive &ar, T &t){
421 //if(0 == (ar.get_flags() & no_tracking))
422 load_standard::invoke(ar, t);
423 //else
424 // load_only::invoke(ar, t);
425 }
426 };
427
428 template<class T>
invokeboost::archive::detail::load_non_pointer_type429 static void invoke(Archive & ar, T &t){
430 typedef typename mpl::eval_if<
431 // if its primitive
432 mpl::equal_to<
433 boost::serialization::implementation_level< T >,
434 mpl::int_<boost::serialization::primitive_type>
435 >,
436 mpl::identity<load_primitive>,
437 // else
438 typename mpl::eval_if<
439 // class info / version
440 mpl::greater_equal<
441 boost::serialization::implementation_level< T >,
442 mpl::int_<boost::serialization::object_class_info>
443 >,
444 // do standard load
445 mpl::identity<load_standard>,
446 // else
447 typename mpl::eval_if<
448 // no tracking
449 mpl::equal_to<
450 boost::serialization::tracking_level< T >,
451 mpl::int_<boost::serialization::track_never>
452 >,
453 // do a fast load
454 mpl::identity<load_only>,
455 // else
456 // do a fast load only tracking is turned off
457 mpl::identity<load_conditional>
458 > > >::type typex;
459 check_object_versioning< T >();
460 check_object_level< T >();
461 typex::invoke(ar, t);
462 }
463 };
464
465 template<class Archive>
466 struct load_pointer_type {
467 struct abstract
468 {
469 template<class T>
register_typeboost::archive::detail::load_pointer_type::abstract470 static const basic_pointer_iserializer * register_type(Archive & /* ar */){
471 // it has? to be polymorphic
472 BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value);
473 return static_cast<basic_pointer_iserializer *>(NULL);
474 }
475 };
476
477 struct non_abstract
478 {
479 template<class T>
register_typeboost::archive::detail::load_pointer_type::non_abstract480 static const basic_pointer_iserializer * register_type(Archive & ar){
481 return ar.register_type(static_cast<T *>(NULL));
482 }
483 };
484
485 template<class T>
register_typeboost::archive::detail::load_pointer_type486 static const basic_pointer_iserializer * register_type(Archive &ar, const T* const /*t*/){
487 // there should never be any need to load an abstract polymorphic
488 // class pointer. Inhibiting code generation for this
489 // permits abstract base classes to be used - note: exception
490 // virtual serialize functions used for plug-ins
491 typedef typename
492 mpl::eval_if<
493 boost::serialization::is_abstract<const T>,
494 boost::mpl::identity<abstract>,
495 boost::mpl::identity<non_abstract>
496 >::type typex;
497 return typex::template register_type< T >(ar);
498 }
499
500 template<class T>
pointer_tweakboost::archive::detail::load_pointer_type501 static T * pointer_tweak(
502 const boost::serialization::extended_type_info & eti,
503 void const * const t,
504 const T &
505 ) {
506 // tweak the pointer back to the base class
507 void * upcast = const_cast<void *>(
508 boost::serialization::void_upcast(
509 eti,
510 boost::serialization::singleton<
511 typename
512 boost::serialization::type_info_implementation< T >::type
513 >::get_const_instance(),
514 t
515 )
516 );
517 if(NULL == upcast)
518 boost::serialization::throw_exception(
519 archive_exception(archive_exception::unregistered_class)
520 );
521 return static_cast<T *>(upcast);
522 }
523
524 template<class T>
check_loadboost::archive::detail::load_pointer_type525 static void check_load(T * const /* t */){
526 check_pointer_level< T >();
527 check_pointer_tracking< T >();
528 }
529
530 static const basic_pointer_iserializer *
findboost::archive::detail::load_pointer_type531 find(const boost::serialization::extended_type_info & type){
532 return static_cast<const basic_pointer_iserializer *>(
533 archive_serializer_map<Archive>::find(type)
534 );
535 }
536
537 template<class Tptr>
invokeboost::archive::detail::load_pointer_type538 static void invoke(Archive & ar, Tptr & t){
539 check_load(t);
540 const basic_pointer_iserializer * bpis_ptr = register_type(ar, t);
541 const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer(
542 // note major hack here !!!
543 // I tried every way to convert Tptr &t (where Tptr might
544 // include const) to void * &. This is the only way
545 // I could make it work. RR
546 (void * & )t,
547 bpis_ptr,
548 find
549 );
550 // if the pointer isn't that of the base class
551 if(newbpis_ptr != bpis_ptr){
552 t = pointer_tweak(newbpis_ptr->get_eti(), t, *t);
553 }
554 }
555 };
556
557 template<class Archive>
558 struct load_enum_type {
559 template<class T>
invokeboost::archive::detail::load_enum_type560 static void invoke(Archive &ar, T &t){
561 // convert integers to correct enum to load
562 int i;
563 ar >> boost::serialization::make_nvp(NULL, i);
564 t = static_cast< T >(i);
565 }
566 };
567
568 template<class Archive>
569 struct load_array_type {
570 template<class T>
invokeboost::archive::detail::load_array_type571 static void invoke(Archive &ar, T &t){
572 typedef typename remove_extent< T >::type value_type;
573
574 // convert integers to correct enum to load
575 // determine number of elements in the array. Consider the
576 // fact that some machines will align elements on boundaries
577 // other than characters.
578 std::size_t current_count = sizeof(t) / (
579 static_cast<char *>(static_cast<void *>(&t[1]))
580 - static_cast<char *>(static_cast<void *>(&t[0]))
581 );
582 boost::serialization::collection_size_type count;
583 ar >> BOOST_SERIALIZATION_NVP(count);
584 if(static_cast<std::size_t>(count) > current_count)
585 boost::serialization::throw_exception(
586 archive::archive_exception(
587 boost::archive::archive_exception::array_size_too_short
588 )
589 );
590 // explict template arguments to pass intel C++ compiler
591 ar >> serialization::make_array<
592 value_type,
593 boost::serialization::collection_size_type
594 >(
595 static_cast<value_type *>(&t[0]),
596 count
597 );
598 }
599 };
600
601 } // detail
602
603 template<class Archive, class T>
load(Archive & ar,T & t)604 inline void load(Archive & ar, T &t){
605 // if this assertion trips. It means we're trying to load a
606 // const object with a compiler that doesn't have correct
607 // function template ordering. On other compilers, this is
608 // handled below.
609 detail::check_const_loading< T >();
610 typedef
611 typename mpl::eval_if<is_pointer< T >,
612 mpl::identity<detail::load_pointer_type<Archive> >
613 ,//else
614 typename mpl::eval_if<is_array< T >,
615 mpl::identity<detail::load_array_type<Archive> >
616 ,//else
617 typename mpl::eval_if<is_enum< T >,
618 mpl::identity<detail::load_enum_type<Archive> >
619 ,//else
620 mpl::identity<detail::load_non_pointer_type<Archive> >
621 >
622 >
623 >::type typex;
624 typex::invoke(ar, t);
625 }
626
627 } // namespace archive
628 } // namespace boost
629
630 #endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP
631