Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/archive/detail/iserializer.hpp @ 47

Last change on this file since 47 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

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