Bayeux  3.4.1
Core Foundation library for SuperNEMO
portable_iarchive.hpp
Go to the documentation of this file.
1 /*****************************************************************************/
87 /*****************************************************************************/
88 
89 #pragma once
90 
91 #include <istream>
92 
93 // basic headers
94 #include <boost/version.hpp>
95 #include <boost/utility/enable_if.hpp>
96 #include <boost/archive/basic_binary_iprimitive.hpp>
97 #include <boost/archive/basic_binary_iarchive.hpp>
98 
99 // funny polymorphics
100 #include <boost/archive/detail/polymorphic_iarchive_route.hpp>
101 
102 // endian and fpclassify
103 #include <boost/endian/conversion.hpp>
104 
105 #if BOOST_VERSION < 106900
106 #include <boost/spirit/home/support/detail/math/fpclassify.hpp>
107 // namespace alias for fp utilities
108 namespace fp = boost::spirit::math;
109 #else
110 #if !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
111 #error "You must build using -DBOOST_MATH_DISABLE_STD_FPCLASSIFY!"
112 #endif
113 #include <boost/math/special_functions/fpclassify.hpp>
114 // namespace alias for fp utilities
115 namespace fp = boost::math;
116 # endif
117 
118 #ifndef BOOST_NO_STD_WSTRING
119 // used for wstring to utf8 conversion
120 #include <boost/program_options/config.hpp>
121 #include <boost/program_options/detail/convert.hpp>
122 #endif
123 
124 // generic type traits for numeric types
125 #include <boost/type_traits/is_integral.hpp>
126 #include <boost/type_traits/is_unsigned.hpp>
127 #include <boost/type_traits/is_arithmetic.hpp>
128 #include <boost/type_traits/is_floating_point.hpp>
129 
131 
132 namespace boost { namespace archive {
133 
134  // forward declaration
136 
137  typedef basic_binary_iprimitive <
139  , std::istream::char_type
140  , std::istream::traits_type
142 
158 
159  // Robert's example derives from common_oarchive but that lacks the
160  // load_override functions so we chose to stay one level higher
161  , public basic_binary_iarchive<portable_iarchive>
162  {
163  // only needed for Robert's hack in basic_binary_iarchive::init
164  friend class basic_binary_iarchive<portable_iarchive>;
165 
166  // workaround for gcc: use a dummy struct
167  // as additional argument type for overloading
168  template <int> struct dummy { dummy(int) {} };
169 
170  // loads directly from stream
171  inline signed char load_signed_char()
172  {
173  signed char c;
175  return c;
176  }
177 
178  // archive initialization
179  void init(unsigned flags)
180  {
181  archive_version_type input_library_version(3);
182 
183  // it is vital to have version information!
184  // if we don't have any we assume boost 1.33
185  if (flags & no_header)
186  set_library_version(input_library_version);
187 
188  // extract and check the magic byte header
189  else if (load_signed_char() != magic_byte)
190  throw archive_exception(archive_exception::invalid_signature);
191 
192  else
193  {
194  // extract version information
195  operator>>(input_library_version);
196 
197  // throw if file version is newer than we are
198  if (input_library_version > archive_version)
199  throw archive_exception(archive_exception::unsupported_version);
200 
201  // else set the library version accordingly
202  else set_library_version(input_library_version);
203  }
204  }
205 
206  public:
218  portable_iarchive(std::istream& is, unsigned flags = 0)
219  : portable_iprimitive(*is.rdbuf(), flags & no_codecvt)
220  , basic_binary_iarchive<portable_iarchive>(flags)
221  {
222  init(flags);
223  }
224 
225  portable_iarchive(std::streambuf& sb, unsigned flags = 0)
226  : portable_iprimitive(sb, flags & no_codecvt)
227  , basic_binary_iarchive<portable_iarchive>(flags)
228  {
229  init(flags);
230  }
231 
233  void load(std::string& s)
234  {
236  }
237 
238 #ifndef BOOST_NO_STD_WSTRING
239 
251  void load(std::wstring& s)
252  {
253  std::string utf8;
254  load(utf8);
255  s = boost::from_utf8(utf8);
256  }
257 #endif
258 
272  void load(bool& b)
273  {
274  switch (signed char c = load_signed_char())
275  {
276  case 0: b = false; break;
277  case 1: b = load_signed_char(); break;
278  default: throw portable_archive_exception(c);
279  }
280  }
281 
289  template <typename T>
290  typename boost::enable_if<boost::is_integral<T> >::type
291  load(T & t, dummy<2> = 0)
292  {
293  // get the number of bytes in the stream
294  if (signed char size = load_signed_char())
295  {
296  // check for negative value in unsigned type
297  if (size < 0 && boost::is_unsigned<T>::value)
299 
300  // check that our type T is large enough
301  else if ((unsigned)abs(size) > sizeof(T))
302  throw portable_archive_exception(size);
303 
304  // reconstruct the value
305  T temp = size < 0 ? -1 : 0;
306  load_binary(&temp, abs(size));
307  // load the value from little endian - it is then converted
308  // to the target type T and fits it because size <= sizeof(T)
309  t = boost::endian::little_to_native(temp);
310  }
311 
312  else t = 0; // zero optimization
313  }
314 
342  template <typename T>
343  typename boost::enable_if<boost::is_floating_point<T> >::type
344  load(T & t, dummy<3> = 0)
345  {
346  typedef typename fp::detail::fp_traits<T>::type traits;
347 
348  // if you end here there are three possibilities:
349  // 1. you're serializing a long double which is not portable
350  // 2. you're serializing a double but have no 64 bit integer
351  // 3. your machine is using an unknown floating point format
352  // after reading the note above you still might decide to
353  // deactivate this static assert and try if it works out.
354  typename traits::bits bits;
355  BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T));
356  BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_iec559);
357 
358  load(bits);
359  traits::set_bits(t, bits);
360 
361  // if the no_infnan flag is set we must throw here
362  if (get_flags() & no_infnan && !fp::isfinite(t))
364 
365  // if you end here your floating point type does not support
366  // denormalized numbers. this might be the case even though
367  // your type conforms to IEC 559 (and thus to IEEE 754)
368  if (std::numeric_limits<T>::has_denorm == std::denorm_absent
369  && fp::fpclassify(t) == (int)FP_SUBNORMAL) // GCC4
371  }
372 
373  // in boost 1.44 version_type was splitted into library_version_type and
374  // item_version_type, plus a whole bunch of additional strong typedefs.
375  template <typename T>
376  typename boost::disable_if<boost::is_arithmetic<T> >::type
377  load(T& t, dummy<4> = 0)
378  {
379  // we provide a generic load routine for all types that feature
380  // conversion operators into an unsigned integer value like those
381  // created through BOOST_STRONG_TYPEDEF(X, some unsigned int) ie.
382  // library_version_type, collection_size_type, item_version_type,
383  // class_id_type, object_id_type, version_type and tracking_type
384  load((typename boost::uint_t<sizeof(T)*CHAR_BIT>::least&)(t));
385  }
386  };
387 
388  // polymorphic portable binary iarchive typedef
389  typedef detail::polymorphic_iarchive_route<portable_iarchive> polymorphic_portable_iarchive;
390 
391 } } // namespace boost::archive
392 
393 // this is required by export which registers all of your
394 // classes with all the inbuilt archives plus our archive.
395 BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::archive::portable_iarchive)
396 BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::archive::polymorphic_portable_iarchive)
void load(bool &b)
Loading bool type.
Definition: portable_iarchive.hpp:272
const archive_version_type archive_version(BOOST_ARCHIVE_VERSION())
boost::disable_if< boost::is_arithmetic< T > >::type load(T &t, dummy< 4 >=0)
Definition: portable_iarchive.hpp:377
Provides error handling and constants.
detail::polymorphic_iarchive_route< portable_iarchive > polymorphic_portable_iarchive
Definition: portable_iarchive.hpp:389
const signed char magic_byte
Definition: portable_archive_exception.hpp:31
Serialization stuff for CLHEP 'vector_3d'.
Definition: portable_archive_exception.hpp:27
void load(Archive &a_ar, geomtools::vector_3d &v_, const unsigned int a_version)
void load(std::wstring &s)
Load wide strings.
Definition: portable_iarchive.hpp:251
Portable binary input archive using little endian format.
Definition: portable_iarchive.hpp:157
Exception being thrown when serialization cannot proceed.
Definition: portable_archive_exception.hpp:56
boost::enable_if< boost::is_integral< T > >::type load(T &t, dummy< 2 >=0)
Load integer types.
Definition: portable_iarchive.hpp:291
basic_binary_iprimitive< portable_iarchive, std::istream::char_type, std::istream::traits_type > portable_iprimitive
Definition: portable_iarchive.hpp:135
boost::enable_if< boost::is_floating_point< T > >::type load(T &t, dummy< 3 >=0)
Load floating point types.
Definition: portable_iarchive.hpp:344
portable_iarchive(std::streambuf &sb, unsigned flags=0)
Definition: portable_iarchive.hpp:225
portable_iarchive(std::istream &is, unsigned flags=0)
Constructor on a stream using ios::binary mode!
Definition: portable_iarchive.hpp:218
const unsigned no_infnan
Definition: portable_archive_exception.hpp:34
library_version_type archive_version_type
Definition: portable_archive_exception.hpp:37
void load(std::string &s)
Load narrow strings.
Definition: portable_iarchive.hpp:233