QxOrm 1.4.9
C++ Object Relational Mapping library
Loading...
Searching...
No Matches
portable_iarchive.hpp
Go to the documentation of this file.
1/*****************************************************************************/
83/*****************************************************************************/
84
85#ifdef _QX_ENABLE_BOOST_SERIALIZATION
86#if _QX_SERIALIZE_PORTABLE_BINARY
87#ifndef _QX_PORTABLE_BINARY_IARCHIVE_H_
88#define _QX_PORTABLE_BINARY_IARCHIVE_H_
89
90#ifdef _MSC_VER
91#pragma once
92#endif // _MSC_VER
93
94#ifdef _MSC_VER
95#pragma warning(push)
96#pragma warning(disable:4996)
97#pragma warning(disable:4661)
98#endif // _MSC_VER
99
100#include <istream>
101
102// basic headers
103#include <boost/version.hpp>
104#include <boost/utility/enable_if.hpp>
105#include <boost/archive/basic_binary_iprimitive.hpp>
106#include <boost/archive/basic_binary_iarchive.hpp>
107
108#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
109#include <boost/archive/shared_ptr_helper.hpp>
110#endif
111
112// endian and fpclassify
113#if BOOST_VERSION < 103600
114#include <boost/integer/endian.hpp>
115#include <boost/math/fpclassify.hpp>
116#elif BOOST_VERSION < 104800
117#include <boost/spirit/home/support/detail/integer/endian.hpp>
118#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
119#else
120#include <boost/spirit/home/support/detail/endian/endian.hpp>
121#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
122#endif
123
124// namespace alias
125#if BOOST_VERSION < 103800
126namespace fp = boost::math;
127#else
128namespace fp = boost::spirit::math;
129#endif
130
131// namespace alias endian
132#if BOOST_VERSION < 104800
133namespace endian = boost::detail;
134#else
135namespace endian = boost::spirit::detail;
136#endif
137
138#if BOOST_VERSION >= 104500 && !defined BOOST_NO_STD_WSTRING
139// used for wstring to utf8 conversion
140#include <boost/program_options/config.hpp>
141#include <boost/program_options/detail/convert.hpp>
142#endif
143
144// generic type traits for numeric types
145#include <boost/type_traits/is_integral.hpp>
146#include <boost/type_traits/is_unsigned.hpp>
147#include <boost/type_traits/is_arithmetic.hpp>
148#include <boost/type_traits/is_floating_point.hpp>
149
151
152// hint from Johan Rade: on VMS there is still support for
153// the VAX floating point format and this macro detects it
154#if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT
155#error "VAX floating point format is not supported!"
156#endif
157
158namespace eos {
159
160 // forward declaration
161 class portable_iarchive;
162
163 typedef boost::archive::basic_binary_iprimitive<
164 portable_iarchive
165 #if BOOST_VERSION < 103400
166 , std::istream
167 #else
168 , std::istream::char_type
169 , std::istream::traits_type
170 #endif
172
188
189 // the example derives from common_oarchive but that lacks the
190 // load_override functions so we chose to stay one level higher
191 , public boost::archive::basic_binary_iarchive<portable_iarchive>
192
193 #if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
194 // mix-in helper class for serializing shared_ptr
195 , public boost::archive::detail::shared_ptr_helper
196 #endif
197 {
198 // only needed for Robert's hack in basic_binary_iarchive::init
199 friend class boost::archive::basic_binary_iarchive<portable_iarchive>;
200
201 // workaround for gcc: use a dummy struct
202 // as additional argument type for overloading
203 template <int> struct dummy { dummy(int) {}};
204
205 // loads directly from stream
206 inline signed char load_signed_char()
207 {
208 signed char c;
209 portable_iprimitive::load(c);
210 return c;
211 }
212
213 // archive initialization
214 void init(unsigned flags)
215 {
216 using namespace boost::archive;
217 archive_version_type input_library_version(3);
218
219 // it is vital to have version information!
220 // if we don't have any we assume boost 1.33
221 if (flags & no_header)
222 set_library_version(input_library_version);
223
224 // extract and check the magic eos byte
225 else if (load_signed_char() != magic_byte)
226 throw archive_exception(archive_exception::invalid_signature);
227
228 else
229 {
230 // extract version information
231 operator>>(input_library_version);
232
233 // throw if file version is newer than we are
234 if (input_library_version > archive_version)
235 throw archive_exception(archive_exception::unsupported_version);
236
237 // else set the library version accordingly
238 else set_library_version(input_library_version);
239 }
240 }
241
242 public:
254 portable_iarchive(std::istream& is, unsigned flags = 0)
255 #if BOOST_VERSION < 103400
256 : portable_iprimitive(is, flags & boost::archive::no_codecvt)
257 #else
258 : portable_iprimitive(*is.rdbuf(), flags & boost::archive::no_codecvt)
259 #endif
260 , boost::archive::basic_binary_iarchive<portable_iarchive>(flags)
261 {
262 init(flags);
263 }
264
265 #if BOOST_VERSION >= 103400
266 portable_iarchive(std::streambuf& sb, unsigned flags = 0)
267 : portable_iprimitive(sb, flags & boost::archive::no_codecvt)
268 , boost::archive::basic_binary_iarchive<portable_iarchive>(flags)
269 {
270 init(flags);
271 }
272 #endif
273
275 void load(std::string& s)
276 {
277 portable_iprimitive::load(s);
278 }
279
280 #ifndef BOOST_NO_STD_WSTRING
293 void load(std::wstring& s)
294 {
295 std::string utf8;
296 load(utf8);
297 s = boost::from_utf8(utf8);
298 }
299 #endif
300
314 void load(bool& b)
315 {
316 switch (signed char c = load_signed_char())
317 {
318 case 0: b = false; break;
319 case 1: b = load_signed_char(); break;
320 default: throw portable_archive_exception(c);
321 }
322 }
323
331 template <typename T>
332 typename boost::enable_if<boost::is_integral<T> >::type
333 load(T & t, dummy<2> = 0)
334 {
335 // get the number of bytes in the stream
336 if (signed char size = load_signed_char())
337 {
338 // check for negative value in unsigned type
339 if (size < 0 && boost::is_unsigned<T>::value)
341
342 // check that our type T is large enough
343 else if ((unsigned) abs(size) > sizeof(T))
344 throw portable_archive_exception(size);
345
346 // reconstruct the value
347 T temp = size < 0 ? -1 : 0;
348 load_binary(&temp, abs(size));
349
350 // load the value from little endian - it is then converted
351 // to the target type T and fits it because size <= sizeof(T)
352 t = endian::load_little_endian<T, sizeof(T)>(&temp);
353 }
354
355 else t = 0; // zero optimization
356 }
357
385 template <typename T>
386 typename boost::enable_if<boost::is_floating_point<T> >::type
387 load(T & t, dummy<3> = 0)
388 {
389 typedef typename fp::detail::fp_traits<T>::type traits;
390
391 // if you end here there are three possibilities:
392 // 1. you're serializing a long double which is not portable
393 // 2. you're serializing a double but have no 64 bit integer
394 // 3. your machine is using an unknown floating point format
395 // after reading the note above you still might decide to
396 // deactivate this static assert and try if it works out.
397 typename traits::bits bits;
398 BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T));
399 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_iec559);
400
401 load(bits);
402 traits::set_bits(t, bits);
403
404 // if the no_infnan flag is set we must throw here
405 if (get_flags() & no_infnan && !fp::isfinite(t))
407
408 // if you end here your floating point type does not support
409 // denormalized numbers. this might be the case even though
410 // your type conforms to IEC 559 (and thus to IEEE 754)
411 if (std::numeric_limits<T>::has_denorm == std::denorm_absent
412 && fp::fpclassify(t) == (int) FP_SUBNORMAL) // GCC4
414 }
415
416 // in boost 1.44 version_type was splitted into library_version_type and
417 // item_version_type, plus a whole bunch of additional strong typedefs.
418 template <typename T>
419 typename boost::disable_if<boost::is_arithmetic<T> >::type
420 load(T& t, dummy<4> = 0)
421 {
422 // we provide a generic load routine for all types that feature
423 // conversion operators into an unsigned integer value like those
424 // created through BOOST_STRONG_TYPEDEF(X, some unsigned int) like
425 // library_version_type, collection_size_type, item_version_type,
426 // class_id_type, object_id_type, version_type and tracking_type
427 load((typename boost::uint_t<sizeof(T)*CHAR_BIT>::least&)(t));
428 }
429 };
430
431} // namespace eos
432
433// this is required by export which registers all of your
434// classes with all the inbuilt archives plus our archive.
435#if BOOST_VERSION < 103500
436#define BOOST_ARCHIVE_CUSTOM_IARCHIVE_TYPES eos::portable_iarchive
437#else
438BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_iarchive)
439#endif
440
441// if you include this header multiple times and your compiler is picky
442// about multiple template instantiations (eg. gcc is) then you need to
443// define NO_EXPLICIT_TEMPLATE_INSTANTIATION before every include but one
444// or you move the instantiation section into an implementation file
445#ifndef NO_EXPLICIT_TEMPLATE_INSTANTIATION
446
447#ifndef _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_
448#define _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_
449
450#include <boost/archive/impl/basic_binary_iarchive.ipp>
451#include <boost/archive/impl/basic_binary_oarchive.ipp>
452#include <boost/archive/impl/basic_binary_iprimitive.ipp>
453#include <boost/archive/impl/basic_binary_oprimitive.ipp>
454
455#if _QX_SERIALIZE_TEXT
456#include <boost/archive/impl/basic_text_oprimitive.ipp>
457#include <boost/archive/impl/basic_text_iprimitive.ipp>
458#include <boost/archive/impl/basic_text_oarchive.ipp>
459#include <boost/archive/impl/basic_text_iarchive.ipp>
460#endif // _QX_SERIALIZE_TEXT
461
462#if (BOOST_VERSION < 104000)
463#include <boost/archive/impl/archive_pointer_iserializer.ipp>
464#include <boost/archive/impl/archive_pointer_oserializer.ipp>
465#elif !defined BOOST_ARCHIVE_SERIALIZER_INCLUDED
466#include <boost/archive/impl/archive_serializer_map.ipp>
467#define BOOST_ARCHIVE_SERIALIZER_INCLUDED
468#endif // (BOOST_VERSION < 104000)
469
470#endif // _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_
471
472namespace boost { namespace archive {
473
474 // explicitly instantiate for this type of binary stream
475 template class basic_binary_iarchive<eos::portable_iarchive>;
476
477 template class basic_binary_iprimitive<
479 #if BOOST_VERSION < 103400
480 , std::istream
481 #else
482 , std::istream::char_type
483 , std::istream::traits_type
484 #endif
485 >;
486
487#if (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON)
488#if (BOOST_VERSION < 104000)
489 template class detail::archive_pointer_iserializer<eos::portable_iarchive>;
490#else // (BOOST_VERSION < 104000)
491 template class detail::archive_serializer_map<eos::portable_iarchive>;
492#endif // (BOOST_VERSION < 104000)
493#endif // (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON)
494
495} } // namespace boost::archive
496
497#endif // NO_EXPLICIT_TEMPLATE_INSTANTIATION
498
499#ifdef _MSC_VER
500#pragma warning(pop)
501#endif // _MSC_VER
502
503#endif // _QX_PORTABLE_BINARY_IARCHIVE_H_
504#endif // _QX_SERIALIZE_PORTABLE_BINARY
505#endif // _QX_ENABLE_BOOST_SERIALIZATION
QX_DLL_EXPORT QDataStream & operator>>(QDataStream &stream, qx::QxBool &t) QX_USED
Exception being thrown when serialization cannot proceed.
Portable binary input archive using little endian format.
void init(unsigned flags)
void load(std::wstring &s)
Load wide strings.
boost::enable_if< boost::is_integral< T > >::type load(T &t, dummy< 2 >=0)
Load integer types.
void load(bool &b)
Loading bool type.
portable_iarchive(std::istream &is, unsigned flags=0)
Constructor on a stream using ios::binary mode!
boost::enable_if< boost::is_floating_point< T > >::type load(T &t, dummy< 3 >=0)
Load floating point types.
boost::disable_if< boost::is_arithmetic< T > >::type load(T &t, dummy< 4 >=0)
void load(std::string &s)
Load narrow strings.
const unsigned no_infnan
const signed char magic_byte
boost::archive::version_type archive_version_type
const archive_version_type archive_version(boost::archive::ARCHIVE_VERSION())
boost::archive::basic_binary_iprimitive< portable_iarchive, std::istream > portable_iprimitive
Provides error handling and constants.