| QxOrm 1.4.3 C++ Object Relational Mapping library

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

- File List
- File Members

portable_iarchive.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_IARCHIVE_H_
    00065 #define _QX_PORTABLE_BINARY_IARCHIVE_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 <istream>
    00078
    00079 // basic headers
    00080 #include <boost/version.hpp>
    00081 #include <boost/utility/enable_if.hpp>
    00082 #include <boost/archive/binary_iarchive.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_unsigned.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 #if (BOOST_VERSION >= 104400)
    00115 #define QX_ARCHIVE_PORTABLE_BINARY_VERSION_PATCH (boost::archive::library_version_type)(3)
    00116 #elif (BOOST_VERSION >= 104200)
    00117 #define QX_ARCHIVE_PORTABLE_BINARY_VERSION_PATCH (boost::archive::version_type)(3)
    00118 #else // (BOOST_VERSION >= 104200)
    00119 #define QX_ARCHIVE_PORTABLE_BINARY_VERSION_PATCH 3
    00120 #endif // (BOOST_VERSION >= 104200)
    00121
    00122 namespace eos {
    00123
    00124    // forward declaration
    00125    class portable_iarchive;
    00126
    00127    // convenience archive base class typedef
    00128    typedef boost::archive::binary_iarchive_impl<
    00129       portable_iarchive
    00130       #if BOOST_VERSION >= 103400
    00131          , std::istream::char_type
    00132          , std::istream::traits_type
    00133       #endif
    00134    > portable_iarchive_base;
    00135
    00153    class portable_iarchive : public portable_iarchive_base
    00154    #if BOOST_VERSION >= 103500
    00155       // mix-in helper class for serializing shared_ptr
    00156       , public boost::archive::detail::shared_ptr_helper
    00157    #endif
    00158    {
    00159       // workaround for gcc: use a dummy struct
    00160       // as additional argument type for overloading
    00161       template <int> struct dummy { dummy(int) {}};
    00162
    00163       // loads directly from stream
    00164       signed char load_signed_char()
    00165       {
    00166          signed char c;
    00167          portable_iarchive_base::load(c);
    00168          return c;
    00169       }
    00170
    00171    public:
    00172
    00174       template <class T>
    00175       typename boost::disable_if<boost::is_arithmetic<T> >::type
    00176       load(T& t, dummy<1> = 0)
    00177       {
    00178          portable_iarchive_base::load(t);
    00179       }
    00180
    00184       void load(bool& b)
    00185       {
    00186          switch (signed char c = load_signed_char())
    00187          {
    00188             case 0: b = false; break;
    00189             case 1: b = load_signed_char(); break;
    00190             default: throw portable_archive_exception(c);
    00191          }
    00192       }
    00193
    00201       template <typename T>
    00202       typename boost::enable_if<boost::is_integral<T> >::type
    00203       load(T & t, dummy<2> = 0)
    00204       {
    00205          // get the number of bytes in the stream
    00206          if (signed char size = load_signed_char())
    00207          {
    00208             // check for negative value in unsigned type
    00209             if (size < 0 && boost::is_unsigned<T>::value) throw portable_archive_exception();
    00210
    00211             // check that our type T is large enough
    00212             else if ((unsigned) abs(size) > sizeof(T)) throw portable_archive_exception(size);
    00213
    00214             // reconstruct the value
    00215             T temp = size < 0 ? -1 : 0;
    00216             load_binary(&temp, abs(size));
    00217
    00218             // load the value from little endian - is is then converted
    00219             // to the target type T and fits it because size <= sizeof(T)
    00220             t = boost::detail::load_little_endian<T, sizeof(T)>(&temp);
    00221          }
    00222          else t = 0; // zero optimization
    00223       }
    00224
    00252       template <typename T>
    00253       typename boost::enable_if<boost::is_floating_point<T> >::type
    00254       load(T & t, dummy<3> = 0)
    00255       {
    00256          typedef typename fp::detail::fp_traits<T>::type traits;
    00257
    00258          // if you end here there are three possibilities:
    00259          // 1. you're serializing a long double which is not portable
    00260          // 2. you're serializing a double but have no 64 bit integer
    00261          // 3. your machine is using an unknown floating point format
    00262          // after reading the note above you still might decide to
    00263          // deactivate this static assert and try if it works out.
    00264          typename traits::bits bits;
    00265          BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T));
    00266          BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_iec559);
    00267
    00268          load(bits);
    00269          traits::set_bits(t, bits);
    00270
    00271          // if you end here your floating point type does not support
    00272          // denormalized numbers. this might be the case even though
    00273          // your type conforms to IEC 559 (and thus to IEEE 754)
    00274          if (std::numeric_limits<T>::has_denorm == std::denorm_absent
    00275          && t && !fp::isnormal(t)) throw portable_archive_exception(t);
    00276       }
    00277
    00279       portable_iarchive(std::istream& is, unsigned flags = 0)
    00280          // the base class constructor calls basic_binary_iarchive::init
    00281          // but also basic_binary_iprimitive::init which loads type sizes
    00282          // and throws an exception when they are different - no way!
    00283          : portable_iarchive_base(is, flags | boost::archive::no_header)
    00284       {
    00285          using namespace boost::archive;
    00286
    00287          // it is vital to have version information!
    00288          // if we don't have any we assume boost 1.33
    00289          if (flags & no_header) set_library_version(QX_ARCHIVE_PORTABLE_BINARY_VERSION_PATCH);
    00290
    00291          // extract and check the magic eos byte
    00292          else if (load_signed_char() != magic_byte) throw archive_exception(archive_exception::invalid_signature);
    00293
    00294          else
    00295          {
    00296             // extract version information
    00297             version_type input_library_version;
    00298             operator>>(input_library_version);
    00299
    00300             // throw if file version is newer than we are
    00301             if (input_library_version > archive_version)
    00302             throw archive_exception(archive_exception::unsupported_version);
    00303
    00304             // else set the library version accordingly
    00305             else set_library_version(input_library_version);
    00306          }
    00307       }
    00308    };
    00309
    00310 } // namespace eos
    00311
    00312 // this is required by export which registers all of your
    00313 // classes with all the inbuilt archives plus our archive.
    00314 #if BOOST_VERSION < 103500
    00315 #define BOOST_ARCHIVE_CUSTOM_IARCHIVE_TYPES eos::portable_iarchive
    00316 #else
    00317 BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_iarchive)
    00318 #endif
    00319
    00320 namespace boost { namespace archive {
    00321
    00322    // explicitly instantiate for this type of binary stream
    00323    template class basic_binary_iarchive<eos::portable_iarchive>;
    00324
    00325    template class basic_binary_iprimitive<
    00326       eos::portable_iarchive
    00327       #if BOOST_VERSION < 103400
    00328          , std::istream
    00329       #else
    00330          , std::istream::char_type
    00331          , std::istream::traits_type
    00332       #endif
    00333    >;
    00334
    00335    template class binary_iarchive_impl<
    00336       eos::portable_iarchive
    00337       #if BOOST_VERSION >= 103400
    00338          , std::istream::char_type
    00339          , std::istream::traits_type
    00340       #endif
    00341    >;
    00342
    00343 #if (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON)
    00344 #if (BOOST_VERSION > 103800)
    00345    template class detail::archive_serializer_map<eos::portable_iarchive>;
    00346 #else
    00347    template class detail::archive_pointer_iserializer<eos::portable_iarchive>;
    00348 #endif // (BOOST_VERSION > 103800)
    00349 #endif // (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON)
    00350
    00351 } } // namespace boost::archive
    00352
    00353 #ifdef _MSC_VER
    00354 #pragma warning(pop)
    00355 #endif // _MSC_VER
    00356
    00357 #endif // _QX_PORTABLE_BINARY_IARCHIVE_H_
    00358 #endif // _QX_SERIALIZE_PORTABLE_BINARY
    00359 #endif // _QX_ENABLE_BOOST_SERIALIZATION