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