sl@0: #ifndef BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP sl@0: #define BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP sl@0: sl@0: // MS compatible compilers support #pragma once sl@0: #if defined(_MSC_VER) && (_MSC_VER >= 1020) sl@0: # pragma once sl@0: #pragma inline_depth(511) sl@0: #pragma inline_recursion(on) sl@0: #endif sl@0: sl@0: #if defined(__MWERKS__) sl@0: #pragma inline_depth(511) sl@0: #endif sl@0: sl@0: /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 sl@0: // iserializer.hpp: interface for serialization system. sl@0: sl@0: // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . sl@0: // Use, modification and distribution is subject to the Boost Software sl@0: // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at sl@0: // http://www.boost.org/LICENSE_1_0.txt) sl@0: sl@0: // See http://www.boost.org for updates, documentation, and revision history. sl@0: sl@0: #include // for placement new sl@0: #include // for auto_ptr sl@0: #include // size_t sl@0: sl@0: #include sl@0: #include sl@0: #if defined(BOOST_NO_STDC_NAMESPACE) sl@0: namespace std{ sl@0: using ::size_t; sl@0: } // namespace std sl@0: #endif sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO sl@0: #include sl@0: #endif sl@0: // the following is need only for dynamic cast of polymorphic pointers sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: namespace boost { sl@0: sl@0: namespace serialization { sl@0: class extended_type_info; sl@0: } // namespace serialization sl@0: sl@0: namespace archive { sl@0: sl@0: // an accessor to permit friend access to archives. Needed because sl@0: // some compilers don't handle friend templates completely sl@0: class load_access { sl@0: public: sl@0: template sl@0: static void load_primitive(Archive &ar, T &t){ sl@0: ar.load(t); sl@0: } sl@0: }; sl@0: sl@0: namespace detail { sl@0: sl@0: template sl@0: class iserializer : public basic_iserializer sl@0: { sl@0: private: sl@0: virtual void destroy(/*const*/ void *address) const { sl@0: boost::serialization::access::destroy(static_cast(address)); sl@0: } sl@0: // private constructor to inhibit any existence other than the sl@0: // static one sl@0: explicit iserializer() : sl@0: basic_iserializer( sl@0: * boost::serialization::type_info_implementation::type::get_instance() sl@0: ) sl@0: {} sl@0: public: sl@0: virtual BOOST_DLLEXPORT void load_object_data( sl@0: basic_iarchive & ar, sl@0: void *x, sl@0: const unsigned int file_version sl@0: ) const BOOST_USED ; sl@0: virtual bool class_info() const { sl@0: return boost::serialization::implementation_level::value sl@0: >= boost::serialization::object_class_info; sl@0: } sl@0: virtual bool tracking(const unsigned int flags) const { sl@0: // if(0 != (flags & no_tracking)) sl@0: // return false; sl@0: return boost::serialization::tracking_level::value sl@0: == boost::serialization::track_always sl@0: || boost::serialization::tracking_level::value sl@0: == boost::serialization::track_selectivly sl@0: && serialized_as_pointer(); sl@0: } sl@0: virtual unsigned int version() const { sl@0: return ::boost::serialization::version::value; sl@0: } sl@0: virtual bool is_polymorphic() const { sl@0: typedef BOOST_DEDUCED_TYPENAME sl@0: boost::serialization::type_info_implementation< sl@0: T sl@0: >::type::is_polymorphic::type typex; sl@0: return typex::value; sl@0: } sl@0: static iserializer & instantiate(){ sl@0: static iserializer instance; sl@0: return instance; sl@0: } sl@0: virtual ~iserializer(){}; sl@0: }; sl@0: sl@0: template sl@0: BOOST_DLLEXPORT void iserializer::load_object_data( sl@0: basic_iarchive & ar, sl@0: void *x, sl@0: const unsigned int file_version sl@0: ) const { sl@0: // make sure call is routed through the higest interface that might sl@0: // be specialized by the user. sl@0: boost::serialization::serialize_adl( sl@0: boost::smart_cast_reference(ar), sl@0: * static_cast(x), sl@0: file_version sl@0: ); sl@0: } sl@0: sl@0: // instantiation of this template creates a static object. Note inversion of sl@0: // normal argument order to workaround bizarre error in MSVC 6.0 which only sl@0: // manifests iftself during compiler time. sl@0: template sl@0: class pointer_iserializer : public archive_pointer_iserializer sl@0: { sl@0: private: sl@0: virtual const basic_iserializer & get_basic_serializer() const { sl@0: return iserializer::instantiate(); sl@0: } sl@0: virtual BOOST_DLLEXPORT void load_object_ptr( sl@0: basic_iarchive & ar, sl@0: void * & x, sl@0: const unsigned int file_version sl@0: ) const BOOST_USED; sl@0: #if defined(__GNUC__) || ( defined(BOOST_MSVC) && (_MSC_VER <= 1300) ) sl@0: public: sl@0: #endif sl@0: // private constructor to inhibit any existence other than the sl@0: // static one. Note GCC doesn't permit constructor to be private sl@0: explicit BOOST_DLLEXPORT pointer_iserializer() BOOST_USED; sl@0: static const pointer_iserializer instance; sl@0: public: sl@0: // at least one compiler (CW) seems to require that serialize_adl sl@0: // be explicitly instantiated. Still under investigation. sl@0: #if ! BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) sl@0: void (* const m)(Archive &, T &, const unsigned); sl@0: boost::serialization::extended_type_info * (* e)(); sl@0: #endif sl@0: static BOOST_DLLEXPORT const pointer_iserializer & instantiate() BOOST_USED; sl@0: virtual ~pointer_iserializer(){}; sl@0: }; sl@0: sl@0: template sl@0: BOOST_DLLEXPORT const pointer_iserializer & sl@0: pointer_iserializer::instantiate() { sl@0: return instance; sl@0: } sl@0: sl@0: // note: instances of this template to be constructed before the main sl@0: // is called in order for things to be initialized properly. For this sl@0: // reason, hiding the instance in a static function as was done above sl@0: // won't work here so we created a free instance here. sl@0: template sl@0: const pointer_iserializer pointer_iserializer::instance; sl@0: sl@0: // note trick to be sure that operator new is using class specific sl@0: // version if such exists. Due to Peter Dimov. sl@0: // note: the following fails if T has no default constructor. sl@0: // otherwise it would have been ideal sl@0: //struct heap_allocator : public T sl@0: //{ sl@0: // T * invoke(){ sl@0: // return ::new(sizeof(T)); sl@0: // } sl@0: //} sl@0: sl@0: // note: this should really be a member of the load_ptr function sl@0: // below but some compilers still complain about this. sl@0: template sl@0: struct heap_allocator sl@0: { sl@0: #if 0 sl@0: // note: this fails on msvc 7.0 and gcc 3.2 sl@0: template struct test; sl@0: typedef char* yes; sl@0: typedef int* no; sl@0: template sl@0: yes has_op_new(U*, test* = 0); sl@0: no has_op_new(...); sl@0: sl@0: template sl@0: T * new_operator(U); sl@0: sl@0: T * new_operator(yes){ sl@0: return (T::operator new)(sizeof(T)); sl@0: } sl@0: T * new_operator(no){ sl@0: return static_cast(operator new(sizeof(T))); sl@0: } sl@0: static T * invoke(){ sl@0: return new_operator(has_op_new(static_cast(NULL))); sl@0: } sl@0: #else sl@0: // while this doesn't handle operator new overload for class T sl@0: static T * invoke(){ sl@0: return static_cast(operator new(sizeof(T))); sl@0: } sl@0: #endif sl@0: }; sl@0: sl@0: // due to Martin Ecker sl@0: template sl@0: class auto_ptr_with_deleter sl@0: { sl@0: public: sl@0: explicit auto_ptr_with_deleter(T* p) : sl@0: m_p(p) sl@0: {} sl@0: ~auto_ptr_with_deleter(){ sl@0: if (m_p) sl@0: boost::serialization::access::destroy(m_p); sl@0: } sl@0: T* get() const { sl@0: return m_p; sl@0: } sl@0: sl@0: T* release() { sl@0: T* p = m_p; sl@0: m_p = NULL; sl@0: return p; sl@0: } sl@0: private: sl@0: T* m_p; sl@0: }; sl@0: sl@0: template sl@0: BOOST_DLLEXPORT void pointer_iserializer::load_object_ptr( sl@0: basic_iarchive & ar, sl@0: void * & x, sl@0: const unsigned int file_version sl@0: ) const { sl@0: Archive & ar_impl = boost::smart_cast_reference(ar); sl@0: sl@0: // if(0 != (ar.get_flags() & no_object_creation)){ sl@0: // ar_impl >> boost::serialization::make_nvp(NULL, * static_cast(x)); sl@0: // return; sl@0: // } sl@0: sl@0: auto_ptr_with_deleter ap(heap_allocator::invoke()); sl@0: if(NULL == ap.get()) sl@0: boost::throw_exception(std::bad_alloc()) ; sl@0: sl@0: T * t = ap.get(); sl@0: x = t; sl@0: sl@0: // catch exception during load_construct_data so that we don't sl@0: // automatically delete the t which is most likely not fully sl@0: // constructed sl@0: BOOST_TRY { sl@0: // this addresses an obscure situtation that occurs when sl@0: // load_constructor de-serializes something through a pointer. sl@0: ar.next_object_pointer(t); sl@0: boost::serialization::load_construct_data_adl( sl@0: ar_impl, sl@0: t, sl@0: file_version sl@0: ); sl@0: } sl@0: BOOST_CATCH(...){ sl@0: BOOST_RETHROW; sl@0: } sl@0: BOOST_CATCH_END sl@0: sl@0: ar_impl >> boost::serialization::make_nvp(NULL, * t); sl@0: ap.release(); sl@0: } sl@0: sl@0: template sl@0: #if ! BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) sl@0: BOOST_DLLEXPORT pointer_iserializer::pointer_iserializer() : sl@0: archive_pointer_iserializer( sl@0: * boost::serialization::type_info_implementation::type::get_instance() sl@0: ), sl@0: m(boost::serialization::serialize_adl), sl@0: e(boost::serialization::type_info_implementation::type::get_instance) sl@0: #else sl@0: BOOST_DLLEXPORT pointer_iserializer::pointer_iserializer() : sl@0: archive_pointer_iserializer( sl@0: * boost::serialization::type_info_implementation::type::get_instance() sl@0: ) sl@0: #endif sl@0: { sl@0: iserializer & bis = iserializer::instantiate(); sl@0: bis.set_bpis(this); sl@0: } sl@0: sl@0: template sl@0: struct load_non_pointer_type { sl@0: // note this bounces the call right back to the archive sl@0: // with no runtime overhead sl@0: struct load_primitive { sl@0: static void invoke(Archive & ar, T & t){ sl@0: load_access::load_primitive(ar, t); sl@0: } sl@0: }; sl@0: // note this bounces the call right back to the archive sl@0: // with no runtime overhead sl@0: struct load_only { sl@0: static void invoke(Archive & ar, T & t){ sl@0: // short cut to user's serializer sl@0: // make sure call is routed through the higest interface that might sl@0: // be specialized by the user. sl@0: boost::serialization::serialize_adl( sl@0: ar, t, boost::serialization::version::value sl@0: ); sl@0: } sl@0: }; sl@0: sl@0: // note this save class information including version sl@0: // and serialization level to the archive sl@0: struct load_standard { sl@0: static void invoke(Archive &ar, T &t){ sl@0: //BOOST_STATIC_ASSERT(! boost::is_const::value); sl@0: // borland - for some reason T is const here - even though sl@0: // its not called that way - so fix it her sl@0: typedef BOOST_DEDUCED_TYPENAME boost::remove_const::type typex; sl@0: void * x = & const_cast(t); sl@0: ar.load_object(x, iserializer::instantiate()); sl@0: } sl@0: }; sl@0: sl@0: struct load_conditional { sl@0: static void invoke(Archive &ar, T &t){ sl@0: //if(0 == (ar.get_flags() & no_tracking)) sl@0: load_standard::invoke(ar, t); sl@0: //else sl@0: // load_only::invoke(ar, t); sl@0: } sl@0: }; sl@0: sl@0: typedef BOOST_DEDUCED_TYPENAME mpl::eval_if< sl@0: // if its primitive sl@0: mpl::equal_to< sl@0: boost::serialization::implementation_level, sl@0: mpl::int_ sl@0: >, sl@0: mpl::identity, sl@0: // else sl@0: BOOST_DEDUCED_TYPENAME mpl::eval_if< sl@0: // class info / version sl@0: mpl::greater_equal< sl@0: boost::serialization::implementation_level, sl@0: mpl::int_ sl@0: >, sl@0: // do standard load sl@0: mpl::identity, sl@0: // else sl@0: BOOST_DEDUCED_TYPENAME mpl::eval_if< sl@0: // no tracking sl@0: mpl::equal_to< sl@0: boost::serialization::tracking_level, sl@0: mpl::int_ sl@0: >, sl@0: // do a fast load sl@0: mpl::identity, sl@0: // else sl@0: // do a fast load only tracking is turned off sl@0: mpl::identity sl@0: > > >::type typex; sl@0: sl@0: static void invoke(Archive & ar, T &t){ sl@0: BOOST_STATIC_ASSERT(( sl@0: mpl::greater_equal< sl@0: boost::serialization::implementation_level, sl@0: mpl::int_ sl@0: >::value sl@0: )); sl@0: typex::invoke(ar, t); sl@0: } sl@0: }; sl@0: sl@0: template sl@0: struct load_pointer_type { sl@0: template sl@0: struct abstract sl@0: { sl@0: static const basic_pointer_iserializer * register_type(Archive & /* ar */){ sl@0: #if ! defined(__BORLANDC__) sl@0: typedef BOOST_DEDUCED_TYPENAME sl@0: boost::serialization::type_info_implementation::type::is_polymorphic typex; sl@0: // it has? to be polymorphic sl@0: BOOST_STATIC_ASSERT(typex::value); sl@0: #endif sl@0: return static_cast(NULL); sl@0: } sl@0: }; sl@0: sl@0: template sl@0: struct non_abstract sl@0: { sl@0: static const basic_pointer_iserializer * register_type(Archive & ar){ sl@0: return ar.register_type(static_cast(NULL)); sl@0: } sl@0: }; sl@0: sl@0: template sl@0: static const basic_pointer_iserializer * register_type(Archive &ar, T & /*t*/){ sl@0: // there should never be any need to load an abstract polymorphic sl@0: // class pointer. Inhibiting code generation for this sl@0: // permits abstract base classes to be used - note: exception sl@0: // virtual serialize functions used for plug-ins sl@0: typedef BOOST_DEDUCED_TYPENAME sl@0: mpl::eval_if< sl@0: serialization::is_abstract, sl@0: mpl::identity >, sl@0: mpl::identity > sl@0: >::type typex; sl@0: return typex::register_type(ar); sl@0: } sl@0: sl@0: template sl@0: static T * pointer_tweak( sl@0: const boost::serialization::extended_type_info & eti, sl@0: void * t, sl@0: T & sl@0: ) { sl@0: // tweak the pointer back to the base class sl@0: return static_cast( sl@0: boost::serialization::void_upcast( sl@0: eti, sl@0: * boost::serialization::type_info_implementation::type::get_instance(), sl@0: t sl@0: ) sl@0: ); sl@0: } sl@0: sl@0: static void invoke(Archive & ar, Tptr & t){ sl@0: const basic_pointer_iserializer * bpis_ptr = register_type(ar, *t); sl@0: const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer( sl@0: * reinterpret_cast(&t), sl@0: bpis_ptr, sl@0: archive_pointer_iserializer::find sl@0: ); sl@0: // if the pointer isn't that of the base class sl@0: if(newbpis_ptr != bpis_ptr){ sl@0: t = pointer_tweak(newbpis_ptr->get_eti(), t, *t); sl@0: } sl@0: } sl@0: }; sl@0: sl@0: template sl@0: struct load_enum_type { sl@0: static void invoke(Archive &ar, T &t){ sl@0: // convert integers to correct enum to load sl@0: int i; sl@0: ar >> boost::serialization::make_nvp(NULL, i); sl@0: t = static_cast(i); sl@0: } sl@0: }; sl@0: sl@0: template sl@0: struct load_array_type { sl@0: static void invoke(Archive &ar, T &t){ sl@0: // convert integers to correct enum to load sl@0: int current_count = sizeof(t) / ( sl@0: static_cast(static_cast(&t[1])) sl@0: - static_cast(static_cast(&t[0])) sl@0: ); sl@0: int count; sl@0: ar >> BOOST_SERIALIZATION_NVP(count); sl@0: if(count > current_count) sl@0: boost::throw_exception(archive::archive_exception( sl@0: boost::archive::archive_exception::array_size_too_short sl@0: )); sl@0: int i; sl@0: for(i = 0; i < count; ++i) sl@0: ar >> boost::serialization::make_nvp("item", t[i]); sl@0: } sl@0: }; sl@0: sl@0: // note bogus arguments to workaround msvc 6 silent runtime failure sl@0: template sl@0: BOOST_DLLEXPORT sl@0: inline const basic_pointer_iserializer & sl@0: instantiate_pointer_iserializer( sl@0: Archive * /* ar = NULL */, sl@0: T * /* t = NULL */ sl@0: ) BOOST_USED; sl@0: sl@0: template sl@0: BOOST_DLLEXPORT sl@0: inline const basic_pointer_iserializer & sl@0: instantiate_pointer_iserializer( sl@0: Archive * /* ar = NULL */, sl@0: T * /* t = NULL */ sl@0: ){ sl@0: // note: reversal of order of arguments to work around msvc 6.0 bug sl@0: // that manifests itself while trying to link. sl@0: return pointer_iserializer::instantiate(); sl@0: } sl@0: sl@0: } // detail sl@0: sl@0: template sl@0: inline void load(Archive &ar, T &t){ sl@0: // if this assertion trips. It means we're trying to load a sl@0: // const object with a compiler that doesn't have correct sl@0: // funtion template ordering. On other compilers, this is sl@0: // handled below. sl@0: BOOST_STATIC_ASSERT(! boost::is_const::value); sl@0: typedef sl@0: BOOST_DEDUCED_TYPENAME mpl::eval_if, sl@0: mpl::identity > sl@0: ,//else sl@0: BOOST_DEDUCED_TYPENAME mpl::eval_if, sl@0: mpl::identity > sl@0: ,//else sl@0: BOOST_DEDUCED_TYPENAME mpl::eval_if, sl@0: mpl::identity > sl@0: ,//else sl@0: mpl::identity > sl@0: > sl@0: > sl@0: >::type typex; sl@0: typex::invoke(ar, t); sl@0: } sl@0: sl@0: // BORLAND sl@0: #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x560)) sl@0: // borland has a couple fo problems sl@0: // a) if function is partiall specialized - see below sl@0: // const paramters are transformed to non-const ones sl@0: // b) implementation of base_object can't be made to work sl@0: // correctly which results in all base_object s being const. sl@0: // So, strip off the const for borland. This breaks the trap sl@0: // for loading const objects - but I see no alternative sl@0: template sl@0: inline void load(Archive &ar, const T & t){ sl@0: load(ar, const_cast(t)); sl@0: } sl@0: #endif sl@0: sl@0: // let wrappers through. (Someday implement is_wrapper) sl@0: #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING sl@0: template sl@0: inline void load(Archive &ar, const serialization::nvp &t){ sl@0: boost::archive::load(ar, const_cast &>(t)); sl@0: } sl@0: template sl@0: inline void load(Archive &ar, const serialization::binary_object &t){ sl@0: boost::archive::load(ar, const_cast(t)); sl@0: } sl@0: sl@0: //template sl@0: //inline void load(Archive &ar, const serialization::binary_object &t){ sl@0: // load(ar, const_cast(t)); sl@0: //} sl@0: #endif sl@0: sl@0: } // namespace archive sl@0: } // namespace boost sl@0: sl@0: #endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP