Statistics
| Revision:

root / tmp / org.txm.statsengine.r.core.win32 / res / win32 / library / BH / include / boost / archive / detail / iserializer.hpp @ 2486

History | View | Annotate | Download (20.6 kB)

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)
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 <cstddef> // size_t, NULL
27

    
28
#include <boost/config.hpp>
29
#include <boost/detail/workaround.hpp>
30
#if defined(BOOST_NO_STDC_NAMESPACE)
31
namespace std{ 
32
    using ::size_t; 
33
} // namespace std
34
#endif
35

    
36
#include <boost/static_assert.hpp>
37

    
38
#include <boost/mpl/eval_if.hpp>
39
#include <boost/mpl/identity.hpp>
40
#include <boost/mpl/greater_equal.hpp>
41
#include <boost/mpl/equal_to.hpp>
42
#include <boost/mpl/bool.hpp>
43
#include <boost/core/no_exceptions_support.hpp>
44

    
45
#ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO   
46
    #include <boost/serialization/extended_type_info_typeid.hpp>   
47
#endif
48
#include <boost/serialization/throw_exception.hpp>
49
#include <boost/serialization/smart_cast.hpp>
50
#include <boost/serialization/static_warning.hpp>
51

    
52
#include <boost/type_traits/is_pointer.hpp>
53
#include <boost/type_traits/is_enum.hpp>
54
#include <boost/type_traits/is_const.hpp>
55
#include <boost/type_traits/remove_const.hpp>
56
#include <boost/type_traits/remove_extent.hpp>
57
#include <boost/type_traits/is_polymorphic.hpp>
58

    
59
#include <boost/serialization/assume_abstract.hpp>
60

    
61
#ifndef BOOST_MSVC
62
    #define DONT_USE_HAS_NEW_OPERATOR (                    \
63
           BOOST_WORKAROUND(__IBMCPP__, < 1210)            \
64
        || defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x590)   \
65
    )
66
#else
67
    #define DONT_USE_HAS_NEW_OPERATOR 0
