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