• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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