Chris@16: #ifndef BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP Chris@16: #define BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP Chris@16: Chris@16: // MS compatible compilers support #pragma once Chris@101: #if defined(_MSC_VER) Chris@16: # pragma once Chris@16: #pragma inline_depth(511) Chris@16: #pragma inline_recursion(on) Chris@16: #endif Chris@16: Chris@16: #if defined(__MWERKS__) Chris@16: #pragma inline_depth(511) Chris@16: #endif Chris@16: Chris@16: /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 Chris@16: // iserializer.hpp: interface for serialization system. Chris@16: Chris@16: // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . Chris@16: // Use, modification and distribution is subject to the Boost Software Chris@16: // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: // See http://www.boost.org for updates, documentation, and revision history. Chris@16: Chris@16: #include // for placement new Chris@16: #include // size_t, NULL Chris@16: Chris@16: #include Chris@16: #include Chris@16: #if defined(BOOST_NO_STDC_NAMESPACE) Chris@16: namespace std{ Chris@16: using ::size_t; Chris@16: } // namespace std Chris@16: #endif Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: Chris@16: #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO Chris@16: #include Chris@16: #endif Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #define DONT_USE_HAS_NEW_OPERATOR ( \ Chris@16: defined(__BORLANDC__) \ Chris@16: || BOOST_WORKAROUND(__IBMCPP__, < 1210) \ Chris@16: || defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x590) \ Chris@16: ) Chris@16: #if ! DONT_USE_HAS_NEW_OPERATOR Chris@16: #include Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: // the following is need only for dynamic cast of polymorphic pointers Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: namespace serialization { Chris@16: class extended_type_info; Chris@16: } // namespace serialization Chris@16: Chris@16: namespace archive { Chris@16: Chris@16: // an accessor to permit friend access to archives. Needed because Chris@16: // some compilers don't handle friend templates completely Chris@16: class load_access { Chris@16: public: Chris@16: template Chris@16: static void load_primitive(Archive &ar, T &t){ Chris@16: ar.load(t); Chris@16: } Chris@16: }; Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: # pragma warning(push) Chris@16: # pragma warning(disable : 4511 4512) Chris@16: #endif Chris@16: Chris@16: template Chris@16: class iserializer : public basic_iserializer Chris@16: { Chris@16: private: Chris@16: virtual void destroy(/*const*/ void *address) const { Chris@16: boost::serialization::access::destroy(static_cast(address)); Chris@16: } Chris@16: protected: Chris@16: // protected constructor since it's always created by singleton Chris@16: explicit iserializer() : Chris@16: basic_iserializer( Chris@16: boost::serialization::singleton< Chris@101: typename Chris@16: boost::serialization::type_info_implementation< T >::type Chris@16: >::get_const_instance() Chris@16: ) Chris@16: {} Chris@16: public: Chris@16: virtual BOOST_DLLEXPORT void load_object_data( Chris@16: basic_iarchive & ar, Chris@16: void *x, Chris@16: const unsigned int file_version Chris@16: ) const BOOST_USED; Chris@16: virtual bool class_info() const { Chris@16: return boost::serialization::implementation_level< T >::value Chris@16: >= boost::serialization::object_class_info; Chris@16: } Chris@16: virtual bool tracking(const unsigned int /* flags */) const { Chris@16: return boost::serialization::tracking_level< T >::value Chris@16: == boost::serialization::track_always Chris@16: || ( boost::serialization::tracking_level< T >::value Chris@16: == boost::serialization::track_selectively Chris@16: && serialized_as_pointer()); Chris@16: } Chris@16: virtual version_type version() const { Chris@16: return version_type(::boost::serialization::version< T >::value); Chris@16: } Chris@16: virtual bool is_polymorphic() const { Chris@16: return boost::is_polymorphic< T >::value; Chris@16: } Chris@16: virtual ~iserializer(){}; Chris@16: }; Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: # pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: template Chris@16: BOOST_DLLEXPORT void iserializer::load_object_data( Chris@16: basic_iarchive & ar, Chris@16: void *x, Chris@16: const unsigned int file_version Chris@16: ) const { Chris@16: // note: we now comment this out. Before we permited archive Chris@16: // version # to be very large. Now we don't. To permit Chris@16: // readers of these old archives, we have to suppress this Chris@16: // code. Perhaps in the future we might re-enable it but Chris@16: // permit its suppression with a runtime switch. Chris@16: #if 0 Chris@16: // trap case where the program cannot handle the current version Chris@16: if(file_version > static_cast(version())) Chris@16: boost::serialization::throw_exception( Chris@16: archive::archive_exception( Chris@16: boost::archive::archive_exception::unsupported_class_version, Chris@16: get_debug_info() Chris@16: ) Chris@16: ); Chris@16: #endif Chris@16: // make sure call is routed through the higest interface that might Chris@16: // be specialized by the user. Chris@16: boost::serialization::serialize_adl( Chris@16: boost::serialization::smart_cast_reference(ar), Chris@16: * static_cast(x), Chris@16: file_version Chris@16: ); Chris@16: } Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: # pragma warning(push) Chris@16: # pragma warning(disable : 4511 4512) Chris@16: #endif Chris@16: Chris@101: // the purpose of this code is to allocate memory for an object Chris@101: // without requiring the constructor to be called. Presumably Chris@101: // the allocated object will be subsequently initialized with Chris@101: // "placement new". Chris@101: // note: we have the boost type trait has_new_operator but we Chris@101: // have no corresponding has_delete_operator. So we presume Chris@101: // that the former being true would imply that the a delete Chris@101: // operator is also defined for the class T. Chris@101: Chris@101: template Chris@101: struct heap_allocation { Chris@101: // boost::has_new_operator< T > doesn't work on these compilers Chris@101: #if DONT_USE_HAS_NEW_OPERATOR Chris@101: // This doesn't handle operator new overload for class T Chris@101: static T * invoke_new(){ Chris@101: return static_cast(operator new(sizeof(T))); Chris@101: } Chris@101: static void invoke_delete(T *t){ Chris@101: (operator delete(t)); Chris@101: } Chris@101: #else Chris@101: // note: we presume that a true value for has_new_operator Chris@101: // implies the existence of a class specific delete operator as well Chris@101: // as a class specific new operator. Chris@101: struct has_new_operator { Chris@101: static T * invoke_new() { Chris@101: return static_cast((T::operator new)(sizeof(T))); Chris@101: } Chris@101: static void invoke_delete(T * t) { Chris@101: // if compilation fails here, the likely cause that the class Chris@101: // T has a class specific new operator but no class specific Chris@101: // delete operator which matches the following signature. Fix Chris@101: // your program to have this. Note that adding operator delete Chris@101: // with only one parameter doesn't seem correct to me since Chris@101: // the standard(3.7.4.2) says " Chris@101: // "If a class T has a member deallocation function named Chris@101: // 'operator delete' with exactly one parameter, then that function Chris@101: // is a usual (non-placement) deallocation function" which I take Chris@101: // to mean that it will call the destructor of type T which we don't Chris@101: // want to do here. Chris@101: // Note: reliance upon automatic conversion from T * to void * here Chris@101: (T::operator delete)(t, sizeof(T)); Chris@101: } Chris@101: }; Chris@101: struct doesnt_have_new_operator { Chris@101: static T* invoke_new() { Chris@101: return static_cast(operator new(sizeof(T))); Chris@101: } Chris@101: static void invoke_delete(T * t) { Chris@101: // Note: I'm reliance upon automatic conversion from T * to void * here Chris@101: (operator delete)(t); Chris@101: } Chris@101: }; Chris@101: static T * invoke_new() { Chris@101: typedef typename Chris@101: mpl::eval_if< Chris@101: boost::has_new_operator< T >, Chris@101: mpl::identity, Chris@101: mpl::identity Chris@101: >::type typex; Chris@101: return typex::invoke_new(); Chris@101: } Chris@101: static void invoke_delete(T *t) { Chris@101: typedef typename Chris@101: mpl::eval_if< Chris@101: boost::has_new_operator< T >, Chris@101: mpl::identity, Chris@101: mpl::identity Chris@101: >::type typex; Chris@101: typex::invoke_delete(t); Chris@101: } Chris@101: #endif Chris@101: explicit heap_allocation(){ Chris@101: m_p = invoke_new(); Chris@101: } Chris@101: ~heap_allocation(){ Chris@101: if (0 != m_p) Chris@101: invoke_delete(m_p); Chris@101: } Chris@101: T* get() const { Chris@101: return m_p; Chris@101: } Chris@101: Chris@101: T* release() { Chris@101: T* p = m_p; Chris@101: m_p = 0; Chris@101: return p; Chris@101: } Chris@101: private: Chris@101: T* m_p; Chris@101: }; Chris@101: Chris@16: template Chris@16: class pointer_iserializer : Chris@16: public basic_pointer_iserializer Chris@16: { Chris@16: private: Chris@101: virtual void * heap_allocation() const { Chris@101: detail::heap_allocation h; Chris@101: T * t = h.get(); Chris@101: h.release(); Chris@101: return t; Chris@101: } Chris@16: virtual const basic_iserializer & get_basic_serializer() const { Chris@16: return boost::serialization::singleton< Chris@16: iserializer Chris@16: >::get_const_instance(); Chris@16: } Chris@16: BOOST_DLLEXPORT virtual void load_object_ptr( Chris@16: basic_iarchive & ar, Chris@101: void * x, Chris@16: const unsigned int file_version Chris@16: ) const BOOST_USED; Chris@16: protected: Chris@16: // this should alway be a singleton so make the constructor protected Chris@16: pointer_iserializer(); Chris@16: ~pointer_iserializer(); Chris@16: }; Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: # pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: // note: BOOST_DLLEXPORT is so that code for polymorphic class Chris@16: // serialized only through base class won't get optimized out Chris@16: template Chris@16: BOOST_DLLEXPORT void pointer_iserializer::load_object_ptr( Chris@16: basic_iarchive & ar, Chris@101: void * t, Chris@16: const unsigned int file_version Chris@16: ) const Chris@16: { Chris@16: Archive & ar_impl = Chris@16: boost::serialization::smart_cast_reference(ar); Chris@16: Chris@101: // note that the above will throw std::bad_alloc if the allocation Chris@101: // fails so we don't have to address this contingency here. Chris@16: Chris@16: // catch exception during load_construct_data so that we don't Chris@16: // automatically delete the t which is most likely not fully Chris@16: // constructed Chris@16: BOOST_TRY { Chris@101: // this addresses an obscure situation that occurs when Chris@16: // load_constructor de-serializes something through a pointer. Chris@16: ar.next_object_pointer(t); Chris@16: boost::serialization::load_construct_data_adl( Chris@16: ar_impl, Chris@101: static_cast(t), Chris@16: file_version Chris@16: ); Chris@16: } Chris@16: BOOST_CATCH(...){ Chris@101: // if we get here the load_construct failed. The heap_allocation Chris@101: // will be automatically deleted so we don't have to do anything Chris@101: // special here. Chris@16: BOOST_RETHROW; Chris@16: } Chris@16: BOOST_CATCH_END Chris@16: Chris@101: ar_impl >> boost::serialization::make_nvp(NULL, * static_cast(t)); Chris@16: } Chris@16: Chris@16: template Chris@16: pointer_iserializer::pointer_iserializer() : Chris@16: basic_pointer_iserializer( Chris@16: boost::serialization::singleton< Chris@101: typename Chris@16: boost::serialization::type_info_implementation< T >::type Chris@16: >::get_const_instance() Chris@16: ) Chris@16: { Chris@16: boost::serialization::singleton< Chris@16: iserializer Chris@16: >::get_mutable_instance().set_bpis(this); Chris@16: archive_serializer_map::insert(this); Chris@16: } Chris@16: Chris@16: template Chris@16: pointer_iserializer::~pointer_iserializer(){ Chris@16: archive_serializer_map::erase(this); Chris@16: } Chris@16: Chris@16: template Chris@16: struct load_non_pointer_type { Chris@16: // note this bounces the call right back to the archive Chris@16: // with no runtime overhead Chris@16: struct load_primitive { Chris@16: template Chris@16: static void invoke(Archive & ar, T & t){ Chris@16: load_access::load_primitive(ar, t); Chris@16: } Chris@16: }; Chris@16: // note this bounces the call right back to the archive Chris@16: // with no runtime overhead Chris@16: struct load_only { Chris@16: template Chris@16: static void invoke(Archive & ar, const T & t){ Chris@16: // short cut to user's serializer Chris@16: // make sure call is routed through the higest interface that might Chris@16: // be specialized by the user. Chris@16: boost::serialization::serialize_adl( Chris@16: ar, Chris@16: const_cast(t), Chris@16: boost::serialization::version< T >::value Chris@16: ); Chris@16: } Chris@16: }; Chris@16: Chris@16: // note this save class information including version Chris@16: // and serialization level to the archive Chris@16: struct load_standard { Chris@16: template Chris@16: static void invoke(Archive &ar, const T & t){ Chris@16: void * x = & const_cast(t); Chris@16: ar.load_object( Chris@16: x, Chris@16: boost::serialization::singleton< Chris@16: iserializer Chris@16: >::get_const_instance() Chris@16: ); Chris@16: } Chris@16: }; Chris@16: Chris@16: struct load_conditional { Chris@16: template Chris@16: static void invoke(Archive &ar, T &t){ Chris@16: //if(0 == (ar.get_flags() & no_tracking)) Chris@16: load_standard::invoke(ar, t); Chris@16: //else Chris@16: // load_only::invoke(ar, t); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: static void invoke(Archive & ar, T &t){ Chris@101: typedef typename mpl::eval_if< Chris@16: // if its primitive Chris@16: mpl::equal_to< Chris@16: boost::serialization::implementation_level< T >, Chris@16: mpl::int_ Chris@16: >, Chris@16: mpl::identity, Chris@16: // else Chris@101: typename mpl::eval_if< Chris@16: // class info / version Chris@16: mpl::greater_equal< Chris@16: boost::serialization::implementation_level< T >, Chris@16: mpl::int_ Chris@16: >, Chris@16: // do standard load Chris@16: mpl::identity, Chris@16: // else Chris@101: typename mpl::eval_if< Chris@16: // no tracking Chris@16: mpl::equal_to< Chris@16: boost::serialization::tracking_level< T >, Chris@16: mpl::int_ Chris@16: >, Chris@16: // do a fast load Chris@16: mpl::identity, Chris@16: // else Chris@16: // do a fast load only tracking is turned off Chris@16: mpl::identity Chris@16: > > >::type typex; Chris@16: check_object_versioning< T >(); Chris@16: check_object_level< T >(); Chris@16: typex::invoke(ar, t); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct load_pointer_type { Chris@16: struct abstract Chris@16: { Chris@16: template Chris@16: static const basic_pointer_iserializer * register_type(Archive & /* ar */){ Chris@16: // it has? to be polymorphic Chris@16: BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value); Chris@16: return static_cast(NULL); Chris@16: } Chris@16: }; Chris@16: Chris@16: struct non_abstract Chris@16: { Chris@16: template Chris@16: static const basic_pointer_iserializer * register_type(Archive & ar){ Chris@16: return ar.register_type(static_cast(NULL)); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: static const basic_pointer_iserializer * register_type(Archive &ar, const T & /*t*/){ Chris@16: // there should never be any need to load an abstract polymorphic Chris@16: // class pointer. Inhibiting code generation for this Chris@16: // permits abstract base classes to be used - note: exception Chris@16: // virtual serialize functions used for plug-ins Chris@101: typedef typename Chris@16: mpl::eval_if< Chris@16: boost::serialization::is_abstract, Chris@16: boost::mpl::identity, Chris@16: boost::mpl::identity Chris@16: >::type typex; Chris@16: return typex::template register_type< T >(ar); Chris@16: } Chris@16: Chris@16: template Chris@16: static T * pointer_tweak( Chris@16: const boost::serialization::extended_type_info & eti, Chris@16: void const * const t, Chris@16: const T & Chris@16: ) { Chris@16: // tweak the pointer back to the base class Chris@101: void * upcast = const_cast( Chris@101: boost::serialization::void_upcast( Chris@101: eti, Chris@101: boost::serialization::singleton< Chris@101: typename Chris@101: boost::serialization::type_info_implementation< T >::type Chris@101: >::get_const_instance(), Chris@101: t Chris@16: ) Chris@16: ); Chris@101: if(NULL == upcast) Chris@101: boost::serialization::throw_exception( Chris@101: archive_exception(archive_exception::unregistered_class) Chris@101: ); Chris@101: return static_cast(upcast); Chris@16: } Chris@16: Chris@16: template Chris@16: static void check_load(T & /* t */){ Chris@16: check_pointer_level< T >(); Chris@16: check_pointer_tracking< T >(); Chris@16: } Chris@16: Chris@16: static const basic_pointer_iserializer * Chris@16: find(const boost::serialization::extended_type_info & type){ Chris@16: return static_cast( Chris@16: archive_serializer_map::find(type) Chris@16: ); Chris@16: } Chris@16: Chris@16: template Chris@16: static void invoke(Archive & ar, Tptr & t){ Chris@16: check_load(*t); Chris@16: const basic_pointer_iserializer * bpis_ptr = register_type(ar, *t); Chris@16: const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer( Chris@16: // note major hack here !!! Chris@16: // I tried every way to convert Tptr &t (where Tptr might Chris@16: // include const) to void * &. This is the only way Chris@16: // I could make it work. RR Chris@16: (void * & )t, Chris@16: bpis_ptr, Chris@16: find Chris@16: ); Chris@16: // if the pointer isn't that of the base class Chris@16: if(newbpis_ptr != bpis_ptr){ Chris@16: t = pointer_tweak(newbpis_ptr->get_eti(), t, *t); Chris@16: } Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct load_enum_type { Chris@16: template Chris@16: static void invoke(Archive &ar, T &t){ Chris@16: // convert integers to correct enum to load Chris@16: int i; Chris@16: ar >> boost::serialization::make_nvp(NULL, i); Chris@16: t = static_cast< T >(i); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct load_array_type { Chris@16: template Chris@16: static void invoke(Archive &ar, T &t){ Chris@101: typedef typename remove_extent< T >::type value_type; Chris@16: Chris@16: // convert integers to correct enum to load Chris@16: // determine number of elements in the array. Consider the Chris@16: // fact that some machines will align elements on boundries Chris@16: // other than characters. Chris@16: std::size_t current_count = sizeof(t) / ( Chris@16: static_cast(static_cast(&t[1])) Chris@16: - static_cast(static_cast(&t[0])) Chris@16: ); Chris@16: boost::serialization::collection_size_type count; Chris@16: ar >> BOOST_SERIALIZATION_NVP(count); Chris@16: if(static_cast(count) > current_count) Chris@16: boost::serialization::throw_exception( Chris@16: archive::archive_exception( Chris@16: boost::archive::archive_exception::array_size_too_short Chris@16: ) Chris@16: ); Chris@16: ar >> serialization::make_array(static_cast(&t[0]),count); Chris@16: } Chris@16: }; Chris@16: Chris@16: } // detail Chris@16: Chris@16: template Chris@16: inline void load(Archive & ar, T &t){ Chris@16: // if this assertion trips. It means we're trying to load a Chris@16: // const object with a compiler that doesn't have correct Chris@16: // funtion template ordering. On other compilers, this is Chris@16: // handled below. Chris@16: detail::check_const_loading< T >(); Chris@16: typedef Chris@101: typename mpl::eval_if, Chris@16: mpl::identity > Chris@16: ,//else Chris@101: typename mpl::eval_if, Chris@16: mpl::identity > Chris@16: ,//else Chris@101: typename mpl::eval_if, Chris@16: mpl::identity > Chris@16: ,//else Chris@16: mpl::identity > Chris@16: > Chris@16: > Chris@16: >::type typex; Chris@16: typex::invoke(ar, t); Chris@16: } Chris@16: Chris@16: #if 0 Chris@16: Chris@16: // BORLAND Chris@16: #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x560)) Chris@16: // borland has a couple of problems Chris@16: // a) if function is partially specialized - see below Chris@16: // const paramters are transformed to non-const ones Chris@16: // b) implementation of base_object can't be made to work Chris@16: // correctly which results in all base_object s being const. Chris@16: // So, strip off the const for borland. This breaks the trap Chris@16: // for loading const objects - but I see no alternative Chris@16: template Chris@16: inline void load(Archive &ar, const T & t){ Chris@16: load(ar, const_cast(t)); Chris@16: } Chris@16: #endif Chris@16: Chris@16: // let wrappers through. Chris@16: #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING Chris@16: template Chris@16: inline void load_wrapper(Archive &ar, const T&t, mpl::true_){ Chris@16: boost::archive::load(ar, const_cast(t)); Chris@16: } Chris@16: Chris@16: #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x560)) Chris@16: template Chris@16: inline void load(Archive &ar, const T&t){ Chris@16: load_wrapper(ar,t,serialization::is_wrapper< T >()); Chris@16: } Chris@16: #endif Chris@16: #endif Chris@16: Chris@16: #endif Chris@16: Chris@16: } // namespace archive Chris@16: } // namespace boost Chris@16: Chris@16: #endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP