Bayeux  3.4.1
Core Foundation library for SuperNEMO
portable_oarchive.hpp
Go to the documentation of this file.
1 /*****************************************************************************/
90 /*****************************************************************************/
91 
92 #pragma once
93 
94 #include <ostream>
95 
96 // basic headers
97 #include <boost/version.hpp>
98 #include <boost/utility/enable_if.hpp>
99 #include <boost/archive/basic_binary_oprimitive.hpp>
100 #include <boost/archive/basic_binary_oarchive.hpp>
101 #include <boost/archive/detail/polymorphic_oarchive_route.hpp>
102 
103 // endian and fpclassify
104 #include <boost/endian/conversion.hpp>
105 
106 // Boost Spirit does not provide FP tools from version 1.69
107 #if BOOST_VERSION < 106900
108 #include <boost/spirit/home/support/detail/math/fpclassify.hpp>
109 // namespace alias for fp utilities
110 namespace fp = boost::spirit::math;
111 #else
112 // So we use here the Boost Math FP stuff but this implies
113 // to build with BOOST_MATH_DISABLE_STD_FPCLASSIFY otherwise
114 // the std fpclassify misses some required typedefs
115 // required from boost::math::detail::fp_traits (bits...)
116 // Also the boost::math::detail::fp_traits_non_native declare
117 // the static constant 'significand' in place of the spirir version 'mantissa';
118 // this implies a workaround (see below).
119 #if !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
120 #error "You must build using -DBOOST_MATH_DISABLE_STD_FPCLASSIFY!"
121 #endif
122 #include <boost/math/special_functions/fpclassify.hpp>
123 // namespace alias for fp utilities
124 namespace fp = boost::math;
125 # endif
126 
127 #ifndef BOOST_NO_STD_WSTRING
128 // used for wstring to utf8 conversion
129 #include <boost/program_options/config.hpp>
130 #include <boost/program_options/detail/convert.hpp>
131 #endif
132 
133 // generic type traits for numeric types
134 #include <boost/type_traits/is_integral.hpp>
135 #include <boost/type_traits/is_signed.hpp>
136 #include <boost/type_traits/is_arithmetic.hpp>
137 #include <boost/type_traits/is_floating_point.hpp>
138 
140 
141 namespace boost { namespace archive {
142 
143  // forward declaration
145 
146  typedef basic_binary_oprimitive <
148  , std::ostream::char_type
149  , std::ostream::traits_type
151 
165 
166  // Robert's example derives from common_oarchive but that lacks the
167  // save_override functions so we chose to stay one level higher
168  , public basic_binary_oarchive<portable_oarchive>
169  {
170  // workaround for gcc: use a dummy struct
171  // as additional argument type for overloading
172  template<int> struct dummy { dummy(int) {} };
173 
174  // stores a signed char directly to stream
175  inline void save_signed_char(const signed char& c)
176  {
178  }
179 
180  // archive initialization
181  void init(unsigned flags)
182  {
183  // it is vital to have version information if the archive is
184  // to be parsed with a newer version of boost::serialization
185  // therefor we create a header, no header means boost 1.33
186  // for backwards compatibility
187  if (flags & no_header)
188  BOOST_ASSERT(archive_version == 3);
189  else
190  {
191  // write our minimalistic header (magic byte plus version)
192  // the boost archives write a string instead - by calling
193  // boost::archive::basic_binary_oarchive<derived_t>::init()
194  save_signed_char(magic_byte);
195 
196  // write current version
197 // save<unsigned>(archive_version);
199  }
200  }
201 
202  public:
214  portable_oarchive(std::ostream& os, unsigned flags = 0)
215  : portable_oprimitive(*os.rdbuf(), flags & no_codecvt)
216  , basic_binary_oarchive<portable_oarchive>(flags)
217  {
218  init(flags);
219  }
220 
221  portable_oarchive(std::streambuf& sb, unsigned flags = 0)
222  : portable_oprimitive(sb, flags & no_codecvt)
223  , basic_binary_oarchive<portable_oarchive>(flags)
224  {
225  init(flags);
226  }
227 
229  void save(const std::string& s)
230  {
232  }
233 
234 #ifndef BOOST_NO_STD_WSTRING
235 
247  void save(const std::wstring& s)
248  {
249  save(boost::to_utf8(s));
250  }
251 #endif
252 
265  void save(const bool& b)
266  {
267  save_signed_char(b);
268  if (b) save_signed_char('T');
269  }
270 
278  template <typename T>
279  typename boost::enable_if<boost::is_integral<T> >::type
280  save(const T & t, dummy<2> = 0)
281  {
282  if (T temp = t)
283  {
284  // examine the number of bytes
285  // needed to represent the number
286  signed char size = 0;
287  do { temp >>= CHAR_BIT; ++size; } while (temp != 0 && temp != (T)-1);
288 
289  // encode the sign bit into the size
290  save_signed_char(t > 0 ? size : -size);
291  BOOST_ASSERT(t > 0 || boost::is_signed<T>::value);
292 
293  // we choose to use little endian because this way we just
294  // save the first size bytes to the stream and skip the rest
295  temp = boost::endian::native_to_little(t);
296 
297  save_binary(&temp, size);
298  }
299  // zero optimization
300  else save_signed_char(0);
301  }
302 
330  template <typename T>
331  typename boost::enable_if<boost::is_floating_point<T> >::type
332  save(const T & t, dummy<3> = 0)
333  {
334  typedef typename fp::detail::fp_traits<T>::type traits;
335 
336  // if the no_infnan flag is set we must throw here
337  if (get_flags() & no_infnan && !fp::isfinite(t))
339 
340  // if you end here there are three possibilities:
341  // 1. you're serializing a long double which is not portable
342  // 2. you're serializing a double but have no 64 bit integer
343  // 3. your machine is using an unknown floating point format
344  // after reading the note above you still might decide to
345  // deactivate this static assert and try if it works out.
346  typename traits::bits bits;
347  BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T));
348  BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_iec559);
349 
350  // examine value closely
351  switch (fp::fpclassify(t))
352  {
353  //case FP_ZERO: bits = 0; break;
354 #if defined(BOOST_MATH_FP_TRAITS_HPP)
355  // Using the traits::significand constant as the mantissa mask from Boost/Math
356  case FP_NAN: bits = traits::exponent | traits::significand; break;
357 #else
358 #if defined(BOOST_SPIRIT_MATH_FP_TRAITS_HPP)
359  // Using the traits::mantissa constant as the mantissa mask from Boost/Spirit
360  case FP_NAN: bits = traits::exponent | traits::mantissa; break;
361 #endif
362 #endif
363  case FP_INFINITE: bits = traits::exponent | (t < 0) * traits::sign; break;
364  case FP_SUBNORMAL: assert(std::numeric_limits<T>::has_denorm); // pass
365  case FP_ZERO: // note that floats can be ±0.0
366  case FP_NORMAL: traits::get_bits(t, bits); break;
367  default: throw portable_archive_exception(t);
368  }
369 
370  save(bits);
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  save(const T& t, dummy<4> = 0)
378  {
379  // we provide a generic save 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) like
382  // library_version_type, collection_size_type, item_version_type,
383  // class_id_type, object_id_type, version_type and tracking_type
384  save((typename boost::uint_t<sizeof(T)*CHAR_BIT>::least)(t));
385  }
386  };
387 
388  // polymorphic portable binary oarchive typedef
389  typedef detail::polymorphic_oarchive_route<portable_oarchive> polymorphic_portable_oarchive;
390 
391 } } // namespace boost::archive
392 
393 // required by export
394 BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::archive::portable_oarchive)
395 BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::archive::polymorphic_portable_oarchive)
detail::polymorphic_oarchive_route< portable_oarchive > polymorphic_portable_oarchive
Definition: portable_oarchive.hpp:389
const archive_version_type archive_version(BOOST_ARCHIVE_VERSION())
void save(Archive &a_ar, const geomtools::vector_3d &v_, const unsigned int a_version)
Provides error handling and constants.
const signed char magic_byte
Definition: portable_archive_exception.hpp:31
Serialization stuff for CLHEP 'vector_3d'.
Definition: portable_archive_exception.hpp:27
void save(const std::string &s)
Save narrow strings.
Definition: portable_oarchive.hpp:229
Exception being thrown when serialization cannot proceed.
Definition: portable_archive_exception.hpp:56
boost::enable_if< boost::is_floating_point< T > >::type save(const T &t, dummy< 3 >=0)
Save floating point types.
Definition: portable_oarchive.hpp:332
std::ostream & operator<<(std::ostream &out_, const placement &)
void save(const std::wstring &s)
Save wide strings.
Definition: portable_oarchive.hpp:247
boost::enable_if< boost::is_integral< T > >::type save(const T &t, dummy< 2 >=0)
Save integer types.
Definition: portable_oarchive.hpp:280
basic_binary_oprimitive< portable_oarchive, std::ostream::char_type, std::ostream::traits_type > portable_oprimitive
Definition: portable_oarchive.hpp:144
portable_oarchive(std::streambuf &sb, unsigned flags=0)
Definition: portable_oarchive.hpp:221
void save(const bool &b)
Saving bool type.
Definition: portable_oarchive.hpp:265
const unsigned no_infnan
Definition: portable_archive_exception.hpp:34
boost::disable_if< boost::is_arithmetic< T > >::type save(const T &t, dummy< 4 >=0)
Definition: portable_oarchive.hpp:377
Portable binary output archive using little endian format.
Definition: portable_oarchive.hpp:164
portable_oarchive(std::ostream &os, unsigned flags=0)
Constructor on a stream using ios::binary mode!
Definition: portable_oarchive.hpp:214