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