QxOrm 1.4.9
C++ Object Relational Mapping library
Loading...
Searching...
No Matches
portable_oarchive.hpp
Go to the documentation of this file.
1/*****************************************************************************/
86/*****************************************************************************/
87
88#ifdef _QX_ENABLE_BOOST_SERIALIZATION
89#if _QX_SERIALIZE_PORTABLE_BINARY
90#ifndef _QX_PORTABLE_BINARY_OARCHIVE_H_
91#define _QX_PORTABLE_BINARY_OARCHIVE_H_
92
93#ifdef _MSC_VER
94#pragma once
95#endif // _MSC_VER
96
97#ifdef _MSC_VER
98#pragma warning(push)
99#pragma warning(disable:4996)
100#pragma warning(disable:4661)
101#endif // _MSC_VER
102
103#include <ostream>
104
105// basic headers
106#include <boost/version.hpp>
107#include <boost/utility/enable_if.hpp>
108#include <boost/archive/basic_binary_oprimitive.hpp>
109#include <boost/archive/basic_binary_oarchive.hpp>
110
111#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
112#include <boost/archive/shared_ptr_helper.hpp>
113#endif
114
115// endian and fpclassify
116#if BOOST_VERSION < 103600
117#include <boost/integer/endian.hpp>
118#include <boost/math/fpclassify.hpp>
119#elif BOOST_VERSION < 104800
120#include <boost/spirit/home/support/detail/integer/endian.hpp>
121#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
122#else
123#include <boost/spirit/home/support/detail/endian/endian.hpp>
124#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
125#endif
126
127// namespace alias fp_classify
128#if BOOST_VERSION < 103800
129namespace fp = boost::math;
130#else
131namespace fp = boost::spirit::math;
132#endif
133
134// namespace alias endian
135#if BOOST_VERSION < 104800
136namespace endian = boost::detail;
137#else
138namespace endian = boost::spirit::detail;
139#endif
140
141#if BOOST_VERSION >= 104500 && !defined BOOST_NO_STD_WSTRING
142// used for wstring to utf8 conversion
143#include <boost/program_options/config.hpp>
144#include <boost/program_options/detail/convert.hpp>
145#endif
146
147// generic type traits for numeric types
148#include <boost/type_traits/is_integral.hpp>
149#include <boost/type_traits/is_signed.hpp>
150#include <boost/type_traits/is_arithmetic.hpp>
151#include <boost/type_traits/is_floating_point.hpp>
152
154
155// hint from Johan Rade: on VMS there is still support for
156// the VAX floating point format and this macro detects it
157#if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT
158#error "VAX floating point format is not supported!"
159#endif
160
161namespace eos {
162
163 // forward declaration
164 class portable_oarchive;
165
166 typedef boost::archive::basic_binary_oprimitive<
167 portable_oarchive
168 #if BOOST_VERSION < 103400
169 , std::ostream
170 #else
171 , std::ostream::char_type
172 , std::ostream::traits_type
173 #endif
175
189
190 // the example derives from common_oarchive but that lacks the
191 // save_override functions so we chose to stay one level higher
192 , public boost::archive::basic_binary_oarchive<portable_oarchive>
193
194 #if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
195 // mix-in helper class for serializing shared_ptr
196 , public boost::archive::detail::shared_ptr_helper
197 #endif
198 {
199 // workaround for gcc: use a dummy struct
200 // as additional argument type for overloading
201 template<int> struct dummy { dummy(int) {}};
202
203 // stores a signed char directly to stream
204 inline void save_signed_char(const signed char& c)
205 {
206 portable_oprimitive::save(c);
207 }
208
209 // archive initialization
210 void init(unsigned flags)
211 {
212 // it is vital to have version information if the archive is
213 // to be parsed with a newer version of boost::serialization
214 // therefor we create a header, no header means boost 1.33
215 if (flags & boost::archive::no_header)
216 BOOST_ASSERT(archive_version == 3);
217 else
218 {
219 // write our minimalistic header (magic byte plus version)
220 // the boost archives write a string instead - by calling
221 // boost::archive::basic_binary_oarchive<derived_t>::init()
223
224 // write current version
225// save<unsigned>(archive_version);
227 }
228 }
229
230 public:
242 portable_oarchive(std::ostream& os, unsigned flags = 0)
243 #if BOOST_VERSION < 103400
244 : portable_oprimitive(os, flags & boost::archive::no_codecvt)
245 #else
246 : portable_oprimitive(*os.rdbuf(), flags & boost::archive::no_codecvt)
247 #endif
248 , boost::archive::basic_binary_oarchive<portable_oarchive>(flags)
249 {
250 init(flags);
251 }
252
253 #if BOOST_VERSION >= 103400
254 portable_oarchive(std::streambuf& sb, unsigned flags = 0)
255 : portable_oprimitive(sb, flags & boost::archive::no_codecvt)
256 , boost::archive::basic_binary_oarchive<portable_oarchive>(flags)
257 {
258 init(flags);
259 }
260 #endif
261
263 void save(const std::string& s)
264 {
265 portable_oprimitive::save(s);
266 }
267
268 #ifndef BOOST_NO_STD_WSTRING
281 void save(const std::wstring& s)
282 {
283 save(boost::to_utf8(s));
284 }
285 #endif
286
299 void save(const bool& b)
300 {
302 if (b) save_signed_char('T');
303 }
304
312 template <typename T>
313 typename boost::enable_if<boost::is_integral<T> >::type
314 save(const T & t, dummy<2> = 0)
315 {
316 if (T temp = t)
317 {
318 // examine the number of bytes
319 // needed to represent the number
320 signed char size = 0;
321 do { temp >>= CHAR_BIT; ++size; }
322 while (temp != 0 && temp != (T) -1);
323
324 // encode the sign bit into the size
325 save_signed_char(t > 0 ? size : -size);
326 BOOST_ASSERT(t > 0 || boost::is_signed<T>::value);
327
328 // we choose to use little endian because this way we just
329 // save the first size bytes to the stream and skip the rest
330 endian::store_little_endian<T, sizeof(T)>(&temp, t);
331
332 save_binary(&temp, size);
333 }
334 // zero optimization
335 else save_signed_char(0);
336 }
337
365 template <typename T>
366 typename boost::enable_if<boost::is_floating_point<T> >::type
367 save(const T & t, dummy<3> = 0)
368 {
369 typedef typename fp::detail::fp_traits<T>::type traits;
370
371 // if the no_infnan flag is set we must throw here
372 if (get_flags() & no_infnan && !fp::isfinite(t))
374
375 // if you end here there are three possibilities:
376 // 1. you're serializing a long double which is not portable
377 // 2. you're serializing a double but have no 64 bit integer
378 // 3. your machine is using an unknown floating point format
379 // after reading the note above you still might decide to
380 // deactivate this static assert and try if it works out.
381 typename traits::bits bits;
382 BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T));
383 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_iec559);
384
385 // examine value closely
386 switch (fp::fpclassify(t))
387 {
388 //case FP_ZERO: bits = 0; break;
389 case FP_NAN: bits = traits::exponent | traits::mantissa; break;
390 case FP_INFINITE: bits = traits::exponent | (t<0) * traits::sign; break;
391 case FP_SUBNORMAL: assert(std::numeric_limits<T>::has_denorm); // pass
392 case FP_ZERO: // note that floats can be ±0.0
393 case FP_NORMAL: traits::get_bits(t, bits); break;
394 default: throw portable_archive_exception(t);
395 }
396
397 save(bits);
398 }
399
400 // in boost 1.44 version_type was splitted into library_version_type and
401 // item_version_type, plus a whole bunch of additional strong typedefs.
402 template <typename T>
403 typename boost::disable_if<boost::is_arithmetic<T> >::type
404 save(const T& t, dummy<4> = 0)
405 {
406 // we provide a generic save routine for all types that feature
407 // conversion operators into an unsigned integer value like those
408 // created through BOOST_STRONG_TYPEDEF(X, some unsigned int) like
409 // library_version_type, collection_size_type, item_version_type,
410 // class_id_type, object_id_type, version_type and tracking_type
411 save((typename boost::uint_t<sizeof(T)*CHAR_BIT>::least)(t));
412 }
413 };
414
415} // namespace eos
416
417// required by export
418#if BOOST_VERSION < 103500
419#define BOOST_ARCHIVE_CUSTOM_OARCHIVE_TYPES eos::portable_oarchive
420#else
421BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_oarchive)
422#endif
423
424// if you include this header multiple times and your compiler is picky
425// about multiple template instantiations (eg. gcc is) then you need to
426// define NO_EXPLICIT_TEMPLATE_INSTANTIATION before every include but one
427// or you move the instantiation section into an implementation file
428#ifndef NO_EXPLICIT_TEMPLATE_INSTANTIATION
429
430#ifndef _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_
431#define _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_
432
433#include <boost/archive/impl/basic_binary_iarchive.ipp>
434#include <boost/archive/impl/basic_binary_oarchive.ipp>
435#include <boost/archive/impl/basic_binary_iprimitive.ipp>
436#include <boost/archive/impl/basic_binary_oprimitive.ipp>
437
438#if _QX_SERIALIZE_TEXT
439#include <boost/archive/impl/basic_text_oprimitive.ipp>
440#include <boost/archive/impl/basic_text_iprimitive.ipp>
441#include <boost/archive/impl/basic_text_oarchive.ipp>
442#include <boost/archive/impl/basic_text_iarchive.ipp>
443#endif // _QX_SERIALIZE_TEXT
444
445#if (BOOST_VERSION < 104000)
446#include <boost/archive/impl/archive_pointer_iserializer.ipp>
447#include <boost/archive/impl/archive_pointer_oserializer.ipp>
448#elif !defined BOOST_ARCHIVE_SERIALIZER_INCLUDED
449#include <boost/archive/impl/archive_serializer_map.ipp>
450#define BOOST_ARCHIVE_SERIALIZER_INCLUDED
451#endif // (BOOST_VERSION < 104000)
452
453#endif // _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_
454
455namespace boost { namespace archive {
456
457 // explicitly instantiate for this type of binary stream
458 template class basic_binary_oarchive<eos::portable_oarchive>;
459
460 template class basic_binary_oprimitive<
462 #if BOOST_VERSION < 103400
463 , std::ostream
464 #else
465 , std::ostream::char_type
466 , std::ostream::traits_type
467 #endif
468 >;
469
470#if (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON)
471#if (BOOST_VERSION < 104000)
472 template class detail::archive_pointer_oserializer<eos::portable_oarchive>;
473#else // (BOOST_VERSION < 104000)
474 template class detail::archive_serializer_map<eos::portable_oarchive>;
475#endif // (BOOST_VERSION < 104000)
476#endif // (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON)
477
478} } // namespace boost::archive
479
480#endif // NO_EXPLICIT_TEMPLATE_INSTANTIATION
481
482#ifdef _MSC_VER
483#pragma warning(pop)
484#endif // _MSC_VER
485
486#endif // _QX_PORTABLE_BINARY_OARCHIVE_H_
487#endif // _QX_SERIALIZE_PORTABLE_BINARY
488#endif // _QX_ENABLE_BOOST_SERIALIZATION
QX_DLL_EXPORT QDataStream & operator<<(QDataStream &stream, const qx::QxBool &t) QX_USED
Exception being thrown when serialization cannot proceed.
Portable binary output archive using little endian format.
void save(const std::string &s)
Save narrow strings.
boost::disable_if< boost::is_arithmetic< T > >::type save(const T &t, dummy< 4 >=0)
void init(unsigned flags)
portable_oarchive(std::ostream &os, unsigned flags=0)
Constructor on a stream using ios::binary mode!
boost::enable_if< boost::is_floating_point< T > >::type save(const T &t, dummy< 3 >=0)
Save floating point types.
void save_signed_char(const signed char &c)
boost::enable_if< boost::is_integral< T > >::type save(const T &t, dummy< 2 >=0)
Save integer types.
void save(const std::wstring &s)
Save wide strings.
void save(const bool &b)
Saving bool type.
const unsigned no_infnan
const signed char magic_byte
boost::archive::basic_binary_oprimitive< portable_oarchive, std::ostream > portable_oprimitive
const archive_version_type archive_version(boost::archive::ARCHIVE_VERSION())
Provides error handling and constants.