Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:27

0001 #ifndef BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP
0002 #define BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP
0003 
0004 // MS compatible compilers support #pragma once
0005 #if defined(BOOST_MSVC)
0006 # pragma once
0007 #if !defined(__clang__)
0008 #pragma inline_depth(255)
0009 #pragma inline_recursion(on)
0010 #endif
0011 #endif
0012 
0013 #if defined(__MWERKS__)
0014 #pragma inline_depth(255)
0015 #endif
0016 
0017 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
0018 // iserializer.hpp: interface for serialization system.
0019 
0020 // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
0021 // Use, modification and distribution is subject to the Boost Software
0022 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0023 // http://www.boost.org/LICENSE_1_0.txt)
0024 
0025 //  See http://www.boost.org for updates, documentation, and revision history.
0026 
0027 #include <new>     // for placement new
0028 #include <cstddef> // size_t, NULL
0029 
0030 #include <boost/config.hpp>
0031 #include <boost/detail/workaround.hpp>
0032 #if defined(BOOST_NO_STDC_NAMESPACE)
0033 namespace std{
0034     using ::size_t;
0035 } // namespace std
0036 #endif
0037 
0038 #include <boost/static_assert.hpp>
0039 
0040 #include <boost/mpl/eval_if.hpp>
0041 #include <boost/mpl/identity.hpp>
0042 #include <boost/mpl/greater_equal.hpp>
0043 #include <boost/mpl/equal_to.hpp>
0044 #include <boost/core/no_exceptions_support.hpp>
0045 
0046 #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO
0047     #include <boost/serialization/extended_type_info_typeid.hpp>
0048 #endif
0049 #include <boost/serialization/throw_exception.hpp>
0050 #include <boost/serialization/smart_cast.hpp>
0051 #include <boost/serialization/static_warning.hpp>
0052 
0053 #include <boost/type_traits/is_pointer.hpp>
0054 #include <boost/type_traits/is_enum.hpp>
0055 #include <boost/type_traits/is_const.hpp>
0056 #include <boost/type_traits/remove_const.hpp>
0057 #include <boost/type_traits/remove_extent.hpp>
0058 #include <boost/type_traits/is_polymorphic.hpp>
0059 
0060 #include <boost/serialization/assume_abstract.hpp>
0061 
0062 #if !defined(BOOST_MSVC) && \
0063     (BOOST_WORKAROUND(__IBMCPP__, < 1210) || \
0064     defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x590))
0065     #define BOOST_SERIALIZATION_DONT_USE_HAS_NEW_OPERATOR 1
0066 #else
0067     #define BOOST_SERIALIZATION_DONT_USE_HAS_NEW_OPERATOR 0
0068 #endif
0069 
0070 #if ! BOOST_SERIALIZATION_DONT_USE_HAS_NEW_OPERATOR
0071 #include <boost/type_traits/has_new_operator.hpp>
0072 #endif
0073 
0074 #include <boost/serialization/serialization.hpp>
0075 #include <boost/serialization/version.hpp>
0076 #include <boost/serialization/level.hpp>
0077 #include <boost/serialization/tracking.hpp>
0078 #include <boost/serialization/type_info_implementation.hpp>
0079 #include <boost/serialization/nvp.hpp>
0080 #include <boost/serialization/void_cast.hpp>
0081 #include <boost/serialization/collection_size_type.hpp>
0082 #include <boost/serialization/singleton.hpp>
0083 #include <boost/serialization/wrapper.hpp>
0084 #include <boost/serialization/array_wrapper.hpp>
0085 
0086 // the following is need only for dynamic cast of polymorphic pointers
0087 #include <boost/archive/archive_exception.hpp>
0088 #include <boost/archive/detail/basic_iarchive.hpp>
0089 #include <boost/archive/detail/basic_iserializer.hpp>
0090 #include <boost/archive/detail/basic_pointer_iserializer.hpp>
0091 #include <boost/archive/detail/archive_serializer_map.hpp>
0092 #include <boost/archive/detail/check.hpp>
0093 
0094 #include <boost/core/addressof.hpp>
0095 
0096 namespace boost {
0097 
0098 namespace serialization {
0099     class extended_type_info;
0100 } // namespace serialization
0101 
0102 namespace archive {
0103 
0104 // an accessor to permit friend access to archives.  Needed because
0105 // some compilers don't handle friend templates completely
0106 class load_access {
0107 public:
0108     template<class Archive, class T>
0109     static void load_primitive(Archive &ar, T &t){
0110         ar.load(t);
0111     }
0112 };
0113 
0114 namespace detail {
0115 
0116 #ifdef BOOST_MSVC
0117 #  pragma warning(push)
0118 #  pragma warning(disable : 4511 4512)
0119 #endif
0120 
0121 template<class Archive, class T>
0122 class iserializer : public basic_iserializer
0123 {
0124 private:
0125     void destroy(/*const*/ void *address) const BOOST_OVERRIDE {
0126         boost::serialization::access::destroy(static_cast<T *>(address));
0127     }
0128 public:
0129     explicit iserializer() :
0130         basic_iserializer(
0131             boost::serialization::singleton<
0132                 typename
0133                 boost::serialization::type_info_implementation< T >::type
0134             >::get_const_instance()
0135         )
0136     {}
0137     BOOST_DLLEXPORT void load_object_data(
0138         basic_iarchive & ar,
0139         void *x,
0140         const unsigned int file_version
0141     ) const BOOST_OVERRIDE BOOST_USED;
0142     bool class_info() const BOOST_OVERRIDE {
0143         return boost::serialization::implementation_level< T >::value
0144             >= boost::serialization::object_class_info;
0145     }
0146     bool tracking(const unsigned int /* flags */) const BOOST_OVERRIDE {
0147         return boost::serialization::tracking_level< T >::value
0148                 == boost::serialization::track_always
0149             || ( boost::serialization::tracking_level< T >::value
0150                 == boost::serialization::track_selectively
0151                 && serialized_as_pointer());
0152     }
0153     version_type version() const BOOST_OVERRIDE {
0154         return version_type(::boost::serialization::version< T >::value);
0155     }
0156     bool is_polymorphic() const BOOST_OVERRIDE {
0157         return boost::is_polymorphic< T >::value;
0158     }
0159     ~iserializer() BOOST_OVERRIDE {}
0160 };
0161 
0162 #ifdef BOOST_MSVC
0163 #  pragma warning(pop)
0164 #endif
0165 
0166 template<class Archive, class T>
0167 BOOST_DLLEXPORT void iserializer<Archive, T>::load_object_data(
0168     basic_iarchive & ar,
0169     void *x,
0170     const unsigned int file_version
0171 ) const {
0172     // note: we now comment this out. Before we permitted archive
0173     // version # to be very large.  Now we don't.  To permit
0174     // readers of these old archives, we have to suppress this
0175     // code.  Perhaps in the future we might re-enable it but
0176     // permit its suppression with a runtime switch.
0177     #if 1
0178     // trap case where the program cannot handle the current version
0179     if(file_version > static_cast<const unsigned int>(version()))
0180         boost::serialization::throw_exception(
0181             archive::archive_exception(
0182                 boost::archive::archive_exception::unsupported_class_version,
0183                 get_debug_info()
0184             )
0185         );
0186     #endif
0187     // make sure call is routed through the highest interface that might
0188     // be specialized by the user.
0189     boost::serialization::serialize_adl(
0190         boost::serialization::smart_cast_reference<Archive &>(ar),
0191         * static_cast<T *>(x),
0192         file_version
0193     );
0194 }
0195 
0196 #ifdef BOOST_MSVC
0197 #  pragma warning(push)
0198 #  pragma warning(disable : 4511 4512)
0199 #endif
0200 
0201 // the purpose of this code is to allocate memory for an object
0202 // without requiring the constructor to be called.  Presumably
0203 // the allocated object will be subsequently initialized with
0204 // "placement new".
0205 // note: we have the boost type trait has_new_operator but we
0206 // have no corresponding has_delete_operator.  So we presume
0207 // that the former being true would imply that the a delete
0208 // operator is also defined for the class T.
0209 
0210 template<class T>
0211 struct heap_allocation {
0212     // boost::has_new_operator< T > doesn't work on these compilers
0213     #if BOOST_SERIALIZATION_DONT_USE_HAS_NEW_OPERATOR
0214         // This doesn't handle operator new overload for class T
0215         static T * invoke_new(){
0216             return static_cast<T *>(operator new(sizeof(T)));
0217         }
0218         static void invoke_delete(T *t){
0219             (operator delete(t));
0220         }
0221     #else
0222         // note: we presume that a true value for has_new_operator
0223         // implies the existence of a class specific delete operator as well
0224         // as a class specific new operator.
0225         struct has_new_operator {
0226             static T * invoke_new() {
0227                 return static_cast<T *>((T::operator new)(sizeof(T)));
0228             }
0229             static void invoke_delete(T * t) {
0230                 // if compilation fails here, the likely cause that the class
0231                 // T has a class specific new operator but no class specific
0232                 // delete operator which matches the following signature.
0233                 // note that this solution addresses the issue that two
0234                 // possible signatures.  But it doesn't address the possibility
0235                 // that the class might have class specific new with NO
0236                 // class specific delete at all.  Patches (compatible with
0237                 // C++03) welcome!
0238                 (operator delete)(t);
0239             }
0240         };
0241         struct doesnt_have_new_operator {
0242             static T* invoke_new() {
0243                 return static_cast<T *>(operator new(sizeof(T)));
0244             }
0245             static void invoke_delete(T * t) {
0246                 // Note: I'm reliance upon automatic conversion from T * to void * here
0247                 (operator delete)(t);
0248             }
0249         };
0250         static T * invoke_new() {
0251             typedef typename
0252                 mpl::eval_if<
0253                     boost::has_new_operator< T >,
0254                     mpl::identity<has_new_operator >,
0255                     mpl::identity<doesnt_have_new_operator >
0256                 >::type typex;
0257             return typex::invoke_new();
0258         }
0259         static void invoke_delete(T *t) {
0260             typedef typename
0261                 mpl::eval_if<
0262                     boost::has_new_operator< T >,
0263                     mpl::identity<has_new_operator >,
0264                     mpl::identity<doesnt_have_new_operator >
0265                 >::type typex;
0266             typex::invoke_delete(t);
0267         }
0268     #endif
0269     explicit heap_allocation(){
0270         m_p = invoke_new();
0271     }
0272     ~heap_allocation(){
0273         if (0 != m_p)
0274             invoke_delete(m_p);
0275     }
0276     T* get() const {
0277         return m_p;
0278     }
0279 
0280     T* release() {
0281         T* p = m_p;
0282         m_p = 0;
0283         return p;
0284     }
0285 private:
0286     T* m_p;
0287 };
0288 
0289 template<class Archive, class T>
0290 class pointer_iserializer :
0291     public basic_pointer_iserializer
0292 {
0293 private:
0294     void * heap_allocation() const BOOST_OVERRIDE {
0295         detail::heap_allocation<T> h;
0296         T * t = h.get();
0297         h.release();
0298         return t;
0299     }
0300     const basic_iserializer & get_basic_serializer() const BOOST_OVERRIDE {
0301         return boost::serialization::singleton<
0302             iserializer<Archive, T>
0303         >::get_const_instance();
0304     }
0305     BOOST_DLLEXPORT void load_object_ptr(
0306         basic_iarchive & ar,
0307         void * x,
0308         const unsigned int file_version
0309     ) const BOOST_OVERRIDE BOOST_USED;
0310 public:
0311     // this should always be a singleton so make the constructor protected
0312     pointer_iserializer();
0313     ~pointer_iserializer() BOOST_OVERRIDE;
0314 };
0315 
0316 #ifdef BOOST_MSVC
0317 #  pragma warning(pop)
0318 #endif
0319 
0320 // note: BOOST_DLLEXPORT is so that code for polymorphic class
0321 // serialized only through base class won't get optimized out
0322 template<class Archive, class T>
0323 BOOST_DLLEXPORT void pointer_iserializer<Archive, T>::load_object_ptr(
0324     basic_iarchive & ar,
0325     void * t,
0326     const unsigned int file_version
0327 ) const
0328 {
0329     Archive & ar_impl =
0330         boost::serialization::smart_cast_reference<Archive &>(ar);
0331 
0332     // note that the above will throw std::bad_alloc if the allocation
0333     // fails so we don't have to address this contingency here.
0334 
0335     // catch exception during load_construct_data so that we don't
0336     // automatically delete the t which is most likely not fully
0337     // constructed
0338     BOOST_TRY {
0339         // this addresses an obscure situation that occurs when
0340         // load_constructor de-serializes something through a pointer.
0341         ar.next_object_pointer(t);
0342         boost::serialization::load_construct_data_adl<Archive, T>(
0343             ar_impl,
0344             static_cast<T *>(t),
0345             file_version
0346         );
0347     }
0348     BOOST_CATCH(...){
0349         // if we get here the load_construct failed.  The heap_allocation
0350         // will be automatically deleted so we don't have to do anything
0351         // special here.
0352         BOOST_RETHROW;
0353     }
0354     BOOST_CATCH_END
0355 
0356     ar_impl >> boost::serialization::make_nvp(NULL, * static_cast<T *>(t));
0357 }
0358 
0359 template<class Archive, class T>
0360 pointer_iserializer<Archive, T>::pointer_iserializer() :
0361     basic_pointer_iserializer(
0362         boost::serialization::singleton<
0363             typename
0364             boost::serialization::type_info_implementation< T >::type
0365         >::get_const_instance()
0366     )
0367 {
0368     boost::serialization::singleton<
0369         iserializer<Archive, T>
0370     >::get_mutable_instance().set_bpis(this);
0371     archive_serializer_map<Archive>::insert(this);
0372 }
0373 
0374 template<class Archive, class T>
0375 pointer_iserializer<Archive, T>::~pointer_iserializer(){
0376     archive_serializer_map<Archive>::erase(this);
0377 }
0378 
0379 template<class Archive>
0380 struct load_non_pointer_type {
0381     // note this bounces the call right back to the archive
0382     // with no runtime overhead
0383     struct load_primitive {
0384         template<class T>
0385         static void invoke(Archive & ar, T & t){
0386             load_access::load_primitive(ar, t);
0387         }
0388     };
0389     // note this bounces the call right back to the archive
0390     // with no runtime overhead
0391     struct load_only {
0392         template<class T>
0393         static void invoke(Archive & ar, const T & t){
0394             // short cut to user's serializer
0395             // make sure call is routed through the highest interface that might
0396             // be specialized by the user.
0397             boost::serialization::serialize_adl(
0398                 ar,
0399                 const_cast<T &>(t),
0400                 boost::serialization::version< T >::value
0401             );
0402         }
0403     };
0404 
0405     // note this save class information including version
0406     // and serialization level to the archive
0407     struct load_standard {
0408         template<class T>
0409         static void invoke(Archive &ar, const T & t){
0410             void * x = boost::addressof(const_cast<T &>(t));
0411             ar.load_object(
0412                 x,
0413                 boost::serialization::singleton<
0414                     iserializer<Archive, T>
0415                 >::get_const_instance()
0416             );
0417         }
0418     };
0419 
0420     struct load_conditional {
0421         template<class T>
0422         static void invoke(Archive &ar, T &t){
0423             //if(0 == (ar.get_flags() & no_tracking))
0424                 load_standard::invoke(ar, t);
0425             //else
0426             //    load_only::invoke(ar, t);
0427         }
0428     };
0429 
0430     template<class T>
0431     static void invoke(Archive & ar, T &t){
0432         typedef typename mpl::eval_if<
0433                 // if its primitive
0434                 mpl::equal_to<
0435                     boost::serialization::implementation_level< T >,
0436                     mpl::int_<boost::serialization::primitive_type>
0437                 >,
0438                 mpl::identity<load_primitive>,
0439             // else
0440             typename mpl::eval_if<
0441             // class info / version
0442             mpl::greater_equal<
0443                         boost::serialization::implementation_level< T >,
0444                         mpl::int_<boost::serialization::object_class_info>
0445                     >,
0446             // do standard load
0447             mpl::identity<load_standard>,
0448         // else
0449         typename mpl::eval_if<
0450             // no tracking
0451                     mpl::equal_to<
0452                         boost::serialization::tracking_level< T >,
0453                         mpl::int_<boost::serialization::track_never>
0454                 >,
0455                 // do a fast load
0456                 mpl::identity<load_only>,
0457             // else
0458             // do a fast load only tracking is turned off
0459             mpl::identity<load_conditional>
0460         > > >::type typex;
0461         check_object_versioning< T >();
0462         check_object_level< T >();
0463         typex::invoke(ar, t);
0464     }
0465 };
0466 
0467 template<class Archive>
0468 struct load_pointer_type {
0469     struct abstract
0470     {
0471         template<class T>
0472         static const basic_pointer_iserializer * register_type(Archive & /* ar */){
0473             // it has? to be polymorphic
0474             BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value);
0475             return static_cast<basic_pointer_iserializer *>(NULL);
0476          }
0477     };
0478 
0479     struct non_abstract
0480     {
0481         template<class T>
0482         static const basic_pointer_iserializer * register_type(Archive & ar){
0483             return ar.register_type(static_cast<T *>(NULL));
0484         }
0485     };
0486 
0487     template<class T>
0488     static const basic_pointer_iserializer * register_type(Archive &ar, const T* const /*t*/){
0489         // there should never be any need to load an abstract polymorphic
0490         // class pointer.  Inhibiting code generation for this
0491         // permits abstract base classes to be used - note: exception
0492         // virtual serialize functions used for plug-ins
0493         typedef typename
0494             mpl::eval_if<
0495                 boost::serialization::is_abstract<const T>,
0496                 boost::mpl::identity<abstract>,
0497                 boost::mpl::identity<non_abstract>
0498             >::type typex;
0499         return typex::template register_type< T >(ar);
0500     }
0501 
0502     template<class T>
0503     static T * pointer_tweak(
0504         const boost::serialization::extended_type_info & eti,
0505         void const * const t,
0506         const T &
0507     ) {
0508         // tweak the pointer back to the base class
0509         void * upcast = const_cast<void *>(
0510             boost::serialization::void_upcast(
0511                 eti,
0512                 boost::serialization::singleton<
0513                     typename
0514                     boost::serialization::type_info_implementation< T >::type
0515                 >::get_const_instance(),
0516                 t
0517             )
0518         );
0519         if(NULL == upcast)
0520             boost::serialization::throw_exception(
0521                 archive_exception(archive_exception::unregistered_class)
0522             );
0523         return static_cast<T *>(upcast);
0524     }
0525 
0526     template<class T>
0527     static void check_load(T * const /* t */){
0528         check_pointer_level< T >();
0529         check_pointer_tracking< T >();
0530     }
0531 
0532     static const basic_pointer_iserializer *
0533     find(const boost::serialization::extended_type_info & type){
0534         return static_cast<const basic_pointer_iserializer *>(
0535             archive_serializer_map<Archive>::find(type)
0536         );
0537     }
0538 
0539     template<class Tptr>
0540     static void invoke(Archive & ar, Tptr & t){
0541         check_load(t);
0542         const basic_pointer_iserializer * bpis_ptr = register_type(ar, t);
0543         const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer(
0544             // note major hack here !!!
0545             // I tried every way to convert Tptr &t (where Tptr might
0546             // include const) to void * &.  This is the only way
0547             // I could make it work. RR
0548             (void * & )t,
0549             bpis_ptr,
0550             find
0551         );
0552         // if the pointer isn't that of the base class
0553         if(newbpis_ptr != bpis_ptr){
0554             t = pointer_tweak(newbpis_ptr->get_eti(), t, *t);
0555         }
0556     }
0557 };
0558 
0559 template<class Archive>
0560 struct load_enum_type {
0561     template<class T>
0562     static void invoke(Archive &ar, T &t){
0563         // convert integers to correct enum to load
0564         int i;
0565         ar >> boost::serialization::make_nvp(NULL, i);
0566         t = static_cast< T >(i);
0567     }
0568 };
0569 
0570 template<class Archive>
0571 struct load_array_type {
0572     template<class T>
0573     static void invoke(Archive &ar, T &t){
0574         typedef typename remove_extent< T >::type value_type;
0575 
0576         // convert integers to correct enum to load
0577         // determine number of elements in the array. Consider the
0578         // fact that some machines will align elements on boundaries
0579         // other than characters.
0580         std::size_t current_count = sizeof(t) / (
0581             static_cast<char *>(static_cast<void *>(&t[1]))
0582             - static_cast<char *>(static_cast<void *>(&t[0]))
0583         );
0584         boost::serialization::collection_size_type count;
0585         ar >> BOOST_SERIALIZATION_NVP(count);
0586         if(static_cast<std::size_t>(count) > current_count)
0587             boost::serialization::throw_exception(
0588                 archive::archive_exception(
0589                     boost::archive::archive_exception::array_size_too_short
0590                 )
0591             );
0592         // explicit template arguments to pass intel C++ compiler
0593         ar >> serialization::make_array<
0594             value_type,
0595             boost::serialization::collection_size_type
0596         >(
0597             static_cast<value_type *>(&t[0]),
0598             count
0599         );
0600     }
0601 };
0602 
0603 } // detail
0604 
0605 template<class Archive, class T>
0606 inline void load(Archive & ar, T &t){
0607     // if this assertion trips. It means we're trying to load a
0608     // const object with a compiler that doesn't have correct
0609     // function template ordering.  On other compilers, this is
0610     // handled below.
0611     detail::check_const_loading< T >();
0612     typedef
0613         typename mpl::eval_if<is_pointer< T >,
0614             mpl::identity<detail::load_pointer_type<Archive> >
0615         ,//else
0616         typename mpl::eval_if<is_array< T >,
0617             mpl::identity<detail::load_array_type<Archive> >
0618         ,//else
0619         typename mpl::eval_if<is_enum< T >,
0620             mpl::identity<detail::load_enum_type<Archive> >
0621         ,//else
0622             mpl::identity<detail::load_non_pointer_type<Archive> >
0623         >
0624         >
0625         >::type typex;
0626     typex::invoke(ar, t);
0627 }
0628 
0629 } // namespace archive
0630 } // namespace boost
0631 
0632 #endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP