cereal
A C++11 library for serialization
json.hpp
Go to the documentation of this file.
1 
3 /*
4  Copyright (c) 2014, Randolph Voorhies, Shane Grant
5  All rights reserved.
6 
7  Redistribution and use in source and binary forms, with or without
8  modification, are permitted provided that the following conditions are met:
9  * Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11  * Redistributions in binary form must reproduce the above copyright
12  notice, this list of conditions and the following disclaimer in the
13  documentation and/or other materials provided with the distribution.
14  * Neither the name of cereal nor the
15  names of its contributors may be used to endorse or promote products
16  derived from this software without specific prior written permission.
17 
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
22  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #ifndef CEREAL_ARCHIVES_JSON_HPP_
30 #define CEREAL_ARCHIVES_JSON_HPP_
31 
32 #include "cereal/cereal.hpp"
33 #include "cereal/details/util.hpp"
34 
35 namespace cereal
36 {
38 
40  { RapidJSONException( const char * what_ ) : Exception( what_ ) {} };
41 }
42 
43 // Inform rapidjson that assert will throw
44 #ifndef RAPIDJSON_ASSERT_THROWS
45 #define RAPIDJSON_ASSERT_THROWS
46 #endif // RAPIDJSON_ASSERT_THROWS
47 
48 // Override rapidjson assertions to throw exceptions by default
49 #ifndef RAPIDJSON_ASSERT
50 #define RAPIDJSON_ASSERT(x) if(!(x)){ \
51  throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); }
52 #endif // RAPIDJSON_ASSERT
53 
54 // Enable support for parsing of nan, inf, -inf
55 #ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
56 #define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag
57 #endif
58 
59 // Enable support for parsing of nan, inf, -inf
60 #ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS
61 #define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag | kParseNanAndInfFlag
62 #endif
63 
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"
69 
70 #include <limits>
71 #include <sstream>
72 #include <stack>
73 #include <vector>
74 #include <string>
75 
76 namespace cereal
77 {
78  // ######################################################################
80 
106  class JSONOutputArchive : public OutputArchive<JSONOutputArchive>, public traits::TextArchive
107  {
108  enum class NodeType { StartObject, InObject, StartArray, InArray };
109 
110  using WriteStream = RAPIDJSON_NAMESPACE::OStreamWrapper;
111  using JSONWriter = RAPIDJSON_NAMESPACE::PrettyWriter<WriteStream>;
112 
113  public:
117 
119  class Options
120  {
121  public:
123  static Options Default(){ return Options(); }
124 
126  static Options NoIndent(){ return Options( JSONWriter::kDefaultMaxDecimalPlaces, IndentChar::space, 0 ); }
127 
129  enum class IndentChar : char
130  {
131  space = ' ',
132  tab = '\t',
133  newline = '\n',
134  carriage_return = '\r'
135  };
136 
138 
142  explicit Options( int precision = JSONWriter::kDefaultMaxDecimalPlaces,
143  IndentChar indentChar = IndentChar::space,
144  unsigned int indentLength = 4 ) :
145  itsPrecision( precision ),
146  itsIndentChar( static_cast<char>(indentChar) ),
147  itsIndentLength( indentLength ) { }
148 
149  private:
150  friend class JSONOutputArchive;
151  int itsPrecision;
152  char itsIndentChar;
153  unsigned int itsIndentLength;
154  };
155 
157 
160  JSONOutputArchive(std::ostream & stream, Options const & options = Options::Default() ) :
162  itsWriteStream(stream),
163  itsWriter(itsWriteStream),
164  itsNextName(nullptr)
165  {
166  itsWriter.SetMaxDecimalPlaces( options.itsPrecision );
167  itsWriter.SetIndent( options.itsIndentChar, options.itsIndentLength );
168  itsNameCounter.push(0);
169  itsNodeStack.push(NodeType::StartObject);
170  }
171 
174  {
175  if (itsNodeStack.top() == NodeType::InObject)
176  itsWriter.EndObject();
177  else if (itsNodeStack.top() == NodeType::InArray)
178  itsWriter.EndArray();
179  }
180 
182 
184  void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
185  {
186  setNextName( name );
187  writeName();
188 
189  auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
190  saveValue( base64string );
191  };
192 
194 
198 
200 
204  void startNode()
205  {
206  writeName();
207  itsNodeStack.push(NodeType::StartObject);
208  itsNameCounter.push(0);
209  }
210 
212  void finishNode()
213  {
214  // if we ended up serializing an empty object or array, writeName
215  // will never have been called - so start and then immediately end
216  // the object/array.
217  //
218  // We'll also end any object/arrays we happen to be in
219  switch(itsNodeStack.top())
220  {
221  case NodeType::StartArray:
222  itsWriter.StartArray();
223  // fall through
224  case NodeType::InArray:
225  itsWriter.EndArray();
226  break;
227  case NodeType::StartObject:
228  itsWriter.StartObject();
229  // fall through
230  case NodeType::InObject:
231  itsWriter.EndObject();
232  break;
233  }
234 
235  itsNodeStack.pop();
236  itsNameCounter.pop();
237  }
238 
240  void setNextName( const char * name )
241  {
242  itsNextName = name;
243  }
244 
246  void saveValue(bool b) { itsWriter.Bool(b); }
248  void saveValue(int i) { itsWriter.Int(i); }
250  void saveValue(unsigned u) { itsWriter.Uint(u); }
252  void saveValue(int64_t i64) { itsWriter.Int64(i64); }
254  void saveValue(uint64_t u64) { itsWriter.Uint64(u64); }
256  void saveValue(double d) { itsWriter.Double(d); }
258  void saveValue(std::string const & s) { itsWriter.String(s.c_str(), static_cast<RAPIDJSON_NAMESPACE::SizeType>( s.size() )); }
260  void saveValue(char const * s) { itsWriter.String(s); }
262  void saveValue(std::nullptr_t) { itsWriter.Null(); }
263 
264  private:
265  // Some compilers/OS have difficulty disambiguating the above for various flavors of longs, so we provide
266  // special overloads to handle these cases.
267 
269  template <class T, traits::EnableIf<sizeof(T) == sizeof(std::int32_t),
270  std::is_signed<T>::value> = traits::sfinae> inline
271  void saveLong(T l){ saveValue( static_cast<std::int32_t>( l ) ); }
272 
274  template <class T, traits::EnableIf<sizeof(T) != sizeof(std::int32_t),
275  std::is_signed<T>::value> = traits::sfinae> inline
276  void saveLong(T l){ saveValue( static_cast<std::int64_t>( l ) ); }
277 
279  template <class T, traits::EnableIf<sizeof(T) == sizeof(std::int32_t),
280  std::is_unsigned<T>::value> = traits::sfinae> inline
281  void saveLong(T lu){ saveValue( static_cast<std::uint32_t>( lu ) ); }
282 
284  template <class T, traits::EnableIf<sizeof(T) != sizeof(std::int32_t),
285  std::is_unsigned<T>::value> = traits::sfinae> inline
286  void saveLong(T lu){ saveValue( static_cast<std::uint64_t>( lu ) ); }
287 
288  public:
289 #ifdef _MSC_VER
291  void saveValue( unsigned long lu ){ saveLong( lu ); };
292 #else // _MSC_VER
294  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
297  void saveValue( T t ){ saveLong( t ); }
298 
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
303  void saveValue( T t ){ saveLong( t ); }
304 #endif // _MSC_VER
305 
307 
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
314  void saveValue(T const & t)
315  {
316  std::stringstream ss; ss.precision( std::numeric_limits<long double>::max_digits10 );
317  ss << t;
318  saveValue( ss.str() );
319  }
320 
322 
334  void writeName()
335  {
336  NodeType const & nodeType = itsNodeStack.top();
337 
338  // Start up either an object or an array, depending on state
339  if(nodeType == NodeType::StartArray)
340  {
341  itsWriter.StartArray();
342  itsNodeStack.top() = NodeType::InArray;
343  }
344  else if(nodeType == NodeType::StartObject)
345  {
346  itsNodeStack.top() = NodeType::InObject;
347  itsWriter.StartObject();
348  }
349 
350  // Array types do not output names
351  if(nodeType == NodeType::InArray) return;
352 
353  if(itsNextName == nullptr)
354  {
355  std::string name = "value" + std::to_string( itsNameCounter.top()++ ) + "\0";
356  saveValue(name);
357  }
358  else
359  {
360  saveValue(itsNextName);
361  itsNextName = nullptr;
362  }
363  }
364 
366  void makeArray()
367  {
368  itsNodeStack.top() = NodeType::StartArray;
369  }
370 
372 
373  private:
374  WriteStream itsWriteStream;
375  JSONWriter itsWriter;
376  char const * itsNextName;
377  std::stack<uint32_t> itsNameCounter;
378  std::stack<NodeType> itsNodeStack;
379  }; // JSONOutputArchive
380 
381  // ######################################################################
383 
419  class JSONInputArchive : public InputArchive<JSONInputArchive>, public traits::TextArchive
420  {
421  private:
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;
427 
428  public:
432 
434 
435  JSONInputArchive(std::istream & stream) :
437  itsNextName( nullptr ),
438  itsReadStream(stream)
439  {
440  itsDocument.ParseStream<>(itsReadStream);
441  if (itsDocument.IsArray())
442  itsIteratorStack.emplace_back(itsDocument.Begin(), itsDocument.End());
443  else
444  itsIteratorStack.emplace_back(itsDocument.MemberBegin(), itsDocument.MemberEnd());
445  }
446 
447  ~JSONInputArchive() CEREAL_NOEXCEPT = default;
448 
450 
455  void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
456  {
457  itsNextName = name;
458 
459  std::string encoded;
460  loadValue( encoded );
461  auto decoded = base64::decode( encoded );
462 
463  if( size != decoded.size() )
464  throw Exception("Decoded binary data size does not match specified size");
465 
466  std::memcpy( data, decoded.data(), decoded.size() );
467  itsNextName = nullptr;
468  };
469 
470  private:
472 
476 
478 
480  class Iterator
481  {
482  public:
483  Iterator() : itsIndex( 0 ), itsType(Null_) {}
484 
485  Iterator(MemberIterator begin, MemberIterator end) :
486  itsMemberItBegin(begin), itsMemberItEnd(end), itsIndex(0), itsType(Member)
487  {
488  if( std::distance( begin, end ) == 0 )
489  itsType = Null_;
490  }
491 
492  Iterator(ValueIterator begin, ValueIterator end) :
493  itsValueItBegin(begin), itsIndex(0), itsType(Value)
494  {
495  if( std::distance( begin, end ) == 0 )
496  itsType = Null_;
497  }
498 
500  Iterator & operator++()
501  {
502  ++itsIndex;
503  return *this;
504  }
505 
507  GenericValue const & value()
508  {
509  switch(itsType)
510  {
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!");
514  }
515  }
516 
518  const char * name() const
519  {
520  if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
521  return itsMemberItBegin[itsIndex].name.GetString();
522  else
523  return nullptr;
524  }
525 
527 
528  inline void search( const char * searchName )
529  {
530  const auto len = std::strlen( searchName );
531  size_t index = 0;
532  for( auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
533  {
534  const auto currentName = it->name.GetString();
535  if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
536  ( std::strlen( currentName ) == len ) )
537  {
538  itsIndex = index;
539  return;
540  }
541  }
542 
543  throw Exception("JSON Parsing failed - provided NVP (" + std::string(searchName) + ") not found");
544  }
545 
546  private:
547  MemberIterator itsMemberItBegin, itsMemberItEnd;
548  ValueIterator itsValueItBegin;
549  size_t itsIndex;
550  enum Type {Value, Member, Null_} itsType;
551  };
552 
554 
562  inline void search()
563  {
564  // The name an NVP provided with setNextName()
565  if( itsNextName )
566  {
567  // The actual name of the current node
568  auto const actualName = itsIteratorStack.back().name();
569 
570  // Do a search if we don't see a name coming up, or if the names don't match
571  if( !actualName || std::strcmp( itsNextName, actualName ) != 0 )
572  itsIteratorStack.back().search( itsNextName );
573  }
574 
575  itsNextName = nullptr;
576  }
577 
578  public:
580 
589  void startNode()
590  {
591  search();
592 
593  if(itsIteratorStack.back().value().IsArray())
594  itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
595  else
596  itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
597  }
598 
600  void finishNode()
601  {
602  itsIteratorStack.pop_back();
603  ++itsIteratorStack.back();
604  }
605 
607 
608  const char * getNodeName() const
609  {
610  return itsIteratorStack.back().name();
611  }
612 
614  void setNextName( const char * name )
615  {
616  itsNextName = name;
617  }
618 
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)
623  {
624  search();
625 
626  val = static_cast<T>( itsIteratorStack.back().value().GetInt() );
627  ++itsIteratorStack.back();
628  }
629 
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)
635  {
636  search();
637 
638  val = static_cast<T>( itsIteratorStack.back().value().GetUint() );
639  ++itsIteratorStack.back();
640  }
641 
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(); RAPIDJSON_ASSERT(itsIteratorStack.back().value().IsNull()); ++itsIteratorStack.back(); }
656 
657  // Special cases to handle various flavors of long, which tend to conflict with
658  // the int32_t or int64_t on various compiler/OS combinations. MSVC doesn't need any of this.
659  #ifndef _MSC_VER
660  private:
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 ) ); }
665 
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 ) ); }
670 
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 ) ); }
675 
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 ) ); }
680 
681  public:
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); }
688 
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
694  loadValue( T & t ){ loadLong(t); }
695  #endif // _MSC_VER
696 
697  private:
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 ); }
704 
705  public:
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>
713  inline void loadValue(T & val)
714  {
715  std::string encoded;
716  loadValue( encoded );
717  stringToNumber( encoded, val );
718  }
719 
721  void loadSize(size_type & size)
722  {
723  if (itsIteratorStack.size() == 1)
724  size = itsDocument.Size();
725  else
726  size = (itsIteratorStack.rbegin() + 1)->value().Size();
727  }
728 
730 
731  private:
732  const char * itsNextName;
733  ReadStream itsReadStream;
734  std::vector<Iterator> itsIteratorStack;
735  RAPIDJSON_NAMESPACE::Document itsDocument;
736  };
737 
738  // ######################################################################
739  // JSONArchive prologue and epilogue functions
740  // ######################################################################
741 
742  // ######################################################################
744 
745  template <class T> inline
747  { }
748 
750  template <class T> inline
752  { }
753 
754  // ######################################################################
756 
757  template <class T> inline
759  { }
760 
762 
763  template <class T> inline
765  { }
766 
767  // ######################################################################
769 
770  template <class T> inline
772  { }
773 
775  template <class T> inline
777  { }
778 
779  // ######################################################################
781 
782  template <class T> inline
784  { }
785 
787 
788  template <class T> inline
790  { }
791 
792  // ######################################################################
794 
796  template <class T> inline
797  void prologue( JSONOutputArchive & ar, SizeTag<T> const & )
798  {
799  ar.makeArray();
800  }
801 
803  template <class T> inline
805  { }
806 
807  // ######################################################################
809 
810  template <class T> inline
812  { }
813 
815  template <class T> inline
817  { }
818 
819  // ######################################################################
821 
825  template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
826  !traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value,
827  !traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
828  inline void prologue( JSONOutputArchive & ar, T const & )
829  {
830  ar.startNode();
831  }
832 
834  template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
835  !traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value,
836  !traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
837  inline void prologue( JSONInputArchive & ar, T const & )
838  {
839  ar.startNode();
840  }
841 
842  // ######################################################################
844 
847  template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
848  !traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value,
849  !traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
850  inline void epilogue( JSONOutputArchive & ar, T const & )
851  {
852  ar.finishNode();
853  }
854 
856  template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
857  !traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value,
858  !traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
859  inline void epilogue( JSONInputArchive & ar, T const & )
860  {
861  ar.finishNode();
862  }
863 
864  // ######################################################################
866  inline
867  void prologue( JSONOutputArchive & ar, std::nullptr_t const & )
868  {
869  ar.writeName();
870  }
871 
873  inline
874  void prologue( JSONInputArchive &, std::nullptr_t const & )
875  { }
876 
877  // ######################################################################
879  inline
880  void epilogue( JSONOutputArchive &, std::nullptr_t const & )
881  { }
882 
884  inline
885  void epilogue( JSONInputArchive &, std::nullptr_t const & )
886  { }
887 
888  // ######################################################################
890  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
891  void prologue( JSONOutputArchive & ar, T const & )
892  {
893  ar.writeName();
894  }
895 
897  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
898  void prologue( JSONInputArchive &, T const & )
899  { }
900 
901  // ######################################################################
903  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
904  void epilogue( JSONOutputArchive &, T const & )
905  { }
906 
908  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
909  void epilogue( JSONInputArchive &, T const & )
910  { }
911 
912  // ######################################################################
914  template<class CharT, class Traits, class Alloc> inline
915  void prologue(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const &)
916  {
917  ar.writeName();
918  }
919 
921  template<class CharT, class Traits, class Alloc> inline
922  void prologue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
923  { }
924 
925  // ######################################################################
927  template<class CharT, class Traits, class Alloc> inline
928  void epilogue(JSONOutputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
929  { }
930 
932  template<class CharT, class Traits, class Alloc> inline
933  void epilogue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
934  { }
935 
936  // ######################################################################
937  // Common JSONArchive serialization functions
938  // ######################################################################
940  template <class T> inline
942  {
943  ar.setNextName( t.name );
944  ar( t.value );
945  }
946 
947  template <class T> inline
948  void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, NameValuePair<T> & t )
949  {
950  ar.setNextName( t.name );
951  ar( t.value );
952  }
953 
955  inline
956  void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::nullptr_t const & t)
957  {
958  ar.saveValue( t );
959  }
960 
962  inline
963  void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::nullptr_t & t)
964  {
965  ar.loadValue( t );
966  }
967 
969  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
971  {
972  ar.saveValue( t );
973  }
974 
976  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
978  {
979  ar.loadValue( t );
980  }
981 
983  template<class CharT, class Traits, class Alloc> inline
984  void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
985  {
986  ar.saveValue( str );
987  }
988 
990  template<class CharT, class Traits, class Alloc> inline
991  void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
992  {
993  ar.loadValue( str );
994  }
995 
996  // ######################################################################
998  template <class T> inline
1000  {
1001  // nothing to do here, we don't explicitly save the size
1002  }
1003 
1005  template <class T> inline
1007  {
1008  ar.loadSize( st.size );
1009  }
1010 } // namespace cereal
1011 
1012 // register archives for polymorphic support
1015 
1016 // tie input and output archives together
1018 
1019 #endif // CEREAL_ARCHIVES_JSON_HPP_
Main cereal functionality.
A wrapper around data that should be serialized after all non-deferred data.
Definition: helpers.hpp:233
The base input archive class.
Definition: cereal.hpp:680
An input archive designed to load data from JSON.
Definition: json.hpp:420
JSONInputArchive(std::istream &stream)
Construct, reading from the provided stream.
Definition: json.hpp:435
::type loadValue(T &t)
Loads a value from the current node - small signed overload.
Definition: json.hpp:694
void loadBinaryValue(void *data, size_t size, const char *name=nullptr)
Loads some binary data, encoded as a base64 string.
Definition: json.hpp:455
void loadSize(size_type &size)
Loads the size for a SizeTag.
Definition: json.hpp:721
const char * getNodeName() const
Retrieves the current node name.
Definition: json.hpp:608
void startNode()
Starts a new node, going into its proper iterator.
Definition: json.hpp:589
void loadValue(T &val)
Loads a value from the current node - long double and long long overloads.
Definition: json.hpp:713
void finishNode()
Finishes the most recently started node.
Definition: json.hpp:600
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: json.hpp:614
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:297
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:758
void prologue(JSONOutputArchive &, NameValuePair< T > const &)
Prologue for NVPs for JSON archives.
Definition: json.hpp:746
#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
Internal misc utilities.