NDDEM
portable_binary.hpp
Go to the documentation of this file.
1 
3 /*
4  Copyright (c) 2014, Randolph Voorhies, Shane Grant
5  All rights reserved.
6 
7  Redistribution and use in source and binary forms, with or without
8  modification, are permitted provided that the following conditions are met:
9  * Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11  * Redistributions in binary form must reproduce the above copyright
12  notice, this list of conditions and the following disclaimer in the
13  documentation and/or other materials provided with the distribution.
14  * Neither the name of the copyright holder nor the
15  names of its contributors may be used to endorse or promote products
16  derived from this software without specific prior written permission.
17 
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
22  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #ifndef CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
30 #define CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
31 
32 #include "cereal/cereal.hpp"
33 #include <sstream>
34 #include <limits>
35 
36 namespace cereal
37 {
38  namespace portable_binary_detail
39  {
41 
43  {
44  static std::int32_t test = 1;
45  return *reinterpret_cast<std::int8_t*>( &test ) == 1;
46  }
47 
49 
52  template <std::size_t DataSize>
53  inline void swap_bytes( std::uint8_t * data )
54  {
55  for( std::size_t i = 0, end = DataSize / 2; i < end; ++i )
56  std::swap( data[i], data[DataSize - i - 1] );
57  }
58  } // end namespace portable_binary_detail
59 
60  // ######################################################################
62 
78  class PortableBinaryOutputArchive : public OutputArchive<PortableBinaryOutputArchive, AllowEmptyClassElision>
79  {
80  public:
82  class Options
83  {
84  public:
86  enum class Endianness : std::uint8_t
87  { big, little };
88 
90  static Options Default(){ return Options(); }
91 
94 
96  static Options BigEndian(){ return Options( Endianness::big ); }
97 
99 
100  explicit Options( Endianness outputEndian = getEndianness() ) :
101  itsOutputEndianness( outputEndian ) { }
102 
103  private:
105  inline static Endianness getEndianness()
107 
111 
114  };
115 
117 
120  PortableBinaryOutputArchive(std::ostream & stream, Options const & options = Options::Default()) :
122  itsStream(stream),
123  itsConvertEndianness( portable_binary_detail::is_little_endian() ^ options.is_little_endian() )
124  {
125  this->operator()( options.is_little_endian() );
126  }
127 
129 
131  template <std::streamsize DataSize> inline
132  void saveBinary( const void * data, std::streamsize size )
133  {
134  std::streamsize writtenSize = 0;
135 
137  {
138  for( std::streamsize i = 0; i < size; i += DataSize )
139  for( std::streamsize j = 0; j < DataSize; ++j )
140  writtenSize += itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ) + DataSize - j - 1 + i, 1 );
141  }
142  else
143  writtenSize = itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size );
144 
145  if(writtenSize != size)
146  throw Exception("Failed to write " + std::to_string(size) + " bytes to output stream! Wrote " + std::to_string(writtenSize));
147  }
148 
149  private:
150  std::ostream & itsStream;
152  };
153 
154  // ######################################################################
156 
180  class PortableBinaryInputArchive : public InputArchive<PortableBinaryInputArchive, AllowEmptyClassElision>
181  {
182  public:
184  class Options
185  {
186  public:
189  { big, little };
190 
192  static Options Default(){ return Options(); }
193 
196 
198  static Options BigEndian(){ return Options( Endianness::big ); }
199 
201 
202  explicit Options( Endianness inputEndian = getEndianness() ) :
203  itsInputEndianness( inputEndian ) { }
204 
205  private:
207  inline static Endianness getEndianness()
209 
213 
216  };
217 
219 
222  PortableBinaryInputArchive(std::istream & stream, Options const & options = Options::Default()) :
224  itsStream(stream),
225  itsConvertEndianness( false )
226  {
227  uint8_t streamLittleEndian;
228  this->operator()( streamLittleEndian );
229  itsConvertEndianness = options.is_little_endian() ^ streamLittleEndian;
230  }
231 
233 
235 
238  template <std::streamsize DataSize> inline
239  void loadBinary( void * const data, std::streamsize size )
240  {
241  // load data
242  auto const readSize = itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size );
243 
244  if(readSize != size)
245  throw Exception("Failed to read " + std::to_string(size) + " bytes from input stream! Read " + std::to_string(readSize));
246 
247  // flip bits if needed
249  {
250  std::uint8_t * ptr = reinterpret_cast<std::uint8_t*>( data );
251  for( std::streamsize i = 0; i < size; i += DataSize )
252  portable_binary_detail::swap_bytes<DataSize>( ptr + i );
253  }
254  }
255 
256  private:
257  std::istream & itsStream;
259  };
260 
261  // ######################################################################
262  // Common BinaryArchive serialization functions
263 
265  template<class T> inline
268  {
269  static_assert( !std::is_floating_point<T>::value ||
270  (std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
271  "Portable binary only supports IEEE 754 standardized floating point" );
272  ar.template saveBinary<sizeof(T)>(std::addressof(t), sizeof(t));
273  }
274 
276  template<class T> inline
279  {
280  static_assert( !std::is_floating_point<T>::value ||
281  (std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
282  "Portable binary only supports IEEE 754 standardized floating point" );
283  ar.template loadBinary<sizeof(T)>(std::addressof(t), sizeof(t));
284  }
285 
287  template <class Archive, class T> inline
288  CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
289  CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, NameValuePair<T> & t )
290  {
291  ar( t.value );
292  }
293 
295  template <class Archive, class T> inline
296  CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
297  CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, SizeTag<T> & t )
298  {
299  ar( t.size );
300  }
301 
303  template <class T> inline
305  {
306  typedef typename std::remove_pointer<T>::type TT;
307  static_assert( !std::is_floating_point<TT>::value ||
308  (std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
309  "Portable binary only supports IEEE 754 standardized floating point" );
310 
311  ar.template saveBinary<sizeof(TT)>( bd.data, static_cast<std::streamsize>( bd.size ) );
312  }
313 
315  template <class T> inline
317  {
318  typedef typename std::remove_pointer<T>::type TT;
319  static_assert( !std::is_floating_point<TT>::value ||
320  (std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
321  "Portable binary only supports IEEE 754 standardized floating point" );
322 
323  ar.template loadBinary<sizeof(TT)>( bd.data, static_cast<std::streamsize>( bd.size ) );
324  }
325 } // namespace cereal
326 
327 // register archives for polymorphic support
330 
331 // tie input and output archives together
333 
334 #endif // CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.hpp:25318
Main cereal functionality.
#define CEREAL_REGISTER_ARCHIVE(Archive)
Registers a specific Archive type with cereal.
Definition: cereal.hpp:195
The base input archive class.
Definition: cereal.hpp:711
PortableBinaryInputArchive & operator()(Types &&... args)
Serializes all passed in data.
Definition: cereal.hpp:728
The base output archive class.
Definition: cereal.hpp:319
PortableBinaryOutputArchive & operator()(Types &&... args)
Serializes all passed in data.
Definition: cereal.hpp:331
A class containing various advanced options for the PortableBinaryInput archive.
Definition: portable_binary.hpp:185
Options(Endianness inputEndian=getEndianness())
Specify specific options for the PortableBinaryInputArchive.
Definition: portable_binary.hpp:202
static Options BigEndian()
Load into big endian.
Definition: portable_binary.hpp:198
static Endianness getEndianness()
Gets the endianness of the system.
Definition: portable_binary.hpp:207
static Options LittleEndian()
Load into little endian.
Definition: portable_binary.hpp:195
std::uint8_t is_little_endian() const
Checks if Options is set for little endian.
Definition: portable_binary.hpp:211
static Options Default()
Default options, preserve system endianness.
Definition: portable_binary.hpp:192
Endianness itsInputEndianness
Definition: portable_binary.hpp:215
Endianness
Represents desired endianness.
Definition: portable_binary.hpp:189
An input archive designed to load data saved using PortableBinaryOutputArchive.
Definition: portable_binary.hpp:181
~PortableBinaryInputArchive() CEREAL_NOEXCEPT=default
uint8_t itsConvertEndianness
If set to true, we will need to swap bytes upon loading.
Definition: portable_binary.hpp:258
PortableBinaryInputArchive(std::istream &stream, Options const &options=Options::Default())
Construct, loading from the provided stream.
Definition: portable_binary.hpp:222
std::istream & itsStream
Definition: portable_binary.hpp:257
void loadBinary(void *const data, std::streamsize size)
Reads size bytes of data from the input stream.
Definition: portable_binary.hpp:239
A class containing various advanced options for the PortableBinaryOutput archive.
Definition: portable_binary.hpp:83
static Options BigEndian()
Save as big endian.
Definition: portable_binary.hpp:96
static Endianness getEndianness()
Gets the endianness of the system.
Definition: portable_binary.hpp:105
Options(Endianness outputEndian=getEndianness())
Specify specific options for the PortableBinaryOutputArchive.
Definition: portable_binary.hpp:100
std::uint8_t is_little_endian() const
Checks if Options is set for little endian.
Definition: portable_binary.hpp:109
static Options LittleEndian()
Save as little endian.
Definition: portable_binary.hpp:93
static Options Default()
Default options, preserve system endianness.
Definition: portable_binary.hpp:90
Endianness itsOutputEndianness
Definition: portable_binary.hpp:113
Endianness
Represents desired endianness.
Definition: portable_binary.hpp:87
An output archive designed to save data in a compact binary representation portable over different ar...
Definition: portable_binary.hpp:79
const uint8_t itsConvertEndianness
If set to true, we will need to swap bytes upon saving.
Definition: portable_binary.hpp:151
~PortableBinaryOutputArchive() CEREAL_NOEXCEPT=default
void saveBinary(const void *data, std::streamsize size)
Writes size bytes of data to the output stream.
Definition: portable_binary.hpp:132
std::ostream & itsStream
Definition: portable_binary.hpp:150
PortableBinaryOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream.
Definition: portable_binary.hpp:120
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
type
The type the bitset is encoded with.
Definition: bitset.hpp:44
void swap_bytes(std::uint8_t *data)
Swaps the order of bytes for some chunk of memory.
Definition: portable_binary.hpp:53
std::uint8_t is_little_endian()
Returns true if the current machine is little endian.
Definition: portable_binary.hpp:42
in certain simple scenarios. They should probably not be used if maximizing performance is the main o...
Definition: access.hpp:42
std::enable_if< std::is_arithmetic< T >::value, void >::type CEREAL_LOAD_FUNCTION_NAME(BinaryInputArchive &ar, T &t)
Loading for POD types from binary.
Definition: binary.hpp:126
CEREAL_SERIALIZE_FUNCTION_NAME(Archive &ar, NameValuePair< T > &t)
Serializing NVP types to binary.
Definition: binary.hpp:134
std::enable_if< std::is_arithmetic< T >::value, void >::type CEREAL_SAVE_FUNCTION_NAME(BinaryOutputArchive &ar, T const &t)
Saving for POD types to binary.
Definition: binary.hpp:118
@ AllowEmptyClassElision
Definition: cereal.hpp:185
Definition: json.hpp:5678
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression, cppcoreguidelines-noexcept-swap, performance-noexcept-swap) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition: json.hpp:25399
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1282
PUGI_IMPL_FN bool is_little_endian()
Definition: pugixml.cpp:1931
signed int int32_t
Definition: stdint.h:123
unsigned char uint8_t
Definition: stdint.h:124
signed char int8_t
Definition: stdint.h:121
A wrapper around data that can be serialized in a binary fashion.
Definition: helpers.hpp:212
PT data
pointer to beginning of data
Definition: helpers.hpp:221
uint64_t size
size in bytes
Definition: helpers.hpp:222
An exception class thrown when things go wrong at runtime.
Definition: helpers.hpp:49
#define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive)
Sets up traits that relate an input archive to an output archive.
Definition: traits.hpp:169
#define CEREAL_ARCHIVE_RESTRICT(INTYPE, OUTTYPE)
A macro to use to restrict which types of archives your function will work for.
Definition: traits.hpp:1315
#define const
Definition: zconf.h:233