PageRenderTime 47ms CodeModel.GetById 14ms app.highlight 27ms RepoModel.GetById 1ms app.codeStats 1ms

/Src/Dependencies/Boost/boost/archive/detail/iserializer.hpp

http://hadesmem.googlecode.com/
C++ Header | 632 lines | 479 code | 62 blank | 91 comment | 17 complexity | 6f39ef866d0cd227cffa5a6d89cf0987 MD5 | raw file
  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, NULL
 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
 37#include <boost/static_assert.hpp>
 38
 39#include <boost/mpl/eval_if.hpp>
 40#include <boost/mpl/identity.hpp>
 41#include <boost/mpl/greater_equal.hpp>
 42#include <boost/mpl/equal_to.hpp>
 43#include <boost/mpl/bool.hpp>
 44#include <boost/detail/no_exceptions_support.hpp>
 45
 46#ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO   
 47    #include <boost/serialization/extended_type_info_typeid.hpp>   
 48#endif
 49#include <boost/serialization/throw_exception.hpp>
 50#include <boost/serialization/smart_cast.hpp>
 51#include <boost/serialization/static_warning.hpp>
 52
 53#include <boost/type_traits/is_pointer.hpp>
 54#include <boost/type_traits/is_enum.hpp>
 55#include <boost/type_traits/is_const.hpp>
 56#include <boost/type_traits/remove_const.hpp>
 57#include <boost/type_traits/remove_extent.hpp>
 58#include <boost/type_traits/is_polymorphic.hpp>
 59
 60#include <boost/serialization/assume_abstract.hpp>
 61
 62#define DONT_USE_HAS_NEW_OPERATOR (                    \
 63    defined(__BORLANDC__)                              \
 64    || defined(__IBMCPP__)                             \
 65    || defined(BOOST_MSVC) && (BOOST_MSVC <= 1300)     \
 66    || defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x590)   \
 67)
 68
 69#if ! DONT_USE_HAS_NEW_OPERATOR
 70#include <boost/type_traits/has_new_operator.hpp>
 71#endif
 72
 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/void_cast.hpp>
 80#include <boost/serialization/array.hpp>
 81#include <boost/serialization/collection_size_type.hpp>
 82#include <boost/serialization/singleton.hpp>
 83#include <boost/serialization/wrapper.hpp>
 84
 85// the following is need only for dynamic cast of polymorphic pointers
 86#include <boost/archive/archive_exception.hpp>
 87#include <boost/archive/detail/basic_iarchive.hpp>
 88#include <boost/archive/detail/basic_iserializer.hpp>
 89#include <boost/archive/detail/basic_pointer_iserializer.hpp>
 90#include <boost/archive/detail/archive_serializer_map.hpp>
 91#include <boost/archive/detail/check.hpp>
 92
 93namespace boost {
 94
 95namespace serialization {
 96    class extended_type_info;
 97} // namespace serialization
 98
 99namespace archive {
100
101// an accessor to permit friend access to archives.  Needed because
102// some compilers don't handle friend templates completely
103class load_access {
104public:
105    template<class Archive, class T>
106    static void load_primitive(Archive &ar, T &t){
107        ar.load(t);
108    }
109};
110
111namespace detail {
112
113#ifdef BOOST_MSVC
114#  pragma warning(push)
115#  pragma warning(disable : 4511 4512)
116#endif
117
118template<class Archive, class T>
119class iserializer : public basic_iserializer
120{
121private:
122    virtual void destroy(/*const*/ void *address) const {
123        boost::serialization::access::destroy(static_cast<T *>(address));
124    }
125protected:
126    // protected constructor since it's always created by singleton
127    explicit iserializer() :
128        basic_iserializer(
129            boost::serialization::singleton<
130                BOOST_DEDUCED_TYPENAME 
131                boost::serialization::type_info_implementation< T >::type
132            >::get_const_instance()
133        )
134    {}
135public:
136    virtual BOOST_DLLEXPORT void load_object_data(
137        basic_iarchive & ar,
138        void *x, 
139        const unsigned int file_version
140    ) const BOOST_USED;
141    virtual bool class_info() const {
142        return boost::serialization::implementation_level< T >::value 
143            >= boost::serialization::object_class_info;
144    }
145    virtual bool tracking(const unsigned int /* flags */) const {
146        return boost::serialization::tracking_level< T >::value 
147                == boost::serialization::track_always
148            || ( boost::serialization::tracking_level< T >::value 
149                == boost::serialization::track_selectively
150                && serialized_as_pointer());
151    }
152    virtual version_type version() const {
153        return version_type(::boost::serialization::version< T >::value);
154    }
155    virtual bool is_polymorphic() const {
156        return boost::is_polymorphic< T >::value;
157    }
158    virtual ~iserializer(){};
159};
160
161#ifdef BOOST_MSVC
162#  pragma warning(pop)
163#endif
164
165template<class Archive, class T>
166BOOST_DLLEXPORT void iserializer<Archive, T>::load_object_data(
167    basic_iarchive & ar,
168    void *x, 
169    const unsigned int file_version
170) const {
171    // note: we now comment this out. Before we permited archive
172    // version # to be very large.  Now we don't.  To permit
173    // readers of these old archives, we have to suppress this 
174    // code.  Perhaps in the future we might re-enable it but
175    // permit its suppression with a runtime switch.
176    #if 0
177    // trap case where the program cannot handle the current version
178    if(file_version > static_cast<const unsigned int>(version()))
179        boost::serialization::throw_exception(
180            archive::archive_exception(
181                boost::archive::archive_exception::unsupported_class_version,
182                get_debug_info()
183            )
184        );
185    #endif
186    // make sure call is routed through the higest interface that might
187    // be specialized by the user.
188    boost::serialization::serialize_adl(
189        boost::serialization::smart_cast_reference<Archive &>(ar),
190        * static_cast<T *>(x), 
191        file_version
192    );
193}
194
195#ifdef BOOST_MSVC
196#  pragma warning(push)
197#  pragma warning(disable : 4511 4512)
198#endif
199
200template<class Archive, class T>
201class pointer_iserializer :
202    public basic_pointer_iserializer
203{
204private:
205    virtual const basic_iserializer & get_basic_serializer() const {
206        return boost::serialization::singleton<
207            iserializer<Archive, T>
208        >::get_const_instance();
209    }
210    BOOST_DLLEXPORT virtual void load_object_ptr(
211        basic_iarchive & ar, 
212        void * & x,
213        const unsigned int file_version
214    ) const BOOST_USED;
215protected:
216    // this should alway be a singleton so make the constructor protected
217    pointer_iserializer();
218    ~pointer_iserializer();
219};
220
221#ifdef BOOST_MSVC
222#  pragma warning(pop)
223#endif
224
225// note trick to be sure that operator new is using class specific
226// version if such exists. Due to Peter Dimov.
227// note: the following fails if T has no default constructor.
228// otherwise it would have been ideal
229//struct heap_allocator : public T 
230//{
231//    T * invoke(){
232//        return ::new(sizeof(T));
233//    }
234//}
235
236template<class T>
237struct heap_allocator
238{
239    // boost::has_new_operator< T > doesn't work on these compilers
240    #if DONT_USE_HAS_NEW_OPERATOR
241        // This doesn't handle operator new overload for class T
242        static T * invoke(){
243            return static_cast<T *>(operator new(sizeof(T)));
244        }
245    #else
246        struct has_new_operator {
247            static T* invoke() {
248                return static_cast<T *>((T::operator new)(sizeof(T)));
249            }
250        };
251        struct doesnt_have_new_operator {
252            static T* invoke() {
253                return static_cast<T *>(operator new(sizeof(T)));
254            }
255        };
256        static T * invoke() {
257            typedef BOOST_DEDUCED_TYPENAME
258                mpl::eval_if<
259                    boost::has_new_operator< T >,
260                    mpl::identity<has_new_operator >,
261                    mpl::identity<doesnt_have_new_operator >    
262                >::type typex;
263            return typex::invoke();
264        }
265    #endif
266};
267
268// due to Martin Ecker
269template <typename T>
270class auto_ptr_with_deleter
271{
272public:
273    explicit auto_ptr_with_deleter(T* p) :
274        m_p(p)
275    {}
276    ~auto_ptr_with_deleter(){
277        if (m_p)
278            boost::serialization::access::destroy(m_p);
279    }
280    T* get() const {
281        return m_p;
282    }
283
284    T* release() {
285        T* p = m_p;
286        m_p = NULL;
287        return p;
288    }
289private:
290    T* m_p;
291};
292
293// note: BOOST_DLLEXPORT is so that code for polymorphic class
294// serialized only through base class won't get optimized out
295template<class Archive, class T>
296BOOST_DLLEXPORT void pointer_iserializer<Archive, T>::load_object_ptr(
297    basic_iarchive & ar, 
298    void * & x,
299    const unsigned int file_version
300) const
301{
302    Archive & ar_impl = 
303        boost::serialization::smart_cast_reference<Archive &>(ar);
304
305    auto_ptr_with_deleter< T > ap(heap_allocator< T >::invoke());
306    if(NULL == ap.get())
307        boost::serialization::throw_exception(std::bad_alloc()) ;
308
309    T * t = ap.get();
310    x = t;
311
312    // catch exception during load_construct_data so that we don't
313    // automatically delete the t which is most likely not fully
314    // constructed
315    BOOST_TRY {
316        // this addresses an obscure situtation that occurs when 
317        // load_constructor de-serializes something through a pointer.
318        ar.next_object_pointer(t);
319        boost::serialization::load_construct_data_adl<Archive, T>(
320            ar_impl,
321            t, 
322            file_version
323        );
324    }
325    BOOST_CATCH(...){
326        ap.release();
327        BOOST_RETHROW;
328    }
329    BOOST_CATCH_END
330
331    ar_impl >> boost::serialization::make_nvp(NULL, * t);
332    ap.release();
333}
334
335template<class Archive, class T>
336pointer_iserializer<Archive, T>::pointer_iserializer() :
337    basic_pointer_iserializer(
338        boost::serialization::singleton<
339            BOOST_DEDUCED_TYPENAME 
340            boost::serialization::type_info_implementation< T >::type
341        >::get_const_instance()
342    )
343{
344    boost::serialization::singleton<
345        iserializer<Archive, T>
346    >::get_mutable_instance().set_bpis(this);
347    archive_serializer_map<Archive>::insert(this);
348}
349
350template<class Archive, class T>
351pointer_iserializer<Archive, T>::~pointer_iserializer(){
352    archive_serializer_map<Archive>::erase(this);
353}
354
355template<class Archive>
356struct load_non_pointer_type {
357    // note this bounces the call right back to the archive
358    // with no runtime overhead
359    struct load_primitive {
360        template<class T>
361        static void invoke(Archive & ar, T & t){
362            load_access::load_primitive(ar, t);
363        }
364    };
365    // note this bounces the call right back to the archive
366    // with no runtime overhead
367    struct load_only {
368        template<class T>
369        static void invoke(Archive & ar, const T & t){
370            // short cut to user's serializer
371            // make sure call is routed through the higest interface that might
372            // be specialized by the user.
373            boost::serialization::serialize_adl(
374                ar, 
375                const_cast<T &>(t), 
376                boost::serialization::version< T >::value
377            );
378        }
379    };
380
381    // note this save class information including version
382    // and serialization level to the archive
383    struct load_standard {
384        template<class T>
385        static void invoke(Archive &ar, const T & t){
386            void * x = & const_cast<T &>(t);
387            ar.load_object(
388                x, 
389                boost::serialization::singleton<
390                    iserializer<Archive, T>
391                >::get_const_instance()
392            );
393        }
394    };
395
396    struct load_conditional {
397        template<class T>
398        static void invoke(Archive &ar, T &t){
399            //if(0 == (ar.get_flags() & no_tracking))
400                load_standard::invoke(ar, t);
401            //else
402            //    load_only::invoke(ar, t);
403        }
404    };
405
406    template<class T>
407    static void invoke(Archive & ar, T &t){
408        typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
409                // if its primitive
410                mpl::equal_to<
411                    boost::serialization::implementation_level< T >,
412                    mpl::int_<boost::serialization::primitive_type>
413                >,
414                mpl::identity<load_primitive>,
415            // else
416            BOOST_DEDUCED_TYPENAME mpl::eval_if<
417            // class info / version
418            mpl::greater_equal<
419                        boost::serialization::implementation_level< T >,
420                        mpl::int_<boost::serialization::object_class_info>
421                    >,
422            // do standard load
423            mpl::identity<load_standard>,
424        // else
425        BOOST_DEDUCED_TYPENAME mpl::eval_if<
426            // no tracking
427                    mpl::equal_to<
428                        boost::serialization::tracking_level< T >,
429                        mpl::int_<boost::serialization::track_never>
430                >,
431                // do a fast load
432                mpl::identity<load_only>,
433            // else
434            // do a fast load only tracking is turned off
435            mpl::identity<load_conditional>
436        > > >::type typex;
437        check_object_versioning< T >();
438        check_object_level< T >();
439        typex::invoke(ar, t);
440    }
441};
442
443template<class Archive>
444struct load_pointer_type {
445    struct abstract
446    {
447        template<class T>
448        static const basic_pointer_iserializer * register_type(Archive & /* ar */){
449            // it has? to be polymorphic
450            BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value);
451            return static_cast<basic_pointer_iserializer *>(NULL);
452         }
453    };
454
455    struct non_abstract
456    {
457        template<class T>
458        static const basic_pointer_iserializer * register_type(Archive & ar){
459            return ar.register_type(static_cast<T *>(NULL));
460        }
461    };
462
463    template<class T>
464    static const basic_pointer_iserializer * register_type(Archive &ar, const T & /*t*/){
465        // there should never be any need to load an abstract polymorphic 
466        // class pointer.  Inhibiting code generation for this
467        // permits abstract base classes to be used - note: exception
468        // virtual serialize functions used for plug-ins
469        typedef BOOST_DEDUCED_TYPENAME
470            mpl::eval_if<
471                boost::serialization::is_abstract<const T>,
472                boost::mpl::identity<abstract>,
473                boost::mpl::identity<non_abstract>  
474            >::type typex;
475        return typex::template register_type< T >(ar);
476    }
477
478    template<class T>
479    static T * pointer_tweak(
480        const boost::serialization::extended_type_info & eti,
481        void const * const t,
482        const T &
483    ) {
484        // tweak the pointer back to the base class
485        return static_cast<T *>(
486            const_cast<void *>(
487                boost::serialization::void_upcast(
488                    eti,
489                    boost::serialization::singleton<
490                        BOOST_DEDUCED_TYPENAME 
491                        boost::serialization::type_info_implementation< T >::type
492                    >::get_const_instance(),
493                    t
494                )
495            )
496        );
497    }
498
499    template<class T>
500    static void check_load(T & /* t */){
501        check_pointer_level< T >();
502        check_pointer_tracking< T >();
503    }
504
505    static const basic_pointer_iserializer *
506    find(const boost::serialization::extended_type_info & type){
507        return static_cast<const basic_pointer_iserializer *>(
508            archive_serializer_map<Archive>::find(type)
509        );
510    }
511
512    template<class Tptr>
513    static void invoke(Archive & ar, Tptr & t){
514        check_load(*t);
515        const basic_pointer_iserializer * bpis_ptr = register_type(ar, *t);
516        const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer(
517            // note major hack here !!!
518            // I tried every way to convert Tptr &t (where Tptr might
519            // include const) to void * &.  This is the only way
520            // I could make it work. RR
521            (void * & )t,
522            bpis_ptr,
523            find
524        );
525        // if the pointer isn't that of the base class
526        if(newbpis_ptr != bpis_ptr){
527            t = pointer_tweak(newbpis_ptr->get_eti(), t, *t);
528        }
529    }
530};
531
532template<class Archive>
533struct load_enum_type {
534    template<class T>
535    static void invoke(Archive &ar, T &t){
536        // convert integers to correct enum to load
537        int i;
538        ar >> boost::serialization::make_nvp(NULL, i);
539        t = static_cast< T >(i);
540    }
541};
542
543template<class Archive>
544struct load_array_type {
545    template<class T>
546    static void invoke(Archive &ar, T &t){
547        typedef BOOST_DEDUCED_TYPENAME remove_extent< T >::type value_type;
548        
549        // convert integers to correct enum to load
550        // determine number of elements in the array. Consider the
551        // fact that some machines will align elements on boundries
552        // other than characters.
553        std::size_t current_count = sizeof(t) / (
554            static_cast<char *>(static_cast<void *>(&t[1])) 
555            - static_cast<char *>(static_cast<void *>(&t[0]))
556        );
557        boost::serialization::collection_size_type count;
558        ar >> BOOST_SERIALIZATION_NVP(count);
559        if(static_cast<std::size_t>(count) > current_count)
560            boost::serialization::throw_exception(
561                archive::archive_exception(
562                    boost::archive::archive_exception::array_size_too_short
563                )
564            );
565        ar >> serialization::make_array(static_cast<value_type*>(&t[0]),count);
566    }
567};
568
569} // detail
570
571template<class Archive, class T>
572inline void load(Archive & ar, T &t){
573    // if this assertion trips. It means we're trying to load a
574    // const object with a compiler that doesn't have correct
575    // funtion template ordering.  On other compilers, this is
576    // handled below.
577    detail::check_const_loading< T >();
578    typedef
579        BOOST_DEDUCED_TYPENAME mpl::eval_if<is_pointer< T >,
580            mpl::identity<detail::load_pointer_type<Archive> >
581        ,//else
582        BOOST_DEDUCED_TYPENAME mpl::eval_if<is_array< T >,
583            mpl::identity<detail::load_array_type<Archive> >
584        ,//else
585        BOOST_DEDUCED_TYPENAME mpl::eval_if<is_enum< T >,
586            mpl::identity<detail::load_enum_type<Archive> >
587        ,//else
588            mpl::identity<detail::load_non_pointer_type<Archive> >
589        >
590        >
591        >::type typex;
592    typex::invoke(ar, t);
593}
594
595#if 0
596
597// BORLAND
598#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x560))
599// borland has a couple of problems
600// a) if function is partially specialized - see below
601// const paramters are transformed to non-const ones
602// b) implementation of base_object can't be made to work
603// correctly which results in all base_object s being const.
604// So, strip off the const for borland.  This breaks the trap
605// for loading const objects - but I see no alternative
606template<class Archive, class T>
607inline void load(Archive &ar, const T & t){
608    load(ar, const_cast<T &>(t));
609}
610#endif
611
612// let wrappers through.
613#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
614template<class Archive, class T>
615inline void load_wrapper(Archive &ar, const T&t, mpl::true_){
616    boost::archive::load(ar, const_cast<T&>(t));
617}
618
619#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x560))
620template<class Archive, class T>
621inline void load(Archive &ar, const T&t){
622  load_wrapper(ar,t,serialization::is_wrapper< T >());
623}
624#endif 
625#endif
626
627#endif
628
629} // namespace archive
630} // namespace boost
631
632#endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP