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