29 #ifndef CEREAL_ARCHIVES_EXTENDABLE_BINARY_HPP_ 30 #define CEREAL_ARCHIVES_EXTENDABLE_BINARY_HPP_ 75 itsOutputEndianness( outputEndian_ ) { }
88 inline std::uint8_t is_little_endian()
const 89 {
return itsOutputEndianness == Endianness::little; }
105 this->saveBinary<sizeof(std::uint8_t)>( &
littleEndian,
sizeof(std::uint8_t) );
113 template <std::
size_t DataSize>
inline 116 std::size_t writtenSize = 0;
118 if( itsConvertEndianness )
120 for( std::size_t i = 0; i < size; i += DataSize )
121 for( std::size_t j = 0; j < DataSize; ++j )
122 writtenSize += static_cast<std::size_t>( itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ) + DataSize - j - 1 + i, 1 ) );
125 writtenSize =
static_cast<std::size_t
>( itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size ) );
127 if(writtenSize != size)
128 throw Exception(
"Failed to write " + std::to_string(size) +
" bytes to output stream! Wrote " + std::to_string(writtenSize));
135 std::size_t writtenSize = 0;
137 writtenSize =
static_cast<std::size_t
>( itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size ) );
139 if(writtenSize != size)
140 throw Exception(
"Failed to write " + std::to_string(size) +
" bytes to output stream! Wrote " + std::to_string(writtenSize));
148 template<std::
size_t DataSize>
inline 151 std::size_t writtenSize = 0;
154 if( itsConvertEndianness )
156 for( std::size_t j = 0; j < size; ++j )
157 writtenSize += static_cast<std::size_t>( itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( dataEndian ) + size - j - 1, 1 ) );
160 writtenSize =
static_cast<std::size_t
>( itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( dataEndian ), size ) );
162 if(writtenSize != size)
163 throw Exception(
"Failed to write " + std::to_string(size) +
" bytes to output stream! Wrote " + std::to_string(writtenSize));
174 static_assert(
sizeof(T) <= (extendable_binary_detail::maxVarintSize*7)/8,
"value is to big to be saved as varint");
175 static_assert(std::is_unsigned<T>::value,
"only unsigned varints are supported");
176 std::array<std::uint8_t, extendable_binary_detail::maxVarintSize> buffer;
177 std::size_t size = 0;
179 buffer[size] = (
static_cast<std::uint8_t
>(v) & 0x7f) | 0x80;
183 buffer[size] =
static_cast<std::uint8_t
>(v) & 0x7f;
192 classVersion = version;
200 objectId = objectId_;
215 polymorphicId = polymorphicId_;
222 polymorphicName = name;
229 if(objectDataNeedsSaving) {
230 saveObjectData(
false);
232 objectDataNeedsSaving =
true;
239 if(objectDataNeedsSaving) {
240 saveObjectData(
false);
249 if(objectDataNeedsSaving) {
251 saveObjectData(
true);
268 void saveObjectData(
bool endOfObject)
270 using namespace extendable_binary_detail;
272 PointerMarkers finalMarker = PointerMarkers::None;
274 finalMarker |= PointerMarkers::IsSharedPtr;
276 if(polymorphicId > 0) {
277 finalMarker |= PointerMarkers::IsPolymorphicPointer;
280 finalMarker |= PointerMarkers::Empty;
282 std::uint8_t t = writeType(FieldType::pointer, static_cast<std::uint8_t>(finalMarker));
283 saveBinary<sizeof(std::uint8_t)>(&t,
sizeof(std::uint8_t));
287 if(polymorphicId > 0) {
288 saveBinary<sizeof(std::int32_t)>(&polymorphicId,
sizeof(std::int32_t));
290 if(
false == polymorphicName.empty()) {
292 saveBinary<sizeof(decltype(polymorphicName)::value_type)>( polymorphicName.c_str(),
293 polymorphicName.size() *
sizeof(decltype(polymorphicName)::value_type));
296 ClassMarkers finalMarker = ClassMarkers::None;
297 if(classVersion > 0) {
298 finalMarker |= ClassMarkers::HasVersion;
302 finalMarker |= ClassMarkers::EmptyClass;
304 std::uint8_t t = writeType(FieldType::class_t, static_cast<std::uint8_t>(finalMarker));
305 saveBinary<sizeof(std::uint8_t)>(&t,
sizeof(std::uint8_t));
307 if(classVersion > 0) {
312 objectDataNeedsSaving =
false;
318 polymorphicName.clear();
325 using namespace extendable_binary_detail;
326 std::uint8_t t = writeType(FieldType::last_field, 0);
327 saveBinary<sizeof(std::uint8_t)>(&t,
sizeof(std::uint8_t));
331 bool objectDataNeedsSaving =
false;
332 std::uint32_t classVersion = 0;
333 bool isPointer =
false;
334 std::uint32_t objectId = 0;
335 std::uint32_t polymorphicId = 0;
336 std::string polymorphicName;
338 std::ostream & itsStream;
339 const uint8_t itsConvertEndianness;
383 std::size_t maxSharedBufferSize_ = std::numeric_limits<std::size_t>::max(),
384 bool ignoreUnknownPolymorphicTypes_ =
true) :
385 itsInputEndianness( inputEndian_ ),
386 itsMaxSharedBufferSize( maxSharedBufferSize_ ),
387 itsIgnoreUnknownPolymorphicTypes( ignoreUnknownPolymorphicTypes_ )
401 itsMaxSharedBufferSize = maxSharedBufferSize_;
410 itsIgnoreUnknownPolymorphicTypes = ignore_;
420 inline std::uint8_t is_little_endian()
const 421 {
return itsInputEndianness == Endianness::little; }
424 inline std::size_t getMaxSharedBufferSize()
const 425 {
return itsMaxSharedBufferSize; }
429 std::size_t itsMaxSharedBufferSize;
430 bool itsIgnoreUnknownPolymorphicTypes;
439 sharedObjectStream(
std::ios::binary |
std::ios::in |
std::ios::out),
440 itsStream(stream, sharedObjectStream, options.itsMaxSharedBufferSize),
441 itsConvertEndianness( false )
443 uint8_t streamLittleEndian;
444 this->loadBinary<sizeof(std::uint8_t)>( &streamLittleEndian,
sizeof(std::uint8_t));
445 itsConvertEndianness = options.is_little_endian() ^ streamLittleEndian;
446 itsIgnoreUnknownPolymorphicTypes = options.itsIgnoreUnknownPolymorphicTypes;
455 template <std::
size_t DataSize>
inline 459 auto const readSize = itsStream.readBinary( reinterpret_cast<char*>( data ), size );
460 if(
false == savedShared.saving.empty()) {
461 itsStream.checkIfMaxSize(size, sharedObjectStream);
462 sharedObjectStream.write(reinterpret_cast<char*>(data), size);
466 throw Exception(
"Failed to read " + std::to_string(size) +
" bytes from input stream! Read " + std::to_string(readSize));
469 if( itsConvertEndianness )
471 std::uint8_t * ptr =
reinterpret_cast<std::uint8_t*
>( data );
472 for( std::size_t i = 0; i < size; i += DataSize )
473 extendable_binary_detail::swap_bytes<DataSize>( ptr + i );
484 template <std::
size_t DataSize>
inline 489 auto const readSize = itsStream.readBinary( reinterpret_cast<char*>( dataEndian ), size );
490 if(
false == savedShared.saving.empty()) {
491 itsStream.checkIfMaxSize(size, sharedObjectStream);
492 sharedObjectStream.write(reinterpret_cast<char*>(data), size);
496 throw Exception(
"Failed to read " + std::to_string(size) +
" bytes from input stream! Read " + std::to_string(readSize));
499 if( itsConvertEndianness ) {
500 std::uint8_t * ptr =
reinterpret_cast<std::uint8_t*
>( dataEndian );
501 for( std::size_t i = 0, end = size / 2; i < end; ++i )
502 std::swap( ptr[i], ptr[size - i - 1] );
512 template <std::
size_t DataSize>
inline 516 std::uint8_t* dest =
reinterpret_cast<std::uint8_t*
>(dest_);
517 std::memcpy(dest, src, size_);
525 if(savedShared.saving.empty()) {
526 itsStream.skipData(size);
528 itsStream.readToOtherStream(size, sharedObjectStream);
539 using namespace extendable_binary_detail;
541 loadBinary<sizeof(std::uint8_t)>(&v,
sizeof(std::uint8_t));
542 lastTypeTag = extendable_binary_detail::readType(v);
543 return lastTypeTag.first != FieldType::omitted_field;
551 template <extendable_binary_detail::FieldType expected_type>
552 inline auto getTypeTag() -> decltype(extendable_binary_detail::readType(std::uint8_t{}))
554 using namespace extendable_binary_detail;
555 static_assert(expected_type != FieldType::last_field,
"should go to loadEndOfClass");
556 if(lastTypeTag.first != expected_type && lastTypeTag.first != FieldType::omitted_field)
557 throw Exception(
"Loaded wrong lastTypeTag, expected: " + std::to_string(static_cast<int>(expected_type))
558 +
" got: " + std::to_string(static_cast<int>(lastTypeTag.first)) );
566 template <extendable_binary_detail::FieldType expected_type>
569 using namespace extendable_binary_detail;
570 static_assert(expected_type != FieldType::last_field,
"should go to loadEndOfClass");
580 static_assert(
sizeof(T) <= (extendable_binary_detail::maxVarintSize*7)/8,
"value is to big to be a varint");
581 static_assert(std::is_unsigned<T>::value,
"only unsigned varints are supported");
583 std::uint32_t f = 0, s = 0;
585 std::uint8_t bytes = 1;
586 std::uint32_t f1 = 0, f2 = 0, f3 = 0, f4 = 0, s1 = 0, s2 = 0, s3 = 0, s4 = 0, s5 = 0, s6 = 0;
587 loadBinarySingle<sizeof(std::uint32_t)>(&f1,
sizeof(std::uint8_t));
592 loadBinarySingle<sizeof(std::uint32_t)>(&f2,
sizeof(std::uint8_t));
595 f = (f1 - 0x80) | (f2 << 7);
598 loadBinarySingle<sizeof(std::uint32_t)>(&f3,
sizeof(std::uint8_t));
601 f = (f1 - 0x80) | ((f2 - 0x80) << 7) | (f3 << 14);
604 loadBinarySingle<sizeof(std::uint32_t)>(&f4,
sizeof(std::uint8_t));
607 f = (f1 - 0x80) | ((f2 - 0x80) << 7) | ((f3 - 0x80) << 14) | (f4 << 21);
610 loadBinarySingle<sizeof(std::uint32_t)>(&s1,
sizeof(std::uint8_t));
613 f = (f1 - 0x80) | ((f2 - 0x80) << 7) | ((f3 - 0x80) << 14) | ((f4 - 0x80) << 21) | (s1 << 28);
617 loadBinarySingle<sizeof(std::uint32_t)>(&s2,
sizeof(std::uint8_t));
620 f = (f1 - 0x80) | ((f2 - 0x80) << 7) | ((f3 - 0x80) << 14) | ((f4 - 0x80) << 21) | ((s1 - 0x80) << 28);
621 s = ((s1 - 0x80) >> 4) | (s2 << 3);
624 loadBinarySingle<sizeof(std::uint32_t)>(&s3,
sizeof(std::uint8_t));
627 f = (f1 - 0x80) | ((f2 - 0x80) << 7) | ((f3 - 0x80) << 14) | ((f4 - 0x80) << 21) | ((s1 - 0x80) << 28);
628 s = ((s1 - 0x80) >> 4) | ((s2 - 0x80) << 3) | s3 << 10;
631 loadBinarySingle<sizeof(std::uint32_t)>(&s4,
sizeof(std::uint8_t));
634 f = (f1 - 0x80) | ((f2 - 0x80) << 7) | ((f3 - 0x80) << 14) | ((f4 - 0x80) << 21) | ((s1 - 0x80) << 28);
635 s = ((s1 - 0x80) >> 4) | ((s2 - 0x80) << 3) | ((s3 - 0x80) << 10) | s4 << 17;
638 loadBinarySingle<sizeof(std::uint32_t)>(&s5,
sizeof(std::uint8_t));
641 f = (f1 - 0x80) | ((f2 - 0x80) << 7) | ((f3 - 0x80) << 14) | ((f4 - 0x80) << 21) | ((s1 - 0x80) << 28);
642 s = ((s1 - 0x80) >> 4) | ((s2 - 0x80) << 3) | ((s3 - 0x80) << 10) | ((s4 - 0x80) << 17) | s5 << 24;
645 loadBinarySingle<sizeof(std::uint32_t)>(&s6,
sizeof(std::uint8_t));
648 f = (f1 - 0x80) | ((f2 - 0x80) << 7) | ((f3 - 0x80) << 14) | ((f4 - 0x80) << 21) | ((s1 - 0x80) << 28);
649 s = ((s1 - 0x80) >> 4) | ((s2 - 0x80) << 3) | ((s3 - 0x80) << 10) | ((s4 - 0x80) << 17) | ((s5 - 0x80) << 24) | s6 << 31;
657 std::uint64_t
final = s;
658 final <<= (
sizeof(s)*8);
660 std::memcpy(&v, &
final,
sizeof(T));
662 copyBinarySingleNoSwap<sizeof(s)>(&v, &f,
sizeof(T));
670 std::uint64_t ignore;
677 resetObjectDetails();
678 using namespace extendable_binary_detail;
679 const auto type = getTypeTagNoError<FieldType::class_t>();
681 case FieldType::class_t: {
682 loadClassData(type.second);
685 case FieldType::pointer: {
686 loadPointerData(type.second);
689 case FieldType::omitted_field: {
690 throw Exception(
"omitted class, should be read earlier");
693 throw Exception(
"Unexpected type expected class or pointer, got:" + std::to_string(static_cast<int>(type.first)));
707 loadEndOfClass(
true);
709 resetObjectDetails();
715 loadEndOfClass(
false);
727 return polymorphicId;
733 return polymorphicName;
745 return false == emptyClass;
767 std::vector<std::pair<std::uint32_t, extendable_binary_detail::StreamPos>> saving;
770 std::map<std::uint32_t, extendable_binary_detail::StreamPos> saved;
771 std::set<std::uint32_t> loaded;
775 inline void resetObjectDetails()
782 polymorphicName.clear();
786 inline void loadClassData(std::uint8_t classMarkers)
788 using namespace extendable_binary_detail;
789 ClassMarkers markers =
static_cast<ClassMarkers
>(classMarkers);
790 if(markers & ClassMarkers::EmptyClass) {
793 if(markers & ClassMarkers::HasVersion) {
794 loadVarint(classVersion);
799 void loadSharedPointer()
801 const auto normalObjectId = objectId & ~detail::msb_32bit;
802 const auto wasSkipped = savedShared.saved.find(normalObjectId);
804 if(wasSkipped == savedShared.saved.end())
807 const bool isNewObjectInStream = (objectId & detail::msb_32bit) != 0;
808 const auto alreadyLoaded = savedShared.loaded.find(normalObjectId);
809 if (
false == isNewObjectInStream) {
811 if (alreadyLoaded == savedShared.loaded.end()) {
813 savedShared.loaded.emplace(normalObjectId);
815 objectId = objectId | detail::msb_32bit;
816 pushLoadShared(wasSkipped->second);
819 }
else if (alreadyLoaded == savedShared.loaded.end()) {
825 savedShared.loaded.emplace(normalObjectId);
826 }
else if (alreadyLoaded != savedShared.loaded.end()) {
829 objectId = normalObjectId;
832 itsStream.skipData(wasSkipped->second.end - wasSkipped->second.start);
837 inline void loadPointerData(std::uint8_t pointerMarkers)
839 using namespace extendable_binary_detail;
840 PointerMarkers markers =
static_cast<PointerMarkers
>(pointerMarkers);
841 if (markers & PointerMarkers::Empty) {
844 if (markers & PointerMarkers::IsSharedPtr) {
845 loadVarint(objectId);
848 if (markers & PointerMarkers::IsPolymorphicPointer) {
849 loadBinary<sizeof(std::int32_t)>(&polymorphicId,
sizeof(std::int32_t));
850 const bool isNewId = polymorphicId & detail::msb_32bit;
851 const bool noPolymorphicCast = polymorphicId & detail::msb2_32bit;
853 std::uint32_t nameSize;
854 loadVarint(nameSize);
856 polymorphicName.resize(nameSize);
857 using char_type = decltype(polymorphicName)::value_type;
858 loadBinary<sizeof(char_type)>(&polymorphicName[0u],
859 nameSize *
sizeof(char_type));
862 }
else if(noPolymorphicCast) {
865 polymorphicName = getPolymorphicName(polymorphicId);
867 if (itsIgnoreUnknownPolymorphicTypes &&
868 false == emptyClass &&
869 false == polymorphic_detail::hasPolymorphicBinding<ExtendableBinaryInputArchive>(polymorphicName)
874 registerPolymorphicName(polymorphicId, polymorphicName);
876 resetObjectDetails();
879 loadEndOfClass(
true);
889 inline void loadEndOfClass(
bool isInObject)
891 using namespace extendable_binary_detail;
892 using return_type = decltype(extendable_binary_detail::readType(std::uint8_t{}));
893 int class_depth = isInObject ? 1 : 0;
894 std::size_t lastIgnoredSizeTag = 0;
896 bool firstPass =
true;
898 if(
false == firstPass) {
903 return_type type = getTypeTagNoError<FieldType::class_t>();
904 switch (type.first) {
905 case FieldType::positive_integer:
906 case FieldType::negative_integer: {
907 skipData(getIntSizeFromTagSize(type.second));
910 case FieldType::floating_point: {
911 skipData(getFloatSizeFromTagSize(type.second));
914 case FieldType::integer_packed:
916 case FieldType::omitted_field:
918 case FieldType::last_field: {
920 if(isSkippedSharedObjectEnd(class_depth)) {
926 case FieldType::class_t: {
927 ClassMarkers markers =
static_cast<ClassMarkers
>(type.second);
928 if(
false == (markers & ClassMarkers::EmptyClass)) {
931 if(markers & ClassMarkers::HasVersion) {
936 case FieldType::pointer: {
937 PointerMarkers markers =
static_cast<PointerMarkers
>(type.second);
938 if(
false == (markers & PointerMarkers::Empty)) {
941 if(markers & PointerMarkers::IsSharedPtr) {
942 std::uint32_t objectIdTmp;
943 loadVarint(objectIdTmp);
944 if(objectIdTmp & detail::msb_32bit) {
945 pushSaveShared(objectIdTmp & ~detail::msb_32bit, class_depth);
948 if(markers & PointerMarkers::IsPolymorphicPointer) {
949 loadBinary<sizeof(std::int32_t)>(&polymorphicId,
sizeof(std::int32_t));
950 if(polymorphicId & detail::msb_32bit) {
951 std::uint32_t nameSize;
952 loadVarint(nameSize);
954 polymorphicName.resize(nameSize);
955 using char_type = decltype(polymorphicName)::value_type;
956 loadBinary<sizeof(char_type)>(&polymorphicName[0u],
957 nameSize *
sizeof(char_type));
960 registerPolymorphicName(polymorphicId, polymorphicName);
967 case FieldType::packed_array: {
970 skipData(type.second * size);
973 case FieldType::packed_struct: {
974 throw Exception(
"packed_struct is not supported yet");
976 case FieldType::size_tag: {
978 const auto sizeTagSize = getIntSizeFromTagSize(type.second);
979 if(sizeTagSize >
sizeof(lastIgnoredSizeTag)) {
980 throw Exception(
"Size tag is to big to be loaded");
982 loadBinarySingle<sizeof(lastIgnoredSizeTag)>(&lastIgnoredSizeTag, sizeTagSize);
986 throw Exception(
"Unknown type of field: " + std::to_string(static_cast<int>(type.first)));
989 }
while(class_depth > 0);
992 inline void pushSaveShared(std::uint32_t skippedObjectId,
int classDepth)
994 savedShared.saving.emplace_back(
995 std::make_pair(skippedObjectId,
997 static_cast<std::streamoff
>(classDepth)
1002 inline bool isSkippedSharedObjectEnd(
int classDepth)
1004 return false == savedShared.saving.empty()
1005 && savedShared.saving.back().second.end ==
static_cast<std::streamoff
>(classDepth);
1009 inline void popSaveShared()
1011 if (savedShared.saving.empty())
1012 throw Exception(
"unexpected end of shared object");
1013 auto &last = savedShared.saving.back();
1014 last.second.end = sharedObjectStream.tellp();
1015 savedShared.saved.emplace(last.first, last.second);
1016 savedShared.saving.pop_back();
1021 itsStream.pushReadingPos(pos);
1026 std::uint32_t classVersion = 0;
1027 bool emptyClass =
false;
1028 std::uint32_t objectId = 0;
1029 std::int32_t polymorphicId = 0;
1030 std::string polymorphicName;
1032 std::size_t lastSizeTag = 0;
1033 std::pair<extendable_binary_detail::FieldType, std::uint8_t> lastTypeTag =
1034 {extendable_binary_detail::FieldType::last_field, 0};
1036 SavedShared savedShared;
1037 std::stringstream sharedObjectStream;
1040 uint8_t itsConvertEndianness;
1041 bool itsIgnoreUnknownPolymorphicTypes;
1049 template <
class T>
inline 1050 typename std::enable_if<std::is_same<T, bool>::value,
void>::type
1053 using namespace extendable_binary_detail;
1054 std::uint8_t v = writeType(FieldType::integer_packed, (t ? 1 : 0));
1055 ar.template saveBinary<sizeof(std::uint8_t)>(&v,
sizeof(std::uint8_t));
1060 template <
class T>
inline 1061 typename std::enable_if<std::is_same<T, bool>::value,
void>::type
1064 using namespace extendable_binary_detail;
1065 const auto type = ar.
getTypeTag<FieldType::integer_packed>();
1066 if( type.first == FieldType::omitted_field )
1072 template<
class T>
inline 1073 typename std::enable_if<std::is_integral<T>::value &&
1074 !std::is_same<T, bool>::value,
void>::type
1077 static_assert(
sizeof(T) <= 32,
"Only integers up to 32 bytes are supported");
1078 using namespace extendable_binary_detail;
1079 using unsigned_type =
typename std::make_unsigned<T>::type;
1081 if( t <= 0xf && t >= 0 ) {
1082 std::uint8_t v = writeType(FieldType::integer_packed, static_cast<std::uint8_t>(t));
1083 ar.template saveBinary<sizeof(std::uint8_t)>(&v,
sizeof(v));
1087 const unsigned_type absolute = t >= 0 ? t : -
static_cast<unsigned_type
>(t);
1088 const auto neededBytes = getIntSizeTagFromByteCount(getHighestBit(absolute));
1089 const auto fieldType = t >= 0 ? FieldType::positive_integer : FieldType::negative_integer;
1090 std::uint8_t v = writeType(fieldType, neededBytes);
1091 ar.template saveBinary<sizeof(std::uint8_t)>(&v,
sizeof(v));
1097 template<
class T>
inline 1098 typename std::enable_if<std::is_integral<T>::value &&
1099 !std::is_same<T, bool>::value,
void>::type
1102 using namespace extendable_binary_detail;
1104 switch(type.first) {
1105 case FieldType::omitted_field:
1107 case FieldType::integer_packed: {
1111 case FieldType::positive_integer: {
1112 const auto neededByteSize = getIntSizeFromTagSize(type.second);
1113 if(neededByteSize >
sizeof(T)) {
1114 throw Exception(
"Integer is to big to be loaded");
1120 case FieldType::negative_integer: {
1121 const auto neededByteSize = getIntSizeFromTagSize(type.second);
1122 if(neededByteSize >
sizeof(T)) {
1123 throw Exception(
"Integer is to big to be loaded");
1125 if(std::is_unsigned<T>::value) {
1126 throw Exception(
"Negative value cannot be loaded to unsigned type");
1134 throw Exception(
"Unexpected type expected: integer got:" + std::to_string(static_cast<int>(type.first)));
1139 template<
class T>
inline 1140 typename std::enable_if<std::is_floating_point<T>::value,
void>::type
1143 static_assert( !std::is_floating_point<T>::value ||
1144 (std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
1145 "Extendable binary only supports IEEE 754 standardized floating point" );
1146 using namespace extendable_binary_detail;
1147 std::uint8_t floatSize = getTagSizeFromFloatType<T>();
1148 std::uint8_t v = writeType(FieldType::floating_point, floatSize);
1149 ar.template saveBinary<sizeof(std::uint8_t)>(&v,
sizeof(std::uint8_t));
1151 ar.template saveBinary<sizeof(T)>(std::addressof(t),
sizeof(t));
1153 auto qNaN = getqNaN<T>();
1154 ar.template saveBinary<sizeof(qNaN)>(std::addressof(qNaN),
sizeof(qNaN));
1159 template<
class T>
inline 1160 typename std::enable_if<std::is_floating_point<T>::value,
void>::type
1163 static_assert( !std::is_floating_point<T>::value ||
1164 (std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
1165 "Extendable binary only supports IEEE 754 standardized floating point" );
1166 static_assert((
sizeof(t) == 4) || (
sizeof(t) == 8),
"unsupported float size");
1167 using namespace extendable_binary_detail;
1168 auto type = ar.
getTypeTag<FieldType::floating_point>();
1169 if(type.first == FieldType::omitted_field)
1171 switch(type.second) {
1174 ar.template loadBinary<sizeof(dest)>(std::addressof(dest),
sizeof(dest));
1181 ar.template loadBinary<sizeof(dest)>(std::addressof(dest),
sizeof(dest));
1189 throw Exception(
"Not supported size of floating point: " + std::to_string(type.second));
1194 template <
class Archive,
class T>
inline 1202 template <
class T>
inline 1205 using namespace extendable_binary_detail;
1206 static_assert(
sizeof(t.size) <= 32,
"Only integers up to 32 bytes are supported");
1208 throw Exception(
"Negative SizeTag is not suppported");
1210 const auto neededBytes = getIntSizeTagFromByteCount(getHighestBit(t.size));
1211 const auto fieldType = FieldType::size_tag;
1212 std::uint8_t v = writeType(fieldType, neededBytes);
1213 ar.template saveBinary<sizeof(std::uint8_t)>(&v,
sizeof(v));
1214 ar.
saveBinarySingle<
sizeof(T)>(std::addressof(t.size),
static_cast<std::size_t
>(neededBytes));
1218 template <
class T>
inline 1221 using namespace extendable_binary_detail;
1222 auto type = ar.
getTypeTag<FieldType::size_tag>();
1223 if(type.first == FieldType::omitted_field) {
1226 const auto neededByteSize = getIntSizeFromTagSize(type.second);
1227 if(neededByteSize >
sizeof(t.size)) {
1228 throw Exception(
"Size tag integer is to big to be loaded");
1240 using namespace extendable_binary_detail;
1241 std::uint8_t v = writeType(FieldType::omitted_field, 0);
1242 ar.template saveBinary<sizeof(std::uint8_t)>(&v,
sizeof(std::uint8_t));
1253 template <
class T>
inline 1256 using TT =
typename std::remove_pointer<T>::type;
1257 using namespace extendable_binary_detail;
1258 std::uint8_t packedSizeOfElem;
1259 if(
sizeof(TT) < 0xf) {
1260 packedSizeOfElem =
sizeof(TT);
1262 packedSizeOfElem = 0xf;
1264 std::uint8_t v = writeType(FieldType::packed_array, packedSizeOfElem);
1265 ar.template saveBinary<sizeof(std::uint8_t)>(&v,
sizeof(std::uint8_t));
1266 if(
sizeof(TT) >= 0xf) {
1271 ar.template saveBinary<sizeof(TT)>( bd.
data,
static_cast<std::size_t
>( bd.
size ) );
1276 template <
class T>
inline 1279 typedef typename std::remove_pointer<T>::type TT;
1280 using namespace extendable_binary_detail;
1281 const auto type = ar.
getTypeTag<FieldType::packed_array>();
1282 if(type.first == FieldType::omitted_field)
1284 std::uint64_t sizeOfElem;
1285 if(type.second == 0xf) {
1288 sizeOfElem = type.second;
1290 if(
sizeof(TT) != sizeOfElem) {
1292 throw Exception(
"Wrong dest type size, expected:" + std::to_string(sizeOfElem) +
" got:" + std::to_string(
sizeof(TT)));
1294 std::uint64_t numberOfElements;
1296 std::uint64_t wholeSize = numberOfElements * sizeOfElem;
1297 if( wholeSize > bd.
size ) {
1298 throw Exception(
"BinaryData is bigger than dest var");
1300 ar.template loadBinary<sizeof(TT)>( bd.
data, wholeSize );
1304 template <
class T>
inline 1311 template <
class T>
inline 1323 template <
class T>
inline 1330 template <
class T>
inline 1342 template <
class T>
inline 1349 template <
class T>
inline 1361 template <
class T>
inline 1368 template <
class T>
inline 1380 template <
class T>
inline 1387 template <
class T>
inline 1410 std::is_arithmetic<T>::value,
1411 std::is_same<T, std::nullptr_t>::value,
1412 std::is_same<T, OmittedFieldTag>::value
1420 template <class T, traits::EnableIf<is_extendablebinary_empty_prologue_and_epilogue1<T>::value> = traits::sfinae>
inline 1427 template <class T, traits::EnableIf<is_extendablebinary_empty_prologue_and_epilogue1<T>::value> = traits::sfinae>
inline 1430 return ar.
loadTypeTag() ? FieldSerialized::YES : FieldSerialized::NO;
1434 template <class T, traits::EnableIf<is_extendablebinary_empty_prologue_and_epilogue1<T>::value> = traits::sfinae>
inline 1439 template <class T, traits::EnableIf<is_extendablebinary_empty_prologue_and_epilogue1<T>::value> = traits::sfinae>
inline 1456 : std::integral_constant<bool, std::is_polymorphic<T>::value>::type {};
1469 template <
class T, std::
size_t V>
1473 template <class T, traits::EnableIf<is_extendablebinary_internal_prologue_and_epilogue1<T>::value> = traits::sfinae>
inline 1478 template <class T, traits::EnableIf<is_extendablebinary_internal_prologue_and_epilogue1<T>::value> = traits::sfinae>
inline 1481 return FieldSerialized::INTERNAL;
1485 template <class T, traits::EnableIf<is_extendablebinary_internal_prologue_and_epilogue1<T>::value> = traits::sfinae>
inline 1490 template <class T, traits::EnableIf<is_extendablebinary_internal_prologue_and_epilogue1<T>::value> = traits::sfinae>
inline 1498 template <class T, traits::EnableIf<!traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, ExtendableBinaryOutputArchive>::value,
1508 template <class T, traits::EnableIf<!traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, ExtendableBinaryInputArchive>::value,
1518 return load ? FieldSerialized::YES : FieldSerialized::NO;
1523 template <class T, traits::EnableIf<!traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, ExtendableBinaryOutputArchive>::value,
1533 template <class T, traits::EnableIf<!traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, ExtendableBinaryInputArchive>::value,
1544 using type = double;
1549 using type = double;
1560 namespace cereal {
namespace traits {
1572 #endif // CEREAL_ARCHIVES_EXTENDABLE_BINARY_HPP_
Options & littleEndian()
Save with little endian order.
Definition: extendable_binary.hpp:78
Implementation details for extendable binary archive.
#define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive)
Sets up traits that relate an input archive to an output archive.
Definition: traits.hpp:169
PT data
pointer to beginning of data
Definition: helpers.hpp:217
void saveClassVersion(std::uint32_t version)
Store temporarily class version to be saved later.
Definition: extendable_binary.hpp:190
A wrapper around size metadata.
Definition: helpers.hpp:271
Wrap polymorphic weak_ptr in shared_ptr.
Definition: traits.hpp:1313
A wrapper around object id.
Definition: helpers.hpp:485
FieldSerialized prologueLoad(ExtendableBinaryInputArchive &ar, T const &)
Prologue for arithmetic types for ExtendableBinary archives.
Definition: extendable_binary.hpp:1428
Tag used to indicate that field is ommited from the archive.
Definition: helpers.hpp:292
A class containing various advanced options for the ExtendableBinaryOutput archive.
Definition: extendable_binary.hpp:62
A wrapper around pointer validity marker.
Definition: helpers.hpp:528
Options & bigEndian()
Save with big endian order.
Definition: extendable_binary.hpp:80
ExtendableBinaryOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream.
Definition: extendable_binary.hpp:99
void saveBinary(const void *data, std::size_t size)
Writes size bytes of data to the output stream.
Definition: extendable_binary.hpp:114
void savePolymorphicId(std::int32_t polymorphicId_)
Store temporarily polymorphic id of type to be saved later.
Definition: extendable_binary.hpp:212
#define CEREAL_SERIALIZE_FUNCTION_NAME
The serialization/deserialization function name to search for.
Definition: macros.hpp:64
A wrapper around polymorphic id.
Definition: helpers.hpp:369
static Options Default()
Default options, preserve system endianness.
Definition: extendable_binary.hpp:70
void saveBinaryNoSwap(const void *data, std::size_t size)
Writes size bytes of data to the output stream without any byte order swapping.
Definition: extendable_binary.hpp:133
void savePointerValidityTag(bool)
Store temporarily validity of pointer (!=nullptr) to be saved later.
Definition: extendable_binary.hpp:205
void saveVarint(T v)
Writes varint to the stream.
Definition: extendable_binary.hpp:172
Flags
Special flags for archives.
Definition: cereal.hpp:158
Class used as an adapter to queue of streams.
Definition: extendable_binary_details.hpp:299
void saveObjectBeginning()
Indicate beginning of new object saving.
Definition: extendable_binary.hpp:227
Types which has empty internal prologue and epilogue (version with one template argument) ...
Definition: extendable_binary.hpp:1448
Definition: traits.hpp:1044
void epilogue(ExtendableBinaryOutputArchive &, T const &)
Epilogue for arithmetic types for ExtendableBinary archives.
Definition: extendable_binary.hpp:1435
Definition: access.hpp:40
#define CEREAL_REGISTER_ARCHIVE(Archive)
Registers a specific Archive type with cereal.
Definition: cereal.hpp:171
#define CEREAL_ARCHIVE_RESTRICT(INTYPE, OUTTYPE)
A macro to use to restrict which types of archives your function will work for.
Definition: traits.hpp:1293
A wrapper around polymorphic id.
Definition: helpers.hpp:399
A wrapper around polymorphic key.
Definition: helpers.hpp:442
Options(Endianness outputEndian_=getEndianness())
Specify specific options for the ExtendableBinaryOutputArchive.
Definition: extendable_binary.hpp:74
Nearest (by precision) floating point type to longdouble supported by Archive.
Definition: common.hpp:134
void saveObjectId(std::uint32_t objectId_)
Store temporarily object id for shared objects to be saved later.
Definition: extendable_binary.hpp:197
void savingOtherField()
Indicate that some field (not beginning of new object) is being saved.
Definition: extendable_binary.hpp:237
Main cereal functionality.
For holding name value pairs.
Definition: helpers.hpp:135
Endianness
Represents desired endianness.
Definition: extendable_binary.hpp:66
#define CEREAL_LOAD_FUNCTION_NAME
The deserialization (load) function name to search for.
Definition: macros.hpp:71
void prologue(ExtendableBinaryOutputArchive &ar, T const &)
Prologue for arithmetic types for ExtendableBinary archives.
Definition: extendable_binary.hpp:1421
void saveObjectEnd()
End of object saving. Called in prologue for objects.
Definition: extendable_binary.hpp:247
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:116
A wrapper around data that can be serialized in a binary fashion.
Definition: helpers.hpp:207
Struct to keep position of start and end in stream.
Definition: extendable_binary_details.hpp:283
The base output archive class.
Definition: cereal.hpp:264
Types which has empty prologue and epilogoue (version with one template argument) ...
Definition: extendable_binary.hpp:1408
An output archive designed to save data in a portable binary representation with forward compatibilit...
Definition: extendable_binary.hpp:58
#define CEREAL_SAVE_FUNCTION_NAME
The serialization (save) function name to search for.
Definition: macros.hpp:78
uint64_t size
size in bytes
Definition: helpers.hpp:218
void savePolymorphicName(const std::string &name)
Store temporarily polymorphic name of type to be saved later.
Definition: extendable_binary.hpp:220
void saveBinarySingle(const void *data, std::size_t size)
Writes size bytes of data to the output stream.
Definition: extendable_binary.hpp:149
Support for types found in <memory>
A class used to disambiguate cases where cereal cannot detect a unique way of serializing a class...
Definition: access.hpp:404
An exception class thrown when things go wrong at runtime.
Definition: helpers.hpp:48