29#ifndef CEREAL_ARCHIVES_JSON_HPP_ 
   30#define CEREAL_ARCHIVES_JSON_HPP_ 
   44#ifndef RAPIDJSON_ASSERT_THROWS 
   45#define RAPIDJSON_ASSERT_THROWS 
   49#ifndef RAPIDJSON_ASSERT 
   50#define RAPIDJSON_ASSERT(x) if(!(x)){ \ 
   51  throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); }
 
   55#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS 
   56#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag 
   60#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS 
   61#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag | kParseNanAndInfFlag 
   64#include "rapidjson/prettywriter.h" 
   65#include "rapidjson/ostreamwrapper.h" 
   66#include "rapidjson/istreamwrapper.h" 
   67#include "rapidjson/document.h" 
   68#include "cereal/external/base64.hpp" 
  108    enum class NodeType { StartObject, InObject, StartArray, InArray };
 
  110    using WriteStream = RAPIDJSON_NAMESPACE::OStreamWrapper;
 
  111    using JSONWriter = 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<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 
  291      void saveValue( 
unsigned long lu ){ saveLong( lu ); };
 
  294      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 = RAPIDJSON_NAMESPACE::IStreamWrapper;
 
  423      typedef RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<>> JSONValue;
 
  424      typedef JSONValue::ConstMemberIterator MemberIterator;
 
  425      typedef JSONValue::ConstValueIterator ValueIterator;
 
  426      typedef 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(); 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      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 
Main cereal functionality.
 
A wrapper around data that should be serialized after all non-deferred data.
Definition: helpers.hpp:233
 
A class containing various advanced options for the JSON archive.
Definition: json.hpp:120
 
static Options NoIndent()
Default options with no indentation.
Definition: json.hpp:126
 
Options(int precision=JSONWriter::kDefaultMaxDecimalPlaces, IndentChar indentChar=IndentChar::space, unsigned int indentLength=4)
Specify specific options for the JSONOutputArchive.
Definition: json.hpp:142
 
static Options Default()
Default options.
Definition: json.hpp:123
 
IndentChar
The character to use for indenting.
Definition: json.hpp:130
 
An output archive designed to save data to JSON.
Definition: json.hpp:107
 
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 saveValue(bool b)
Saves a bool to the current node.
Definition: json.hpp:246
 
void finishNode()
Designates the most recently added node as finished.
Definition: json.hpp:212
 
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: json.hpp:240
 
void writeName()
Write the name of the upcoming node and prepare object/array state.
Definition: json.hpp:334
 
void makeArray()
Designates that the current node should be output as an array, not an object.
Definition: json.hpp:366
 
void saveValue(int64_t i64)
Saves an int64 to the current node.
Definition: json.hpp:252
 
void saveValue(T t)
Serialize a long if it would not be caught otherwise.
Definition: json.hpp:297
 
void saveValue(int i)
Saves an int to the current node.
Definition: json.hpp:248
 
~JSONOutputArchive() CEREAL_NOEXCEPT
Destructor, flushes the JSON.
Definition: json.hpp:173
 
void saveValue(std::nullptr_t)
Saves a nullptr to the current node.
Definition: json.hpp:262
 
JSONOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream.
Definition: json.hpp:160
 
void saveValue(double d)
Saves a double to the current node.
Definition: json.hpp:256
 
void saveValue(unsigned u)
Saves a uint to the current node.
Definition: json.hpp:250
 
void saveValue(T const &t)
Save exotic arithmetic as strings to current node.
Definition: json.hpp:314
 
void startNode()
Starts a new node in the JSON output.
Definition: json.hpp:204
 
void saveValue(char const *s)
Saves a const char * to the current node.
Definition: json.hpp:260
 
void saveValue(std::string const &s)
Saves a string to the current node.
Definition: json.hpp:258
 
void saveValue(uint64_t u64)
Saves a uint64 to the current node.
Definition: json.hpp:254
 
For holding name value pairs.
Definition: helpers.hpp:140
 
The base output archive class.
Definition: cereal.hpp:319
 
A wrapper around size metadata.
Definition: helpers.hpp:313
 
#define CEREAL_REGISTER_ARCHIVE(Archive)
Registers a specific Archive type with cereal.
Definition: cereal.hpp:195
 
CEREAL_SIZE_TYPE size_type
The size type used by cereal.
Definition: helpers.hpp:61
 
void epilogue(JSONOutputArchive &, NameValuePair< T > const &)
Epilogue for NVPs for JSON archives.
Definition: json.hpp:763
 
void prologue(JSONOutputArchive &, NameValuePair< T > const &)
Prologue for NVPs for JSON archives.
Definition: json.hpp:751
 
#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
 
An exception class thrown when things go wrong at runtime.
Definition: helpers.hpp:49
 
An exception thrown when rapidjson fails an internal assertion.
Definition: json.hpp:40
 
Type traits only struct used to mark an archive as human readable (text based)
Definition: traits.hpp:1321
 
#define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive)
Sets up traits that relate an input archive to an output archive.
Definition: traits.hpp:169
 
typename detail::EnableIfHelper< Conditions... >::type EnableIf
Provides a way to enable a function if conditions are met.
Definition: traits.hpp:116