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