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