#ifndef BOOST_ARCHIVE_OSERIALIZER_HPP #define BOOST_ARCHIVE_OSERIALIZER_HPP // MS compatible compilers support #pragma once #if defined(_MSC_VER) # 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 // oserializer.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 <boost/assert.hpp> #include <cstddef> // NULL #include <boost/config.hpp> #include <boost/static_assert.hpp> #include <boost/detail/workaround.hpp> #include <boost/mpl/eval_if.hpp> #include <boost/mpl/equal_to.hpp> #include <boost/mpl/greater_equal.hpp> #include <boost/mpl/identity.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/assume_abstract.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/is_polymorphic.hpp> #include <boost/type_traits/remove_extent.hpp> #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/archive/archive_exception.hpp> #include <boost/archive/detail/basic_oarchive.hpp> #include <boost/archive/detail/basic_oserializer.hpp> #include <boost/archive/detail/basic_pointer_oserializer.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 save_access { public: template<class Archive> static void end_preamble(Archive & ar){ ar.end_preamble(); } template<class Archive, class T> static void save_primitive(Archive & ar, const T & t){ ar.end_preamble(); ar.save(t); } }; namespace detail { #ifdef BOOST_MSVC # pragma warning(push) # pragma warning(disable : 4511 4512) #endif template<class Archive, class T> class oserializer : public basic_oserializer { private: // private constructor to inhibit any existence other than the // static one public: explicit BOOST_DLLEXPORT oserializer() : basic_oserializer( boost::serialization::singleton< typename boost::serialization::type_info_implementation< T >::type >::get_const_instance() ) {} virtual BOOST_DLLEXPORT void save_object_data( basic_oarchive & ar, const void *x ) 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 ~oserializer(){} }; #ifdef BOOST_MSVC # pragma warning(pop) #endif template<class Archive, class T> BOOST_DLLEXPORT void oserializer<Archive, T>::save_object_data( basic_oarchive & ar, const void *x ) const { // make sure call is routed through the highest interface that might // be specialized by the user. BOOST_STATIC_ASSERT(boost::is_const< T >::value == false); boost::serialization::serialize_adl( boost::serialization::smart_cast_reference<Archive &>(ar), * static_cast<T *>(const_cast<void *>(x)), version() ); } #ifdef BOOST_MSVC # pragma warning(push) # pragma warning(disable : 4511 4512) #endif template<class Archive, class T> class pointer_oserializer : public basic_pointer_oserializer { private: const basic_oserializer & get_basic_serializer() const { return boost::serialization::singleton< oserializer<Archive, T> >::get_const_instance(); } virtual BOOST_DLLEXPORT void save_object_ptr( basic_oarchive & ar, const void * x ) const BOOST_USED; public: pointer_oserializer(); ~pointer_oserializer(); }; #ifdef BOOST_MSVC # pragma warning(pop) #endif template<class Archive, class T> BOOST_DLLEXPORT void pointer_oserializer<Archive, T>::save_object_ptr( basic_oarchive & ar, const void * x ) const { BOOST_ASSERT(NULL != x); // make sure call is routed through the highest interface that might // be specialized by the user. T * t = static_cast<T *>(const_cast<void *>(x)); const unsigned int file_version = boost::serialization::version< T >::value; Archive & ar_impl = boost::serialization::smart_cast_reference<Archive &>(ar); boost::serialization::save_construct_data_adl<Archive, T>( ar_impl, t, file_version ); ar_impl << boost::serialization::make_nvp(NULL, * t); } template<class Archive, class T> pointer_oserializer<Archive, T>::pointer_oserializer() : basic_pointer_oserializer( boost::serialization::singleton< typename boost::serialization::type_info_implementation< T >::type >::get_const_instance() ) { // make sure appropriate member function is instantiated boost::serialization::singleton< oserializer<Archive, T> >::get_mutable_instance().set_bpos(this); archive_serializer_map<Archive>::insert(this); } template<class Archive, class T> pointer_oserializer<Archive, T>::~pointer_oserializer(){ archive_serializer_map<Archive>::erase(this); } template<class Archive> struct save_non_pointer_type { // note this bounces the call right back to the archive // with no runtime overhead struct save_primitive { template<class T> static void invoke(Archive & ar, const T & t){ save_access::save_primitive(ar, t); } }; // same as above but passes through serialization struct save_only { template<class T> static void invoke(Archive & ar, const T & t){ // make sure call is routed through the highest interface that might // be specialized by the user. boost::serialization::serialize_adl( ar, const_cast<T &>(t), ::boost::serialization::version< T >::value ); } }; // adds class information to the archive. This includes // serialization level and class version struct save_standard { template<class T> static void invoke(Archive &ar, const T & t){ ar.save_object( & t, boost::serialization::singleton< oserializer<Archive, T> >::get_const_instance() ); } }; // adds class information to the archive. This includes // serialization level and class version struct save_conditional { template<class T> static void invoke(Archive &ar, const T &t){ //if(0 == (ar.get_flags() & no_tracking)) save_standard::invoke(ar, t); //else // save_only::invoke(ar, t); } }; template<class T> static void invoke(Archive & ar, const T & t){ typedef typename mpl::eval_if< // if its primitive mpl::equal_to< boost::serialization::implementation_level< T >, mpl::int_<boost::serialization::primitive_type> >, mpl::identity<save_primitive>, // else typename mpl::eval_if< // class info / version mpl::greater_equal< boost::serialization::implementation_level< T >, mpl::int_<boost::serialization::object_class_info> >, // do standard save mpl::identity<save_standard>, // else typename mpl::eval_if< // no tracking mpl::equal_to< boost::serialization::tracking_level< T >, mpl::int_<boost::serialization::track_never> >, // do a fast save mpl::identity<save_only>, // else // do a fast save only tracking is turned off mpl::identity<save_conditional> > > >::type typex; check_object_versioning< T >(); typex::invoke(ar, t); } template<class T> static void invoke(Archive & ar, T & t){ check_object_level< T >(); check_object_tracking< T >(); invoke(ar, const_cast<const T &>(t)); } }; template<class Archive> struct save_pointer_type { struct abstract { template<class T> static const basic_pointer_oserializer * register_type(Archive & /* ar */){ // it has? to be polymorphic BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value); return NULL; } }; struct non_abstract { template<class T> static const basic_pointer_oserializer * register_type(Archive & ar){ return ar.register_type(static_cast<T *>(NULL)); } }; template<class T> static const basic_pointer_oserializer * register_type(Archive &ar, T & /*t*/){ // there should never be any need to save 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 typename mpl::eval_if< boost::serialization::is_abstract< T >, mpl::identity<abstract>, mpl::identity<non_abstract> >::type typex; return typex::template register_type< T >(ar); } struct non_polymorphic { template<class T> static void save( Archive &ar, T & t ){ const basic_pointer_oserializer & bpos = boost::serialization::singleton< pointer_oserializer<Archive, T> >::get_const_instance(); // save the requested pointer type ar.save_pointer(& t, & bpos); } }; struct polymorphic { template<class T> static void save( Archive &ar, T & t ){ typename boost::serialization::type_info_implementation< T >::type const & i = boost::serialization::singleton< typename boost::serialization::type_info_implementation< T >::type >::get_const_instance(); boost::serialization::extended_type_info const * const this_type = & i; // retrieve the true type of the object pointed to // if this assertion fails its an error in this library BOOST_ASSERT(NULL != this_type); const boost::serialization::extended_type_info * true_type = i.get_derived_extended_type_info(t); // note:if this exception is thrown, be sure that derived pointer // is either registered or exported. if(NULL == true_type){ boost::serialization::throw_exception( archive_exception( archive_exception::unregistered_class, "derived class not registered or exported" ) ); } // if its not a pointer to a more derived type const void *vp = static_cast<const void *>(&t); if(*this_type == *true_type){ const basic_pointer_oserializer * bpos = register_type(ar, t); ar.save_pointer(vp, bpos); return; } // convert pointer to more derived type. if this is thrown // it means that the base/derived relationship hasn't be registered vp = serialization::void_downcast( *true_type, *this_type, static_cast<const void *>(&t) ); if(NULL == vp){ boost::serialization::throw_exception( archive_exception( archive_exception::unregistered_cast, true_type->get_debug_info(), this_type->get_debug_info() ) ); } // since true_type is valid, and this only gets made if the // pointer oserializer object has been created, this should never // fail const basic_pointer_oserializer * bpos = static_cast<const basic_pointer_oserializer *>( boost::serialization::singleton< archive_serializer_map<Archive> >::get_const_instance().find(*true_type) ); BOOST_ASSERT(NULL != bpos); if(NULL == bpos) boost::serialization::throw_exception( archive_exception( archive_exception::unregistered_class, "derived class not registered or exported" ) ); ar.save_pointer(vp, bpos); } }; template<class T> static void save( Archive & ar, const T & t ){ check_pointer_level< T >(); check_pointer_tracking< T >(); typedef typename mpl::eval_if< is_polymorphic< T >, mpl::identity<polymorphic>, mpl::identity<non_polymorphic> >::type type; type::save(ar, const_cast<T &>(t)); } template<class TPtr> static void invoke(Archive &ar, const TPtr t){ register_type(ar, * t); if(NULL == t){ basic_oarchive & boa = boost::serialization::smart_cast_reference<basic_oarchive &>(ar); boa.save_null_pointer(); save_access::end_preamble(ar); return; } save(ar, * t); } }; template<class Archive> struct save_enum_type { template<class T> static void invoke(Archive &ar, const T &t){ // convert enum to integers on save const int i = static_cast<int>(t); ar << boost::serialization::make_nvp(NULL, i); } }; template<class Archive> struct save_array_type { template<class T> static void invoke(Archive &ar, const T &t){ typedef typename boost::remove_extent< T >::type value_type; save_access::end_preamble(ar); // consider alignment std::size_t c = sizeof(t) / ( static_cast<const char *>(static_cast<const void *>(&t[1])) - static_cast<const char *>(static_cast<const void *>(&t[0])) ); boost::serialization::collection_size_type count(c); ar << BOOST_SERIALIZATION_NVP(count); ar << serialization::make_array(static_cast<value_type const*>(&t[0]),count); } }; } // detail template<class Archive, class T> inline void save(Archive & ar, /*const*/ T &t){ typedef typename mpl::eval_if<is_pointer< T >, mpl::identity<detail::save_pointer_type<Archive> >, //else typename mpl::eval_if<is_enum< T >, mpl::identity<detail::save_enum_type<Archive> >, //else typename mpl::eval_if<is_array< T >, mpl::identity<detail::save_array_type<Archive> >, //else mpl::identity<detail::save_non_pointer_type<Archive> > > > >::type typex; typex::invoke(ar, t); } } // namespace archive } // namespace boost #endif // BOOST_ARCHIVE_OSERIALIZER_HPP