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

Revision 857, 20.2 KB checked in by igarcia, 18 years ago (diff)
Line 
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
73namespace boost {
74
75namespace serialization {
76    class extended_type_info;
77} // namespace serialization
78
79namespace archive {
80
81// an accessor to permit friend access to archives.  Needed because
82// some compilers don't handle friend templates completely
83class save_access {
84public:
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
96namespace detail {
97
98template<class Archive, class T>
99class oserializer : public basic_oserializer
100{
101private:
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    {}
109public:
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 flags) 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
141template<class Archive, class T>
142BOOST_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.
158template<class T, class Archive>
159class pointer_oserializer : public archive_pointer_oserializer<Archive>
160{
161private:
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) )
170public:
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;
176public:
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
187template<class T, class Archive>
188BOOST_DLLEXPORT const pointer_oserializer<T, Archive> &
189pointer_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.
197template<class T, class Archive>
198const pointer_oserializer<T, Archive> pointer_oserializer<T, Archive>::instance;
199
200template<class T, class Archive>
201BOOST_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
219template<class T, class Archive>
220#if !defined(__BORLANDC__)
221BOOST_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
228BOOST_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
239template<class Archive, class T>
240struct 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
326template<class Archive, class TPtr>
327struct 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
471template<class Archive, class T>
472struct 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
481template<class Archive, class T>
482struct 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
500template<class Archive, class T>
501BOOST_DLLEXPORT const basic_pointer_oserializer &
502instantiate_pointer_oserializer(
503    Archive * /* ar = NULL */,
504    T * /* t = NULL */
505) BOOST_USED ;
506// definition
507template<class Archive, class T>
508BOOST_DLLEXPORT const basic_pointer_oserializer &
509instantiate_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
520template<class Archive, class T>
521inline 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
541template<class T>
542struct 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
559template<class Archive, class T>
560inline 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
Note: See TracBrowser for help on using the repository browser.