| QxOrm 1.4.3 C++ Object Relational Mapping library

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

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