123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- #ifndef CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
- #define CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
- #include "cereal/cereal.hpp"
- #include <sstream>
- #include <limits>
- namespace cereal
- {
- namespace portable_binary_detail
- {
-
-
- inline std::uint8_t is_little_endian()
- {
- static std::int32_t test = 1;
- return *reinterpret_cast<std::int8_t*>( &test ) == 1;
- }
-
-
- template <std::size_t DataSize>
- inline void swap_bytes( std::uint8_t * data )
- {
- for( std::size_t i = 0, end = DataSize / 2; i < end; ++i )
- std::swap( data[i], data[DataSize - i - 1] );
- }
- }
-
-
-
- class PortableBinaryOutputArchive : public OutputArchive<PortableBinaryOutputArchive, AllowEmptyClassElision>
- {
- public:
-
- class Options
- {
- public:
-
- enum class Endianness : std::uint8_t
- { big, little };
-
- static Options Default(){ return Options(); }
-
- static Options LittleEndian(){ return Options( Endianness::little ); }
-
- static Options BigEndian(){ return Options( Endianness::big ); }
-
-
- explicit Options( Endianness outputEndian = getEndianness() ) :
- itsOutputEndianness( outputEndian ) { }
- private:
-
- inline static Endianness getEndianness()
- { return portable_binary_detail::is_little_endian() ? Endianness::little : Endianness::big; }
-
- inline std::uint8_t is_little_endian() const
- { return itsOutputEndianness == Endianness::little; }
- friend class PortableBinaryOutputArchive;
- Endianness itsOutputEndianness;
- };
-
-
- PortableBinaryOutputArchive(std::ostream & stream, Options const & options = Options::Default()) :
- OutputArchive<PortableBinaryOutputArchive, AllowEmptyClassElision>(this),
- itsStream(stream),
- itsConvertEndianness( portable_binary_detail::is_little_endian() ^ options.is_little_endian() )
- {
- this->operator()( options.is_little_endian() );
- }
- ~PortableBinaryOutputArchive() CEREAL_NOEXCEPT = default;
-
- template <std::streamsize DataSize> inline
- void saveBinary( const void * data, std::streamsize size )
- {
- std::streamsize writtenSize = 0;
- if( itsConvertEndianness )
- {
- for( std::streamsize i = 0; i < size; i += DataSize )
- for( std::streamsize j = 0; j < DataSize; ++j )
- writtenSize += itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ) + DataSize - j - 1 + i, 1 );
- }
- else
- writtenSize = itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size );
- if(writtenSize != size)
- throw Exception("Failed to write " + std::to_string(size) + " bytes to output stream! Wrote " + std::to_string(writtenSize));
- }
- private:
- std::ostream & itsStream;
- const uint8_t itsConvertEndianness;
- };
-
-
-
- class PortableBinaryInputArchive : public InputArchive<PortableBinaryInputArchive, AllowEmptyClassElision>
- {
- public:
-
- class Options
- {
- public:
-
- enum class Endianness : std::uint8_t
- { big, little };
-
- static Options Default(){ return Options(); }
-
- static Options LittleEndian(){ return Options( Endianness::little ); }
-
- static Options BigEndian(){ return Options( Endianness::big ); }
-
-
- explicit Options( Endianness inputEndian = getEndianness() ) :
- itsInputEndianness( inputEndian ) { }
- private:
-
- inline static Endianness getEndianness()
- { return portable_binary_detail::is_little_endian() ? Endianness::little : Endianness::big; }
-
- inline std::uint8_t is_little_endian() const
- { return itsInputEndianness == Endianness::little; }
- friend class PortableBinaryInputArchive;
- Endianness itsInputEndianness;
- };
-
-
- PortableBinaryInputArchive(std::istream & stream, Options const & options = Options::Default()) :
- InputArchive<PortableBinaryInputArchive, AllowEmptyClassElision>(this),
- itsStream(stream),
- itsConvertEndianness( false )
- {
- uint8_t streamLittleEndian;
- this->operator()( streamLittleEndian );
- itsConvertEndianness = options.is_little_endian() ^ streamLittleEndian;
- }
- ~PortableBinaryInputArchive() CEREAL_NOEXCEPT = default;
-
-
- template <std::streamsize DataSize> inline
- void loadBinary( void * const data, std::streamsize size )
- {
-
- auto const readSize = itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size );
- if(readSize != size)
- throw Exception("Failed to read " + std::to_string(size) + " bytes from input stream! Read " + std::to_string(readSize));
-
- if( itsConvertEndianness )
- {
- std::uint8_t * ptr = reinterpret_cast<std::uint8_t*>( data );
- for( std::streamsize i = 0; i < size; i += DataSize )
- portable_binary_detail::swap_bytes<DataSize>( ptr + i );
- }
- }
- private:
- std::istream & itsStream;
- uint8_t itsConvertEndianness;
- };
-
-
-
- template<class T> inline
- typename std::enable_if<std::is_arithmetic<T>::value, void>::type
- CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, T const & t)
- {
- static_assert( !std::is_floating_point<T>::value ||
- (std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
- "Portable binary only supports IEEE 754 standardized floating point" );
- ar.template saveBinary<sizeof(T)>(std::addressof(t), sizeof(t));
- }
-
- template<class T> inline
- typename std::enable_if<std::is_arithmetic<T>::value, void>::type
- CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, T & t)
- {
- static_assert( !std::is_floating_point<T>::value ||
- (std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
- "Portable binary only supports IEEE 754 standardized floating point" );
- ar.template loadBinary<sizeof(T)>(std::addressof(t), sizeof(t));
- }
-
- template <class Archive, class T> inline
- CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
- CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, NameValuePair<T> & t )
- {
- ar( t.value );
- }
-
- template <class Archive, class T> inline
- CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
- CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, SizeTag<T> & t )
- {
- ar( t.size );
- }
-
- template <class T> inline
- void CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, BinaryData<T> const & bd)
- {
- typedef typename std::remove_pointer<T>::type TT;
- static_assert( !std::is_floating_point<TT>::value ||
- (std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
- "Portable binary only supports IEEE 754 standardized floating point" );
- ar.template saveBinary<sizeof(TT)>( bd.data, static_cast<std::streamsize>( bd.size ) );
- }
-
- template <class T> inline
- void CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, BinaryData<T> & bd)
- {
- typedef typename std::remove_pointer<T>::type TT;
- static_assert( !std::is_floating_point<TT>::value ||
- (std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
- "Portable binary only supports IEEE 754 standardized floating point" );
- ar.template loadBinary<sizeof(TT)>( bd.data, static_cast<std::streamsize>( bd.size ) );
- }
- }
- CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryOutputArchive)
- CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryInputArchive)
- CEREAL_SETUP_ARCHIVE_TRAITS(cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive)
- #endif
|