Ugly, not-to-be-pushed sucking in of all of Boost to get windows to work.
[dyninst.git] / external / boost / archive / detail / iserializer.hpp
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) && (_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 // 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 <memory>  // for auto_ptr
27 #include <cstddef> // size_t
28
29 #include <boost/config.hpp>
30 #include <boost/detail/workaround.hpp>
31 #if defined(BOOST_NO_STDC_NAMESPACE)
32 namespace std{ 
33     using ::size_t; 
34 } // namespace std
35 #endif
36 #include <boost/throw_exception.hpp>
37 #include <boost/smart_cast.hpp>
38 #include <boost/static_assert.hpp>
39 #include <boost/static_warning.hpp>
40 #include <boost/detail/no_exceptions_support.hpp>
41
42 #include <boost/type_traits/is_pointer.hpp>
43 #include <boost/type_traits/is_fundamental.hpp>
44 #include <boost/type_traits/is_enum.hpp>
45 #include <boost/type_traits/is_same.hpp>
46 #include <boost/type_traits/is_const.hpp>
47 #include <boost/type_traits/remove_const.hpp>
48 #include <boost/serialization/is_abstract.hpp>
49
50 #include <boost/mpl/eval_if.hpp>
51 #include <boost/mpl/if.hpp>
52 #include <boost/mpl/identity.hpp>
53 #include <boost/mpl/or.hpp>
54 #include <boost/mpl/and.hpp>
55 #include <boost/mpl/less.hpp>
56 #include <boost/mpl/greater_equal.hpp>
57 #include <boost/mpl/int.hpp>
58 #include <boost/mpl/list.hpp>
59 #include <boost/mpl/empty.hpp>
60 #include <boost/mpl/not.hpp>
61
62 #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO
63     #include <boost/serialization/extended_type_info_typeid.hpp>
64 #endif
65
66 // the following is need only for dynamic cast of polymorphic pointers
67 #include <boost/archive/detail/basic_iarchive.hpp>
68 #include <boost/archive/detail/basic_iserializer.hpp>
69 #include <boost/archive/detail/archive_pointer_iserializer.hpp>
70 #include <boost/archive/archive_exception.hpp>
71
72 #include <boost/serialization/force_include.hpp>
73 #include <boost/serialization/serialization.hpp>
74 #include <boost/serialization/version.hpp>
75 #include <boost/serialization/level.hpp>
76 #include <boost/serialization/tracking.hpp>
77 #include <boost/serialization/type_info_implementation.hpp>
78 #include <boost/serialization/nvp.hpp>
79 #include <boost/serialization/binary_object.hpp>
80 #include <boost/serialization/void_cast.hpp>
81
82 namespace boost {
83
84 namespace serialization {
85     class extended_type_info;
86 } // namespace serialization
87
88 namespace archive {
89
90 // an accessor to permit friend access to archives.  Needed because
91 // some compilers don't handle friend templates completely
92 class load_access {
93 public:
94     template<class Archive, class T>
95     static void load_primitive(Archive &ar, T &t){
96         ar.load(t);
97     }
98 };
99
100 namespace detail {
101
102 template<class Archive, class T>
103 class iserializer : public basic_iserializer
104 {
105 private:
106     virtual void destroy(/*const*/ void *address) const {
107         boost::serialization::access::destroy(static_cast<T *>(address));
108     }
109     // private constructor to inhibit any existence other than the 
110     // static one
111     explicit iserializer() :
112         basic_iserializer(
113             * boost::serialization::type_info_implementation<T>::type::get_instance()
114         )
115     {}
116 public:
117     virtual BOOST_DLLEXPORT void load_object_data(
118         basic_iarchive & ar,
119         void *x, 
120         const unsigned int file_version
121     ) const BOOST_USED ;
122     virtual bool class_info() const {
123         return boost::serialization::implementation_level<T>::value 
124             >= boost::serialization::object_class_info;
125     }
126     virtual bool tracking(const unsigned int) const {
127 //        if(0 != (flags & no_tracking))
128 //            return false;
129         return boost::serialization::tracking_level<T>::value 
130                 == boost::serialization::track_always
131             || boost::serialization::tracking_level<T>::value 
132                 == boost::serialization::track_selectivly
133             && serialized_as_pointer();
134     }
135     virtual unsigned int version() const {
136         return ::boost::serialization::version<T>::value;
137     }
138     virtual bool is_polymorphic() const {
139         typedef BOOST_DEDUCED_TYPENAME 
140             boost::serialization::type_info_implementation<
141                 T
142             >::type::is_polymorphic::type typex;
143         return typex::value;
144     }
145     static iserializer & instantiate(){
146         static iserializer instance;
147         return instance;
148     }
149     virtual ~iserializer(){};
150 };
151
152 template<class Archive, class T>
153 BOOST_DLLEXPORT void iserializer<Archive, T>::load_object_data(
154     basic_iarchive & ar,
155     void *x, 
156     const unsigned int file_version
157 ) const {
158     // make sure call is routed through the higest interface that might
159     // be specialized by the user.
160     boost::serialization::serialize_adl(
161         boost::smart_cast_reference<Archive &>(ar),
162         * static_cast<T *>(x), 
163         file_version
164     );
165 }
166
167 // instantiation of this template creates a static object.  Note inversion of
168 // normal argument order to workaround bizarre error in MSVC 6.0 which only
169 // manifests iftself during compiler time.
170 template<class T, class Archive>
171 class pointer_iserializer : public archive_pointer_iserializer<Archive> 
172 {
173 private:
174     virtual const basic_iserializer & get_basic_serializer() const {
175         return iserializer<Archive, T>::instantiate();
176     }
177     virtual BOOST_DLLEXPORT void load_object_ptr(
178         basic_iarchive & ar, 
179         void * & x,
180         const unsigned int file_version
181     ) const BOOST_USED;
182 #if defined(__GNUC__) || ( defined(BOOST_MSVC) && (_MSC_VER <= 1300) )
183 public:
184 #endif
185     // private constructor to inhibit any existence other than the 
186     // static one.  Note GCC doesn't permit constructor to be private
187     explicit BOOST_DLLEXPORT pointer_iserializer() BOOST_USED;
188     static const pointer_iserializer instance;
189 public:
190     // at least one compiler (CW) seems to require that serialize_adl
191     // be explicitly instantiated. Still under investigation. 
192     #if !defined(__BORLANDC__)
193     void (* const m)(Archive &, T &, const unsigned);
194     boost::serialization::extended_type_info * (* e)();
195     #endif
196     static BOOST_DLLEXPORT const pointer_iserializer & instantiate() BOOST_USED;
197     virtual ~pointer_iserializer(){};
198 };
199
200 template<class T, class Archive>
201 BOOST_DLLEXPORT const pointer_iserializer<T, Archive> & 
202 pointer_iserializer<T, Archive>::instantiate() {
203     return instance;
204 }
205
206 // note: instances of this template to be constructed before the main
207 // is called in order for things to be initialized properly.  For this
208 // reason, hiding the instance in a static function as was done above
209 // won't work here so we created a free instance here.
210 template<class T, class Archive>
211 const pointer_iserializer<T, Archive> pointer_iserializer<T, Archive>::instance;
212
213 // note trick to be sure that operator new is using class specific
214 // version if such exists. Due to Peter Dimov.
215 // note: the following fails if T has no default constructor.
216 // otherwise it would have been ideal
217 //struct heap_allocator : public T 
218 //{
219 //    T * invoke(){
220 //        return ::new(sizeof(T));
221 //    }
222 //}
223
224 // note: this should really be a member of the load_ptr function
225 // below but some compilers still complain about this.
226 template<class T>
227 struct heap_allocator
228 {
229     #if 0
230         // note: this fails on msvc 7.0 and gcc 3.2
231         template <class U, U x> struct test;
232         typedef char* yes;
233         typedef int* no;
234         template <class U>
235         yes has_op_new(U*, test<void* (*)(std::size_t), &U::operator new>* = 0);
236         no has_op_new(...);
237
238         template<class U>
239         T * new_operator(U);
240
241         T * new_operator(yes){
242             return (T::operator new)(sizeof(T));
243         }
244         T * new_operator(no){
245             return static_cast<T *>(operator new(sizeof(T)));
246         }
247         static T * invoke(){
248             return new_operator(has_op_new(static_cast<T *>(NULL)));
249         }
250     #else
251         // while this doesn't handle operator new overload for class T
252         static T * invoke(){
253             return static_cast<T *>(operator new(sizeof(T)));
254         }
255     #endif
256 };
257
258 // due to Martin Ecker
259 template <typename T>
260 class auto_ptr_with_deleter
261 {
262 public:
263     explicit auto_ptr_with_deleter(T* p) :
264         m_p(p)
265     {}
266     ~auto_ptr_with_deleter(){
267         if (m_p)
268             boost::serialization::access::destroy(m_p);
269     }
270     T* get() const {
271         return m_p;
272     }
273
274     T* release() {
275         T* p = m_p;
276         m_p = NULL;
277         return p;
278     }
279 private:
280     T* m_p;
281 };
282
283 template<class T, class Archive>
284 BOOST_DLLEXPORT void pointer_iserializer<T, Archive>::load_object_ptr(
285     basic_iarchive & ar, 
286     void * & x,
287     const unsigned int file_version
288 ) const {
289     Archive & ar_impl = boost::smart_cast_reference<Archive &>(ar);
290
291 //    if(0 != (ar.get_flags() & no_object_creation)){
292 //        ar_impl >> boost::serialization::make_nvp(NULL, * static_cast<T *>(x));
293 //        return;
294 //    }
295
296     auto_ptr_with_deleter<T> ap(heap_allocator<T>::invoke());
297     if(NULL == ap.get())
298         boost::throw_exception(std::bad_alloc()) ;
299
300     T * t = ap.get();
301     x = t;
302
303     // catch exception during load_construct_data so that we don't
304     // automatically delete the t which is most likely not fully
305     // constructed
306     BOOST_TRY {
307         // this addresses an obscure situtation that occurs when 
308         // load_constructor de-serializes something through a pointer.
309         ar.next_object_pointer(t);
310         boost::serialization::load_construct_data_adl<Archive, T>(
311             ar_impl,
312             t, 
313             file_version
314         );
315     }
316     BOOST_CATCH(...){
317         BOOST_RETHROW;
318     }
319     BOOST_CATCH_END
320
321     ar_impl >> boost::serialization::make_nvp(NULL, * t);
322     ap.release();
323 }
324
325 template<class T, class Archive>
326 #if !defined(__BORLANDC__)
327 BOOST_DLLEXPORT pointer_iserializer<T, Archive>::pointer_iserializer() :
328     archive_pointer_iserializer<Archive>(
329         * boost::serialization::type_info_implementation<T>::type::get_instance()
330     ),
331     m(boost::serialization::serialize_adl<Archive, T>),
332     e(boost::serialization::type_info_implementation<T>::type::get_instance)
333 #else
334 BOOST_DLLEXPORT pointer_iserializer<T, Archive>::pointer_iserializer() :
335     archive_pointer_iserializer<Archive>(
336         * boost::serialization::type_info_implementation<T>::type::get_instance()
337     )
338 #endif
339 {
340     iserializer<Archive, T> & bis = iserializer<Archive, T>::instantiate();
341     bis.set_bpis(this);
342 }
343
344 template<class Archive, class T>
345 struct load_non_pointer_type {
346     // note this bounces the call right back to the archive
347     // with no runtime overhead
348     struct load_primitive {
349         static void invoke(Archive & ar, T & t){
350             load_access::load_primitive(ar, t);
351         }
352     };
353     // note this bounces the call right back to the archive
354     // with no runtime overhead
355     struct load_only {
356         static void invoke(Archive & ar, T & t){
357             // short cut to user's serializer
358             // make sure call is routed through the higest interface that might
359             // be specialized by the user.
360             boost::serialization::serialize_adl(
361                 ar, t, boost::serialization::version<T>::value
362             );
363         }
364     };
365
366     // note this save class information including version
367     // and serialization level to the archive
368     struct load_standard {
369         static void invoke(Archive &ar, T &t){
370             //BOOST_STATIC_ASSERT(! boost::is_const<T>::value);
371             // borland - for some reason T is const here - even though
372             // its not called that way - so fix it her
373             typedef BOOST_DEDUCED_TYPENAME boost::remove_const<T>::type typex;
374             void * x = & const_cast<typex &>(t);
375             ar.load_object(x, iserializer<Archive, T>::instantiate());
376         }
377     };
378
379     struct load_conditional {
380         static void invoke(Archive &ar, T &t){
381             //if(0 == (ar.get_flags() & no_tracking))
382                 load_standard::invoke(ar, t);
383             //else
384             //    load_only::invoke(ar, t);
385         }
386     };
387
388     typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
389             // if its primitive
390             mpl::equal_to<
391                 boost::serialization::implementation_level<T>,
392                 mpl::int_<boost::serialization::primitive_type>
393             >,
394             mpl::identity<load_primitive>,
395         // else
396         BOOST_DEDUCED_TYPENAME mpl::eval_if<
397         // class info / version
398         mpl::greater_equal<
399                     boost::serialization::implementation_level<T>,
400                     mpl::int_<boost::serialization::object_class_info>
401                 >,
402         // do standard load
403         mpl::identity<load_standard>,
404     // else
405     BOOST_DEDUCED_TYPENAME mpl::eval_if<
406         // no tracking
407                 mpl::equal_to<
408                     boost::serialization::tracking_level<T>,
409                     mpl::int_<boost::serialization::track_never>
410             >,
411             // do a fast load
412             mpl::identity<load_only>,
413         // else
414         // do a fast load only tracking is turned off
415         mpl::identity<load_conditional>
416     > > >::type typex;
417
418     static void invoke(Archive & ar, T &t){
419         BOOST_STATIC_ASSERT((
420             mpl::greater_equal<
421                 boost::serialization::implementation_level<T>, 
422                 mpl::int_<boost::serialization::primitive_type>
423             >::value
424         ));
425         typex::invoke(ar, t);
426     }
427 };
428
429 template<class Archive, class Tptr>
430 struct load_pointer_type {
431     template<class T>
432     struct abstract
433     {
434         static const basic_pointer_iserializer * register_type(Archive & /* ar */){
435             #if ! defined(__BORLANDC__)
436             typedef BOOST_DEDUCED_TYPENAME 
437                 boost::serialization::type_info_implementation<T>::type::is_polymorphic typex;
438             // it has? to be polymorphic
439             BOOST_STATIC_ASSERT(typex::value);
440             #endif
441             return static_cast<basic_pointer_iserializer *>(NULL);
442          }
443     };
444
445     template<class T>
446     struct non_abstract
447     {
448         static const basic_pointer_iserializer * register_type(Archive & ar){
449             return ar.register_type(static_cast<T *>(NULL));
450         }
451     };
452
453     template<class T>
454     static const basic_pointer_iserializer * register_type(Archive &ar, T & /*t*/){
455         // there should never be any need to load an abstract polymorphic 
456         // class pointer.  Inhibiting code generation for this
457         // permits abstract base classes to be used - note: exception
458         // virtual serialize functions used for plug-ins
459         typedef BOOST_DEDUCED_TYPENAME
460             mpl::eval_if<
461                 serialization::is_abstract<T>,
462                 mpl::identity<abstract<T> >,
463                 mpl::identity<non_abstract<T> >    
464             >::type typex;
465         return typex::register_type(ar);
466     }
467
468     template<class T>
469     static T * pointer_tweak(
470         const boost::serialization::extended_type_info & eti,
471         void * t,
472         T &
473     ) {
474         // tweak the pointer back to the base class
475         return static_cast<T *>(
476             boost::serialization::void_upcast(
477                 eti,
478                 * boost::serialization::type_info_implementation<T>::type::get_instance(),
479                 t
480             )
481         );
482     }
483
484     static void invoke(Archive & ar, Tptr & t){
485         const basic_pointer_iserializer * bpis_ptr = register_type(ar, *t);
486         const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer(
487             * reinterpret_cast<void **>(&t),
488             bpis_ptr,
489             archive_pointer_iserializer<Archive>::find
490         );
491         // if the pointer isn't that of the base class
492         if(newbpis_ptr != bpis_ptr){
493             t = pointer_tweak(newbpis_ptr->get_eti(), t, *t);
494         }
495     }
496 };
497
498 template<class Archive, class T>
499 struct load_enum_type {
500     static void invoke(Archive &ar, T &t){
501         // convert integers to correct enum to load
502         int i;
503         ar >> boost::serialization::make_nvp(NULL, i);
504         t = static_cast<T>(i);
505     }
506 };
507
508 template<class Archive, class T>
509 struct load_array_type {
510     static void invoke(Archive &ar, T &t){
511         // convert integers to correct enum to load
512         int current_count = sizeof(t) / (
513             static_cast<char *>(static_cast<void *>(&t[1])) 
514             - static_cast<char *>(static_cast<void *>(&t[0]))
515         );
516         int count;
517         ar >> BOOST_SERIALIZATION_NVP(count);
518         if(count > current_count)
519             boost::throw_exception(archive::archive_exception(
520                 boost::archive::archive_exception::array_size_too_short
521             ));
522         int i;
523         for(i = 0; i < count; ++i)
524             ar >> boost::serialization::make_nvp("item", t[i]);
525     }
526 };
527
528 // note bogus arguments to workaround msvc 6 silent runtime failure
529 template<class Archive, class T>
530 BOOST_DLLEXPORT 
531 inline const basic_pointer_iserializer &
532 instantiate_pointer_iserializer(
533     Archive * /* ar = NULL */,
534     T * /* t = NULL */
535 ) BOOST_USED;
536
537 template<class Archive, class T>
538 BOOST_DLLEXPORT 
539 inline const basic_pointer_iserializer &
540 instantiate_pointer_iserializer(
541     Archive * /* ar = NULL */,
542     T * /* t = NULL */
543 ){
544     // note: reversal of order of arguments to work around msvc 6.0 bug
545     // that manifests itself while trying to link.
546     return pointer_iserializer<T, Archive>::instantiate();
547 }
548
549 } // detail
550
551 template<class Archive, class T>
552 inline void load(Archive &ar, T &t){
553     // if this assertion trips. It means we're trying to load a
554     // const object with a compiler that doesn't have correct
555     // funtion template ordering.  On other compilers, this is
556     // handled below.
557     BOOST_STATIC_ASSERT(! boost::is_const<T>::value);
558     typedef
559         BOOST_DEDUCED_TYPENAME mpl::eval_if<is_pointer<T>,
560             mpl::identity<detail::load_pointer_type<Archive, T> >
561         ,//else
562         BOOST_DEDUCED_TYPENAME mpl::eval_if<is_array<T>,
563             mpl::identity<detail::load_array_type<Archive, T> >
564         ,//else
565         BOOST_DEDUCED_TYPENAME mpl::eval_if<is_enum<T>,
566             mpl::identity<detail::load_enum_type<Archive, T> >
567         ,//else
568             mpl::identity<detail::load_non_pointer_type<Archive, T> >
569         >
570         >
571         >::type typex;
572     typex::invoke(ar, t);
573 }
574
575 // BORLAND
576 #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x560))
577 // borland has a couple fo problems
578 // a) if function is partiall specialized - see below
579 // const paramters are transformed to non-const ones
580 // b) implementation of base_object can't be made to work
581 // correctly which results in all base_object s being const.
582 // So, strip off the const for borland.  This breaks the trap
583 // for loading const objects - but I see no alternative
584 template<class Archive, class T>
585 inline void load(Archive &ar, const T & t){
586         load(ar, const_cast<T &>(t));
587 }
588 #endif
589
590 // let wrappers through.  (Someday implement is_wrapper)
591 #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
592 template<class Archive, class T>
593 inline void load(Archive &ar, const serialization::nvp<T> &t){
594         boost::archive::load(ar, const_cast<serialization::nvp<T> &>(t));
595 }
596 template<class Archive>
597 inline void load(Archive &ar, const serialization::binary_object &t){
598         boost::archive::load(ar, const_cast<serialization::binary_object &>(t));
599 }
600
601 //template<class Archive, class T>
602 //inline void load(Archive &ar, const serialization::binary_object &t){
603 //      load(ar, const_cast<binary_object &>(t));
604 //}
605 #endif
606
607 } // namespace archive
608 } // namespace boost
609
610 #endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP