| #ifndef BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP |
| #define BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP |
| |
| // MS compatible compilers support #pragma once |
| #if defined(_MSC_VER) && (_MSC_VER >= 1020) |
| # pragma once |
| #pragma inline_depth(511) |
| #pragma inline_recursion(on) |
| #endif |
| |
| #if defined(__MWERKS__) |
| #pragma inline_depth(511) |
| #endif |
| |
| /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 |
| // iserializer.hpp: interface for serialization system. |
| |
| // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . |
| // Use, modification and distribution is subject to the Boost Software |
| // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| |
| // See http://www.boost.org for updates, documentation, and revision history. |
| |
| #include <new> // for placement new |
| #include <memory> // for auto_ptr |
| #include <cstddef> // size_t, NULL |
| |
| #include <boost/config.hpp> |
| #include <boost/detail/workaround.hpp> |
| #if defined(BOOST_NO_STDC_NAMESPACE) |
| namespace std{ |
| using ::size_t; |
| } // namespace std |
| #endif |
| |
| #include <boost/static_assert.hpp> |
| |
| #include <boost/mpl/eval_if.hpp> |
| #include <boost/mpl/identity.hpp> |
| #include <boost/mpl/greater_equal.hpp> |
| #include <boost/mpl/equal_to.hpp> |
| #include <boost/mpl/bool.hpp> |
| #include <boost/detail/no_exceptions_support.hpp> |
| |
| #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO |
| #include <boost/serialization/extended_type_info_typeid.hpp> |
| #endif |
| #include <boost/serialization/throw_exception.hpp> |
| #include <boost/serialization/smart_cast.hpp> |
| #include <boost/serialization/static_warning.hpp> |
| |
| #include <boost/type_traits/is_pointer.hpp> |
| #include <boost/type_traits/is_enum.hpp> |
| #include <boost/type_traits/is_const.hpp> |
| #include <boost/type_traits/remove_const.hpp> |
| #include <boost/type_traits/remove_extent.hpp> |
| #include <boost/type_traits/is_polymorphic.hpp> |
| |
| #include <boost/serialization/assume_abstract.hpp> |
| |
| #define DONT_USE_HAS_NEW_OPERATOR ( \ |
| defined(__BORLANDC__) \ |
| || defined(__IBMCPP__) \ |
| || defined(BOOST_MSVC) && (BOOST_MSVC <= 1300) \ |
| || defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x590) \ |
| ) |
| |
| #if ! DONT_USE_HAS_NEW_OPERATOR |
| #include <boost/type_traits/has_new_operator.hpp> |
| #endif |
| |
| #include <boost/serialization/serialization.hpp> |
| #include <boost/serialization/version.hpp> |
| #include <boost/serialization/level.hpp> |
| #include <boost/serialization/tracking.hpp> |
| #include <boost/serialization/type_info_implementation.hpp> |
| #include <boost/serialization/nvp.hpp> |
| #include <boost/serialization/void_cast.hpp> |
| #include <boost/serialization/array.hpp> |
| #include <boost/serialization/collection_size_type.hpp> |
| #include <boost/serialization/singleton.hpp> |
| #include <boost/serialization/wrapper.hpp> |
| |
| // the following is need only for dynamic cast of polymorphic pointers |
| #include <boost/archive/archive_exception.hpp> |
| #include <boost/archive/detail/basic_iarchive.hpp> |
| #include <boost/archive/detail/basic_iserializer.hpp> |
| #include <boost/archive/detail/basic_pointer_iserializer.hpp> |
| #include <boost/archive/detail/archive_serializer_map.hpp> |
| #include <boost/archive/detail/check.hpp> |
| |
| namespace boost { |
| |
| namespace serialization { |
| class extended_type_info; |
| } // namespace serialization |
| |
| namespace archive { |
| |
| // an accessor to permit friend access to archives. Needed because |
| // some compilers don't handle friend templates completely |
| class load_access { |
| public: |
| template<class Archive, class T> |
| static void load_primitive(Archive &ar, T &t){ |
| ar.load(t); |
| } |
| }; |
| |
| namespace detail { |
| |
| #ifdef BOOST_MSVC |
| # pragma warning(push) |
| # pragma warning(disable : 4511 4512) |
| #endif |
| |
| template<class Archive, class T> |
| class iserializer : public basic_iserializer |
| { |
| private: |
| virtual void destroy(/*const*/ void *address) const { |
| boost::serialization::access::destroy(static_cast<T *>(address)); |
| } |
| protected: |
| // protected constructor since it's always created by singleton |
| explicit iserializer() : |
| basic_iserializer( |
| boost::serialization::singleton< |
| BOOST_DEDUCED_TYPENAME |
| boost::serialization::type_info_implementation< T >::type |
| >::get_const_instance() |
| ) |
| {} |
| public: |
| virtual BOOST_DLLEXPORT void load_object_data( |
| basic_iarchive & ar, |
| void *x, |
| const unsigned int file_version |
| ) const BOOST_USED; |
| virtual bool class_info() const { |
| return boost::serialization::implementation_level< T >::value |
| >= boost::serialization::object_class_info; |
| } |
| virtual bool tracking(const unsigned int /* flags */) const { |
| return boost::serialization::tracking_level< T >::value |
| == boost::serialization::track_always |
| || ( boost::serialization::tracking_level< T >::value |
| == boost::serialization::track_selectively |
| && serialized_as_pointer()); |
| } |
| virtual version_type version() const { |
| return version_type(::boost::serialization::version< T >::value); |
| } |
| virtual bool is_polymorphic() const { |
| return boost::is_polymorphic< T >::value; |
| } |
| virtual ~iserializer(){}; |
| }; |
| |
| #ifdef BOOST_MSVC |
| # pragma warning(pop) |
| #endif |
| |
| template<class Archive, class T> |
| BOOST_DLLEXPORT void iserializer<Archive, T>::load_object_data( |
| basic_iarchive & ar, |
| void *x, |
| const unsigned int file_version |
| ) const { |
| // note: we now comment this out. Before we permited archive |
| // version # to be very large. Now we don't. To permit |
| // readers of these old archives, we have to suppress this |
| // code. Perhaps in the future we might re-enable it but |
| // permit its suppression with a runtime switch. |
| #if 0 |
| // trap case where the program cannot handle the current version |
| if(file_version > static_cast<const unsigned int>(version())) |
| boost::serialization::throw_exception( |
| archive::archive_exception( |
| boost::archive::archive_exception::unsupported_class_version, |
| get_debug_info() |
| ) |
| ); |
| #endif |
| // make sure call is routed through the higest interface that might |
| // be specialized by the user. |
| boost::serialization::serialize_adl( |
| boost::serialization::smart_cast_reference<Archive &>(ar), |
| * static_cast<T *>(x), |
| file_version |
| ); |
| } |
| |
| #ifdef BOOST_MSVC |
| # pragma warning(push) |
| # pragma warning(disable : 4511 4512) |
| #endif |
| |
| template<class Archive, class T> |
| class pointer_iserializer : |
| public basic_pointer_iserializer |
| { |
| private: |
| virtual const basic_iserializer & get_basic_serializer() const { |
| return boost::serialization::singleton< |
| iserializer<Archive, T> |
| >::get_const_instance(); |
| } |
| BOOST_DLLEXPORT virtual void load_object_ptr( |
| basic_iarchive & ar, |
| void * & x, |
| const unsigned int file_version |
| ) const BOOST_USED; |
| protected: |
| // this should alway be a singleton so make the constructor protected |
| pointer_iserializer(); |
| ~pointer_iserializer(); |
| }; |
| |
| #ifdef BOOST_MSVC |
| # pragma warning(pop) |
| #endif |
| |
| // note trick to be sure that operator new is using class specific |
| // version if such exists. Due to Peter Dimov. |
| // note: the following fails if T has no default constructor. |
| // otherwise it would have been ideal |
| //struct heap_allocator : public T |
| //{ |
| // T * invoke(){ |
| // return ::new(sizeof(T)); |
| // } |
| //} |
| |
| template<class T> |
| struct heap_allocator |
| { |
| // boost::has_new_operator< T > doesn't work on these compilers |
| #if DONT_USE_HAS_NEW_OPERATOR |
| // This doesn't handle operator new overload for class T |
| static T * invoke(){ |
| return static_cast<T *>(operator new(sizeof(T))); |
| } |
| #else |
| struct has_new_operator { |
| static T* invoke() { |
| return static_cast<T *>((T::operator new)(sizeof(T))); |
| } |
| }; |
| struct doesnt_have_new_operator { |
| static T* invoke() { |
| return static_cast<T *>(operator new(sizeof(T))); |
| } |
| }; |
| static T * invoke() { |
| typedef BOOST_DEDUCED_TYPENAME |
| mpl::eval_if< |
| boost::has_new_operator< T >, |
| mpl::identity<has_new_operator >, |
| mpl::identity<doesnt_have_new_operator > |
| >::type typex; |
| return typex::invoke(); |
| } |
| #endif |
| }; |
| |
| // due to Martin Ecker |
| template <typename T> |
| class auto_ptr_with_deleter |
| { |
| public: |
| explicit auto_ptr_with_deleter(T* p) : |
| m_p(p) |
| {} |
| ~auto_ptr_with_deleter(){ |
| if (m_p) |
| boost::serialization::access::destroy(m_p); |
| } |
| T* get() const { |
| return m_p; |
| } |
| |
| T* release() { |
| T* p = m_p; |
| m_p = NULL; |
| return p; |
| } |
| private: |
| T* m_p; |
| }; |
| |
| // note: BOOST_DLLEXPORT is so that code for polymorphic class |
| // serialized only through base class won't get optimized out |
| template<class Archive, class T> |
| BOOST_DLLEXPORT void pointer_iserializer<Archive, T>::load_object_ptr( |
| basic_iarchive & ar, |
| void * & x, |
| const unsigned int file_version |
| ) const |
| { |
| Archive & ar_impl = |
| boost::serialization::smart_cast_reference<Archive &>(ar); |
| |
| auto_ptr_with_deleter< T > ap(heap_allocator< T >::invoke()); |
| if(NULL == ap.get()) |
| boost::serialization::throw_exception(std::bad_alloc()) ; |
| |
| T * t = ap.get(); |
| x = t; |
| |
| // catch exception during load_construct_data so that we don't |
| // automatically delete the t which is most likely not fully |
| // constructed |
| BOOST_TRY { |
| // this addresses an obscure situtation that occurs when |
| // load_constructor de-serializes something through a pointer. |
| ar.next_object_pointer(t); |
| boost::serialization::load_construct_data_adl<Archive, T>( |
| ar_impl, |
| t, |
| file_version |
| ); |
| } |
| BOOST_CATCH(...){ |
| ap.release(); |
| BOOST_RETHROW; |
| } |
| BOOST_CATCH_END |
| |
| ar_impl >> boost::serialization::make_nvp(NULL, * t); |
| ap.release(); |
| } |
| |
| template<class Archive, class T> |
| pointer_iserializer<Archive, T>::pointer_iserializer() : |
| basic_pointer_iserializer( |
| boost::serialization::singleton< |
| BOOST_DEDUCED_TYPENAME |
| boost::serialization::type_info_implementation< T >::type |
| >::get_const_instance() |
| ) |
| { |
| boost::serialization::singleton< |
| iserializer<Archive, T> |
| >::get_mutable_instance().set_bpis(this); |
| archive_serializer_map<Archive>::insert(this); |
| } |
| |
| template<class Archive, class T> |
| pointer_iserializer<Archive, T>::~pointer_iserializer(){ |
| archive_serializer_map<Archive>::erase(this); |
| } |
| |
| template<class Archive> |
| struct load_non_pointer_type { |
| // note this bounces the call right back to the archive |
| // with no runtime overhead |
| struct load_primitive { |
| template<class T> |
| static void invoke(Archive & ar, T & t){ |
| load_access::load_primitive(ar, t); |
| } |
| }; |
| // note this bounces the call right back to the archive |
| // with no runtime overhead |
| struct load_only { |
| template<class T> |
| static void invoke(Archive & ar, const T & t){ |
| // short cut to user's serializer |
| // make sure call is routed through the higest interface that might |
| // be specialized by the user. |
| boost::serialization::serialize_adl( |
| ar, |
| const_cast<T &>(t), |
| boost::serialization::version< T >::value |
| ); |
| } |
| }; |
| |
| // note this save class information including version |
| // and serialization level to the archive |
| struct load_standard { |
| template<class T> |
| static void invoke(Archive &ar, const T & t){ |
| void * x = & const_cast<T &>(t); |
| ar.load_object( |
| x, |
| boost::serialization::singleton< |
| iserializer<Archive, T> |
| >::get_const_instance() |
| ); |
| } |
| }; |
| |
| struct load_conditional { |
| template<class T> |
| static void invoke(Archive &ar, T &t){ |
| //if(0 == (ar.get_flags() & no_tracking)) |
| load_standard::invoke(ar, t); |
| //else |
| // load_only::invoke(ar, t); |
| } |
| }; |
| |
| template<class T> |
| static void invoke(Archive & ar, T &t){ |
| typedef BOOST_DEDUCED_TYPENAME mpl::eval_if< |
| // if its primitive |
| mpl::equal_to< |
| boost::serialization::implementation_level< T >, |
| mpl::int_<boost::serialization::primitive_type> |
| >, |
| mpl::identity<load_primitive>, |
| // else |
| BOOST_DEDUCED_TYPENAME mpl::eval_if< |
| // class info / version |
| mpl::greater_equal< |
| boost::serialization::implementation_level< T >, |
| mpl::int_<boost::serialization::object_class_info> |
| >, |
| // do standard load |
| mpl::identity<load_standard>, |
| // else |
| BOOST_DEDUCED_TYPENAME mpl::eval_if< |
| // no tracking |
| mpl::equal_to< |
| boost::serialization::tracking_level< T >, |
| mpl::int_<boost::serialization::track_never> |
| >, |
| // do a fast load |
| mpl::identity<load_only>, |
| // else |
| // do a fast load only tracking is turned off |
| mpl::identity<load_conditional> |
| > > >::type typex; |
| check_object_versioning< T >(); |
| check_object_level< T >(); |
| typex::invoke(ar, t); |
| } |
| }; |
| |
| template<class Archive> |
| struct load_pointer_type { |
| struct abstract |
| { |
| template<class T> |
| static const basic_pointer_iserializer * register_type(Archive & /* ar */){ |
| // it has? to be polymorphic |
| BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value); |
| return static_cast<basic_pointer_iserializer *>(NULL); |
| } |
| }; |
| |
| struct non_abstract |
| { |
| template<class T> |
| static const basic_pointer_iserializer * register_type(Archive & ar){ |
| return ar.register_type(static_cast<T *>(NULL)); |
| } |
| }; |
| |
| template<class T> |
| static const basic_pointer_iserializer * register_type(Archive &ar, const T & /*t*/){ |
| // there should never be any need to load an abstract polymorphic |
| // class pointer. Inhibiting code generation for this |
| // permits abstract base classes to be used - note: exception |
| // virtual serialize functions used for plug-ins |
| typedef BOOST_DEDUCED_TYPENAME |
| mpl::eval_if< |
| boost::serialization::is_abstract<const T>, |
| boost::mpl::identity<abstract>, |
| boost::mpl::identity<non_abstract> |
| >::type typex; |
| return typex::template register_type< T >(ar); |
| } |
| |
| template<class T> |
| static T * pointer_tweak( |
| const boost::serialization::extended_type_info & eti, |
| void const * const t, |
| const T & |
| ) { |
| // tweak the pointer back to the base class |
| return static_cast<T *>( |
| const_cast<void *>( |
| boost::serialization::void_upcast( |
| eti, |
| boost::serialization::singleton< |
| BOOST_DEDUCED_TYPENAME |
| boost::serialization::type_info_implementation< T >::type |
| >::get_const_instance(), |
| t |
| ) |
| ) |
| ); |
| } |
| |
| template<class T> |
| static void check_load(T & /* t */){ |
| check_pointer_level< T >(); |
| check_pointer_tracking< T >(); |
| } |
| |
| static const basic_pointer_iserializer * |
| find(const boost::serialization::extended_type_info & type){ |
| return static_cast<const basic_pointer_iserializer *>( |
| archive_serializer_map<Archive>::find(type) |
| ); |
| } |
| |
| template<class Tptr> |
| static void invoke(Archive & ar, Tptr & t){ |
| check_load(*t); |
| const basic_pointer_iserializer * bpis_ptr = register_type(ar, *t); |
| const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer( |
| // note major hack here !!! |
| // I tried every way to convert Tptr &t (where Tptr might |
| // include const) to void * &. This is the only way |
| // I could make it work. RR |
| (void * & )t, |
| bpis_ptr, |
| find |
| ); |
| // if the pointer isn't that of the base class |
| if(newbpis_ptr != bpis_ptr){ |
| t = pointer_tweak(newbpis_ptr->get_eti(), t, *t); |
| } |
| } |
| }; |
| |
| template<class Archive> |
| struct load_enum_type { |
| template<class T> |
| static void invoke(Archive &ar, T &t){ |
| // convert integers to correct enum to load |
| int i; |
| ar >> boost::serialization::make_nvp(NULL, i); |
| t = static_cast< T >(i); |
| } |
| }; |
| |
| template<class Archive> |
| struct load_array_type { |
| template<class T> |
| static void invoke(Archive &ar, T &t){ |
| typedef BOOST_DEDUCED_TYPENAME remove_extent< T >::type value_type; |
| |
| // convert integers to correct enum to load |
| // determine number of elements in the array. Consider the |
| // fact that some machines will align elements on boundries |
| // other than characters. |
| std::size_t current_count = sizeof(t) / ( |
| static_cast<char *>(static_cast<void *>(&t[1])) |
| - static_cast<char *>(static_cast<void *>(&t[0])) |
| ); |
| boost::serialization::collection_size_type count; |
| ar >> BOOST_SERIALIZATION_NVP(count); |
| if(static_cast<std::size_t>(count) > current_count) |
| boost::serialization::throw_exception( |
| archive::archive_exception( |
| boost::archive::archive_exception::array_size_too_short |
| ) |
| ); |
| ar >> serialization::make_array(static_cast<value_type*>(&t[0]),count); |
| } |
| }; |
| |
| } // detail |
| |
| template<class Archive, class T> |
| inline void load(Archive & ar, T &t){ |
| // if this assertion trips. It means we're trying to load a |
| // const object with a compiler that doesn't have correct |
| // funtion template ordering. On other compilers, this is |
| // handled below. |
| detail::check_const_loading< T >(); |
| typedef |
| BOOST_DEDUCED_TYPENAME mpl::eval_if<is_pointer< T >, |
| mpl::identity<detail::load_pointer_type<Archive> > |
| ,//else |
| BOOST_DEDUCED_TYPENAME mpl::eval_if<is_array< T >, |
| mpl::identity<detail::load_array_type<Archive> > |
| ,//else |
| BOOST_DEDUCED_TYPENAME mpl::eval_if<is_enum< T >, |
| mpl::identity<detail::load_enum_type<Archive> > |
| ,//else |
| mpl::identity<detail::load_non_pointer_type<Archive> > |
| > |
| > |
| >::type typex; |
| typex::invoke(ar, t); |
| } |
| |
| #if 0 |
| |
| // BORLAND |
| #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x560)) |
| // borland has a couple of problems |
| // a) if function is partially specialized - see below |
| // const paramters are transformed to non-const ones |
| // b) implementation of base_object can't be made to work |
| // correctly which results in all base_object s being const. |
| // So, strip off the const for borland. This breaks the trap |
| // for loading const objects - but I see no alternative |
| template<class Archive, class T> |
| inline void load(Archive &ar, const T & t){ |
| load(ar, const_cast<T &>(t)); |
| } |
| #endif |
| |
| // let wrappers through. |
| #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING |
| template<class Archive, class T> |
| inline void load_wrapper(Archive &ar, const T&t, mpl::true_){ |
| boost::archive::load(ar, const_cast<T&>(t)); |
| } |
| |
| #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x560)) |
| template<class Archive, class T> |
| inline void load(Archive &ar, const T&t){ |
| load_wrapper(ar,t,serialization::is_wrapper< T >()); |
| } |
| #endif |
| #endif |
| |
| #endif |
| |
| } // namespace archive |
| } // namespace boost |
| |
| #endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP |