QxOrm  1.4.1
C++ Object Relational Mapping library
portable_oarchive.hpp
Go to the documentation of this file.
00001 /*****************************************************************************/
00060 /*****************************************************************************/
00061 
00062 #ifdef _QX_ENABLE_BOOST_SERIALIZATION
00063 #if _QX_SERIALIZE_PORTABLE_BINARY
00064 #ifndef _QX_PORTABLE_BINARY_OARCHIVE_H_
00065 #define _QX_PORTABLE_BINARY_OARCHIVE_H_
00066 
00067 #ifdef _MSC_VER
00068 #pragma once
00069 #endif // _MSC_VER
00070 
00071 #ifdef _MSC_VER
00072 #pragma warning(push)
00073 #pragma warning(disable:4996)
00074 #pragma warning(disable:4661)
00075 #endif // _MSC_VER
00076 
00077 #include <ostream>
00078 
00079 // basic headers
00080 #include <boost/version.hpp>
00081 #include <boost/utility/enable_if.hpp>
00082 #include <boost/archive/binary_oarchive.hpp>
00083 
00084 // endian and fpclassify
00085 #if BOOST_VERSION < 103600
00086 #include <boost/integer/endian.hpp>
00087 #include <boost/math/fpclassify.hpp>
00088 #else
00089 #include <boost/spirit/home/support/detail/integer/endian.hpp>
00090 #include <boost/spirit/home/support/detail/math/fpclassify.hpp>
00091 #endif
00092 
00093 // namespace alias
00094 #if BOOST_VERSION < 103800
00095 namespace fp = boost::math;
00096 #else
00097 namespace fp = boost::spirit::math;
00098 #endif
00099 
00100 // generic type traits for numeric types
00101 #include <boost/type_traits/is_integral.hpp>
00102 #include <boost/type_traits/is_signed.hpp>
00103 #include <boost/type_traits/is_arithmetic.hpp>
00104 #include <boost/type_traits/is_floating_point.hpp>
00105 
00106 #include "portable_archive_exception.hpp"
00107 
00108 // hint from Johan Rade: on VMS there is still support for
00109 // the VAX floating point format and this macro detects it
00110 #if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT
00111 #error "VAX floating point format is not supported!"
00112 #endif
00113 
00114 namespace eos {
00115 
00116    // forward declaration
00117    class portable_oarchive;
00118 
00119    // convenience archive base class typedef
00120    typedef boost::archive::binary_oarchive_impl<
00121       portable_oarchive
00122       #if BOOST_VERSION >= 103400
00123          , std::ostream::char_type 
00124          , std::ostream::traits_type
00125       #endif
00126    > portable_oarchive_base;
00127 
00143    class portable_oarchive : public portable_oarchive_base
00144       #if BOOST_VERSION >= 103500
00145          // mix-in helper class for serializing shared_ptr
00146          , public boost::archive::detail::shared_ptr_helper
00147       #endif
00148    {
00149       // workaround for gcc: use a dummy struct
00150       // as additional argument type for overloading
00151       template<int> struct dummy { dummy(int) {}};
00152 
00153       // stores a signed char directly to stream
00154       void save_signed_char(const signed char& c) 
00155       { 
00156          portable_oarchive_base::save(c); 
00157       }
00158 
00159    public:
00160 
00162       template<class T>
00163       typename boost::disable_if<boost::is_arithmetic<T> >::type 
00164       save(const T & t, dummy<1> = 0)
00165       {
00166          portable_oarchive_base::save(t);
00167       }
00168 
00170       void save(const bool& b) 
00171       {
00172          save_signed_char(b);
00173          if (b) save_signed_char('T');
00174       }
00175 
00183       template <typename T>
00184       typename boost::enable_if<boost::is_integral<T> >::type
00185       save(const T & t, dummy<2> = 0)
00186       {
00187          if (T temp = t)
00188          {
00189             // examine the number of bytes
00190             // needed to represent the number
00191             signed char size = 0;
00192             do { temp >>= CHAR_BIT; ++size; } 
00193             while (temp != 0 && temp != (T) -1);
00194 
00195             // encode the sign bit into the size
00196             save_signed_char(t > 0 ? size : -size);
00197             BOOST_ASSERT(t > 0 || boost::is_signed<T>::value);
00198 
00199             // we choose to use little endian because this way we just
00200             // save the first size bytes to the stream and skip the rest
00201             boost::detail::store_little_endian<T, sizeof(T)>(&temp, t);
00202             save_binary(&temp, size);
00203          }
00204          // zero optimization
00205          else save_signed_char(0);
00206       }
00207 
00235       template <typename T>
00236       typename boost::enable_if<boost::is_floating_point<T> >::type
00237       save(const T & t, dummy<3> = 0)
00238       {
00239          typedef typename fp::detail::fp_traits<T>::type traits;
00240 
00241          // it is not supported to serialize infinity or not-a-number
00242          if (!fp::isfinite(t)) throw portable_archive_exception(t);
00243 
00244          // if you end here there are three possibilities:
00245          // 1. you're serializing a long double which is not portable
00246          // 2. you're serializing a double but have no 64 bit integer
00247          // 3. your machine is using an unknown floating point format
00248          // after reading the note above you still might decide to 
00249          // deactivate this static assert and try if it works out.
00250          typename traits::bits bits;
00251          BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T));
00252          BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_iec559);
00253 
00254          traits::get_bits(t, bits);
00255          save(bits);
00256       }
00257 
00259       portable_oarchive(std::ostream& os, unsigned flags = 0)
00260          // the base class constructor calls basic_binary_oarchive::init
00261          // but also basic_binary_oprimitive::init which stores type sizes
00262          // for comparison when loading them on a different platform
00263          : portable_oarchive_base(os, flags | boost::archive::no_header) 
00264       {
00265          // it is vital to have version information if the archive is
00266          // to be parsed with a newer version of boost::serialization
00267          // therefor we create a header, no header means boost 1.33
00268          if (flags & boost::archive::no_header)
00269             BOOST_ASSERT(archive_version == 3);
00270          else
00271          {
00272             // write our minimalistic header (magic byte plus version)
00273             // the boost archives write a string instead - by calling
00274             // boost::archive::basic_binary_oarchive<derived_t>::init()
00275             save_signed_char(magic_byte);
00276 
00277             // write current version
00278             operator<<(archive_version);
00279          }
00280       }
00281    };
00282 
00283 } // namespace eos
00284 
00285 // required by export
00286 #if BOOST_VERSION < 103500
00287 #define BOOST_ARCHIVE_CUSTOM_OARCHIVE_TYPES eos::portable_oarchive
00288 #else
00289 BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_oarchive)
00290 #endif
00291 
00292 namespace boost { namespace archive {
00293 
00294    // explicitly instantiate for this type of binary stream
00295    template class basic_binary_oarchive<eos::portable_oarchive>;
00296 
00297    template class basic_binary_oprimitive<
00298       eos::portable_oarchive
00299       #if BOOST_VERSION < 103400
00300          , std::ostream
00301       #else
00302          , std::ostream::char_type
00303          , std::ostream::traits_type
00304       #endif
00305    >;
00306 
00307    template class binary_oarchive_impl<
00308       eos::portable_oarchive
00309       #if BOOST_VERSION >= 103400
00310          , std::ostream::char_type
00311          , std::ostream::traits_type
00312       #endif
00313    >;
00314 
00315 #if (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON)
00316 #if (BOOST_VERSION > 103800)
00317    template class detail::archive_serializer_map<eos::portable_oarchive>;
00318 #else
00319    template class detail::archive_pointer_oserializer<eos::portable_oarchive>;
00320 #endif // (BOOST_VERSION > 103800)
00321 #endif // (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON)
00322 
00323 } } // namespace boost::archive
00324 
00325 #ifdef _MSC_VER
00326 #pragma warning(pop)
00327 #endif // _MSC_VER
00328 
00329 #endif // _QX_PORTABLE_BINARY_OARCHIVE_H_
00330 #endif // _QX_SERIALIZE_PORTABLE_BINARY
00331 #endif // _QX_ENABLE_BOOST_SERIALIZATION