cereal
A C++11 library for serialization
portable_binary.hpp
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
36namespace cereal
37{
38 namespace portable_binary_detail
39 {
41
42 inline std::uint8_t is_little_endian()
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
93 static Options LittleEndian(){ return Options( Endianness::little ); }
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()
106 { return portable_binary_detail::is_little_endian() ? Endianness::little : Endianness::big; }
107
109 inline std::uint8_t is_little_endian() const
110 { return itsOutputEndianness == Endianness::little; }
111
112 friend class PortableBinaryOutputArchive;
113 Endianness itsOutputEndianness;
114 };
115
117
120 PortableBinaryOutputArchive(std::ostream & stream, Options const & options = Options::Default()) :
121 OutputArchive<PortableBinaryOutputArchive, AllowEmptyClassElision>(this),
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
136 if( itsConvertEndianness )
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;
151 const uint8_t itsConvertEndianness;
152 };
153
154 // ######################################################################
156
180 class PortableBinaryInputArchive : public InputArchive<PortableBinaryInputArchive, AllowEmptyClassElision>
181 {
182 public:
185 {
186 public:
188 enum class Endianness : std::uint8_t
189 { big, little };
190
192 static Options Default(){ return Options(); }
193
195 static Options LittleEndian(){ return Options( Endianness::little ); }
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()
208 { return portable_binary_detail::is_little_endian() ? Endianness::little : Endianness::big; }
209
211 inline std::uint8_t is_little_endian() const
212 { return itsInputEndianness == Endianness::little; }
213
214 friend class PortableBinaryInputArchive;
215 Endianness itsInputEndianness;
216 };
217
219
222 PortableBinaryInputArchive(std::istream & stream, Options const & options = Options::Default()) :
223 InputArchive<PortableBinaryInputArchive, AllowEmptyClassElision>(this),
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
248 if( itsConvertEndianness )
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;
258 uint8_t itsConvertEndianness;
259 };
260
261 // ######################################################################
262 // Common BinaryArchive serialization functions
263
265 template<class T> inline
266 typename std::enable_if<std::is_arithmetic<T>::value, void>::type
267 CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, T const & t)
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
277 typename std::enable_if<std::is_arithmetic<T>::value, void>::type
278 CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, T & t)
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
304 void CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, BinaryData<T> const & bd)
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
316 void CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, BinaryData<T> & bd)
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_
Main cereal functionality.
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 Options LittleEndian()
Load into little endian.
Definition: portable_binary.hpp:195
static Options Default()
Default options, preserve system endianness.
Definition: portable_binary.hpp:192
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(std::istream &stream, Options const &options=Options::Default())
Construct, loading from the provided stream.
Definition: portable_binary.hpp:222
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
Options(Endianness outputEndian=getEndianness())
Specify specific options for the PortableBinaryOutputArchive.
Definition: portable_binary.hpp:100
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
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
void saveBinary(const void *data, std::streamsize size)
Writes size bytes of data to the output stream.
Definition: portable_binary.hpp:132
PortableBinaryOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream.
Definition: portable_binary.hpp:120
#define CEREAL_REGISTER_ARCHIVE(Archive)
Registers a specific Archive type with cereal.
Definition: cereal.hpp:195
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
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
#define CEREAL_LOAD_FUNCTION_NAME
The deserialization (load) function name to search for.
Definition: macros.hpp:85
#define CEREAL_SAVE_FUNCTION_NAME
The serialization (save) function name to search for.
Definition: macros.hpp:92
#define CEREAL_SERIALIZE_FUNCTION_NAME
The serialization/deserialization function name to search for.
Definition: macros.hpp:78
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