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