| QxOrm 1.4.9 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 /*****************************************************************************/
    00083 /*****************************************************************************/
    00084
    00085 #ifdef _QX_ENABLE_BOOST_SERIALIZATION
    00086 #if _QX_SERIALIZE_PORTABLE_BINARY
    00087 #ifndef _QX_PORTABLE_BINARY_IARCHIVE_H_
    00088 #define _QX_PORTABLE_BINARY_IARCHIVE_H_
    00089
    00090 #ifdef _MSC_VER
    00091 #pragma once
    00092 #endif // _MSC_VER
    00093
    00094 #ifdef _MSC_VER
    00095 #pragma warning(push)
    00096 #pragma warning(disable:4996)
    00097 #pragma warning(disable:4661)
    00098 #endif // _MSC_VER
    00099
    00100 #include <istream>
    00101
    00102 // basic headers
    00103 #include <boost/version.hpp>
    00104 #include <boost/utility/enable_if.hpp>
    00105 #include <boost/archive/basic_binary_iprimitive.hpp>
    00106 #include <boost/archive/basic_binary_iarchive.hpp>
    00107
    00108 #if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
    00109 #include <boost/archive/shared_ptr_helper.hpp>
    00110 #endif
    00111
    00112 // endian and fpclassify
    00113 #if BOOST_VERSION < 103600
    00114 #include <boost/integer/endian.hpp>
    00115 #include <boost/math/fpclassify.hpp>
    00116 #elif BOOST_VERSION < 104800
    00117 #include <boost/spirit/home/support/detail/integer/endian.hpp>
    00118 #include <boost/spirit/home/support/detail/math/fpclassify.hpp>
    00119 #else
    00120 #include <boost/spirit/home/support/detail/endian/endian.hpp>
    00121 #include <boost/spirit/home/support/detail/math/fpclassify.hpp>
    00122 #endif
    00123
    00124 // namespace alias
    00125 #if BOOST_VERSION < 103800
    00126 namespace fp = boost::math;
    00127 #else
    00128 namespace fp = boost::spirit::math;
    00129 #endif
    00130
    00131 // namespace alias endian
    00132 #if BOOST_VERSION < 104800
    00133 namespace endian = boost::detail;
    00134 #else
    00135 namespace endian = boost::spirit::detail;
    00136 #endif
    00137
    00138 #if BOOST_VERSION >= 104500 && !defined BOOST_NO_STD_WSTRING
    00139 // used for wstring to utf8 conversion
    00140 #include <boost/program_options/config.hpp>
    00141 #include <boost/program_options/detail/convert.hpp>
    00142 #endif
    00143
    00144 // generic type traits for numeric types
    00145 #include <boost/type_traits/is_integral.hpp>
    00146 #include <boost/type_traits/is_unsigned.hpp>
    00147 #include <boost/type_traits/is_arithmetic.hpp>
    00148 #include <boost/type_traits/is_floating_point.hpp>
    00149
    00150 #include "portable_archive_exception.hpp"
    00151
    00152 // hint from Johan Rade: on VMS there is still support for
    00153 // the VAX floating point format and this macro detects it
    00154 #if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT
    00155 #error "VAX floating point format is not supported!"
    00156 #endif
    00157
    00158 namespace eos {
    00159
    00160         // forward declaration
    00161         class portable_iarchive;
    00162
    00163         typedef boost::archive::basic_binary_iprimitive<
    00164                 portable_iarchive
    00165         #if BOOST_VERSION < 103400
    00166                 , std::istream
    00167         #else
    00168                 , std::istream::char_type
    00169                 , std::istream::traits_type
    00170         #endif
    00171         > portable_iprimitive;
    00172
    00187         class portable_iarchive : public portable_iprimitive
    00188
    00189                 // the example derives from common_oarchive but that lacks the
    00190                 // load_override functions so we chose to stay one level higher
    00191                 , public boost::archive::basic_binary_iarchive<portable_iarchive>
    00192
    00193         #if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
    00194                 // mix-in helper class for serializing shared_ptr
    00195                 , public boost::archive::detail::shared_ptr_helper
    00196         #endif
    00197         {
    00198                 // only needed for Robert's hack in basic_binary_iarchive::init
    00199                 friend class boost::archive::basic_binary_iarchive<portable_iarchive>;
    00200
    00201                 // workaround for gcc: use a dummy struct
    00202                 // as additional argument type for overloading
    00203                 template <int> struct dummy { dummy(int) {}};
    00204
    00205                 // loads directly from stream
    00206                 inline signed char load_signed_char()
    00207                 {
    00208                         signed char c;
    00209                         portable_iprimitive::load(c);
    00210                         return c;
    00211                 }
    00212
    00213                 // archive initialization
    00214                 void init(unsigned flags)
    00215                 {
    00216                         using namespace boost::archive;
    00217                         archive_version_type input_library_version(3);
    00218
    00219                         // it is vital to have version information!
    00220                         // if we don't have any we assume boost 1.33
    00221                         if (flags & no_header)
    00222                                 set_library_version(input_library_version);
    00223
    00224                         // extract and check the magic eos byte
    00225                         else if (load_signed_char() != magic_byte)
    00226                                 throw archive_exception(archive_exception::invalid_signature);
    00227
    00228                         else
    00229                         {
    00230                                 // extract version information
    00231                                 operator>>(input_library_version);
    00232
    00233                                 // throw if file version is newer than we are
    00234                                 if (input_library_version > archive_version)
    00235                                         throw archive_exception(archive_exception::unsupported_version);
    00236
    00237                                 // else set the library version accordingly
    00238                                 else set_library_version(input_library_version);
    00239                         }
    00240                 }
    00241
    00242         public:
    00254                 portable_iarchive(std::istream& is, unsigned flags = 0)
    00255                 #if BOOST_VERSION < 103400
    00256                         : portable_iprimitive(is, flags & boost::archive::no_codecvt)
    00257                 #else
    00258                         : portable_iprimitive(*is.rdbuf(), flags & boost::archive::no_codecvt)
    00259                 #endif
    00260                         , boost::archive::basic_binary_iarchive<portable_iarchive>(flags)
    00261                 {
    00262                         init(flags);
    00263                 }
    00264
    00265         #if BOOST_VERSION >= 103400
    00266                 portable_iarchive(std::streambuf& sb, unsigned flags = 0)
    00267                         : portable_iprimitive(sb, flags & boost::archive::no_codecvt)
    00268                         , boost::archive::basic_binary_iarchive<portable_iarchive>(flags)
    00269                 {
    00270                         init(flags);
    00271                 }
    00272         #endif
    00273
    00275                 void load(std::string& s)
    00276                 {
    00277                         portable_iprimitive::load(s);
    00278                 }
    00279
    00280         #ifndef BOOST_NO_STD_WSTRING
    00281
    00293                 void load(std::wstring& s)
    00294                 {
    00295                         std::string utf8;
    00296                         load(utf8);
    00297                         s = boost::from_utf8(utf8);
    00298                 }
    00299         #endif
    00300
    00314                 void load(bool& b)
    00315                 {
    00316                         switch (signed char c = load_signed_char())
    00317                         {
    00318                         case 0: b = false; break;
    00319                         case 1: b = load_signed_char(); break;
    00320                         default: throw portable_archive_exception(c);
    00321                         }
    00322                 }
    00323
    00331                 template <typename T>
    00332                 typename boost::enable_if<boost::is_integral<T> >::type
    00333                 load(T & t, dummy<2> = 0)
    00334                 {
    00335                         // get the number of bytes in the stream
    00336                         if (signed char size = load_signed_char())
    00337                         {
    00338                                 // check for negative value in unsigned type
    00339                                 if (size < 0 && boost::is_unsigned<T>::value)
    00340                                         throw portable_archive_exception();
    00341
    00342                                 // check that our type T is large enough
    00343                                 else if ((unsigned) abs(size) > sizeof(T))
    00344                                         throw portable_archive_exception(size);
    00345
    00346                                 // reconstruct the value
    00347                                 T temp = size < 0 ? -1 : 0;
    00348                                 load_binary(&temp, abs(size));
    00349
    00350                                 // load the value from little endian - it is then converted
    00351                                 // to the target type T and fits it because size <= sizeof(T)
    00352                                 t = endian::load_little_endian<T, sizeof(T)>(&temp);
    00353                         }
    00354
    00355                         else t = 0; // zero optimization
    00356                 }
    00357
    00385                 template <typename T>
    00386                 typename boost::enable_if<boost::is_floating_point<T> >::type
    00387                 load(T & t, dummy<3> = 0)
    00388                 {
    00389                         typedef typename fp::detail::fp_traits<T>::type traits;
    00390
    00391                         // if you end here there are three possibilities:
    00392                         // 1. you're serializing a long double which is not portable
    00393                         // 2. you're serializing a double but have no 64 bit integer
    00394                         // 3. your machine is using an unknown floating point format
    00395                         // after reading the note above you still might decide to
    00396                         // deactivate this static assert and try if it works out.
    00397                         typename traits::bits bits;
    00398                         BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T));
    00399                         BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_iec559);
    00400
    00401                         load(bits);
    00402                         traits::set_bits(t, bits);
    00403
    00404                         // if the no_infnan flag is set we must throw here
    00405                         if (get_flags() & no_infnan && !fp::isfinite(t))
    00406                                 throw portable_archive_exception(t);
    00407
    00408                         // if you end here your floating point type does not support
    00409                         // denormalized numbers. this might be the case even though
    00410                         // your type conforms to IEC 559 (and thus to IEEE 754)
    00411                         if (std::numeric_limits<T>::has_denorm == std::denorm_absent
    00412                                 && fp::fpclassify(t) == (int) FP_SUBNORMAL) // GCC4
    00413                                 throw portable_archive_exception(t);
    00414                 }
    00415
    00416                 // in boost 1.44 version_type was splitted into library_version_type and
    00417                 // item_version_type, plus a whole bunch of additional strong typedefs.
    00418                 template <typename T>
    00419                 typename boost::disable_if<boost::is_arithmetic<T> >::type
    00420                 load(T& t, dummy<4> = 0)
    00421                 {
    00422                         // we provide a generic load routine for all types that feature
    00423                         // conversion operators into an unsigned integer value like those
    00424                         // created through BOOST_STRONG_TYPEDEF(X, some unsigned int) like
    00425                         // library_version_type, collection_size_type, item_version_type,
    00426                         // class_id_type, object_id_type, version_type and tracking_type
    00427                         load((typename boost::uint_t<sizeof(T)*CHAR_BIT>::least&)(t));
    00428                 }
    00429         };
    00430
    00431 } // namespace eos
    00432
    00433 // this is required by export which registers all of your
    00434 // classes with all the inbuilt archives plus our archive.
    00435 #if BOOST_VERSION < 103500
    00436 #define BOOST_ARCHIVE_CUSTOM_IARCHIVE_TYPES eos::portable_iarchive
    00437 #else
    00438 BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_iarchive)
    00439 #endif
    00440
    00441 // if you include this header multiple times and your compiler is picky
    00442 // about multiple template instantiations (eg. gcc is) then you need to
    00443 // define NO_EXPLICIT_TEMPLATE_INSTANTIATION before every include but one
    00444 // or you move the instantiation section into an implementation file
    00445 #ifndef NO_EXPLICIT_TEMPLATE_INSTANTIATION
    00446
    00447 #ifndef _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_
    00448 #define _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_
    00449
    00450 #include <boost/archive/impl/basic_binary_iarchive.ipp>
    00451 #include <boost/archive/impl/basic_binary_oarchive.ipp>
    00452 #include <boost/archive/impl/basic_binary_iprimitive.ipp>
    00453 #include <boost/archive/impl/basic_binary_oprimitive.ipp>
    00454
    00455 #if _QX_SERIALIZE_TEXT
    00456 #include <boost/archive/impl/basic_text_oprimitive.ipp>
    00457 #include <boost/archive/impl/basic_text_iprimitive.ipp>
    00458 #include <boost/archive/impl/basic_text_oarchive.ipp>
    00459 #include <boost/archive/impl/basic_text_iarchive.ipp>
    00460 #endif // _QX_SERIALIZE_TEXT
    00461
    00462 #if (BOOST_VERSION < 104000)
    00463 #include <boost/archive/impl/archive_pointer_iserializer.ipp>
    00464 #include <boost/archive/impl/archive_pointer_oserializer.ipp>
    00465 #elif !defined BOOST_ARCHIVE_SERIALIZER_INCLUDED
    00466 #include <boost/archive/impl/archive_serializer_map.ipp>
    00467 #define BOOST_ARCHIVE_SERIALIZER_INCLUDED
    00468 #endif // (BOOST_VERSION < 104000)
    00469
    00470 #endif // _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_
    00471
    00472 namespace boost { namespace archive {
    00473
    00474         // explicitly instantiate for this type of binary stream
    00475         template class basic_binary_iarchive<eos::portable_iarchive>;
    00476
    00477         template class basic_binary_iprimitive<
    00478                 eos::portable_iarchive
    00479         #if BOOST_VERSION < 103400
    00480                 , std::istream
    00481         #else
    00482                 , std::istream::char_type
    00483                 , std::istream::traits_type
    00484         #endif
    00485         >;
    00486
    00487 #if (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON)
    00488 #if (BOOST_VERSION < 104000)
    00489         template class detail::archive_pointer_iserializer<eos::portable_iarchive>;
    00490 #else // (BOOST_VERSION < 104000)
    00491         template class detail::archive_serializer_map<eos::portable_iarchive>;
    00492 #endif // (BOOST_VERSION < 104000)
    00493 #endif // (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON)
    00494
    00495 } } // namespace boost::archive
    00496
    00497 #endif // NO_EXPLICIT_TEMPLATE_INSTANTIATION
    00498
    00499 #ifdef _MSC_VER
    00500 #pragma warning(pop)
    00501 #endif // _MSC_VER
    00502
    00503 #endif // _QX_PORTABLE_BINARY_IARCHIVE_H_
    00504 #endif // _QX_SERIALIZE_PORTABLE_BINARY
    00505 #endif // _QX_ENABLE_BOOST_SERIALIZATION