1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/ossrv_pub/boost_apis/boost/archive/detail/oserializer.hpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,574 @@
1.4 +#ifndef BOOST_ARCHIVE_OSERIALIZER_HPP
1.5 +#define BOOST_ARCHIVE_OSERIALIZER_HPP
1.6 +
1.7 +// MS compatible compilers support #pragma once
1.8 +#if defined(_MSC_VER) && (_MSC_VER >= 1020)
1.9 +# pragma once
1.10 +#pragma inline_depth(511)
1.11 +#pragma inline_recursion(on)
1.12 +#endif
1.13 +
1.14 +#if defined(__MWERKS__)
1.15 +#pragma inline_depth(511)
1.16 +#endif
1.17 +
1.18 +/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
1.19 +// oserializer.hpp: interface for serialization system.
1.20 +
1.21 +// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
1.22 +// Use, modification and distribution is subject to the Boost Software
1.23 +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
1.24 +// http://www.boost.org/LICENSE_1_0.txt)
1.25 +
1.26 +// See http://www.boost.org for updates, documentation, and revision history.
1.27 +
1.28 +#include <cassert>
1.29 +
1.30 +#include <boost/config.hpp>
1.31 +#include <boost/detail/workaround.hpp>
1.32 +#include <boost/throw_exception.hpp>
1.33 +#include <boost/smart_cast.hpp>
1.34 +#include <boost/static_assert.hpp>
1.35 +#include <boost/static_warning.hpp>
1.36 +
1.37 +#include <boost/type_traits/is_pointer.hpp>
1.38 +#include <boost/type_traits/is_fundamental.hpp>
1.39 +#include <boost/type_traits/is_enum.hpp>
1.40 +#include <boost/type_traits/is_volatile.hpp>
1.41 +#include <boost/type_traits/is_const.hpp>
1.42 +#include <boost/type_traits/is_same.hpp>
1.43 +#include <boost/serialization/is_abstract.hpp>
1.44 +
1.45 +#include <boost/mpl/eval_if.hpp>
1.46 +#include <boost/mpl/and.hpp>
1.47 +#include <boost/mpl/less.hpp>
1.48 +#include <boost/mpl/greater_equal.hpp>
1.49 +#include <boost/mpl/equal_to.hpp>
1.50 +#include <boost/mpl/int.hpp>
1.51 +#include <boost/mpl/identity.hpp>
1.52 +#include <boost/mpl/list.hpp>
1.53 +#include <boost/mpl/empty.hpp>
1.54 +#include <boost/mpl/not.hpp>
1.55 +
1.56 + #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO
1.57 + #include <boost/serialization/extended_type_info_typeid.hpp>
1.58 + #endif
1.59 +// the following is need only for dynamic cast of polymorphic pointers
1.60 +#include <boost/archive/detail/basic_oarchive.hpp>
1.61 +#include <boost/archive/detail/basic_oserializer.hpp>
1.62 +#include <boost/archive/detail/archive_pointer_oserializer.hpp>
1.63 +
1.64 +#include <boost/serialization/force_include.hpp>
1.65 +#include <boost/serialization/serialization.hpp>
1.66 +#include <boost/serialization/version.hpp>
1.67 +#include <boost/serialization/level.hpp>
1.68 +#include <boost/serialization/tracking.hpp>
1.69 +#include <boost/serialization/type_info_implementation.hpp>
1.70 +#include <boost/serialization/nvp.hpp>
1.71 +#include <boost/serialization/void_cast.hpp>
1.72 +
1.73 +#include <boost/archive/archive_exception.hpp>
1.74 +
1.75 +namespace boost {
1.76 +
1.77 +namespace serialization {
1.78 + class extended_type_info;
1.79 +} // namespace serialization
1.80 +
1.81 +namespace archive {
1.82 +
1.83 +// an accessor to permit friend access to archives. Needed because
1.84 +// some compilers don't handle friend templates completely
1.85 +class save_access {
1.86 +public:
1.87 + template<class Archive>
1.88 + static void end_preamble(Archive & ar){
1.89 + ar.end_preamble();
1.90 + }
1.91 + template<class Archive, class T>
1.92 + static void save_primitive(Archive & ar, const T & t){
1.93 + ar.end_preamble();
1.94 + ar.save(t);
1.95 + }
1.96 +};
1.97 +
1.98 +namespace detail {
1.99 +
1.100 +template<class Archive, class T>
1.101 +class oserializer : public basic_oserializer
1.102 +{
1.103 +private:
1.104 + // private constructor to inhibit any existence other than the
1.105 + // static one
1.106 + explicit oserializer() :
1.107 + basic_oserializer(
1.108 + * boost::serialization::type_info_implementation<T>::type::get_instance()
1.109 + )
1.110 + {}
1.111 +public:
1.112 + virtual BOOST_DLLEXPORT void save_object_data(
1.113 + basic_oarchive & ar,
1.114 + const void *x
1.115 + ) const BOOST_USED ;
1.116 + virtual bool class_info() const {
1.117 + return boost::serialization::implementation_level<T>::value
1.118 + >= boost::serialization::object_class_info;
1.119 + }
1.120 + virtual bool tracking(const unsigned int flags) const {
1.121 +// if(0 != (flags & no_tracking))
1.122 +// return false;
1.123 + return boost::serialization::tracking_level<T>::value == boost::serialization::track_always
1.124 + || boost::serialization::tracking_level<T>::value == boost::serialization::track_selectivly
1.125 + && serialized_as_pointer();
1.126 + }
1.127 + virtual unsigned int version() const {
1.128 + return ::boost::serialization::version<T>::value;
1.129 + }
1.130 + virtual bool is_polymorphic() const {
1.131 + typedef BOOST_DEDUCED_TYPENAME boost::serialization::type_info_implementation<
1.132 + T
1.133 + >::type::is_polymorphic::type typex;
1.134 + return typex::value;
1.135 + }
1.136 + static oserializer & instantiate(){
1.137 + static oserializer instance;
1.138 + return instance;
1.139 + }
1.140 + virtual ~oserializer(){}
1.141 +};
1.142 +
1.143 +template<class Archive, class T>
1.144 +BOOST_DLLEXPORT void oserializer<Archive, T>::save_object_data(
1.145 + basic_oarchive & ar,
1.146 + const void *x
1.147 +) const {
1.148 + // make sure call is routed through the highest interface that might
1.149 + // be specialized by the user.
1.150 + boost::serialization::serialize_adl(
1.151 + boost::smart_cast_reference<Archive &>(ar),
1.152 + * static_cast<T *>(const_cast<void *>(x)),
1.153 + version()
1.154 + );
1.155 +}
1.156 +
1.157 +// instantiation of this template creates a static object. Note inversion of
1.158 +// normal argument order to workaround bizarre error in MSVC 6.0 which only
1.159 +// manifests iftself during compiler time.
1.160 +template<class T, class Archive>
1.161 +class pointer_oserializer : public archive_pointer_oserializer<Archive>
1.162 +{
1.163 +private:
1.164 + virtual const basic_oserializer & get_basic_serializer() const {
1.165 + return oserializer<Archive, T>::instantiate();
1.166 + }
1.167 + virtual BOOST_DLLEXPORT void save_object_ptr(
1.168 + basic_oarchive & ar,
1.169 + const void * x
1.170 + ) const BOOST_USED ;
1.171 +#if defined(__GNUC__) || ( defined(BOOST_MSVC) && (_MSC_VER <= 1300) )
1.172 +public:
1.173 +#endif
1.174 + // private constructor to inhibit any existence other than the
1.175 + // static one. Note GCC doesn't permit constructor to be private
1.176 + explicit BOOST_DLLEXPORT pointer_oserializer() BOOST_USED;
1.177 + static const pointer_oserializer instance;
1.178 +public:
1.179 + #if ! BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
1.180 + // at least one compiler (CW) seems to require that serialize_adl
1.181 + // be explicitly instantiated. Still under investigation.
1.182 + void (* const m)(Archive &, T &, const unsigned);
1.183 + boost::serialization::extended_type_info * (* e)();
1.184 + #endif
1.185 + static BOOST_DLLEXPORT const pointer_oserializer & instantiate() BOOST_USED;
1.186 + virtual ~pointer_oserializer(){}
1.187 +};
1.188 +
1.189 +template<class T, class Archive>
1.190 +BOOST_DLLEXPORT const pointer_oserializer<T, Archive> &
1.191 +pointer_oserializer<T, Archive>::instantiate(){
1.192 + return instance;
1.193 +}
1.194 +
1.195 +// note: instances of this template to be constructed before the main
1.196 +// is called in order for things to be initialized properly. For this
1.197 +// reason, hiding the instance in a static function as was done above
1.198 +// won't work here so we created a free instance here.
1.199 +template<class T, class Archive>
1.200 +const pointer_oserializer<T, Archive> pointer_oserializer<T, Archive>::instance;
1.201 +
1.202 +template<class T, class Archive>
1.203 +BOOST_DLLEXPORT void pointer_oserializer<T, Archive>::save_object_ptr(
1.204 + basic_oarchive & ar,
1.205 + const void * x
1.206 +) const {
1.207 + assert(NULL != x);
1.208 + // make sure call is routed through the highest interface that might
1.209 + // be specialized by the user.
1.210 + T * t = static_cast<T *>(const_cast<void *>(x));
1.211 + const unsigned int file_version = boost::serialization::version<T>::value;
1.212 + Archive & ar_impl = boost::smart_cast_reference<Archive &>(ar);
1.213 + boost::serialization::save_construct_data_adl<Archive, T>(
1.214 + ar_impl,
1.215 + t,
1.216 + file_version
1.217 + );
1.218 + ar_impl << boost::serialization::make_nvp(NULL, * t);
1.219 +}
1.220 +
1.221 +template<class T, class Archive>
1.222 +#if ! BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
1.223 +BOOST_DLLEXPORT pointer_oserializer<T, Archive>::pointer_oserializer() :
1.224 + archive_pointer_oserializer<Archive>(
1.225 + * boost::serialization::type_info_implementation<T>::type::get_instance()
1.226 + ),
1.227 + m(boost::serialization::serialize_adl<Archive, T>),
1.228 + e(boost::serialization::type_info_implementation<T>::type::get_instance)
1.229 +#else
1.230 +BOOST_DLLEXPORT pointer_oserializer<T, Archive>::pointer_oserializer() :
1.231 + archive_pointer_oserializer<Archive>(
1.232 + * boost::serialization::type_info_implementation<T>::type::get_instance()
1.233 + )
1.234 +#endif
1.235 +{
1.236 + // make sure appropriate member function is instantiated
1.237 + oserializer<Archive, T> & bos = oserializer<Archive, T>::instantiate();
1.238 + bos.set_bpos(this);
1.239 +}
1.240 +
1.241 +template<class Archive, class T>
1.242 +struct save_non_pointer_type {
1.243 + // note this bounces the call right back to the archive
1.244 + // with no runtime overhead
1.245 + struct save_primitive {
1.246 + static void invoke(Archive & ar, const T & t){
1.247 + save_access::save_primitive(ar, t);
1.248 + }
1.249 + };
1.250 + // same as above but passes through serialization
1.251 + struct save_only {
1.252 + static void invoke(Archive & ar, const T & t){
1.253 + // make sure call is routed through the highest interface that might
1.254 + // be specialized by the user.
1.255 + boost::serialization::serialize_adl(
1.256 + ar,
1.257 + const_cast<T &>(t),
1.258 + ::boost::serialization::version<T>::value
1.259 + );
1.260 + }
1.261 + };
1.262 + // adds class information to the archive. This includes
1.263 + // serialization level and class version
1.264 + struct save_standard {
1.265 + static void invoke(Archive &ar, const T & t){
1.266 + ar.save_object(& t, oserializer<Archive, T>::instantiate());
1.267 + }
1.268 + };
1.269 +
1.270 + // adds class information to the archive. This includes
1.271 + // serialization level and class version
1.272 + struct save_conditional {
1.273 + static void invoke(Archive &ar, const T &t){
1.274 + //if(0 == (ar.get_flags() & no_tracking))
1.275 + save_standard::invoke(ar, t);
1.276 + //else
1.277 + // save_only::invoke(ar, t);
1.278 + }
1.279 + };
1.280 +
1.281 + typedef
1.282 + BOOST_DEDUCED_TYPENAME mpl::eval_if<
1.283 + // if its primitive
1.284 + mpl::equal_to<
1.285 + boost::serialization::implementation_level<T>,
1.286 + mpl::int_<boost::serialization::primitive_type>
1.287 + >,
1.288 + mpl::identity<save_primitive>,
1.289 + // else
1.290 + BOOST_DEDUCED_TYPENAME mpl::eval_if<
1.291 + // class info / version
1.292 + mpl::greater_equal<
1.293 + boost::serialization::implementation_level<T>,
1.294 + mpl::int_<boost::serialization::object_class_info>
1.295 + >,
1.296 + // do standard save
1.297 + mpl::identity<save_standard>,
1.298 + // else
1.299 + BOOST_DEDUCED_TYPENAME mpl::eval_if<
1.300 + // no tracking
1.301 + mpl::equal_to<
1.302 + boost::serialization::tracking_level<T>,
1.303 + mpl::int_<boost::serialization::track_never>
1.304 + >,
1.305 + // do a fast save
1.306 + mpl::identity<save_only>,
1.307 + // else
1.308 + // do a fast save only tracking is turned off
1.309 + mpl::identity<save_conditional>
1.310 + > > >::type typex;
1.311 +
1.312 + static void invoke(Archive & ar, const T & t){
1.313 + // check that we're not trying to serialize something that
1.314 + // has been marked not to be serialized. If this your program
1.315 + // traps here, you've tried to serialize a class whose trait
1.316 + // has been marked "non-serializable". Either reset the trait
1.317 + // (see level.hpp) or change program not to serialize items of this class
1.318 + BOOST_STATIC_ASSERT((
1.319 + mpl::greater_equal<
1.320 + boost::serialization::implementation_level<T>,
1.321 + mpl::int_<boost::serialization::primitive_type>
1.322 + >::value
1.323 + ));
1.324 + typex::invoke(ar, t);
1.325 + };
1.326 +};
1.327 +
1.328 +template<class Archive, class TPtr>
1.329 +struct save_pointer_type {
1.330 + template<class T>
1.331 + struct abstract
1.332 + {
1.333 + static const basic_pointer_oserializer * register_type(Archive & /* ar */){
1.334 + // it has? to be polymorphic
1.335 + BOOST_STATIC_ASSERT(
1.336 + boost::serialization::type_info_implementation<T>::type::is_polymorphic::value
1.337 + );
1.338 + return static_cast<const basic_pointer_oserializer *>(NULL);
1.339 + }
1.340 + };
1.341 +
1.342 + template<class T>
1.343 + struct non_abstract
1.344 + {
1.345 + static const basic_pointer_oserializer * register_type(Archive & ar){
1.346 + return ar.register_type(static_cast<T *>(NULL));
1.347 + }
1.348 + };
1.349 +
1.350 + template<class T>
1.351 + static const basic_pointer_oserializer * register_type(Archive &ar, T & /*t*/){
1.352 + // there should never be any need to save an abstract polymorphic
1.353 + // class pointer. Inhibiting code generation for this
1.354 + // permits abstract base classes to be used - note: exception
1.355 + // virtual serialize functions used for plug-ins
1.356 + typedef
1.357 + BOOST_DEDUCED_TYPENAME mpl::eval_if<
1.358 + serialization::is_abstract<T>,
1.359 + mpl::identity<abstract<T> >,
1.360 + mpl::identity<non_abstract<T> >
1.361 + >::type typex;
1.362 + return typex::register_type(ar);
1.363 + }
1.364 +
1.365 + template<class T>
1.366 + struct non_polymorphic
1.367 + {
1.368 + static void save(
1.369 + Archive &ar,
1.370 + const T & t,
1.371 + const basic_pointer_oserializer * bpos_ptr
1.372 + ){
1.373 + // save the requested pointer type
1.374 + ar.save_pointer(& t, bpos_ptr);
1.375 + }
1.376 + };
1.377 +
1.378 + template<class T>
1.379 + struct polymorphic
1.380 + {
1.381 + static void save(
1.382 + Archive &ar,
1.383 + const T & t,
1.384 + const basic_pointer_oserializer * bpos_ptr
1.385 + ){
1.386 + const boost::serialization::extended_type_info * this_type
1.387 + = boost::serialization::type_info_implementation<T>::type::get_instance();
1.388 + // retrieve the true type of the object pointed to
1.389 + // if this assertion fails its an error in this library
1.390 + assert(NULL != this_type);
1.391 + const boost::serialization::extended_type_info * true_type
1.392 + = boost::serialization::type_info_implementation<T>::type::get_derived_extended_type_info(t);
1.393 + // note:if this exception is thrown, be sure that derived pointer
1.394 + // is either regsitered or exported.
1.395 + if(NULL == true_type){
1.396 + boost::throw_exception(
1.397 + archive_exception(archive_exception::unregistered_class)
1.398 + );
1.399 + }
1.400 +
1.401 + // if its not a pointer to a more derived type
1.402 + const void *vp = static_cast<const void *>(&t);
1.403 + if(*this_type == *true_type){
1.404 + ar.save_pointer(vp, bpos_ptr);
1.405 + return;
1.406 + }
1.407 + // convert pointer to more derived type. if this is thrown
1.408 + // it means that the base/derived relationship hasn't be registered
1.409 + vp = serialization::void_downcast(*true_type, *this_type, &t);
1.410 + if(NULL == vp){
1.411 + boost::throw_exception(
1.412 + archive_exception(archive_exception::unregistered_cast)
1.413 + );
1.414 + }
1.415 +
1.416 + // sice true_type is valid, and this only gets made if the
1.417 + // pointer oserializer object has been created, this should never
1.418 + // fail
1.419 + bpos_ptr = archive_pointer_oserializer<Archive>::find(* true_type);
1.420 + assert(NULL != bpos_ptr);
1.421 + if(NULL == bpos_ptr)
1.422 + boost::throw_exception(
1.423 + archive_exception(archive_exception::unregistered_class)
1.424 + );
1.425 + ar.save_pointer(vp, bpos_ptr);
1.426 + }
1.427 + };
1.428 +
1.429 + template<class T>
1.430 + static void save(
1.431 + Archive & ar,
1.432 + const T &t,
1.433 + const basic_pointer_oserializer * bpos_ptr
1.434 + ){
1.435 + typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
1.436 + BOOST_DEDUCED_TYPENAME boost::serialization::
1.437 + type_info_implementation<T>::type::is_polymorphic,
1.438 + mpl::identity<polymorphic<T> >,
1.439 + mpl::identity<non_polymorphic<T> >
1.440 + >::type typey;
1.441 + typey::save(ar, const_cast<T &>(t), bpos_ptr);
1.442 + }
1.443 +
1.444 + template<class T>
1.445 + static void const_check(T & t){
1.446 + BOOST_STATIC_ASSERT(! boost::is_const<T>::value);
1.447 + }
1.448 +
1.449 + static void invoke(Archive &ar, const TPtr t){
1.450 + #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
1.451 + // if your program traps here, its because you tried to do
1.452 + // something like ar << t where t is a pointer to a const value
1.453 + // void f3(A const* a, text_oarchive& oa)
1.454 + // {
1.455 + // oa << a;
1.456 + // }
1.457 + // with a compiler which doesn't support remove_const
1.458 + // const_check(* t);
1.459 + #else
1.460 + // otherwise remove the const
1.461 + #endif
1.462 + const basic_pointer_oserializer * bpos_ptr = register_type(ar, * t);
1.463 + if(NULL == t){
1.464 + basic_oarchive & boa = boost::smart_cast_reference<basic_oarchive &>(ar);
1.465 + boa.save_null_pointer();
1.466 + save_access::end_preamble(ar);
1.467 + return;
1.468 + }
1.469 + save(ar, * t, bpos_ptr);
1.470 + };
1.471 +};
1.472 +
1.473 +template<class Archive, class T>
1.474 +struct save_enum_type
1.475 +{
1.476 + static void invoke(Archive &ar, const T &t){
1.477 + // convert enum to integers on save
1.478 + const int i = static_cast<int>(t);
1.479 + ar << boost::serialization::make_nvp(NULL, i);
1.480 + }
1.481 +};
1.482 +
1.483 +template<class Archive, class T>
1.484 +struct save_array_type
1.485 +{
1.486 + static void invoke(Archive &ar, const T &t){
1.487 + save_access::end_preamble(ar);
1.488 + // consider alignment
1.489 + int count = sizeof(t) / (
1.490 + static_cast<const char *>(static_cast<const void *>(&t[1]))
1.491 + - static_cast<const char *>(static_cast<const void *>(&t[0]))
1.492 + );
1.493 + ar << BOOST_SERIALIZATION_NVP(count);
1.494 + int i;
1.495 + for(i = 0; i < count; ++i)
1.496 + ar << boost::serialization::make_nvp("item", t[i]);
1.497 + }
1.498 +};
1.499 +
1.500 +// note bogus arguments to workaround msvc 6 silent runtime failure
1.501 +// declaration to satisfy gcc
1.502 +template<class Archive, class T>
1.503 +BOOST_DLLEXPORT const basic_pointer_oserializer &
1.504 +instantiate_pointer_oserializer(
1.505 + Archive * /* ar = NULL */,
1.506 + T * /* t = NULL */
1.507 +) BOOST_USED ;
1.508 +// definition
1.509 +template<class Archive, class T>
1.510 +BOOST_DLLEXPORT const basic_pointer_oserializer &
1.511 +instantiate_pointer_oserializer(
1.512 + Archive * /* ar = NULL */,
1.513 + T * /* t = NULL */
1.514 +){
1.515 + // note: reversal of order of arguments to work around msvc 6.0 bug
1.516 + // that manifests itself while trying to link.
1.517 + return pointer_oserializer<T, Archive>::instantiate();
1.518 +}
1.519 +
1.520 +} // detail
1.521 +
1.522 +template<class Archive, class T>
1.523 +inline void save(Archive & ar, const T &t){
1.524 + typedef
1.525 + BOOST_DEDUCED_TYPENAME mpl::eval_if<is_pointer<T>,
1.526 + mpl::identity<detail::save_pointer_type<Archive, T> >,
1.527 + //else
1.528 + BOOST_DEDUCED_TYPENAME mpl::eval_if<is_enum<T>,
1.529 + mpl::identity<detail::save_enum_type<Archive, T> >,
1.530 + //else
1.531 + BOOST_DEDUCED_TYPENAME mpl::eval_if<is_array<T>,
1.532 + mpl::identity<detail::save_array_type<Archive, T> >,
1.533 + //else
1.534 + mpl::identity<detail::save_non_pointer_type<Archive, T> >
1.535 + >
1.536 + >
1.537 + >::type typex;
1.538 + typex::invoke(ar, t);
1.539 +}
1.540 +
1.541 +#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
1.542 +
1.543 +template<class T>
1.544 +struct check_tracking {
1.545 + typedef BOOST_DEDUCED_TYPENAME mpl::if_<
1.546 + // if its never tracked.
1.547 + BOOST_DEDUCED_TYPENAME mpl::equal_to<
1.548 + serialization::tracking_level<T>,
1.549 + mpl::int_<serialization::track_never>
1.550 + >,
1.551 + // it better not be a pointer
1.552 + mpl::not_<is_pointer<T> >,
1.553 + //else
1.554 + // otherwise if it might be tracked. So there shouldn't
1.555 + // be any problem making a const
1.556 + is_const<T>
1.557 + >::type typex;
1.558 + BOOST_STATIC_CONSTANT(bool, value = typex::value);
1.559 +};
1.560 +
1.561 +template<class Archive, class T>
1.562 +inline void save(Archive & ar, T &t){
1.563 + // if your program traps here, it indicates taht your doing one of the following:
1.564 + // a) serializing an object of a type marked "track_never" through a pointer.
1.565 + // b) saving an non-const object of a type not markd "track_never)
1.566 + // Either of these conditions may be an indicator of an error usage of the
1.567 + // serialization library and should be double checked. See documentation on
1.568 + // object tracking.
1.569 + BOOST_STATIC_ASSERT(check_tracking<T>::value);
1.570 + save(ar, const_cast<const T &>(t));
1.571 +}
1.572 +#endif
1.573 +
1.574 +} // namespace archive
1.575 +} // namespace boost
1.576 +
1.577 +#endif // BOOST_ARCHIVE_OSERIALIZER_HPP