You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
531 lines
17 KiB
531 lines
17 KiB
#ifndef BOOST_ARCHIVE_OSERIALIZER_HPP |
|
#define BOOST_ARCHIVE_OSERIALIZER_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 |
|
// 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< |
|
BOOST_DEDUCED_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< |
|
BOOST_DEDUCED_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 |
|
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<save_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 save |
|
mpl::identity<save_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 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 |
|
BOOST_DEDUCED_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 |
|
){ |
|
BOOST_DEDUCED_TYPENAME |
|
boost::serialization::type_info_implementation< T >::type const |
|
& i = boost::serialization::singleton< |
|
BOOST_DEDUCED_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 BOOST_DEDUCED_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 BOOST_DEDUCED_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 |
|
BOOST_DEDUCED_TYPENAME mpl::eval_if<is_pointer< T >, |
|
mpl::identity<detail::save_pointer_type<Archive> >, |
|
//else |
|
BOOST_DEDUCED_TYPENAME mpl::eval_if<is_enum< T >, |
|
mpl::identity<detail::save_enum_type<Archive> >, |
|
//else |
|
BOOST_DEDUCED_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
|
|
|