29 #ifndef CEREAL_ARCHIVES_JSON_HPP_
30 #define CEREAL_ARCHIVES_JSON_HPP_
44 #ifndef CEREAL_RAPIDJSON_ASSERT_THROWS
45 #define CEREAL_RAPIDJSON_ASSERT_THROWS
46 #endif // CEREAL_RAPIDJSON_ASSERT_THROWS
49 #ifndef CEREAL_RAPIDJSON_ASSERT
50 #define CEREAL_RAPIDJSON_ASSERT(x) if(!(x)){ \
51 throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); }
52 #endif // RAPIDJSON_ASSERT
55 #ifndef CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS
56 #define CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag
60 #ifndef CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS
61 #define CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag | kParseNanAndInfFlag
64 #include "cereal/external/rapidjson/prettywriter.h"
65 #include "cereal/external/rapidjson/ostreamwrapper.h"
66 #include "cereal/external/rapidjson/istreamwrapper.h"
67 #include "cereal/external/rapidjson/document.h"
68 #include "cereal/external/base64.hpp"
108 enum class NodeType { StartObject, InObject, StartArray, InArray };
110 using WriteStream = CEREAL_RAPIDJSON_NAMESPACE::OStreamWrapper;
111 using JSONWriter = CEREAL_RAPIDJSON_NAMESPACE::PrettyWriter<WriteStream>;
134 carriage_return =
'\r'
142 explicit Options(
int precision = JSONWriter::kDefaultMaxDecimalPlaces,
144 unsigned int indentLength = 4 ) :
145 itsPrecision( precision ),
146 itsIndentChar( static_cast<char>(indentChar) ),
147 itsIndentLength( indentLength ) { }
153 unsigned int itsIndentLength;
162 itsWriteStream(stream),
163 itsWriter(itsWriteStream),
166 itsWriter.SetMaxDecimalPlaces( options.itsPrecision );
167 itsWriter.SetIndent( options.itsIndentChar, options.itsIndentLength );
168 itsNameCounter.push(0);
169 itsNodeStack.push(NodeType::StartObject);
175 if (itsNodeStack.top() == NodeType::InObject)
176 itsWriter.EndObject();
177 else if (itsNodeStack.top() == NodeType::InArray)
178 itsWriter.EndArray();
189 auto base64string = base64::encode(
reinterpret_cast<const unsigned char *
>( data ), size );
207 itsNodeStack.push(NodeType::StartObject);
208 itsNameCounter.push(0);
219 switch(itsNodeStack.top())
221 case NodeType::StartArray:
222 itsWriter.StartArray();
224 case NodeType::InArray:
225 itsWriter.EndArray();
227 case NodeType::StartObject:
228 itsWriter.StartObject();
230 case NodeType::InObject:
231 itsWriter.EndObject();
236 itsNameCounter.pop();
258 void saveValue(std::string
const & s) { itsWriter.String(s.c_str(),
static_cast<CEREAL_RAPIDJSON_NAMESPACE::SizeType
>( s.size() )); }
270 std::is_signed<T>::value> = traits::sfinae>
inline
271 void saveLong(T l){
saveValue(
static_cast<std::int32_t
>( l ) ); }
275 std::is_signed<T>::value> = traits::sfinae>
inline
276 void saveLong(T l){
saveValue(
static_cast<std::int64_t
>( l ) ); }
280 std::is_unsigned<T>::value> = traits::sfinae>
inline
281 void saveLong(T lu){
saveValue(
static_cast<std::uint32_t
>( lu ) ); }
285 std::is_unsigned<T>::value> = traits::sfinae>
inline
286 void saveLong(T lu){
saveValue(
static_cast<std::uint64_t
>( lu ) ); }
289 #if defined(_MSC_VER) && _MSC_VER < 1916
290 void saveValue(
unsigned long lu ){ saveLong( lu ); };
293 template <class T, traits::EnableIf<std::is_same<T, long>::value,
295 !std::is_same<T, int>::value,
296 !std::is_same<T, std::int64_t>::value> = traits::sfinae>
inline
300 template <class T, traits::EnableIf<std::is_same<T, unsigned long>::value,
301 !std::is_same<T, unsigned>::value,
302 !std::is_same<T, std::uint64_t>::value> = traits::sfinae>
inline
308 template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
309 !std::is_same<T, long>::value,
310 !std::is_same<T, unsigned long>::value,
311 !std::is_same<T, std::int64_t>::value,
312 !std::is_same<T, std::uint64_t>::value,
313 (
sizeof(T) >=
sizeof(
long double) ||
sizeof(T) >=
sizeof(
long long))> = traits::sfinae>
inline
316 std::stringstream ss; ss.precision( std::numeric_limits<long double>::max_digits10 );
336 NodeType
const & nodeType = itsNodeStack.top();
339 if(nodeType == NodeType::StartArray)
341 itsWriter.StartArray();
342 itsNodeStack.top() = NodeType::InArray;
344 else if(nodeType == NodeType::StartObject)
346 itsNodeStack.top() = NodeType::InObject;
347 itsWriter.StartObject();
351 if(nodeType == NodeType::InArray)
return;
353 if(itsNextName ==
nullptr)
355 std::string name =
"value" + std::to_string( itsNameCounter.top()++ ) +
"\0";
361 itsNextName =
nullptr;
368 itsNodeStack.top() = NodeType::StartArray;
374 WriteStream itsWriteStream;
375 JSONWriter itsWriter;
376 char const * itsNextName;
377 std::stack<uint32_t> itsNameCounter;
378 std::stack<NodeType> itsNodeStack;
422 using ReadStream = CEREAL_RAPIDJSON_NAMESPACE::IStreamWrapper;
423 typedef CEREAL_RAPIDJSON_NAMESPACE::GenericValue<CEREAL_RAPIDJSON_NAMESPACE::UTF8<>> JSONValue;
424 typedef JSONValue::ConstMemberIterator MemberIterator;
425 typedef JSONValue::ConstValueIterator ValueIterator;
426 typedef CEREAL_RAPIDJSON_NAMESPACE::Document::GenericValue GenericValue;
437 itsNextName( nullptr ),
438 itsReadStream(stream)
440 itsDocument.ParseStream<>(itsReadStream);
441 if (itsDocument.IsArray())
442 itsIteratorStack.emplace_back(itsDocument.Begin(), itsDocument.End());
444 itsIteratorStack.emplace_back(itsDocument.MemberBegin(), itsDocument.MemberEnd());
461 auto decoded = base64::decode( encoded );
463 if( size != decoded.size() )
464 throw Exception(
"Decoded binary data size does not match specified size");
466 std::memcpy( data, decoded.data(), decoded.size() );
467 itsNextName =
nullptr;
483 Iterator() : itsIndex( 0 ), itsType(Null_) {}
485 Iterator(MemberIterator begin, MemberIterator end) :
486 itsMemberItBegin(begin), itsMemberItEnd(end), itsIndex(0), itsSize(std::distance(begin, end)), itsType(Member)
492 Iterator(ValueIterator begin, ValueIterator end) :
493 itsValueItBegin(begin), itsIndex(0), itsSize(std::distance(begin, end)), itsType(Value)
500 Iterator & operator++()
507 GenericValue
const & value()
509 if( itsIndex >= itsSize )
514 case Value :
return itsValueItBegin[itsIndex];
515 case Member:
return itsMemberItBegin[itsIndex].value;
516 default:
throw cereal::Exception(
"JSONInputArchive internal error: null or empty iterator to object or array!");
521 const char * name()
const
523 if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
524 return itsMemberItBegin[itsIndex].name.GetString();
531 inline void search(
const char * searchName )
533 const auto len = std::strlen( searchName );
535 for(
auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
537 const auto currentName = it->name.GetString();
538 if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
539 ( std::strlen( currentName ) == len ) )
546 throw Exception(
"JSON Parsing failed - provided NVP (" + std::string(searchName) +
") not found");
550 MemberIterator itsMemberItBegin, itsMemberItEnd;
551 ValueIterator itsValueItBegin;
552 size_t itsIndex, itsSize;
553 enum Type {Value, Member, Null_} itsType;
568 auto localNextName = itsNextName;
569 itsNextName =
nullptr;
575 auto const actualName = itsIteratorStack.back().name();
578 if( !actualName || std::strcmp( localNextName, actualName ) != 0 )
579 itsIteratorStack.back().search( localNextName );
598 if(itsIteratorStack.back().value().IsArray())
599 itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
601 itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
607 itsIteratorStack.pop_back();
608 ++itsIteratorStack.back();
615 return itsIteratorStack.back().name();
625 template <class T, traits::EnableIf<std::is_signed<T>::value,
626 sizeof(T) <
sizeof(int64_t)> = traits::sfinae>
inline
631 val =
static_cast<T
>( itsIteratorStack.back().value().GetInt() );
632 ++itsIteratorStack.back();
636 template <class T, traits::EnableIf<std::is_unsigned<T>::value,
637 sizeof(T) <
sizeof(uint64_t),
638 !std::is_same<bool, T>::value> = traits::sfinae>
inline
643 val =
static_cast<T
>( itsIteratorStack.back().value().GetUint() );
644 ++itsIteratorStack.back();
648 void loadValue(
bool & val) { search(); val = itsIteratorStack.back().value().GetBool(); ++itsIteratorStack.back(); }
650 void loadValue(int64_t & val) { search(); val = itsIteratorStack.back().value().GetInt64(); ++itsIteratorStack.back(); }
652 void loadValue(uint64_t & val) { search(); val = itsIteratorStack.back().value().GetUint64(); ++itsIteratorStack.back(); }
654 void loadValue(
float & val) { search(); val =
static_cast<float>(itsIteratorStack.back().value().GetDouble()); ++itsIteratorStack.back(); }
656 void loadValue(
double & val) { search(); val = itsIteratorStack.back().value().GetDouble(); ++itsIteratorStack.back(); }
658 void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
660 void loadValue(std::nullptr_t&) { search(); CEREAL_RAPIDJSON_ASSERT(itsIteratorStack.back().value().IsNull()); ++itsIteratorStack.back(); }
667 template <
class T>
inline
668 typename std::enable_if<
sizeof(T) ==
sizeof(std::int32_t) && std::is_signed<T>::value,
void>::type
669 loadLong(T & l){
loadValue(
reinterpret_cast<std::int32_t&
>( l ) ); }
672 template <
class T>
inline
673 typename std::enable_if<
sizeof(T) ==
sizeof(std::int64_t) && std::is_signed<T>::value,
void>::type
674 loadLong(T & l){
loadValue(
reinterpret_cast<std::int64_t&
>( l ) ); }
677 template <
class T>
inline
678 typename std::enable_if<
sizeof(T) ==
sizeof(std::uint32_t) && !std::is_signed<T>::value,
void>::type
679 loadLong(T & lu){
loadValue(
reinterpret_cast<std::uint32_t&
>( lu ) ); }
682 template <
class T>
inline
683 typename std::enable_if<
sizeof(T) ==
sizeof(std::uint64_t) && !std::is_signed<T>::value,
void>::type
684 loadLong(T & lu){
loadValue(
reinterpret_cast<std::uint64_t&
>( lu ) ); }
688 template <
class T>
inline
689 typename std::enable_if<std::is_same<T, long>::value &&
690 sizeof(T) >=
sizeof(std::int64_t) &&
691 !std::is_same<T, std::int64_t>::value,
void>::type
695 template <
class T>
inline
696 typename std::enable_if<std::is_same<T, unsigned long>::value &&
697 sizeof(T) >=
sizeof(std::uint64_t) &&
698 !std::is_same<T, std::uint64_t>::value,
void>::type
704 void stringToNumber( std::string
const & str,
long long & val ) { val = std::stoll( str ); }
706 void stringToNumber( std::string
const & str,
unsigned long long & val ) { val = std::stoull( str ); }
708 void stringToNumber( std::string
const & str,
long double & val ) { val = std::stold( str ); }
712 template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
713 !std::is_same<T, long>::value,
714 !std::is_same<T, unsigned long>::value,
715 !std::is_same<T, std::int64_t>::value,
716 !std::is_same<T, std::uint64_t>::value,
717 (
sizeof(T) >=
sizeof(
long double) ||
sizeof(T) >=
sizeof(
long long))> = traits::sfinae>
722 stringToNumber( encoded, val );
728 if (itsIteratorStack.size() == 1)
729 size = itsDocument.Size();
731 size = (itsIteratorStack.rbegin() + 1)->value().Size();
737 const char * itsNextName;
738 ReadStream itsReadStream;
739 std::vector<Iterator> itsIteratorStack;
740 CEREAL_RAPIDJSON_NAMESPACE::Document itsDocument;
750 template <
class T>
inline
755 template <
class T>
inline
762 template <
class T>
inline
768 template <
class T>
inline
775 template <
class T>
inline
780 template <
class T>
inline
787 template <
class T>
inline
793 template <
class T>
inline
801 template <
class T>
inline
808 template <
class T>
inline
815 template <
class T>
inline
820 template <
class T>
inline
830 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
831 !traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value,
832 !traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
839 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
840 !traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value,
841 !traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
852 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
853 !traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value,
854 !traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
861 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
862 !traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value,
863 !traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
895 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline
896 void prologue( JSONOutputArchive & ar, T
const & )
902 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline
903 void prologue( JSONInputArchive &, T
const & )
908 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline
909 void epilogue( JSONOutputArchive &, T
const & )
913 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline
914 void epilogue( JSONInputArchive &, T
const & )
919 template<
class CharT,
class Traits,
class Alloc>
inline
926 template<
class CharT,
class Traits,
class Alloc>
inline
932 template<
class CharT,
class Traits,
class Alloc>
inline
937 template<
class CharT,
class Traits,
class Alloc>
inline
945 template <
class T>
inline
952 template <
class T>
inline
955 ar.setNextName( t.name );
974 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline
981 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline
988 template<
class CharT,
class Traits,
class Alloc>
inline
995 template<
class CharT,
class Traits,
class Alloc>
inline
1003 template <
class T>
inline
1010 template <
class T>
inline
1024 #endif // CEREAL_ARCHIVES_JSON_HPP_