• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef BOOST_ARCHIVE_OSERIALIZER_HPP
2 #define BOOST_ARCHIVE_OSERIALIZER_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 // oserializer.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 <boost/assert.hpp>
26 #include <cstddef> // NULL
27 
28 #include <boost/config.hpp>
29 
30 #include <boost/static_assert.hpp>
31 #include <boost/detail/workaround.hpp>
32 
33 #include <boost/mpl/eval_if.hpp>
34 #include <boost/mpl/equal_to.hpp>
35 #include <boost/mpl/greater_equal.hpp>
36 #include <boost/mpl/identity.hpp>
37 #include <boost/mpl/bool_fwd.hpp>
38 
39 #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO
40     #include <boost/serialization/extended_type_info_typeid.hpp>
41 #endif
42 #include <boost/serialization/throw_exception.hpp>
43 #include <boost/serialization/smart_cast.hpp>
44 #include <boost/serialization/assume_abstract.hpp>
45 #include <boost/serialization/static_warning.hpp>
46 
47 #include <boost/type_traits/is_pointer.hpp>
48 #include <boost/type_traits/is_enum.hpp>
49 #include <boost/type_traits/is_const.hpp>
50 #include <boost/type_traits/is_polymorphic.hpp>
51 #include <boost/type_traits/remove_extent.hpp>
52 
53 #include <boost/serialization/serialization.hpp>
54 #include <boost/serialization/version.hpp>
55 #include <boost/serialization/level.hpp>
56 #include <boost/serialization/tracking.hpp>
57 #include <boost/serialization/type_info_implementation.hpp>
58 #include <boost/serialization/nvp.hpp>
59 #include <boost/serialization/void_cast.hpp>
60 #include <boost/serialization/collection_size_type.hpp>
61 #include <boost/serialization/array_wrapper.hpp>
62 
63 #include <boost/serialization/singleton.hpp>
64 
65 #include <boost/archive/archive_exception.hpp>
66 #include <boost/archive/detail/basic_oarchive.hpp>
67 #include <boost/archive/detail/basic_oserializer.hpp>
68 #include <boost/archive/detail/basic_pointer_oserializer.hpp>
69 #include <boost/archive/detail/archive_serializer_map.hpp>
70 #include <boost/archive/detail/check.hpp>
71 
72 #include <boost/core/addressof.hpp>
73 
74 namespace boost {
75 
76 namespace serialization {
77     class extended_type_info;
78 } // namespace serialization
79 
80 namespace archive {
81 
82 // an accessor to permit friend access to archives.  Needed because
83 // some compilers don't handle friend templates completely
84 class save_access {
85 public:
86     template<class Archive>
end_preamble(Archive & ar)87     static void end_preamble(Archive & ar){
88         ar.end_preamble();
89     }
90     template<class Archive, class T>
save_primitive(Archive & ar,const T & t)91     static void save_primitive(Archive & ar, const  T & t){
92         ar.end_preamble();
93         ar.save(t);
94     }
95 };
96 
97 namespace detail {
98 
99 #ifdef BOOST_MSVC
100 #  pragma warning(push)
101 #  pragma warning(disable : 4511 4512)
102 #endif
103 
104 template<class Archive, class T>
105 class oserializer : public basic_oserializer
106 {
107 private:
108     // private constructor to inhibit any existence other than the
109     // static one
110 public:
oserializer()111     explicit BOOST_DLLEXPORT oserializer() :
112         basic_oserializer(
113             boost::serialization::singleton<
114                 typename
115                 boost::serialization::type_info_implementation< T >::type
116             >::get_const_instance()
117         )
118     {}
119     BOOST_DLLEXPORT void save_object_data(
120         basic_oarchive & ar,
121         const void *x
122     ) const BOOST_OVERRIDE BOOST_USED;
class_info() const123     bool class_info() const BOOST_OVERRIDE {
124         return boost::serialization::implementation_level< T >::value
125             >= boost::serialization::object_class_info;
126     }
tracking(const unsigned int) const127     bool tracking(const unsigned int /* flags */) const BOOST_OVERRIDE {
128         return boost::serialization::tracking_level< T >::value == boost::serialization::track_always
129             || (boost::serialization::tracking_level< T >::value == boost::serialization::track_selectively
130                 && serialized_as_pointer());
131     }
version() const132     version_type version() const BOOST_OVERRIDE {
133         return version_type(::boost::serialization::version< T >::value);
134     }
is_polymorphic() const135     bool is_polymorphic() const BOOST_OVERRIDE {
136         return boost::is_polymorphic< T >::value;
137     }
~oserializer()138     ~oserializer() BOOST_OVERRIDE {}
139 };
140 
141 #ifdef BOOST_MSVC
142 #  pragma warning(pop)
143 #endif
144 
145 template<class Archive, class T>
save_object_data(basic_oarchive & ar,const void * x) const146 BOOST_DLLEXPORT void oserializer<Archive, T>::save_object_data(
147     basic_oarchive & ar,
148     const void *x
149 ) const {
150     // make sure call is routed through the highest interface that might
151     // be specialized by the user.
152     BOOST_STATIC_ASSERT(boost::is_const< T >::value == false);
153     boost::serialization::serialize_adl(
154         boost::serialization::smart_cast_reference<Archive &>(ar),
155         * static_cast<T *>(const_cast<void *>(x)),
156         version()
157     );
158 }
159 
160 #ifdef BOOST_MSVC
161 #  pragma warning(push)
162 #  pragma warning(disable : 4511 4512)
163 #endif
164 
165 template<class Archive, class T>
166 class pointer_oserializer :
167     public basic_pointer_oserializer
168 {
169 private:
170     const basic_oserializer &
get_basic_serializer() const171     get_basic_serializer() const BOOST_OVERRIDE {
172         return boost::serialization::singleton<
173             oserializer<Archive, T>
174         >::get_const_instance();
175     }
176     BOOST_DLLEXPORT void save_object_ptr(
177         basic_oarchive & ar,
178         const void * x
179     ) const BOOST_OVERRIDE BOOST_USED;
180 public:
181     pointer_oserializer();
182     ~pointer_oserializer() BOOST_OVERRIDE;
183 };
184 
185 #ifdef BOOST_MSVC
186 #  pragma warning(pop)
187 #endif
188 
189 template<class Archive, class T>
save_object_ptr(basic_oarchive & ar,const void * x) const190 BOOST_DLLEXPORT void pointer_oserializer<Archive, T>::save_object_ptr(
191     basic_oarchive & ar,
192     const void * x
193 ) const {
194     BOOST_ASSERT(NULL != x);
195     // make sure call is routed through the highest interface that might
196     // be specialized by the user.
197     T * t = static_cast<T *>(const_cast<void *>(x));
198     const unsigned int file_version = boost::serialization::version< T >::value;
199     Archive & ar_impl
200         = boost::serialization::smart_cast_reference<Archive &>(ar);
201     boost::serialization::save_construct_data_adl<Archive, T>(
202         ar_impl,
203         t,
204         file_version
205     );
206     ar_impl << boost::serialization::make_nvp(NULL, * t);
207 }
208 
209 template<class Archive, class T>
pointer_oserializer()210 pointer_oserializer<Archive, T>::pointer_oserializer() :
211     basic_pointer_oserializer(
212         boost::serialization::singleton<
213             typename
214             boost::serialization::type_info_implementation< T >::type
215         >::get_const_instance()
216     )
217 {
218     // make sure appropriate member function is instantiated
219     boost::serialization::singleton<
220         oserializer<Archive, T>
221     >::get_mutable_instance().set_bpos(this);
222     archive_serializer_map<Archive>::insert(this);
223 }
224 
225 template<class Archive, class T>
~pointer_oserializer()226 pointer_oserializer<Archive, T>::~pointer_oserializer(){
227     archive_serializer_map<Archive>::erase(this);
228 }
229 
230 template<class Archive>
231 struct save_non_pointer_type {
232     // note this bounces the call right back to the archive
233     // with no runtime overhead
234     struct save_primitive {
235         template<class T>
invokeboost::archive::detail::save_non_pointer_type::save_primitive236         static void invoke(Archive & ar, const T & t){
237             save_access::save_primitive(ar, t);
238         }
239     };
240     // same as above but passes through serialization
241     struct save_only {
242         template<class T>
invokeboost::archive::detail::save_non_pointer_type::save_only243         static void invoke(Archive & ar, const T & t){
244             // make sure call is routed through the highest interface that might
245             // be specialized by the user.
246             boost::serialization::serialize_adl(
247                 ar,
248                 const_cast<T &>(t),
249                 ::boost::serialization::version< T >::value
250             );
251         }
252     };
253     // adds class information to the archive. This includes
254     // serialization level and class version
255     struct save_standard {
256         template<class T>
invokeboost::archive::detail::save_non_pointer_type::save_standard257         static void invoke(Archive &ar, const T & t){
258             ar.save_object(
259                 boost::addressof(t),
260                 boost::serialization::singleton<
261                     oserializer<Archive, T>
262                 >::get_const_instance()
263             );
264         }
265     };
266 
267 
268 
269     // adds class information to the archive. This includes
270     // serialization level and class version
271     struct save_conditional {
272         template<class T>
invokeboost::archive::detail::save_non_pointer_type::save_conditional273         static void invoke(Archive &ar, const T &t){
274             //if(0 == (ar.get_flags() & no_tracking))
275                 save_standard::invoke(ar, t);
276             //else
277             //   save_only::invoke(ar, t);
278         }
279     };
280 
281 
282     template<class T>
invokeboost::archive::detail::save_non_pointer_type283     static void invoke(Archive & ar, const T & t){
284         typedef
285             typename mpl::eval_if<
286             // if its primitive
287                 mpl::equal_to<
288                     boost::serialization::implementation_level< T >,
289                     mpl::int_<boost::serialization::primitive_type>
290                 >,
291                 mpl::identity<save_primitive>,
292             // else
293             typename mpl::eval_if<
294                 // class info / version
295                 mpl::greater_equal<
296                     boost::serialization::implementation_level< T >,
297                     mpl::int_<boost::serialization::object_class_info>
298                 >,
299                 // do standard save
300                 mpl::identity<save_standard>,
301             // else
302             typename mpl::eval_if<
303                     // no tracking
304                 mpl::equal_to<
305                     boost::serialization::tracking_level< T >,
306                     mpl::int_<boost::serialization::track_never>
307                 >,
308                 // do a fast save
309                 mpl::identity<save_only>,
310             // else
311                 // do a fast save only tracking is turned off
312                 mpl::identity<save_conditional>
313             > > >::type typex;
314         check_object_versioning< T >();
315         typex::invoke(ar, t);
316     }
317     template<class T>
invokeboost::archive::detail::save_non_pointer_type318     static void invoke(Archive & ar, T & t){
319         check_object_level< T >();
320         check_object_tracking< T >();
321         invoke(ar, const_cast<const T &>(t));
322     }
323 };
324 
325 template<class Archive>
326 struct save_pointer_type {
327     struct abstract
328     {
329         template<class T>
register_typeboost::archive::detail::save_pointer_type::abstract330         static const basic_pointer_oserializer * register_type(Archive & /* ar */){
331             // it has? to be polymorphic
332             BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value);
333             return NULL;
334         }
335     };
336 
337     struct non_abstract
338     {
339         template<class T>
register_typeboost::archive::detail::save_pointer_type::non_abstract340         static const basic_pointer_oserializer * register_type(Archive & ar){
341             return ar.register_type(static_cast<T *>(NULL));
342         }
343     };
344 
345     template<class T>
register_typeboost::archive::detail::save_pointer_type346     static const basic_pointer_oserializer * register_type(Archive &ar, T* const /*t*/){
347         // there should never be any need to save an abstract polymorphic
348         // class pointer.  Inhibiting code generation for this
349         // permits abstract base classes to be used - note: exception
350         // virtual serialize functions used for plug-ins
351         typedef
352             typename mpl::eval_if<
353                 boost::serialization::is_abstract< T >,
354                 mpl::identity<abstract>,
355                 mpl::identity<non_abstract>
356             >::type typex;
357         return typex::template register_type< T >(ar);
358     }
359 
360     struct non_polymorphic
361     {
362         template<class T>
saveboost::archive::detail::save_pointer_type::non_polymorphic363         static void save(
364             Archive &ar,
365             T & t
366         ){
367             const basic_pointer_oserializer & bpos =
368                 boost::serialization::singleton<
369                     pointer_oserializer<Archive, T>
370                 >::get_const_instance();
371             // save the requested pointer type
372             ar.save_pointer(& t, & bpos);
373         }
374     };
375 
376     struct polymorphic
377     {
378         template<class T>
saveboost::archive::detail::save_pointer_type::polymorphic379         static void save(
380             Archive &ar,
381             T & t
382         ){
383             typename
384             boost::serialization::type_info_implementation< T >::type const
385             & i = boost::serialization::singleton<
386                 typename
387                 boost::serialization::type_info_implementation< T >::type
388             >::get_const_instance();
389 
390             boost::serialization::extended_type_info const * const this_type = & i;
391 
392             // retrieve the true type of the object pointed to
393             // if this assertion fails its an error in this library
394             BOOST_ASSERT(NULL != this_type);
395 
396             const boost::serialization::extended_type_info * true_type =
397                 i.get_derived_extended_type_info(t);
398 
399             // note:if this exception is thrown, be sure that derived pointer
400             // is either registered or exported.
401             if(NULL == true_type){
402                 boost::serialization::throw_exception(
403                     archive_exception(
404                         archive_exception::unregistered_class,
405                         "derived class not registered or exported"
406                     )
407                 );
408             }
409 
410             // if its not a pointer to a more derived type
411             const void *vp = static_cast<const void *>(&t);
412             if(*this_type == *true_type){
413                 const basic_pointer_oserializer * bpos = register_type(ar, &t);
414                 ar.save_pointer(vp, bpos);
415                 return;
416             }
417             // convert pointer to more derived type. if this is thrown
418             // it means that the base/derived relationship hasn't be registered
419             vp = serialization::void_downcast(
420                 *true_type,
421                 *this_type,
422                 static_cast<const void *>(&t)
423             );
424             if(NULL == vp){
425                 boost::serialization::throw_exception(
426                     archive_exception(
427                         archive_exception::unregistered_cast,
428                         true_type->get_debug_info(),
429                         this_type->get_debug_info()
430                     )
431                 );
432             }
433 
434             // since true_type is valid, and this only gets made if the
435             // pointer oserializer object has been created, this should never
436             // fail
437             const basic_pointer_oserializer * bpos
438                 = static_cast<const basic_pointer_oserializer *>(
439                     boost::serialization::singleton<
440                         archive_serializer_map<Archive>
441                     >::get_const_instance().find(*true_type)
442                 );
443             BOOST_ASSERT(NULL != bpos);
444             if(NULL == bpos)
445                 boost::serialization::throw_exception(
446                     archive_exception(
447                         archive_exception::unregistered_class,
448                         "derived class not registered or exported"
449                     )
450                 );
451             ar.save_pointer(vp, bpos);
452         }
453     };
454 
455     template<class T>
saveboost::archive::detail::save_pointer_type456     static void save(
457         Archive & ar,
458         const T & t
459     ){
460         check_pointer_level< T >();
461         check_pointer_tracking< T >();
462         typedef typename mpl::eval_if<
463             is_polymorphic< T >,
464             mpl::identity<polymorphic>,
465             mpl::identity<non_polymorphic>
466         >::type type;
467         type::save(ar, const_cast<T &>(t));
468     }
469 
470     template<class TPtr>
invokeboost::archive::detail::save_pointer_type471     static void invoke(Archive &ar, const TPtr t){
472         register_type(ar, t);
473         if(NULL == t){
474             basic_oarchive & boa
475                 = boost::serialization::smart_cast_reference<basic_oarchive &>(ar);
476             boa.save_null_pointer();
477             save_access::end_preamble(ar);
478             return;
479         }
480         save(ar, * t);
481     }
482 };
483 
484 template<class Archive>
485 struct save_enum_type
486 {
487     template<class T>
invokeboost::archive::detail::save_enum_type488     static void invoke(Archive &ar, const T &t){
489         // convert enum to integers on save
490         const int i = static_cast<int>(t);
491         ar << boost::serialization::make_nvp(NULL, i);
492     }
493 };
494 
495 template<class Archive>
496 struct save_array_type
497 {
498     template<class T>
invokeboost::archive::detail::save_array_type499     static void invoke(Archive &ar, const T &t){
500         typedef typename boost::remove_extent< T >::type value_type;
501 
502         save_access::end_preamble(ar);
503         // consider alignment
504         std::size_t c = sizeof(t) / (
505             static_cast<const char *>(static_cast<const void *>(&t[1]))
506             - static_cast<const char *>(static_cast<const void *>(&t[0]))
507         );
508         boost::serialization::collection_size_type count(c);
509         ar << BOOST_SERIALIZATION_NVP(count);
510         // explict template arguments to pass intel C++ compiler
511         ar << serialization::make_array<
512             const value_type,
513             boost::serialization::collection_size_type
514         >(
515             static_cast<const value_type *>(&t[0]),
516             count
517         );
518     }
519 };
520 
521 } // detail
522 
523 template<class Archive, class T>
save(Archive & ar,T & t)524 inline void save(Archive & ar, /*const*/ T &t){
525     typedef
526         typename mpl::eval_if<is_pointer< T >,
527             mpl::identity<detail::save_pointer_type<Archive> >,
528         //else
529         typename mpl::eval_if<is_enum< T >,
530             mpl::identity<detail::save_enum_type<Archive> >,
531         //else
532         typename mpl::eval_if<is_array< T >,
533             mpl::identity<detail::save_array_type<Archive> >,
534         //else
535             mpl::identity<detail::save_non_pointer_type<Archive> >
536         >
537         >
538         >::type typex;
539     typex::invoke(ar, t);
540 }
541 
542 } // namespace archive
543 } // namespace boost
544 
545 #endif // BOOST_ARCHIVE_OSERIALIZER_HPP
546