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 );
190 saveValue( base64string );
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 ) ); }
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, std::int32_t>::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, std::uint32_t>::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 );
318 saveValue( ss.str() );
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";
360 saveValue(itsNextName);
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());
460 loadValue( encoded );
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), itsType(Member)
488 if( std::distance( begin, end ) == 0 )
492 Iterator(ValueIterator begin, ValueIterator end) :
493 itsValueItBegin(begin), itsIndex(0), itsType(Value)
495 if( std::distance( begin, end ) == 0 )
500 Iterator & operator++()
507 GenericValue
const & value()
511 case Value :
return itsValueItBegin[itsIndex];
512 case Member:
return itsMemberItBegin[itsIndex].value;
513 default:
throw cereal::Exception(
"JSONInputArchive internal error: null or empty iterator to object or array!");
518 const char * name()
const 520 if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
521 return itsMemberItBegin[itsIndex].name.GetString();
528 inline void search(
const char * searchName )
530 const auto len = std::strlen( searchName );
532 for(
auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
534 const auto currentName = it->name.GetString();
535 if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
536 ( std::strlen( currentName ) == len ) )
543 throw Exception(
"JSON Parsing failed - provided NVP (" + std::string(searchName) +
") not found");
547 MemberIterator itsMemberItBegin, itsMemberItEnd;
548 ValueIterator itsValueItBegin;
550 enum Type {Value, Member, Null_} itsType;
568 auto const actualName = itsIteratorStack.back().name();
571 if( !actualName || std::strcmp( itsNextName, actualName ) != 0 )
572 itsIteratorStack.back().search( itsNextName );
575 itsNextName =
nullptr;
593 if(itsIteratorStack.back().value().IsArray())
594 itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
596 itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
602 itsIteratorStack.pop_back();
603 ++itsIteratorStack.back();
610 return itsIteratorStack.back().name();
620 template <class T, traits::EnableIf<std::is_signed<T>::value,
621 sizeof(T) <
sizeof(int64_t)> = traits::sfinae>
inline 622 void loadValue(T & val)
626 val =
static_cast<T
>( itsIteratorStack.back().value().GetInt() );
627 ++itsIteratorStack.back();
631 template <class T, traits::EnableIf<std::is_unsigned<T>::value,
632 sizeof(T) <
sizeof(uint64_t),
633 !std::is_same<bool, T>::value> = traits::sfinae>
inline 634 void loadValue(T & val)
638 val =
static_cast<T
>( itsIteratorStack.back().value().GetUint() );
639 ++itsIteratorStack.back();
643 void loadValue(
bool & val) { search(); val = itsIteratorStack.back().value().GetBool(); ++itsIteratorStack.back(); }
645 void loadValue(int64_t & val) { search(); val = itsIteratorStack.back().value().GetInt64(); ++itsIteratorStack.back(); }
647 void loadValue(uint64_t & val) { search(); val = itsIteratorStack.back().value().GetUint64(); ++itsIteratorStack.back(); }
649 void loadValue(
float & val) { search(); val =
static_cast<float>(itsIteratorStack.back().value().GetDouble()); ++itsIteratorStack.back(); }
651 void loadValue(
double & val) { search(); val = itsIteratorStack.back().value().GetDouble(); ++itsIteratorStack.back(); }
653 void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
655 void loadValue(std::nullptr_t&) { search(); CEREAL_RAPIDJSON_ASSERT(itsIteratorStack.back().value().IsNull()); ++itsIteratorStack.back(); }
662 template <
class T>
inline 663 typename std::enable_if<sizeof(T) == sizeof(std::int32_t) && std::is_signed<T>::value,
void>::type
664 loadLong(T & l){ loadValue( reinterpret_cast<std::int32_t&>( l ) ); }
667 template <
class T>
inline 668 typename std::enable_if<sizeof(T) == sizeof(std::int64_t) && std::is_signed<T>::value,
void>::type
669 loadLong(T & l){ loadValue( reinterpret_cast<std::int64_t&>( l ) ); }
672 template <
class T>
inline 673 typename std::enable_if<sizeof(T) == sizeof(std::uint32_t) && !std::is_signed<T>::value,
void>::type
674 loadLong(T & lu){ loadValue( reinterpret_cast<std::uint32_t&>( lu ) ); }
677 template <
class T>
inline 678 typename std::enable_if<sizeof(T) == sizeof(std::uint64_t) && !std::is_signed<T>::value,
void>::type
679 loadLong(T & lu){ loadValue( reinterpret_cast<std::uint64_t&>( lu ) ); }
683 template <
class T>
inline 684 typename std::enable_if<std::is_same<T, long>::value &&
685 sizeof(T) >=
sizeof(std::int64_t) &&
686 !std::is_same<T, std::int64_t>::value,
void>::type
687 loadValue( T & t ){ loadLong(t); }
690 template <
class T>
inline 691 typename std::enable_if<std::is_same<T, unsigned long>::value &&
692 sizeof(T) >=
sizeof(std::uint64_t) &&
693 !std::is_same<T, std::uint64_t>::value,
void>::type
699 void stringToNumber( std::string
const & str,
long long & val ) { val = std::stoll( str ); }
701 void stringToNumber( std::string
const & str,
unsigned long long & val ) { val = std::stoull( str ); }
703 void stringToNumber( std::string
const & str,
long double & val ) { val = std::stold( str ); }
707 template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
708 !std::is_same<T, long>::value,
709 !std::is_same<T, unsigned long>::value,
710 !std::is_same<T, std::int64_t>::value,
711 !std::is_same<T, std::uint64_t>::value,
712 (
sizeof(T) >=
sizeof(
long double) ||
sizeof(T) >=
sizeof(
long long))> = traits::sfinae>
716 loadValue( encoded );
717 stringToNumber( encoded, val );
723 if (itsIteratorStack.size() == 1)
724 size = itsDocument.Size();
726 size = (itsIteratorStack.rbegin() + 1)->value().Size();
732 const char * itsNextName;
733 ReadStream itsReadStream;
734 std::vector<Iterator> itsIteratorStack;
735 CEREAL_RAPIDJSON_NAMESPACE::Document itsDocument;
745 template <
class T>
inline 750 template <
class T>
inline 757 template <
class T>
inline 763 template <
class T>
inline 770 template <
class T>
inline 775 template <
class T>
inline 782 template <
class T>
inline 788 template <
class T>
inline 796 template <
class T>
inline 803 template <
class T>
inline 810 template <
class T>
inline 815 template <
class T>
inline 825 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
834 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
847 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
856 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
890 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 897 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 903 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 908 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 914 template<
class CharT,
class Traits,
class Alloc>
inline 921 template<
class CharT,
class Traits,
class Alloc>
inline 927 template<
class CharT,
class Traits,
class Alloc>
inline 932 template<
class CharT,
class Traits,
class Alloc>
inline 940 template <
class T>
inline 947 template <
class T>
inline 969 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 976 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 983 template<
class CharT,
class Traits,
class Alloc>
inline 990 template<
class CharT,
class Traits,
class Alloc>
inline 998 template <
class T>
inline 1005 template <
class T>
inline 1019 #endif // CEREAL_ARCHIVES_JSON_HPP_ void saveValue(T t)
Serialize a long if it would not be caught otherwise.
Definition: json.hpp:297
static Options Default()
Default options.
Definition: json.hpp:123
void saveValue(int64_t i64)
Saves an int64 to the current node.
Definition: json.hpp:252
An exception thrown when rapidjson fails an internal assertion.
Definition: json.hpp:39
void startNode()
Starts a new node in the JSON output.
Definition: json.hpp:204
void saveValue(std::string const &s)
Saves a string to the current node.
Definition: json.hpp:258
#define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive)
Sets up traits that relate an input archive to an output archive.
Definition: traits.hpp:169
void saveValue(uint64_t u64)
Saves a uint64 to the current node.
Definition: json.hpp:254
void saveValue(int i)
Saves an int to the current node.
Definition: json.hpp:248
A wrapper around size metadata.
Definition: helpers.hpp:312
void finishNode()
Designates the most recently added node as finished.
Definition: json.hpp:212
A class containing various advanced options for the JSON archive.
Definition: json.hpp:119
void prologue(JSONOutputArchive &, NameValuePair< T > const &)
Prologue for NVPs for JSON archives.
Definition: json.hpp:746
typename detail::EnableIfHelper< Conditions... >::type EnableIf
Provides a way to enable a function if conditions are met.
Definition: traits.hpp:116
void writeName()
Write the name of the upcoming node and prepare object/array state.
Definition: json.hpp:334
Checks to see if the base class used in a cast has a minimal serialization.
Definition: traits.hpp:1195
void saveValue(std::nullptr_t)
Saves a nullptr to the current node.
Definition: json.hpp:262
void saveValue(char const *s)
Saves a const char * to the current node.
Definition: json.hpp:260
Options(int precision=JSONWriter::kDefaultMaxDecimalPlaces, IndentChar indentChar=IndentChar::space, unsigned int indentLength=4)
Specify specific options for the JSONOutputArchive.
Definition: json.hpp:142
Type traits only struct used to mark an archive as human readable (text based)
Definition: traits.hpp:1321
static Options NoIndent()
Default options with no indentation.
Definition: json.hpp:126
An output archive designed to save data to JSON.
Definition: json.hpp:106
void saveValue(double d)
Saves a double to the current node.
Definition: json.hpp:256
Definition: traits.hpp:1066
Definition: access.hpp:41
#define CEREAL_REGISTER_ARCHIVE(Archive)
Registers a specific Archive type with cereal.
Definition: cereal.hpp:195
void makeArray()
Designates that the current node should be output as an array, not an object.
Definition: json.hpp:366
void saveValue(T const &t)
Save exotic arithmetic as strings to current node.
Definition: json.hpp:314
Main cereal functionality.
~JSONOutputArchive() CEREAL_NOEXCEPT
Destructor, flushes the JSON.
Definition: json.hpp:173
For holding name value pairs.
Definition: helpers.hpp:139
#define CEREAL_LOAD_FUNCTION_NAME
The deserialization (load) function name to search for.
Definition: macros.hpp:85
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: json.hpp:240
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
A wrapper around data that should be serialized after all non-deferred data.
Definition: helpers.hpp:232
void saveValue(unsigned u)
Saves a uint to the current node.
Definition: json.hpp:250
The base output archive class.
Definition: cereal.hpp:296
CEREAL_SIZE_TYPE size_type
The size type used by cereal.
Definition: helpers.hpp:61
void saveValue(bool b)
Saves a bool to the current node.
Definition: json.hpp:246
IndentChar
The character to use for indenting.
Definition: json.hpp:129
#define CEREAL_SAVE_FUNCTION_NAME
The serialization (save) function name to search for.
Definition: macros.hpp:92
void saveBinaryValue(const void *data, size_t size, const char *name=nullptr)
Saves some binary data, encoded as a base64 string, with an optional name.
Definition: json.hpp:184
void epilogue(JSONOutputArchive &, NameValuePair< T > const &)
Epilogue for NVPs for JSON archives.
Definition: json.hpp:758
JSONOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream.
Definition: json.hpp:160
An exception class thrown when things go wrong at runtime.
Definition: helpers.hpp:48