sl@0: #ifndef BOOST_ARCHIVE_OSERIALIZER_HPP sl@0: #define BOOST_ARCHIVE_OSERIALIZER_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: // oserializer.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 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: 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: 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: #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 save_access { sl@0: public: sl@0: template sl@0: static void end_preamble(Archive & ar){ sl@0: ar.end_preamble(); sl@0: } sl@0: template sl@0: static void save_primitive(Archive & ar, const T & t){ sl@0: ar.end_preamble(); sl@0: ar.save(t); sl@0: } sl@0: }; sl@0: sl@0: namespace detail { sl@0: sl@0: template sl@0: class oserializer : public basic_oserializer sl@0: { sl@0: private: sl@0: // private constructor to inhibit any existence other than the sl@0: // static one sl@0: explicit oserializer() : sl@0: basic_oserializer( sl@0: * boost::serialization::type_info_implementation::type::get_instance() sl@0: ) sl@0: {} sl@0: public: sl@0: virtual BOOST_DLLEXPORT void save_object_data( sl@0: basic_oarchive & ar, sl@0: const void *x 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 == boost::serialization::track_always sl@0: || boost::serialization::tracking_level::value == 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 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 oserializer & instantiate(){ sl@0: static oserializer instance; sl@0: return instance; sl@0: } sl@0: virtual ~oserializer(){} sl@0: }; sl@0: sl@0: template sl@0: BOOST_DLLEXPORT void oserializer::save_object_data( sl@0: basic_oarchive & ar, sl@0: const void *x sl@0: ) const { sl@0: // make sure call is routed through the highest 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(const_cast(x)), sl@0: 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_oserializer : public archive_pointer_oserializer sl@0: { sl@0: private: sl@0: virtual const basic_oserializer & get_basic_serializer() const { sl@0: return oserializer::instantiate(); sl@0: } sl@0: virtual BOOST_DLLEXPORT void save_object_ptr( sl@0: basic_oarchive & ar, sl@0: const void * x 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_oserializer() BOOST_USED; sl@0: static const pointer_oserializer instance; sl@0: public: sl@0: #if ! BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) sl@0: // at least one compiler (CW) seems to require that serialize_adl sl@0: // be explicitly instantiated. Still under investigation. 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_oserializer & instantiate() BOOST_USED; sl@0: virtual ~pointer_oserializer(){} sl@0: }; sl@0: sl@0: template sl@0: BOOST_DLLEXPORT const pointer_oserializer & sl@0: pointer_oserializer::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_oserializer pointer_oserializer::instance; sl@0: sl@0: template sl@0: BOOST_DLLEXPORT void pointer_oserializer::save_object_ptr( sl@0: basic_oarchive & ar, sl@0: const void * x sl@0: ) const { sl@0: assert(NULL != x); sl@0: // make sure call is routed through the highest interface that might sl@0: // be specialized by the user. sl@0: T * t = static_cast(const_cast(x)); sl@0: const unsigned int file_version = boost::serialization::version::value; sl@0: Archive & ar_impl = boost::smart_cast_reference(ar); sl@0: boost::serialization::save_construct_data_adl( sl@0: ar_impl, sl@0: t, sl@0: file_version sl@0: ); sl@0: ar_impl << boost::serialization::make_nvp(NULL, * t); sl@0: } sl@0: sl@0: template sl@0: #if ! BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) sl@0: BOOST_DLLEXPORT pointer_oserializer::pointer_oserializer() : sl@0: archive_pointer_oserializer( 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_oserializer::pointer_oserializer() : sl@0: archive_pointer_oserializer( sl@0: * boost::serialization::type_info_implementation::type::get_instance() sl@0: ) sl@0: #endif sl@0: { sl@0: // make sure appropriate member function is instantiated sl@0: oserializer & bos = oserializer::instantiate(); sl@0: bos.set_bpos(this); sl@0: } sl@0: sl@0: template sl@0: struct save_non_pointer_type { sl@0: // note this bounces the call right back to the archive sl@0: // with no runtime overhead sl@0: struct save_primitive { sl@0: static void invoke(Archive & ar, const T & t){ sl@0: save_access::save_primitive(ar, t); sl@0: } sl@0: }; sl@0: // same as above but passes through serialization sl@0: struct save_only { sl@0: static void invoke(Archive & ar, const T & t){ sl@0: // make sure call is routed through the highest interface that might sl@0: // be specialized by the user. sl@0: boost::serialization::serialize_adl( sl@0: ar, sl@0: const_cast(t), sl@0: ::boost::serialization::version::value sl@0: ); sl@0: } sl@0: }; sl@0: // adds class information to the archive. This includes sl@0: // serialization level and class version sl@0: struct save_standard { sl@0: static void invoke(Archive &ar, const T & t){ sl@0: ar.save_object(& t, oserializer::instantiate()); sl@0: } sl@0: }; sl@0: sl@0: // adds class information to the archive. This includes sl@0: // serialization level and class version sl@0: struct save_conditional { sl@0: static void invoke(Archive &ar, const T &t){ sl@0: //if(0 == (ar.get_flags() & no_tracking)) sl@0: save_standard::invoke(ar, t); sl@0: //else sl@0: // save_only::invoke(ar, t); sl@0: } sl@0: }; sl@0: sl@0: typedef sl@0: 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 save 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 save sl@0: mpl::identity, sl@0: // else sl@0: // do a fast save only tracking is turned off sl@0: mpl::identity sl@0: > > >::type typex; sl@0: sl@0: static void invoke(Archive & ar, const T & t){ sl@0: // check that we're not trying to serialize something that sl@0: // has been marked not to be serialized. If this your program sl@0: // traps here, you've tried to serialize a class whose trait sl@0: // has been marked "non-serializable". Either reset the trait sl@0: // (see level.hpp) or change program not to serialize items of this class 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 save_pointer_type { sl@0: template sl@0: struct abstract sl@0: { sl@0: static const basic_pointer_oserializer * register_type(Archive & /* ar */){ sl@0: // it has? to be polymorphic sl@0: BOOST_STATIC_ASSERT( sl@0: boost::serialization::type_info_implementation::type::is_polymorphic::value sl@0: ); 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_oserializer * 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_oserializer * register_type(Archive &ar, T & /*t*/){ sl@0: // there should never be any need to save 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 sl@0: BOOST_DEDUCED_TYPENAME 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: struct non_polymorphic sl@0: { sl@0: static void save( sl@0: Archive &ar, sl@0: const T & t, sl@0: const basic_pointer_oserializer * bpos_ptr sl@0: ){ sl@0: // save the requested pointer type sl@0: ar.save_pointer(& t, bpos_ptr); sl@0: } sl@0: }; sl@0: sl@0: template sl@0: struct polymorphic sl@0: { sl@0: static void save( sl@0: Archive &ar, sl@0: const T & t, sl@0: const basic_pointer_oserializer * bpos_ptr sl@0: ){ sl@0: const boost::serialization::extended_type_info * this_type sl@0: = boost::serialization::type_info_implementation::type::get_instance(); sl@0: // retrieve the true type of the object pointed to sl@0: // if this assertion fails its an error in this library sl@0: assert(NULL != this_type); sl@0: const boost::serialization::extended_type_info * true_type sl@0: = boost::serialization::type_info_implementation::type::get_derived_extended_type_info(t); sl@0: // note:if this exception is thrown, be sure that derived pointer sl@0: // is either regsitered or exported. sl@0: if(NULL == true_type){ sl@0: boost::throw_exception( sl@0: archive_exception(archive_exception::unregistered_class) sl@0: ); sl@0: } sl@0: sl@0: // if its not a pointer to a more derived type sl@0: const void *vp = static_cast(&t); sl@0: if(*this_type == *true_type){ sl@0: ar.save_pointer(vp, bpos_ptr); sl@0: return; sl@0: } sl@0: // convert pointer to more derived type. if this is thrown sl@0: // it means that the base/derived relationship hasn't be registered sl@0: vp = serialization::void_downcast(*true_type, *this_type, &t); sl@0: if(NULL == vp){ sl@0: boost::throw_exception( sl@0: archive_exception(archive_exception::unregistered_cast) sl@0: ); sl@0: } sl@0: sl@0: // sice true_type is valid, and this only gets made if the sl@0: // pointer oserializer object has been created, this should never sl@0: // fail sl@0: bpos_ptr = archive_pointer_oserializer::find(* true_type); sl@0: assert(NULL != bpos_ptr); sl@0: if(NULL == bpos_ptr) sl@0: boost::throw_exception( sl@0: archive_exception(archive_exception::unregistered_class) sl@0: ); sl@0: ar.save_pointer(vp, bpos_ptr); sl@0: } sl@0: }; sl@0: sl@0: template sl@0: static void save( sl@0: Archive & ar, sl@0: const T &t, sl@0: const basic_pointer_oserializer * bpos_ptr sl@0: ){ sl@0: typedef BOOST_DEDUCED_TYPENAME mpl::eval_if< sl@0: BOOST_DEDUCED_TYPENAME boost::serialization:: sl@0: type_info_implementation::type::is_polymorphic, sl@0: mpl::identity >, sl@0: mpl::identity > sl@0: >::type typey; sl@0: typey::save(ar, const_cast(t), bpos_ptr); sl@0: } sl@0: sl@0: template sl@0: static void const_check(T & t){ sl@0: BOOST_STATIC_ASSERT(! boost::is_const::value); sl@0: } sl@0: sl@0: static void invoke(Archive &ar, const TPtr t){ sl@0: #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION sl@0: // if your program traps here, its because you tried to do sl@0: // something like ar << t where t is a pointer to a const value sl@0: // void f3(A const* a, text_oarchive& oa) sl@0: // { sl@0: // oa << a; sl@0: // } sl@0: // with a compiler which doesn't support remove_const sl@0: // const_check(* t); sl@0: #else sl@0: // otherwise remove the const sl@0: #endif sl@0: const basic_pointer_oserializer * bpos_ptr = register_type(ar, * t); sl@0: if(NULL == t){ sl@0: basic_oarchive & boa = boost::smart_cast_reference(ar); sl@0: boa.save_null_pointer(); sl@0: save_access::end_preamble(ar); sl@0: return; sl@0: } sl@0: save(ar, * t, bpos_ptr); sl@0: }; sl@0: }; sl@0: sl@0: template sl@0: struct save_enum_type sl@0: { sl@0: static void invoke(Archive &ar, const T &t){ sl@0: // convert enum to integers on save sl@0: const int i = static_cast(t); sl@0: ar << boost::serialization::make_nvp(NULL, i); sl@0: } sl@0: }; sl@0: sl@0: template sl@0: struct save_array_type sl@0: { sl@0: static void invoke(Archive &ar, const T &t){ sl@0: save_access::end_preamble(ar); sl@0: // consider alignment sl@0: int count = sizeof(t) / ( sl@0: static_cast(static_cast(&t[1])) sl@0: - static_cast(static_cast(&t[0])) sl@0: ); sl@0: ar << BOOST_SERIALIZATION_NVP(count); 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: // declaration to satisfy gcc sl@0: template sl@0: BOOST_DLLEXPORT const basic_pointer_oserializer & sl@0: instantiate_pointer_oserializer( sl@0: Archive * /* ar = NULL */, sl@0: T * /* t = NULL */ sl@0: ) BOOST_USED ; sl@0: // definition sl@0: template sl@0: BOOST_DLLEXPORT const basic_pointer_oserializer & sl@0: instantiate_pointer_oserializer( 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_oserializer::instantiate(); sl@0: } sl@0: sl@0: } // detail sl@0: sl@0: template sl@0: inline void save(Archive & ar, const T &t){ 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: #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING sl@0: sl@0: template sl@0: struct check_tracking { sl@0: typedef BOOST_DEDUCED_TYPENAME mpl::if_< sl@0: // if its never tracked. sl@0: BOOST_DEDUCED_TYPENAME mpl::equal_to< sl@0: serialization::tracking_level, sl@0: mpl::int_ sl@0: >, sl@0: // it better not be a pointer sl@0: mpl::not_ >, sl@0: //else sl@0: // otherwise if it might be tracked. So there shouldn't sl@0: // be any problem making a const sl@0: is_const sl@0: >::type typex; sl@0: BOOST_STATIC_CONSTANT(bool, value = typex::value); sl@0: }; sl@0: sl@0: template sl@0: inline void save(Archive & ar, T &t){ sl@0: // if your program traps here, it indicates taht your doing one of the following: sl@0: // a) serializing an object of a type marked "track_never" through a pointer. sl@0: // b) saving an non-const object of a type not markd "track_never) sl@0: // Either of these conditions may be an indicator of an error usage of the sl@0: // serialization library and should be double checked. See documentation on sl@0: // object tracking. sl@0: BOOST_STATIC_ASSERT(check_tracking::value); sl@0: save(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_OSERIALIZER_HPP