![]() |
QxOrm
1.2.3
C++ Object Relational Mapping library
|
00001 /*****************************************************************************/ 00060 /*****************************************************************************/ 00061 00062 #if _QX_SERIALIZE_PORTABLE_BINARY 00063 #ifndef _QX_PORTABLE_BINARY_OARCHIVE_H_ 00064 #define _QX_PORTABLE_BINARY_OARCHIVE_H_ 00065 00066 #ifdef _MSC_VER 00067 #pragma once 00068 #endif // _MSC_VER 00069 00070 #ifdef _MSC_VER 00071 #pragma warning(push) 00072 #pragma warning(disable:4996) 00073 #pragma warning(disable:4661) 00074 #endif // _MSC_VER 00075 00076 #include <ostream> 00077 00078 // basic headers 00079 #include <boost/version.hpp> 00080 #include <boost/utility/enable_if.hpp> 00081 #include <boost/archive/binary_oarchive.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_signed.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 namespace eos { 00114 00115 // forward declaration 00116 class portable_oarchive; 00117 00118 // convenience archive base class typedef 00119 typedef boost::archive::binary_oarchive_impl< 00120 portable_oarchive 00121 #if BOOST_VERSION >= 103400 00122 , std::ostream::char_type 00123 , std::ostream::traits_type 00124 #endif 00125 > portable_oarchive_base; 00126 00142 class portable_oarchive : public portable_oarchive_base 00143 #if BOOST_VERSION >= 103500 00144 // mix-in helper class for serializing shared_ptr 00145 , public boost::archive::detail::shared_ptr_helper 00146 #endif 00147 { 00148 // workaround for gcc: use a dummy struct 00149 // as additional argument type for overloading 00150 template<int> struct dummy { dummy(int) {}}; 00151 00152 // stores a signed char directly to stream 00153 void save_signed_char(const signed char& c) 00154 { 00155 portable_oarchive_base::save(c); 00156 } 00157 00158 public: 00159 00161 template<class T> 00162 typename boost::disable_if<boost::is_arithmetic<T> >::type 00163 save(const T & t, dummy<1> = 0) 00164 { 00165 portable_oarchive_base::save(t); 00166 } 00167 00169 void save(const bool& b) 00170 { 00171 save_signed_char(b); 00172 if (b) save_signed_char('T'); 00173 } 00174 00182 template <typename T> 00183 typename boost::enable_if<boost::is_integral<T> >::type 00184 save(const T & t, dummy<2> = 0) 00185 { 00186 if (T temp = t) 00187 { 00188 // examine the number of bytes 00189 // needed to represent the number 00190 signed char size = 0; 00191 do { temp >>= CHAR_BIT; ++size; } 00192 while (temp != 0 && temp != (T) -1); 00193 00194 // encode the sign bit into the size 00195 save_signed_char(t > 0 ? size : -size); 00196 BOOST_ASSERT(t > 0 || boost::is_signed<T>::value); 00197 00198 // we choose to use little endian because this way we just 00199 // save the first size bytes to the stream and skip the rest 00200 boost::detail::store_little_endian<T, sizeof(T)>(&temp, t); 00201 save_binary(&temp, size); 00202 } 00203 // zero optimization 00204 else save_signed_char(0); 00205 } 00206 00234 template <typename T> 00235 typename boost::enable_if<boost::is_floating_point<T> >::type 00236 save(const T & t, dummy<3> = 0) 00237 { 00238 typedef typename fp::detail::fp_traits<T>::type traits; 00239 00240 // it is not supported to serialize infinity or not-a-number 00241 if (!fp::isfinite(t)) throw portable_archive_exception(t); 00242 00243 // if you end here there are three possibilities: 00244 // 1. you're serializing a long double which is not portable 00245 // 2. you're serializing a double but have no 64 bit integer 00246 // 3. your machine is using an unknown floating point format 00247 // after reading the note above you still might decide to 00248 // deactivate this static assert and try if it works out. 00249 typename traits::bits bits; 00250 BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T)); 00251 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_iec559); 00252 00253 traits::get_bits(t, bits); 00254 save(bits); 00255 } 00256 00258 portable_oarchive(std::ostream& os, unsigned flags = 0) 00259 // the base class constructor calls basic_binary_oarchive::init 00260 // but also basic_binary_oprimitive::init which stores type sizes 00261 // for comparison when loading them on a different platform 00262 : portable_oarchive_base(os, flags | boost::archive::no_header) 00263 { 00264 // it is vital to have version information if the archive is 00265 // to be parsed with a newer version of boost::serialization 00266 // therefor we create a header, no header means boost 1.33 00267 if (flags & boost::archive::no_header) 00268 BOOST_ASSERT(archive_version == 3); 00269 else 00270 { 00271 // write our minimalistic header (magic byte plus version) 00272 // the boost archives write a string instead - by calling 00273 // boost::archive::basic_binary_oarchive<derived_t>::init() 00274 save_signed_char(magic_byte); 00275 00276 // write current version 00277 operator<<(archive_version); 00278 } 00279 } 00280 }; 00281 00282 } // namespace eos 00283 00284 // required by export 00285 #if BOOST_VERSION < 103500 00286 #define BOOST_ARCHIVE_CUSTOM_OARCHIVE_TYPES eos::portable_oarchive 00287 #else 00288 BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_oarchive) 00289 #endif 00290 00291 namespace boost { namespace archive { 00292 00293 // explicitly instantiate for this type of binary stream 00294 template class basic_binary_oarchive<eos::portable_oarchive>; 00295 00296 template class basic_binary_oprimitive< 00297 eos::portable_oarchive 00298 #if BOOST_VERSION < 103400 00299 , std::ostream 00300 #else 00301 , std::ostream::char_type 00302 , std::ostream::traits_type 00303 #endif 00304 >; 00305 00306 template class binary_oarchive_impl< 00307 eos::portable_oarchive 00308 #if BOOST_VERSION >= 103400 00309 , std::ostream::char_type 00310 , std::ostream::traits_type 00311 #endif 00312 >; 00313 00314 #if (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON) 00315 #if (BOOST_VERSION > 103800) 00316 template class detail::archive_serializer_map<eos::portable_oarchive>; 00317 #else 00318 template class detail::archive_pointer_oserializer<eos::portable_oarchive>; 00319 #endif // (BOOST_VERSION > 103800) 00320 #endif // (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON) 00321 00322 } } // namespace boost::archive 00323 00324 #ifdef _MSC_VER 00325 #pragma warning(pop) 00326 #endif // _MSC_VER 00327 00328 #endif // _QX_PORTABLE_BINARY_OARCHIVE_H_ 00329 #endif //_QX_SERIALIZE_PORTABLE_BINARY