Ugly, not-to-be-pushed sucking in of all of Boost to get windows to work.
[dyninst.git] / external / boost / archive / detail / oserializer.hpp
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 <cassert>
26
27 #include <boost/config.hpp>
28 #include <boost/detail/workaround.hpp>
29 #include <boost/throw_exception.hpp>
30 #include <boost/smart_cast.hpp>
31 #include <boost/static_assert.hpp>
32 #include <boost/static_warning.hpp>
33
34 #include <boost/type_traits/is_pointer.hpp>
35 #include <boost/type_traits/is_fundamental.hpp>
36 #include <boost/type_traits/is_enum.hpp>
37 #include <boost/type_traits/is_volatile.hpp>
38 #include <boost/type_traits/is_const.hpp>
39 #include <boost/type_traits/is_same.hpp>
40 #include <boost/serialization/is_abstract.hpp>
41
42 #include <boost/mpl/eval_if.hpp>
43 #include <boost/mpl/and.hpp>
44 #include <boost/mpl/less.hpp>
45 #include <boost/mpl/greater_equal.hpp>
46 #include <boost/mpl/equal_to.hpp>
47 #include <boost/mpl/int.hpp>
48 #include <boost/mpl/identity.hpp>
49 #include <boost/mpl/list.hpp>
50 #include <boost/mpl/empty.hpp>
51 #include <boost/mpl/not.hpp>
52
53 #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO
54     #include <boost/serialization/extended_type_info_typeid.hpp>
55 #endif
56
57 // the following is need only for dynamic cast of polymorphic pointers
58 #include <boost/archive/detail/basic_oarchive.hpp>
59 #include <boost/archive/detail/basic_oserializer.hpp>
60 #include <boost/archive/detail/archive_pointer_oserializer.hpp>
61
62 #include <boost/serialization/force_include.hpp>
63 #include <boost/serialization/serialization.hpp>
64 #include <boost/serialization/version.hpp>
65 #include <boost/serialization/level.hpp>
66 #include <boost/serialization/tracking.hpp>
67 #include <boost/serialization/type_info_implementation.hpp>
68 #include <boost/serialization/nvp.hpp>
69 #include <boost/serialization/void_cast.hpp>
70
71 #include <boost/archive/archive_exception.hpp>
72
73 namespace boost {
74
75 namespace serialization {
76     class extended_type_info;
77 } // namespace serialization
78
79 namespace archive {
80
81 // an accessor to permit friend access to archives.  Needed because
82 // some compilers don't handle friend templates completely
83 class save_access {
84 public:
85     template<class Archive>
86     static void end_preamble(Archive & ar){
87         ar.end_preamble();
88     }
89     template<class Archive, class T>
90     static void save_primitive(Archive & ar, const  T & t){
91         ar.end_preamble();
92         ar.save(t);
93     }
94 };
95
96 namespace detail {
97
98 template<class Archive, class T>
99 class oserializer : public basic_oserializer
100 {
101 private:
102     // private constructor to inhibit any existence other than the 
103     // static one
104     explicit oserializer() :
105         basic_oserializer(
106             * boost::serialization::type_info_implementation<T>::type::get_instance()
107         )
108     {}
109 public:
110     virtual BOOST_DLLEXPORT void save_object_data(
111         basic_oarchive & ar,    
112         const void *x
113     ) const BOOST_USED ;
114     virtual bool class_info() const {
115         return boost::serialization::implementation_level<T>::value 
116             >= boost::serialization::object_class_info;
117     }
118     virtual bool tracking(const unsigned int) const {
119 //        if(0 != (flags &  no_tracking))
120 //            return false;
121         return boost::serialization::tracking_level<T>::value == boost::serialization::track_always
122             || boost::serialization::tracking_level<T>::value == boost::serialization::track_selectivly
123             && serialized_as_pointer();
124     }
125     virtual unsigned int version() const {
126         return ::boost::serialization::version<T>::value;
127     }
128     virtual bool is_polymorphic() const {
129         typedef BOOST_DEDUCED_TYPENAME boost::serialization::type_info_implementation<
130             T
131         >::type::is_polymorphic::type typex;
132         return typex::value;
133     }
134     static oserializer & instantiate(){
135         static oserializer instance;
136         return instance;
137     }
138     virtual ~oserializer(){}
139 };
140
141 template<class Archive, class T>
142 BOOST_DLLEXPORT void oserializer<Archive, T>::save_object_data(
143     basic_oarchive & ar,    
144     const void *x
145 ) const {
146     // make sure call is routed through the highest interface that might
147     // be specialized by the user.
148     boost::serialization::serialize_adl(
149         boost::smart_cast_reference<Archive &>(ar),
150         * static_cast<T *>(const_cast<void *>(x)),
151         version()
152     );
153 }
154
155 // instantiation of this template creates a static object.  Note inversion of
156 // normal argument order to workaround bizarre error in MSVC 6.0 which only
157 // manifests iftself during compiler time.
158 template<class T, class Archive>
159 class pointer_oserializer : public archive_pointer_oserializer<Archive> 
160 {
161 private:
162     virtual const basic_oserializer & get_basic_serializer() const {
163         return oserializer<Archive, T>::instantiate();
164     }
165     virtual BOOST_DLLEXPORT void save_object_ptr(
166         basic_oarchive & ar,
167         const void * x
168     ) const BOOST_USED ;
169 #if defined(__GNUC__) || ( defined(BOOST_MSVC) && (_MSC_VER <= 1300) )
170 public:
171 #endif
172     // private constructor to inhibit any existence other than the 
173     // static one.  Note GCC doesn't permit constructor to be private
174     explicit BOOST_DLLEXPORT pointer_oserializer() BOOST_USED;
175     static const pointer_oserializer instance;
176 public:
177     #if !defined(__BORLANDC__)
178     // at least one compiler (CW) seems to require that serialize_adl
179     // be explicitly instantiated. Still under investigation. 
180     void (* const m)(Archive &, T &, const unsigned);
181     boost::serialization::extended_type_info * (* e)();
182     #endif
183     static BOOST_DLLEXPORT const pointer_oserializer & instantiate() BOOST_USED;
184     virtual ~pointer_oserializer(){}
185 };
186
187 template<class T, class Archive>
188 BOOST_DLLEXPORT const pointer_oserializer<T, Archive> & 
189 pointer_oserializer<T, Archive>::instantiate(){
190     return instance;
191 }
192
193 // note: instances of this template to be constructed before the main
194 // is called in order for things to be initialized properly.  For this
195 // reason, hiding the instance in a static function as was done above
196 // won't work here so we created a free instance here.
197 template<class T, class Archive>
198 const pointer_oserializer<T, Archive> pointer_oserializer<T, Archive>::instance;
199
200 template<class T, class Archive>
201 BOOST_DLLEXPORT void pointer_oserializer<T, Archive>::save_object_ptr(
202     basic_oarchive & ar,
203     const void * x
204 ) const {
205     assert(NULL != x);
206     // make sure call is routed through the highest interface that might
207     // be specialized by the user.
208     T * t = static_cast<T *>(const_cast<void *>(x));
209     const unsigned int file_version = boost::serialization::version<T>::value;
210     Archive & ar_impl = boost::smart_cast_reference<Archive &>(ar);
211     boost::serialization::save_construct_data_adl<Archive, T>(
212         ar_impl, 
213         t, 
214         file_version
215     );
216     ar_impl << boost::serialization::make_nvp(NULL, * t);
217 }
218
219 template<class T, class Archive>
220 #if !defined(__BORLANDC__)
221 BOOST_DLLEXPORT pointer_oserializer<T, Archive>::pointer_oserializer() :
222     archive_pointer_oserializer<Archive>(
223         * boost::serialization::type_info_implementation<T>::type::get_instance()
224     ),
225     m(boost::serialization::serialize_adl<Archive, T>),
226     e(boost::serialization::type_info_implementation<T>::type::get_instance)
227 #else
228 BOOST_DLLEXPORT pointer_oserializer<T, Archive>::pointer_oserializer() :
229     archive_pointer_oserializer<Archive>(
230         * boost::serialization::type_info_implementation<T>::type::get_instance()
231     )
232 #endif
233 {
234     // make sure appropriate member function is instantiated
235     oserializer<Archive, T> & bos = oserializer<Archive, T>::instantiate();
236     bos.set_bpos(this);
237 }
238
239 template<class Archive, class T>
240 struct save_non_pointer_type {
241     // note this bounces the call right back to the archive
242     // with no runtime overhead
243     struct save_primitive {
244         static void invoke(Archive & ar, const T & t){
245             save_access::save_primitive(ar, t);
246         }
247     };
248     // same as above but passes through serialization
249     struct save_only {
250         static void invoke(Archive & ar, const T & t){
251             // make sure call is routed through the highest interface that might
252             // be specialized by the user.
253             boost::serialization::serialize_adl(
254                 ar, 
255                 const_cast<T &>(t), 
256                 ::boost::serialization::version<T>::value
257             );
258         }
259     };
260     // adds class information to the archive. This includes
261     // serialization level and class version
262     struct save_standard {
263         static void invoke(Archive &ar, const T & t){
264             ar.save_object(& t, oserializer<Archive, T>::instantiate());
265         }
266     };
267
268     // adds class information to the archive. This includes
269     // serialization level and class version
270     struct save_conditional {
271         static void invoke(Archive &ar, const T &t){
272             //if(0 == (ar.get_flags() & no_tracking))
273                 save_standard::invoke(ar, t);
274             //else
275             //   save_only::invoke(ar, t);
276         }
277     };
278
279     typedef 
280         BOOST_DEDUCED_TYPENAME mpl::eval_if<
281         // if its primitive
282             mpl::equal_to<
283                 boost::serialization::implementation_level<T>,
284                 mpl::int_<boost::serialization::primitive_type>
285             >,
286             mpl::identity<save_primitive>,
287         // else
288         BOOST_DEDUCED_TYPENAME mpl::eval_if<
289             // class info / version
290             mpl::greater_equal<
291                 boost::serialization::implementation_level<T>,
292                 mpl::int_<boost::serialization::object_class_info>
293             >,
294             // do standard save
295             mpl::identity<save_standard>,
296         // else
297         BOOST_DEDUCED_TYPENAME mpl::eval_if<
298                 // no tracking
299             mpl::equal_to<
300                 boost::serialization::tracking_level<T>,
301                 mpl::int_<boost::serialization::track_never>
302             >,
303             // do a fast save
304             mpl::identity<save_only>,
305         // else
306             // do a fast save only tracking is turned off
307             mpl::identity<save_conditional>
308     > > >::type typex; 
309
310     static void invoke(Archive & ar, const T & t){
311         // check that we're not trying to serialize something that
312         // has been marked not to be serialized.  If this your program
313         // traps here, you've tried to serialize a class whose trait
314         // has been marked "non-serializable". Either reset the trait
315         // (see level.hpp) or change program not to serialize items of this class
316         BOOST_STATIC_ASSERT((
317             mpl::greater_equal<
318                 boost::serialization::implementation_level<T>, 
319                 mpl::int_<boost::serialization::primitive_type>
320             >::value
321         ));
322         typex::invoke(ar, t);
323     };
324 };
325
326 template<class Archive, class TPtr>
327 struct save_pointer_type {
328     template<class T>
329     struct abstract
330     {
331         static const basic_pointer_oserializer * register_type(Archive & /* ar */){
332             // it has? to be polymorphic
333             BOOST_STATIC_ASSERT(
334                 boost::serialization::type_info_implementation<T>::type::is_polymorphic::value
335             );
336             return static_cast<const basic_pointer_oserializer *>(NULL);
337         }
338     };
339
340     template<class T>
341     struct non_abstract
342     {
343         static const basic_pointer_oserializer * register_type(Archive & ar){
344             return ar.register_type(static_cast<T *>(NULL));
345         }
346     };
347
348     template<class T>
349     static const basic_pointer_oserializer * register_type(Archive &ar, T & /*t*/){
350         // there should never be any need to save an abstract polymorphic 
351         // class pointer.  Inhibiting code generation for this
352         // permits abstract base classes to be used - note: exception
353         // virtual serialize functions used for plug-ins
354         typedef 
355             BOOST_DEDUCED_TYPENAME mpl::eval_if<
356                 serialization::is_abstract<T>,
357                 mpl::identity<abstract<T> >,
358                 mpl::identity<non_abstract<T> >       
359             >::type typex;
360         return typex::register_type(ar);
361     }
362
363     template<class T>
364     struct non_polymorphic
365     {
366         static void save(
367             Archive &ar, 
368             const T & t, 
369             const basic_pointer_oserializer * bpos_ptr
370         ){
371             // save the requested pointer type
372             ar.save_pointer(& t, bpos_ptr);
373         }
374     };
375
376     template<class T>
377     struct polymorphic
378     {
379         static void save(
380             Archive &ar, 
381             const T & t, 
382             const basic_pointer_oserializer * bpos_ptr
383         ){
384             const boost::serialization::extended_type_info * this_type
385                 = boost::serialization::type_info_implementation<T>::type::get_instance();
386             // retrieve the true type of the object pointed to
387             // if this assertion fails its an error in this library
388             assert(NULL != this_type);
389             const boost::serialization::extended_type_info * true_type 
390                 = boost::serialization::type_info_implementation<T>::type::get_derived_extended_type_info(t);
391             // note:if this exception is thrown, be sure that derived pointer
392             // is either regsitered or exported.
393             if(NULL == true_type){
394                 boost::throw_exception(
395                     archive_exception(archive_exception::unregistered_class)
396                 );
397             }
398
399             // if its not a pointer to a more derived type
400             const void *vp = static_cast<const void *>(&t);
401             if(*this_type == *true_type){
402                 ar.save_pointer(vp, bpos_ptr);
403                 return;
404             }
405             // convert pointer to more derived type. if this is thrown
406             // it means that the base/derived relationship hasn't be registered
407             vp = serialization::void_downcast(*true_type, *this_type, &t);
408             if(NULL == vp){
409                 boost::throw_exception(
410                     archive_exception(archive_exception::unregistered_cast)
411                 );
412             }
413
414             // sice true_type is valid, and this only gets made if the 
415             // pointer oserializer object has been created, this should never
416             // fail
417             bpos_ptr = archive_pointer_oserializer<Archive>::find(* true_type);
418             assert(NULL != bpos_ptr);
419             if(NULL == bpos_ptr)
420                 boost::throw_exception(
421                     archive_exception(archive_exception::unregistered_class)
422                 );
423             ar.save_pointer(vp, bpos_ptr);
424         }
425     };
426
427     template<class T>
428     static void save(
429         Archive & ar, 
430         const T &t,
431         const basic_pointer_oserializer * bpos_ptr
432     ){
433         typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
434             BOOST_DEDUCED_TYPENAME boost::serialization::
435                 type_info_implementation<T>::type::is_polymorphic,
436             mpl::identity<polymorphic<T> >,
437             mpl::identity<non_polymorphic<T> >
438         >::type typey;
439         typey::save(ar, const_cast<T &>(t), bpos_ptr);
440     }
441
442     template<class T>
443     static void const_check(T & t){
444         BOOST_STATIC_ASSERT(! boost::is_const<T>::value);
445     }
446
447     static void invoke(Archive &ar, const TPtr t){
448         #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
449             // if your program traps here, its because you tried to do
450             // something like ar << t where t is a pointer to a const value
451             // void f3(A const* a, text_oarchive& oa)
452             // {
453             //     oa << a;
454             // }
455             // with a compiler which doesn't support remove_const
456             // const_check(* t);
457         #else
458             // otherwise remove the const
459         #endif
460         const basic_pointer_oserializer * bpos_ptr =  register_type(ar, * t);
461         if(NULL == t){
462             basic_oarchive & boa = boost::smart_cast_reference<basic_oarchive &>(ar);
463             boa.save_null_pointer();
464             save_access::end_preamble(ar);
465             return;
466         }
467         save(ar, * t, bpos_ptr);
468     };
469 };
470
471 template<class Archive, class T>
472 struct save_enum_type
473 {
474     static void invoke(Archive &ar, const T &t){
475         // convert enum to integers on save
476         const int i = static_cast<int>(t);
477         ar << boost::serialization::make_nvp(NULL, i);
478     }
479 };
480
481 template<class Archive, class T>
482 struct save_array_type
483 {
484     static void invoke(Archive &ar, const T &t){
485         save_access::end_preamble(ar);
486         // consider alignment
487         int count = sizeof(t) / (
488             static_cast<const char *>(static_cast<const void *>(&t[1])) 
489             - static_cast<const char *>(static_cast<const void *>(&t[0]))
490         );
491         ar << BOOST_SERIALIZATION_NVP(count);
492         int i;
493         for(i = 0; i < count; ++i)
494             ar << boost::serialization::make_nvp("item", t[i]);
495     }
496 };
497
498 // note bogus arguments to workaround msvc 6 silent runtime failure
499 // declaration to satisfy gcc
500 template<class Archive, class T>
501 BOOST_DLLEXPORT const basic_pointer_oserializer &
502 instantiate_pointer_oserializer(
503     Archive * /* ar = NULL */,
504     T * /* t = NULL */
505 ) BOOST_USED ;
506 // definition
507 template<class Archive, class T>
508 BOOST_DLLEXPORT const basic_pointer_oserializer &
509 instantiate_pointer_oserializer(
510     Archive * /* ar = NULL */,
511     T * /* t = NULL */
512 ){
513     // note: reversal of order of arguments to work around msvc 6.0 bug
514     // that manifests itself while trying to link.
515     return pointer_oserializer<T, Archive>::instantiate();
516 }
517
518 } // detail
519
520 template<class Archive, class T>
521 inline void save(Archive & ar, const T &t){
522     typedef 
523         BOOST_DEDUCED_TYPENAME mpl::eval_if<is_pointer<T>,
524             mpl::identity<detail::save_pointer_type<Archive, T> >,
525         //else
526         BOOST_DEDUCED_TYPENAME mpl::eval_if<is_enum<T>,
527             mpl::identity<detail::save_enum_type<Archive, T> >,
528         //else
529         BOOST_DEDUCED_TYPENAME mpl::eval_if<is_array<T>,
530             mpl::identity<detail::save_array_type<Archive, T> >,
531         //else
532             mpl::identity<detail::save_non_pointer_type<Archive, T> >
533         >
534         >
535         >::type typex;
536     typex::invoke(ar, t);
537 }
538
539 #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
540
541 template<class T>
542 struct check_tracking {
543     typedef BOOST_DEDUCED_TYPENAME mpl::if_<
544         // if its never tracked.
545         BOOST_DEDUCED_TYPENAME mpl::equal_to<
546             serialization::tracking_level<T>,
547             mpl::int_<serialization::track_never>
548         >,
549         // it better not be a pointer
550         mpl::not_<is_pointer<T> >,
551     //else
552         // otherwise if it might be tracked.  So there shouldn't
553         // be any problem making a const
554         is_const<T>
555     >::type typex;
556     BOOST_STATIC_CONSTANT(bool, value = typex::value);
557 };
558
559 template<class Archive, class T>
560 inline void save(Archive & ar, T &t){
561     // if your program traps here, it indicates taht your doing one of the following:
562     // a) serializing an object of a type marked "track_never" through a pointer.
563     // b) saving an non-const object of a type not markd "track_never)
564     // Either of these conditions may be an indicator of an error usage of the
565     // serialization library and should be double checked.  See documentation on
566     // object tracking.
567     BOOST_STATIC_ASSERT(check_tracking<T>::value);
568         save(ar, const_cast<const T &>(t));
569 }
570 #endif
571
572 } // namespace archive
573 } // namespace boost
574
575 #endif // BOOST_ARCHIVE_OSERIALIZER_HPP