source: NonGTP/Boost/boost/archive/detail/iserializer.hpp @ 857

Revision 857, 20.2 KB checked in by igarcia, 18 years ago (diff)
Line 
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_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
82namespace boost {
83
84namespace serialization {
85    class extended_type_info;
86} // namespace serialization
87
88namespace archive {
89
90// an accessor to permit friend access to archives.  Needed because
91// some compilers don't handle friend templates completely
92class load_access {
93public:
94    template<class Archive, class T>
95    static void load_primitive(Archive &ar, T &t){
96        ar.load(t);
97    }
98};
99
100namespace detail {
101
102template<class Archive, class T>
103class iserializer : public basic_iserializer
104{
105private:
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    {}
116public:
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 flags) 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
152template<class Archive, class T>
153BOOST_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.
170template<class T, class Archive>
171class pointer_iserializer : public archive_pointer_iserializer<Archive>
172{
173private:
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) )
183public:
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;
189public:
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
200template<class T, class Archive>
201BOOST_DLLEXPORT const pointer_iserializer<T, Archive> &
202pointer_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.
210template<class T, class Archive>
211const 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.
226template<class T>
227struct 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
259template <typename T>
260class auto_ptr_with_deleter
261{
262public:
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    }
279private:
280    T* m_p;
281};
282
283template<class T, class Archive>
284BOOST_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
325template<class T, class Archive>
326#if !defined(__BORLANDC__)
327BOOST_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
334BOOST_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
344template<class Archive, class T>
345struct 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
429template<class Archive, class Tptr>
430struct 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
498template<class Archive, class T>
499struct 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
508template<class Archive, class T>
509struct 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
529template<class Archive, class T>
530BOOST_DLLEXPORT
531inline const basic_pointer_iserializer &
532instantiate_pointer_iserializer(
533    Archive * /* ar = NULL */,
534    T * /* t = NULL */
535) BOOST_USED;
536
537template<class Archive, class T>
538BOOST_DLLEXPORT
539inline const basic_pointer_iserializer &
540instantiate_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
551template<class Archive, class T>
552inline 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
584template<class Archive, class T>
585inline 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
592template<class Archive, class T>
593inline void load(Archive &ar, const serialization::nvp<T> &t){
594        boost::archive::load(ar, const_cast<serialization::nvp<T> &>(t));
595}
596template<class Archive>
597inline 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
Note: See TracBrowser for help on using the repository browser.