68
#endif
69

    
70
#if ! DONT_USE_HAS_NEW_OPERATOR
71
#include <boost/type_traits/has_new_operator.hpp>
72
#endif
73

    
74
#include <boost/serialization/serialization.hpp>
75
#include <boost/serialization/version.hpp>
76
#include <boost/serialization/level.hpp>
77
#include <boost/serialization/tracking.hpp>
78
#include <boost/serialization/type_info_implementation.hpp>
79
#include <boost/serialization/nvp.hpp>
80
#include <boost/serialization/void_cast.hpp>
81
#include <boost/serialization/array.hpp>
82
#include <boost/serialization/collection_size_type.hpp>
83
#include <boost/serialization/singleton.hpp>
84
#include <boost/serialization/wrapper.hpp>
85

    
86
// the following is need only for dynamic cast of polymorphic pointers
87
#include <boost/archive/archive_exception.hpp>
88
#include <boost/archive/detail/basic_iarchive.hpp>
89
#include <boost/archive/detail/basic_iserializer.hpp>
90
#include <boost/archive/detail/basic_pointer_iserializer.hpp>
91
#include <boost/archive/detail/archive_serializer_map.hpp>
92
#include <boost/archive/detail/check.hpp>
93

    
94
namespace boost {
95

    
96
namespace serialization {
97
    class extended_type_info;
98
} // namespace serialization
99

    
100
namespace archive {
101

    
102
// an accessor to permit friend access to archives.  Needed because
103
// some compilers don't handle friend templates completely
104
class load_access {
105
public:
106
    template<class Archive, class T>
107
    static void load_primitive(Archive &ar, T &t){
108
        ar.load(t);
109
    }
110
};
111

    
112
namespace detail {
113

    
114
#ifdef BOOST_MSVC
115
#  pragma warning(push)
116
#  pragma warning(disable : 4511 4512)
117
#endif
118

    
119
template<class Archive, class T>
120
class iserializer : public basic_iserializer
121
{
122
private:
123
    virtual void destroy(/*const*/ void *address) const {
124
        boost::serialization::access::destroy(static_cast<T *>(address));
125
    }
126
protected:
127
    // protected constructor since it's always created by singleton
128
    explicit iserializer() :
129
        basic_iserializer(
130
            boost::serialization::singleton<
131
                typename 
132
                boost::serialization::type_info_implementation< T >::type
133
            >::get_const_instance()
134
        )
135
    {}
136
public:
137
    virtual BOOST_DLLEXPORT void load_object_data(
138
        basic_iarchive & ar,
139
        void *x, 
140
        const unsigned int file_version
141
    ) const BOOST_USED;
142
    virtual bool class_info() const {
143
        return boost::serialization::implementation_level< T >::value 
144
            >= boost::serialization::object_class_info;
145
    }
146
    virtual bool tracking(const unsigned int /* flags */) const {
147
        return boost::serialization::tracking_level< T >::value 
148
                == boost::serialization::track_always
149
            || ( boost::serialization::tracking_level< T >::value 
150
                == boost::serialization::track_selectively
151
                && serialized_as_pointer());
152
    }
153
    virtual version_type version() const {
154
        return version_type(::boost::serialization::version< T >::value);
155
    }
156
    virtual bool is_polymorphic() const {
157
        return boost::is_polymorphic< T >::value;
158
    }
159
    virtual ~iserializer(){};
160
};
161

    
162
#ifdef BOOST_MSVC
163
#  pragma warning(pop)
164
#endif
165

    
166
template<class Archive, class T>
167
BOOST_DLLEXPORT void iserializer<Archive, T>::load_object_data(
168
    basic_iarchive & ar,
169
    void *x, 
170
    const unsigned int file_version
171
) const {
172
    // note: we now comment this out. Before we permited archive
173
    // version # to be very large.  Now we don't.  To permit
174
    // readers of these old archives, we have to suppress this 
175
    // code.  Perhaps in the future we might re-enable it but
176
    // permit its suppression with a runtime switch.
177
    #if 0
178
    // trap case where the program cannot handle the current version
179
    if(file_version > static_cast<const unsigned int>(version()))
180
        boost::serialization::throw_exception(
181
            archive::archive_exception(
182
                boost::archive::archive_exception::unsupported_class_version,
183
                get_debug_info()
184
            )
185
        );
186
    #endif
187
    // make sure call is routed through the higest interface that might
188
    // be specialized by the user.
189
    boost::serialization::serialize_adl(
190
        boost::serialization::smart_cast_reference<Archive &>(ar),
191
        * static_cast<T *>(x), 
192
        file_version
193
    );
194
}
195

196
#ifdef BOOST_MSVC
197
#  pragma warning(push)
198
#  pragma warning(disable : 4511 4512)
199
#endif
200

    
201
// the purpose of this code is to allocate memory for an object
202
// without requiring the constructor to be called.  Presumably
203
// the allocated object will be subsequently initialized with
204
// "placement new". 
205
// note: we have the boost type trait has_new_operator but we
206
// have no corresponding has_delete_operator.  So we presume
207
// that the former being true would imply that the a delete
208
// operator is also defined for the class T.
209

    
210
template<class T>
211
struct heap_allocation {
212
    // boost::has_new_operator< T > doesn't work on these compilers
213
    #if DONT_USE_HAS_NEW_OPERATOR
214
        // This doesn't handle operator new overload for class T
215
        static T * invoke_new(){
216
            return static_cast<T *>(operator new(sizeof(T)));
217
        }
218
        static void invoke_delete(T *t){
219
            (operator delete(t));
220
        }
221
    #else
222
        // note: we presume that a true value for has_new_operator
223
        // implies the existence of a class specific delete operator as well
224
        // as a class specific new operator.
225
        struct has_new_operator {
226
            static T * invoke_new() {
227
                return static_cast<T *>((T::operator new)(sizeof(T)));
228
            }
229
            template<void D(void *, std::size_t)>
230
            static void deleter(void * t, std::size_t s){
231
                D(t, s);
232
            }
233

    
234
            template<void D(void *)>
235
            static void deleter(void * t, std::size_t s){
236
                D(t);
237
            }
238
            static void invoke_delete(T * t) {
239
                // if compilation fails here, the likely cause that the class
240
                // T has a class specific new operator but no class specific
241
                // delete operator which matches the following signature.
242
                // note that this solution addresses the issue that two
243
                // possible signatures.  But it doesn't address the possibility
244
                // that the class might have class specific new with NO
245
                // class specific delete at all.  Patches (compatible with
246
                // C++03) welcome!
247
                deleter<T::operator delete>(t, sizeof(T));
248
            }
249
        };
250
        struct doesnt_have_new_operator {
251
            static T* invoke_new() {
252
                return static_cast<T *>(operator new(sizeof(T)));
253
            }
254
            static void invoke_delete(T * t) {
255
                // Note: I'm reliance upon automatic conversion from T * to void * here
256
                (operator delete)(t);
257
            }
258
        };
259
        static T * invoke_new() {
260
            typedef typename
261
                mpl::eval_if<
262
                    boost::has_new_operator< T >,
263
                    mpl::identity<has_new_operator >,
264
                    mpl::identity<doesnt_have_new_operator >    
265
                >::type typex;
266
            return typex::invoke_new();
267
        }
268
        static void invoke_delete(T *t) {
269
            typedef typename
270
                mpl::eval_if<
271
                    boost::has_new_operator< T >,
272
                    mpl::identity<has_new_operator >,
273
                    mpl::identity<doesnt_have_new_operator >    
274
                >::type typex;
275
            typex::invoke_delete(t);
276
        }
277
    #endif
278
    explicit heap_allocation(){
279
        m_p = invoke_new();
280
    }
281
    ~heap_allocation(){
282
        if (0 != m_p)
283
            invoke_delete(m_p);
284
    }
285
    T* get() const {
286
        return m_p;
287
    }
288

    
289
    T* release() {
290
        T* p = m_p;
291
        m_p = 0;
292
        return p;
293
    }
294
private:
295
    T* m_p;
296
};
297

    
298
template<class Archive, class T>
299
class pointer_iserializer :
300
    public basic_pointer_iserializer
301
{
302
private:
303
    virtual void * heap_allocation() const {
304
        detail::heap_allocation<T> h;
305
        T * t = h.get();
306
        h.release();
307
        return t;
308
    }
309
    virtual const basic_iserializer & get_basic_serializer() const {
310
        return boost::serialization::singleton<
311
            iserializer<Archive, T>
312
        >::get_const_instance();
313
    }
314
    BOOST_DLLEXPORT virtual void load_object_ptr(
315
        basic_iarchive & ar, 
316
        void * x,
317
        const unsigned int file_version
318
    ) const BOOST_USED;
319
protected:
320
    // this should alway be a singleton so make the constructor protected
321
    pointer_iserializer();
322
    ~pointer_iserializer();
323
};
324

    
325
#ifdef BOOST_MSVC
326
#  pragma warning(pop)
327
#endif
328

    
329
// note: BOOST_DLLEXPORT is so that code for polymorphic class
330
// serialized only through base class won't get optimized out
331
template<class Archive, class T>
332
BOOST_DLLEXPORT void pointer_iserializer<Archive, T>::load_object_ptr(
333
    basic_iarchive & ar, 
334
    void * t,
335
    const unsigned int file_version
336
) const
337
{
338
    Archive & ar_impl = 
339
        boost::serialization::smart_cast_reference<Archive &>(ar);
340

    
341
    // note that the above will throw std::bad_alloc if the allocation
342
    // fails so we don't have to address this contingency here.
343

    
344
    // catch exception during load_construct_data so that we don't
345
    // automatically delete the t which is most likely not fully
346
    // constructed
347
    BOOST_TRY {
348
        // this addresses an obscure situation that occurs when 
349
        // load_constructor de-serializes something through a pointer.
350
        ar.next_object_pointer(t);
351
        boost::serialization::load_construct_data_adl<Archive, T>(
352
            ar_impl,
353
            static_cast<T *>(t),
354
            file_version
355
        );
356
    }
357
    BOOST_CATCH(...){
358
        // if we get here the load_construct failed.  The heap_allocation
359
        // will be automatically deleted so we don't have to do anything
360
        // special here.
361
        BOOST_RETHROW;
362
    }
363
    BOOST_CATCH_END
364

    
365
    ar_impl >> boost::serialization::make_nvp(NULL, * static_cast<T *>(t));
366
}
367

    
368
template<class Archive, class T>
369
pointer_iserializer<Archive, T>::pointer_iserializer() :
370
    basic_pointer_iserializer(
371
        boost::serialization::singleton<
372
            typename 
373
            boost::serialization::type_info_implementation< T >::type
374
        >::get_const_instance()
375
    )
376
{
377
    boost::serialization::singleton<
378
        iserializer<Archive, T>
379
    >::get_mutable_instance().set_bpis(this);
380
    archive_serializer_map<Archive>::insert(this);
381
}
382

    
383
template<class Archive, class T>
384
pointer_iserializer<Archive, T>::~pointer_iserializer(){
385
    archive_serializer_map<Archive>::erase(this);
386
}
387

    
388
template<class Archive>
389
struct load_non_pointer_type {
390
    // note this bounces the call right back to the archive
391
    // with no runtime overhead
392
    struct load_primitive {
393
        template<class T>
394
        static void invoke(Archive & ar, T & t){
395
            load_access::load_primitive(ar, t);
396
        }
397
    };
398
    // note this bounces the call right back to the archive
399
    // with no runtime overhead
400
    struct load_only {
401
        template<class T>
402
        static void invoke(Archive & ar, const T & t){
403
            // short cut to user's serializer
404
            // make sure call is routed through the higest interface that might
405
            // be specialized by the user.
406
            boost::serialization::serialize_adl(
407
                ar, 
408
                const_cast<T &>(t), 
409
                boost::serialization::version< T >::value
410
            );
411
        }
412
    };
413

    
414
    // note this save class information including version
415
    // and serialization level to the archive
416
    struct load_standard {
417
        template<class T>
418
        static void invoke(Archive &ar, const T & t){
419
            void * x = & const_cast<T &>(t);
420
            ar.load_object(
421
                x, 
422
                boost::serialization::singleton<
423
                    iserializer<Archive, T>
424
                >::get_const_instance()
425
            );
426
        }
427
    };
428

    
429
    struct load_conditional {
430
        template<class T>
431
        static void invoke(Archive &ar, T &t){
432
            //if(0 == (ar.get_flags() & no_tracking))
433
                load_standard::invoke(ar, t);
434
            //else
435
            //    load_only::invoke(ar, t);
436
        }
437
    };
438

    
439
    template<class T>
440
    static void invoke(Archive & ar, T &t){
441
        typedef typename mpl::eval_if<
442
                // if its primitive
443
                mpl::equal_to<
444
                    boost::serialization::implementation_level< T >,
445
                    mpl::int_<boost::serialization::primitive_type>
446
                >,
447
                mpl::identity<load_primitive>,
448
            // else
449
            typename mpl::eval_if<
450
            // class info / version
451
            mpl::greater_equal<
452
                        boost::serialization::implementation_level< T >,
453
                        mpl::int_<boost::serialization::object_class_info>
454
                    >,
455
            // do standard load
456
            mpl::identity<load_standard>,
457
        // else
458
        typename mpl::eval_if<
459
            // no tracking
460
                    mpl::equal_to<
461
                        boost::serialization::tracking_level< T >,
462
                        mpl::int_<boost::serialization::track_never>
463
                >,
464
                // do a fast load
465
                mpl::identity<load_only>,
466
            // else
467
            // do a fast load only tracking is turned off
468
            mpl::identity<load_conditional>
469
        > > >::type typex;
470
        check_object_versioning< T >();
471
        check_object_level< T >();
472
        typex::invoke(ar, t);
473
    }
474
};
475

    
476
template<class Archive>
477
struct load_pointer_type {
478
    struct abstract
479
    {
480
        template<class T>
481
        static const basic_pointer_iserializer * register_type(Archive & /* ar */){
482
            // it has? to be polymorphic
483
            BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value);
484
            return static_cast<basic_pointer_iserializer *>(NULL);
485
         }
486
    };
487

    
488
    struct non_abstract
489
    {
490
        template<class T>
491
        static const basic_pointer_iserializer * register_type(Archive & ar){
492
            return ar.register_type(static_cast<T *>(NULL));
493
        }
494
    };
495

    
496
    template<class T>
497
    static const basic_pointer_iserializer * register_type(Archive &ar, const T & /*t*/){
498
        // there should never be any need to load an abstract polymorphic 
499
        // class pointer.  Inhibiting code generation for this
500
        // permits abstract base classes to be used - note: exception
501
        // virtual serialize functions used for plug-ins
502
        typedef typename
503
            mpl::eval_if<
504
                boost::serialization::is_abstract<const T>,
505
                boost::mpl::identity<abstract>,
506
                boost::mpl::identity<non_abstract>  
507
            >::type typex;
508
        return typex::template register_type< T >(ar);
509
    }
510

    
511
    template<class T>
512
    static T * pointer_tweak(
513
        const boost::serialization::extended_type_info & eti,
514
        void const * const t,
515
        const T &
516
    ) {
517
        // tweak the pointer back to the base class
518
        void * upcast = const_cast<void *>(
519
            boost::serialization::void_upcast(
520
                eti,
521
                boost::serialization::singleton<
522
                    typename 
523
                    boost::serialization::type_info_implementation< T >::type
524
                >::get_const_instance(),
525
                t
526
            )
527
        );
528
        if(NULL == upcast)
529
            boost::serialization::throw_exception(
530
                archive_exception(archive_exception::unregistered_class)
531
            );
532
        return static_cast<T *>(upcast);
533
    }
534

    
535
    template<class T>
536
    static void check_load(T & /* t */){
537
        check_pointer_level< T >();
538
        check_pointer_tracking< T >();
539
    }
540

    
541
    static const basic_pointer_iserializer *
542
    find(const boost::serialization::extended_type_info & type){
543
        return static_cast<const basic_pointer_iserializer *>(
544
            archive_serializer_map<Archive>::find(type)
545
        );
546
    }
547

    
548
    template<class Tptr>
549
    static void invoke(Archive & ar, Tptr & t){
550
        check_load(*t);
551
        const basic_pointer_iserializer * bpis_ptr = register_type(ar, *t);
552
        const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer(
553
            // note major hack here !!!
554
            // I tried every way to convert Tptr &t (where Tptr might
555
            // include const) to void * &.  This is the only way
556
            // I could make it work. RR
557
            (void * & )t,
558
            bpis_ptr,
559
            find
560
        );
561
        // if the pointer isn't that of the base class
562
        if(newbpis_ptr != bpis_ptr){
563
            t = pointer_tweak(newbpis_ptr->get_eti(), t, *t);
564
        }
565
    }
566
};
567

    
568
template<class Archive>
569
struct load_enum_type {
570
    template<class T>
571
    static void invoke(Archive &ar, T &t){
572
        // convert integers to correct enum to load
573
        int i;
574
        ar >> boost::serialization::make_nvp(NULL, i);
575
        t = static_cast< T >(i);
576
    }
577
};
578

    
579
template<class Archive>
580
struct load_array_type {
581
    template<class T>
582
    static void invoke(Archive &ar, T &t){
583
        typedef typename remove_extent< T >::type value_type;
584
        
585
        // convert integers to correct enum to load
586
        // determine number of elements in the array. Consider the
587
        // fact that some machines will align elements on boundries
588
        // other than characters.
589
        std::size_t current_count = sizeof(t) / (
590
            static_cast<char *>(static_cast<void *>(&t[1])) 
591
            - static_cast<char *>(static_cast<void *>(&t[0]))
592
        );
593
        boost::serialization::collection_size_type count;
594
        ar >> BOOST_SERIALIZATION_NVP(count);
595
        if(static_cast<std::size_t>(count) > current_count)
596
            boost::serialization::throw_exception(
597
                archive::archive_exception(
598
                    boost::archive::archive_exception::array_size_too_short
599
                )
600
            );
601
        ar >> serialization::make_array(static_cast<value_type*>(&t[0]),count);
602
    }
603
};
604

    
605
} // detail
606

    
607
template<class Archive, class T>
608
inline void load(Archive & ar, T &t){
609
    // if this assertion trips. It means we're trying to load a
610
    // const object with a compiler that doesn't have correct
611
    // funtion template ordering.  On other compilers, this is
612
    // handled below.
613
    detail::check_const_loading< T >();
614
    typedef
615
        typename mpl::eval_if<is_pointer< T >,
616
            mpl::identity<detail::load_pointer_type<Archive> >
617
        ,//else
618
        typename mpl::eval_if<is_array< T >,
619
            mpl::identity<detail::load_array_type<Archive> >
620
        ,//else
621
        typename mpl::eval_if<is_enum< T >,
622
            mpl::identity<detail::load_enum_type<Archive> >
623
        ,//else
624
            mpl::identity<detail::load_non_pointer_type<Archive> >
625
        >
626
        >
627
        >::type typex;
628
    typex::invoke(ar, t);
629
}
630

    
631
} // namespace archive
632
} // namespace boost
633

    
634
#endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP