| QxOrm 1.4.5 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 /*****************************************************************************/
    00086 /*****************************************************************************/
    00087
    00088 #ifdef _QX_ENABLE_BOOST_SERIALIZATION
    00089 #if _QX_SERIALIZE_PORTABLE_BINARY
    00090 #ifndef _QX_PORTABLE_BINARY_OARCHIVE_H_
    00091 #define _QX_PORTABLE_BINARY_OARCHIVE_H_
    00092
    00093 #ifdef _MSC_VER
    00094 #pragma once
    00095 #endif // _MSC_VER
    00096
    00097 #ifdef _MSC_VER
    00098 #pragma warning(push)
    00099 #pragma warning(disable:4996)
    00100 #pragma warning(disable:4661)
    00101 #endif // _MSC_VER
    00102
    00103 #include <ostream>
    00104
    00105 // basic headers
    00106 #include <boost/version.hpp>
    00107 #include <boost/utility/enable_if.hpp>
    00108 #include <boost/archive/basic_binary_oprimitive.hpp>
    00109 #include <boost/archive/basic_binary_oarchive.hpp>
    00110
    00111 #if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
    00112 #include <boost/archive/shared_ptr_helper.hpp>
    00113 #endif
    00114
    00115 // endian and fpclassify
    00116 #if BOOST_VERSION < 103600
    00117 #include <boost/integer/endian.hpp>
    00118 #include <boost/math/fpclassify.hpp>
    00119 #elif BOOST_VERSION < 104800
    00120 #include <boost/spirit/home/support/detail/integer/endian.hpp>
    00121 #include <boost/spirit/home/support/detail/math/fpclassify.hpp>
    00122 #else
    00123 #include <boost/spirit/home/support/detail/endian/endian.hpp>
    00124 #include <boost/spirit/home/support/detail/math/fpclassify.hpp>
    00125 #endif
    00126
    00127 // namespace alias fp_classify
    00128 #if BOOST_VERSION < 103800
    00129 namespace fp = boost::math;
    00130 #else
    00131 namespace fp = boost::spirit::math;
    00132 #endif
    00133
    00134 // namespace alias endian
    00135 #if BOOST_VERSION < 104800
    00136 namespace endian = boost::detail;
    00137 #else
    00138 namespace endian = boost::spirit::detail;
    00139 #endif
    00140
    00141 #if BOOST_VERSION >= 104500 && !defined BOOST_NO_STD_WSTRING
    00142 // used for wstring to utf8 conversion
    00143 #include <boost/program_options/config.hpp>
    00144 #include <boost/program_options/detail/convert.hpp>
    00145 #endif
    00146
    00147 // generic type traits for numeric types
    00148 #include <boost/type_traits/is_integral.hpp>
    00149 #include <boost/type_traits/is_signed.hpp>
    00150 #include <boost/type_traits/is_arithmetic.hpp>
    00151 #include <boost/type_traits/is_floating_point.hpp>
    00152
    00153 #include "portable_archive_exception.hpp"
    00154
    00155 // hint from Johan Rade: on VMS there is still support for
    00156 // the VAX floating point format and this macro detects it
    00157 #if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT
    00158 #error "VAX floating point format is not supported!"
    00159 #endif
    00160
    00161 namespace eos {
    00162
    00163         // forward declaration
    00164         class portable_oarchive;
    00165
    00166         typedef boost::archive::basic_binary_oprimitive<
    00167                 portable_oarchive
    00168         #if BOOST_VERSION < 103400
    00169                 , std::ostream
    00170         #else
    00171                 , std::ostream::char_type
    00172                 , std::ostream::traits_type
    00173         #endif
    00174         > portable_oprimitive;
    00175
    00188         class portable_oarchive : public portable_oprimitive
    00189
    00190                 // the example derives from common_oarchive but that lacks the
    00191                 // save_override functions so we chose to stay one level higher
    00192                 , public boost::archive::basic_binary_oarchive<portable_oarchive>
    00193
    00194         #if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
    00195                 // mix-in helper class for serializing shared_ptr
    00196                 , public boost::archive::detail::shared_ptr_helper
    00197         #endif
    00198         {
    00199                 // workaround for gcc: use a dummy struct
    00200                 // as additional argument type for overloading
    00201                 template<int> struct dummy { dummy(int) {}};
    00202
    00203                 // stores a signed char directly to stream
    00204                 inline void save_signed_char(const signed char& c)
    00205                 {
    00206                         portable_oprimitive::save(c);
    00207                 }
    00208
    00209                 // archive initialization
    00210                 void init(unsigned flags)
    00211                 {
    00212                         // it is vital to have version information if the archive is
    00213                         // to be parsed with a newer version of boost::serialization
    00214                         // therefor we create a header, no header means boost 1.33
    00215                         if (flags & boost::archive::no_header)
    00216                                 BOOST_ASSERT(archive_version == 3);
    00217                         else
    00218                         {
    00219                                 // write our minimalistic header (magic byte plus version)
    00220                                 // the boost archives write a string instead - by calling
    00221                                 // boost::archive::basic_binary_oarchive<derived_t>::init()
    00222                                 save_signed_char(magic_byte);
    00223
    00224                                 // write current version
    00225 //                              save<unsigned>(archive_version);
    00226                                 operator<<(archive_version);
    00227                         }
    00228                 }
    00229
    00230         public:
    00242                 portable_oarchive(std::ostream& os, unsigned flags = 0)
    00243                 #if BOOST_VERSION < 103400
    00244                         : portable_oprimitive(os, flags & boost::archive::no_codecvt)
    00245                 #else
    00246                         : portable_oprimitive(*os.rdbuf(), flags & boost::archive::no_codecvt)
    00247                 #endif
    00248                         , boost::archive::basic_binary_oarchive<portable_oarchive>(flags)
    00249                 {
    00250                         init(flags);
    00251                 }
    00252
    00253         #if BOOST_VERSION >= 103400
    00254                 portable_oarchive(std::streambuf& sb, unsigned flags = 0)
    00255                         : portable_oprimitive(sb, flags & boost::archive::no_codecvt)
    00256                         , boost::archive::basic_binary_oarchive<portable_oarchive>(flags)
    00257                 {
    00258                         init(flags);
    00259                 }
    00260         #endif
    00261
    00263                 void save(const std::string& s)
    00264                 {
    00265                         portable_oprimitive::save(s);
    00266                 }
    00267
    00268         #ifndef BOOST_NO_STD_WSTRING
    00269
    00281                 void save(const std::wstring& s)
    00282                 {
    00283                         save(boost::to_utf8(s));
    00284                 }
    00285         #endif
    00286
    00299                 void save(const bool& b)
    00300                 {
    00301                         save_signed_char(b);
    00302                         if (b) save_signed_char('T');
    00303                 }
    00304
    00312                 template <typename T>
    00313                 typename boost::enable_if<boost::is_integral<T> >::type
    00314                 save(const T & t, dummy<2> = 0)
    00315                 {
    00316                         if (T temp = t)
    00317                         {
    00318                                 // examine the number of bytes
    00319                                 // needed to represent the number
    00320                                 signed char size = 0;
    00321                                 do { temp >>= CHAR_BIT; ++size; }
    00322                                 while (temp != 0 && temp != (T) -1);
    00323
    00324                                 // encode the sign bit into the size
    00325                                 save_signed_char(t > 0 ? size : -size);
    00326                                 BOOST_ASSERT(t > 0 || boost::is_signed<T>::value);
    00327
    00328                                 // we choose to use little endian because this way we just
    00329                                 // save the first size bytes to the stream and skip the rest
    00330                                 endian::store_little_endian<T, sizeof(T)>(&temp, t);
    00331
    00332                                 save_binary(&temp, size);
    00333                         }
    00334                         // zero optimization
    00335                         else save_signed_char(0);
    00336                 }
    00337
    00365                 template <typename T>
    00366                 typename boost::enable_if<boost::is_floating_point<T> >::type
    00367                 save(const T & t, dummy<3> = 0)
    00368                 {
    00369                         typedef typename fp::detail::fp_traits<T>::type traits;
    00370
    00371                         // if the no_infnan flag is set we must throw here
    00372                         if (get_flags() & no_infnan && !fp::isfinite(t))
    00373                                 throw portable_archive_exception(t);
    00374
    00375                         // if you end here there are three possibilities:
    00376                         // 1. you're serializing a long double which is not portable
    00377                         // 2. you're serializing a double but have no 64 bit integer
    00378                         // 3. your machine is using an unknown floating point format
    00379                         // after reading the note above you still might decide to
    00380                         // deactivate this static assert and try if it works out.
    00381                         typename traits::bits bits;
    00382                         BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T));
    00383                         BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_iec559);
    00384
    00385                         // examine value closely
    00386                         switch (fp::fpclassify(t))
    00387                         {
    00388                         //case FP_ZERO: bits = 0; break;
    00389                         case FP_NAN: bits = traits::exponent | traits::mantissa; break;
    00390                         case FP_INFINITE: bits = traits::exponent | (t<0) * traits::sign; break;
    00391                         case FP_SUBNORMAL: assert(std::numeric_limits<T>::has_denorm); // pass
    00392                         case FP_ZERO: // note that floats can be ±0.0
    00393                         case FP_NORMAL: traits::get_bits(t, bits); break;
    00394                         default: throw portable_archive_exception(t);
    00395                         }
    00396
    00397                         save(bits);
    00398                 }
    00399
    00400                 // in boost 1.44 version_type was splitted into library_version_type and
    00401                 // item_version_type, plus a whole bunch of additional strong typedefs.
    00402                 template <typename T>
    00403                 typename boost::disable_if<boost::is_arithmetic<T> >::type
    00404                 save(const T& t, dummy<4> = 0)
    00405                 {
    00406                         // we provide a generic save routine for all types that feature
    00407                         // conversion operators into an unsigned integer value like those
    00408                         // created through BOOST_STRONG_TYPEDEF(X, some unsigned int) like
    00409                         // library_version_type, collection_size_type, item_version_type,
    00410                         // class_id_type, object_id_type, version_type and tracking_type
    00411                         save((typename boost::uint_t<sizeof(T)*CHAR_BIT>::least)(t));
    00412                 }
    00413         };
    00414
    00415 } // namespace eos
    00416
    00417 // required by export
    00418 #if BOOST_VERSION < 103500
    00419 #define BOOST_ARCHIVE_CUSTOM_OARCHIVE_TYPES eos::portable_oarchive
    00420 #else
    00421 BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_oarchive)
    00422 #endif
    00423
    00424 // if you include this header multiple times and your compiler is picky
    00425 // about multiple template instantiations (eg. gcc is) then you need to
    00426 // define NO_EXPLICIT_TEMPLATE_INSTANTIATION before every include but one
    00427 // or you move the instantiation section into an implementation file
    00428 #ifndef NO_EXPLICIT_TEMPLATE_INSTANTIATION
    00429
    00430 #ifndef _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_
    00431 #define _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_
    00432
    00433 #include <boost/archive/impl/basic_binary_iarchive.ipp>
    00434 #include <boost/archive/impl/basic_binary_oarchive.ipp>
    00435 #include <boost/archive/impl/basic_binary_iprimitive.ipp>
    00436 #include <boost/archive/impl/basic_binary_oprimitive.ipp>
    00437
    00438 #if _QX_SERIALIZE_TEXT
    00439 #include <boost/archive/impl/basic_text_oprimitive.ipp>
    00440 #include <boost/archive/impl/basic_text_iprimitive.ipp>
    00441 #include <boost/archive/impl/basic_text_oarchive.ipp>
    00442 #include <boost/archive/impl/basic_text_iarchive.ipp>
    00443 #endif // _QX_SERIALIZE_TEXT
    00444
    00445 #if (BOOST_VERSION < 104000)
    00446 #include <boost/archive/impl/archive_pointer_iserializer.ipp>
    00447 #include <boost/archive/impl/archive_pointer_oserializer.ipp>
    00448 #elif !defined BOOST_ARCHIVE_SERIALIZER_INCLUDED
    00449 #include <boost/archive/impl/archive_serializer_map.ipp>
    00450 #define BOOST_ARCHIVE_SERIALIZER_INCLUDED
    00451 #endif // (BOOST_VERSION < 104000)
    00452
    00453 #endif // _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_
    00454
    00455 namespace boost { namespace archive {
    00456
    00457         // explicitly instantiate for this type of binary stream
    00458         template class basic_binary_oarchive<eos::portable_oarchive>;
    00459
    00460         template class basic_binary_oprimitive<
    00461                 eos::portable_oarchive
    00462         #if BOOST_VERSION < 103400
    00463                 , std::ostream
    00464         #else
    00465                 , std::ostream::char_type
    00466                 , std::ostream::traits_type
    00467         #endif
    00468         >;
    00469
    00470 #if (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON)
    00471 #if (BOOST_VERSION < 104000)
    00472         template class detail::archive_pointer_oserializer<eos::portable_oarchive>;
    00473 #else // (BOOST_VERSION < 104000)
    00474         template class detail::archive_serializer_map<eos::portable_oarchive>;
    00475 #endif // (BOOST_VERSION < 104000)
    00476 #endif // (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON)
    00477
    00478 } } // namespace boost::archive
    00479
    00480 #endif // NO_EXPLICIT_TEMPLATE_INSTANTIATION
    00481
    00482 #ifdef _MSC_VER
    00483 #pragma warning(pop)
    00484 #endif // _MSC_VER
    00485
    00486 #endif // _QX_PORTABLE_BINARY_OARCHIVE_H_
    00487 #endif // _QX_SERIALIZE_PORTABLE_BINARY
    00488 #endif // _QX_ENABLE_BOOST_SERIALIZATION