Collage  1.0.1
Object-Oriented C++ Network Library
dataOStreamArchive.ipp
1 
2 /* Copyright (c) 2012, Daniel Nachbaur <danielnachbaur@googlemail.com>
3  *
4  * This library is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU Lesser General Public License version 2.1 as published
6  * by the Free Software Foundation.
7  *
8  * This library is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
11  * details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library; if not, write to the Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17 
18 
19 template< typename T >
20 void DataOStreamArchive::save_array( const boost::serialization::array< T >& a,
21  unsigned int )
22 {
23  _stream << Array< const T >( a.address(), a.count( ));
24 }
25 
26 template< class C, class T, class A >
27 void DataOStreamArchive::save( const std::basic_string< C, T, A >& s )
28 {
29  // implementation only valid for narrow string
30  BOOST_STATIC_ASSERT( sizeof(C) == sizeof(char));
31  _stream << s;
32 }
33 
34 template< typename T >
35 typename boost::enable_if< boost::is_integral<T> >::type
36 DataOStreamArchive::save( const T& t )
37 {
38 #if BOOST_VERSION < 104800
39  namespace bs = boost::detail;
40 #else
41  namespace bs = boost::spirit::detail;
42 #endif
43 
44  if( T temp = t )
45  {
46  // examine the number of bytes
47  // needed to represent the number
48  signed char size = 0;
49  do
50  {
51 #pragma clang diagnostic push
52 #pragma clang diagnostic ignored "-Wshift-count-overflow"
53  temp >>= CHAR_BIT;
54 #pragma clang diagnostic pop
55  ++size;
56  }
57  while( temp != 0 && temp != (T) -1 );
58 
59  // encode the sign bit into the size
60  _saveSignedChar( t > 0 ? size : -size );
61  BOOST_ASSERT( t > 0 || boost::is_signed<T>::value) ;
62 
63  // we choose to use little endian because this way we just
64  // save the first size bytes to the stream and skip the rest
65  bs::store_little_endian<T, sizeof(T)>( &temp, t );
66  save_binary( &temp, size );
67  }
68  else
69  // zero optimization
70  _saveSignedChar (0 );
71 }
72 
73 template< typename T >
74 typename boost::enable_if< boost::is_floating_point<T> >::type
75 DataOStreamArchive::save( const T& t )
76 {
77  namespace fp = boost::spirit::math;
78 
79  typedef typename fp::detail::fp_traits<T>::type traits;
80 
81  // if the no_infnan flag is set we must throw here
82  if( get_flags() & serialization::no_infnan && !fp::isfinite( t ))
83  throw DataStreamArchiveException( t );
84 
85  // if you end here there are three possibilities:
86  // 1. you're serializing a long double which is not portable
87  // 2. you're serializing a double but have no 64 bit integer
88  // 3. your machine is using an unknown floating point format
89  // after reading the note above you still might decide to
90  // deactivate this static assert and try if it works out.
91  typename traits::bits bits;
92  BOOST_STATIC_ASSERT( sizeof(bits) == sizeof(T));
93  BOOST_STATIC_ASSERT( std::numeric_limits<T>::is_iec559 );
94 
95  // examine value closely
96  switch( fp::fpclassify( t ))
97  {
98  case FP_ZERO:
99  bits = 0;
100  break;
101  case FP_NAN:
102  bits = traits::exponent | traits::mantissa;
103  break;
104  case FP_INFINITE:
105  bits = traits::exponent | (t<0) * traits::sign;
106  break;
107  case FP_SUBNORMAL:
108  assert( std::numeric_limits<T>::has_denorm );
109  case FP_NORMAL:
110  traits::get_bits(t, bits);
111  break;
112  default:
113  throw DataStreamArchiveException( t );
114  }
115 
116  save( bits );
117 }