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 // Override rapidjson assertions to throw exceptions by default
44 #ifndef CEREAL_RAPIDJSON_ASSERT
45 #define CEREAL_RAPIDJSON_ASSERT(x) if(!(x)){ \
46  throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); }
47 #endif // RAPIDJSON_ASSERT
48 
49 // Enable support for parsing of nan, inf, -inf
50 #define CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag
51 #define CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag | kParseNanAndInfFlag
52 
53 #include "cereal/external/rapidjson/prettywriter.h"
54 #include "cereal/external/rapidjson/ostreamwrapper.h"
55 #include "cereal/external/rapidjson/istreamwrapper.h"
56 #include "cereal/external/rapidjson/document.h"
57 #include "cereal/external/base64.hpp"
58 
59 #include <limits>
60 #include <sstream>
61 #include <stack>
62 #include <vector>
63 #include <string>
64 
65 namespace cereal
66 {
67  // ######################################################################
69 
95  class JSONOutputArchive : public OutputArchive<JSONOutputArchive>, public traits::TextArchive
96  {
97  enum class NodeType { StartObject, InObject, StartArray, InArray };
98 
99  using WriteStream = CEREAL_RAPIDJSON_NAMESPACE::OStreamWrapper;
100  using JSONWriter = CEREAL_RAPIDJSON_NAMESPACE::PrettyWriter<WriteStream>;
101 
102  public:
105 
108  class Options
109  {
110  public:
112  static Options Default(){ return Options(); }
113 
115  static Options NoIndent(){ return Options( JSONWriter::kDefaultMaxDecimalPlaces, IndentChar::space, 0 ); }
116 
118  enum class IndentChar : char
119  {
120  space = ' ',
121  tab = '\t',
122  newline = '\n',
123  carriage_return = '\r'
124  };
125 
127 
131  explicit Options( int precision = JSONWriter::kDefaultMaxDecimalPlaces,
132  IndentChar indentChar = IndentChar::space,
133  unsigned int indentLength = 4 ) :
134  itsPrecision( precision ),
135  itsIndentChar( static_cast<char>(indentChar) ),
136  itsIndentLength( indentLength ) { }
137 
138  private:
139  friend class JSONOutputArchive;
140  int itsPrecision;
141  char itsIndentChar;
142  unsigned int itsIndentLength;
143  };
144 
146 
149  JSONOutputArchive(std::ostream & stream, Options const & options = Options::Default() ) :
151  itsWriteStream(stream),
152  itsWriter(itsWriteStream),
153  itsNextName(nullptr)
154  {
155  itsWriter.SetMaxDecimalPlaces( options.itsPrecision );
156  itsWriter.SetIndent( options.itsIndentChar, options.itsIndentLength );
157  itsNameCounter.push(0);
158  itsNodeStack.push(NodeType::StartObject);
159  }
160 
163  {
164  if (itsNodeStack.top() == NodeType::InObject)
165  itsWriter.EndObject();
166  else if (itsNodeStack.top() == NodeType::InArray)
167  itsWriter.EndArray();
168  }
169 
171 
173  void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
174  {
175  setNextName( name );
176  writeName();
177 
178  auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
179  saveValue( base64string );
180  };
181 
183 
186 
189 
193  void startNode()
194  {
195  writeName();
196  itsNodeStack.push(NodeType::StartObject);
197  itsNameCounter.push(0);
198  }
199 
201  void finishNode()
202  {
203  // if we ended up serializing an empty object or array, writeName
204  // will never have been called - so start and then immediately end
205  // the object/array.
206  //
207  // We'll also end any object/arrays we happen to be in
208  switch(itsNodeStack.top())
209  {
210  case NodeType::StartArray:
211  itsWriter.StartArray();
212  case NodeType::InArray:
213  itsWriter.EndArray();
214  break;
215  case NodeType::StartObject:
216  itsWriter.StartObject();
217  case NodeType::InObject:
218  itsWriter.EndObject();
219  break;
220  }
221 
222  itsNodeStack.pop();
223  itsNameCounter.pop();
224  }
225 
227  void setNextName( const char * name )
228  {
229  itsNextName = name;
230  }
231 
233  void saveValue(bool b) { itsWriter.Bool(b); }
235  void saveValue(int i) { itsWriter.Int(i); }
237  void saveValue(unsigned u) { itsWriter.Uint(u); }
239  void saveValue(int64_t i64) { itsWriter.Int64(i64); }
241  void saveValue(uint64_t u64) { itsWriter.Uint64(u64); }
243  void saveValue(double d) { itsWriter.Double(d); }
245  void saveValue(std::string const & s) { itsWriter.String(s.c_str(), static_cast<CEREAL_RAPIDJSON_NAMESPACE::SizeType>( s.size() )); }
247  void saveValue(char const * s) { itsWriter.String(s); }
249  void saveValue(std::nullptr_t) { itsWriter.Null(); }
250 
251  private:
252  // Some compilers/OS have difficulty disambiguating the above for various flavors of longs, so we provide
253  // special overloads to handle these cases.
254 
256  template <class T, traits::EnableIf<sizeof(T) == sizeof(std::int32_t),
257  std::is_signed<T>::value> = traits::sfinae> inline
258  void saveLong(T l){ saveValue( static_cast<std::int32_t>( l ) ); }
259 
261  template <class T, traits::EnableIf<sizeof(T) != sizeof(std::int32_t),
262  std::is_signed<T>::value> = traits::sfinae> inline
263  void saveLong(T l){ saveValue( static_cast<std::int64_t>( l ) ); }
264 
266  template <class T, traits::EnableIf<sizeof(T) == sizeof(std::int32_t),
267  std::is_unsigned<T>::value> = traits::sfinae> inline
268  void saveLong(T lu){ saveValue( static_cast<std::uint32_t>( lu ) ); }
269 
271  template <class T, traits::EnableIf<sizeof(T) != sizeof(std::int32_t),
272  std::is_unsigned<T>::value> = traits::sfinae> inline
273  void saveLong(T lu){ saveValue( static_cast<std::uint64_t>( lu ) ); }
274 
275  public:
276 #ifdef _MSC_VER
277  void saveValue( unsigned long lu ){ saveLong( lu ); };
279 #else // _MSC_VER
280  template <class T, traits::EnableIf<std::is_same<T, long>::value,
282  !std::is_same<T, std::int32_t>::value,
283  !std::is_same<T, std::int64_t>::value> = traits::sfinae> inline
284  void saveValue( T t ){ saveLong( t ); }
285 
287  template <class T, traits::EnableIf<std::is_same<T, unsigned long>::value,
288  !std::is_same<T, std::uint32_t>::value,
289  !std::is_same<T, std::uint64_t>::value> = traits::sfinae> inline
290  void saveValue( T t ){ saveLong( t ); }
291 #endif // _MSC_VER
292 
294 
295  template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
296  !std::is_same<T, long>::value,
297  !std::is_same<T, unsigned long>::value,
298  !std::is_same<T, std::int64_t>::value,
299  !std::is_same<T, std::uint64_t>::value,
300  (sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long))> = traits::sfinae> inline
301  void saveValue(T const & t)
302  {
303  std::stringstream ss; ss.precision( std::numeric_limits<long double>::max_digits10 );
304  ss << t;
305  saveValue( ss.str() );
306  }
307 
309 
321  void writeName()
322  {
323  NodeType const & nodeType = itsNodeStack.top();
324 
325  // Start up either an object or an array, depending on state
326  if(nodeType == NodeType::StartArray)
327  {
328  itsWriter.StartArray();
329  itsNodeStack.top() = NodeType::InArray;
330  }
331  else if(nodeType == NodeType::StartObject)
332  {
333  itsNodeStack.top() = NodeType::InObject;
334  itsWriter.StartObject();
335  }
336 
337  // Array types do not output names
338  if(nodeType == NodeType::InArray) return;
339 
340  if(itsNextName == nullptr)
341  {
342  std::string name = "value" + std::to_string( itsNameCounter.top()++ ) + "\0";
343  saveValue(name);
344  }
345  else
346  {
347  saveValue(itsNextName);
348  itsNextName = nullptr;
349  }
350  }
351 
353  void makeArray()
354  {
355  itsNodeStack.top() = NodeType::StartArray;
356  }
357 
359 
360  private:
361  WriteStream itsWriteStream;
362  JSONWriter itsWriter;
363  char const * itsNextName;
364  std::stack<uint32_t> itsNameCounter;
365  std::stack<NodeType> itsNodeStack;
366  }; // JSONOutputArchive
367 
368  // ######################################################################
370 
406  class JSONInputArchive : public InputArchive<JSONInputArchive>, public traits::TextArchive
407  {
408  private:
409  using ReadStream = CEREAL_RAPIDJSON_NAMESPACE::IStreamWrapper;
410  typedef CEREAL_RAPIDJSON_NAMESPACE::GenericValue<CEREAL_RAPIDJSON_NAMESPACE::UTF8<>> JSONValue;
411  typedef JSONValue::ConstMemberIterator MemberIterator;
412  typedef JSONValue::ConstValueIterator ValueIterator;
413  typedef CEREAL_RAPIDJSON_NAMESPACE::Document::GenericValue GenericValue;
414 
415  public:
418 
421 
422  JSONInputArchive(std::istream & stream) :
424  itsNextName( nullptr ),
425  itsReadStream(stream)
426  {
427  itsDocument.ParseStream<>(itsReadStream);
428  if (itsDocument.IsArray())
429  itsIteratorStack.emplace_back(itsDocument.Begin(), itsDocument.End());
430  else
431  itsIteratorStack.emplace_back(itsDocument.MemberBegin(), itsDocument.MemberEnd());
432  }
433 
434  ~JSONInputArchive() CEREAL_NOEXCEPT = default;
435 
437 
442  void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
443  {
444  itsNextName = name;
445 
446  std::string encoded;
447  loadValue( encoded );
448  auto decoded = base64::decode( encoded );
449 
450  if( size != decoded.size() )
451  throw Exception("Decoded binary data size does not match specified size");
452 
453  std::memcpy( data, decoded.data(), decoded.size() );
454  itsNextName = nullptr;
455  };
456 
457  private:
459 
462 
465 
467  class Iterator
468  {
469  public:
470  Iterator() : itsIndex( 0 ), itsType(Null_) {}
471 
472  Iterator(MemberIterator begin, MemberIterator end) :
473  itsMemberItBegin(begin), itsMemberItEnd(end), itsIndex(0), itsType(Member)
474  {
475  if( std::distance( begin, end ) == 0 )
476  itsType = Null_;
477  }
478 
479  Iterator(ValueIterator begin, ValueIterator end) :
480  itsValueItBegin(begin), itsValueItEnd(end), itsIndex(0), itsType(Value)
481  {
482  if( std::distance( begin, end ) == 0 )
483  itsType = Null_;
484  }
485 
487  Iterator & operator++()
488  {
489  ++itsIndex;
490  return *this;
491  }
492 
494  GenericValue const & value()
495  {
496  switch(itsType)
497  {
498  case Value : return itsValueItBegin[itsIndex];
499  case Member: return itsMemberItBegin[itsIndex].value;
500  default: throw cereal::Exception("JSONInputArchive internal error: null or empty iterator to object or array!");
501  }
502  }
503 
505  const char * name() const
506  {
507  if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
508  return itsMemberItBegin[itsIndex].name.GetString();
509  else
510  return nullptr;
511  }
512 
514 
515  inline void search( const char * searchName )
516  {
517  const auto len = std::strlen( searchName );
518  size_t index = 0;
519  for( auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
520  {
521  const auto currentName = it->name.GetString();
522  if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
523  ( std::strlen( currentName ) == len ) )
524  {
525  itsIndex = index;
526  return;
527  }
528  }
529 
530  throw Exception("JSON Parsing failed - provided NVP (" + std::string(searchName) + ") not found");
531  }
532 
533  private:
534  MemberIterator itsMemberItBegin, itsMemberItEnd;
535  ValueIterator itsValueItBegin, itsValueItEnd;
536  size_t itsIndex;
537  enum Type {Value, Member, Null_} itsType;
538  };
539 
541 
549  inline void search()
550  {
551  // The name an NVP provided with setNextName()
552  if( itsNextName )
553  {
554  // The actual name of the current node
555  auto const actualName = itsIteratorStack.back().name();
556 
557  // Do a search if we don't see a name coming up, or if the names don't match
558  if( !actualName || std::strcmp( itsNextName, actualName ) != 0 )
559  itsIteratorStack.back().search( itsNextName );
560  }
561 
562  itsNextName = nullptr;
563  }
564 
565  public:
567 
576  void startNode()
577  {
578  search();
579 
580  if(itsIteratorStack.back().value().IsArray())
581  itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
582  else
583  itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
584  }
585 
587  void finishNode()
588  {
589  itsIteratorStack.pop_back();
590  ++itsIteratorStack.back();
591  }
592 
594 
595  const char * getNodeName() const
596  {
597  return itsIteratorStack.back().name();
598  }
599 
601  void setNextName( const char * name )
602  {
603  itsNextName = name;
604  }
605 
607  template <class T, traits::EnableIf<std::is_signed<T>::value,
608  sizeof(T) < sizeof(int64_t)> = traits::sfinae> inline
609  void loadValue(T & val)
610  {
611  search();
612 
613  val = static_cast<T>( itsIteratorStack.back().value().GetInt() );
614  ++itsIteratorStack.back();
615  }
616 
618  template <class T, traits::EnableIf<std::is_unsigned<T>::value,
619  sizeof(T) < sizeof(uint64_t),
620  !std::is_same<bool, T>::value> = traits::sfinae> inline
621  void loadValue(T & val)
622  {
623  search();
624 
625  val = static_cast<T>( itsIteratorStack.back().value().GetUint() );
626  ++itsIteratorStack.back();
627  }
628 
630  void loadValue(bool & val) { search(); val = itsIteratorStack.back().value().GetBool(); ++itsIteratorStack.back(); }
632  void loadValue(int64_t & val) { search(); val = itsIteratorStack.back().value().GetInt64(); ++itsIteratorStack.back(); }
634  void loadValue(uint64_t & val) { search(); val = itsIteratorStack.back().value().GetUint64(); ++itsIteratorStack.back(); }
636  void loadValue(float & val) { search(); val = static_cast<float>(itsIteratorStack.back().value().GetDouble()); ++itsIteratorStack.back(); }
638  void loadValue(double & val) { search(); val = itsIteratorStack.back().value().GetDouble(); ++itsIteratorStack.back(); }
640  void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
642  void loadValue(std::nullptr_t&) { search(); CEREAL_RAPIDJSON_ASSERT(itsIteratorStack.back().value().IsNull()); ++itsIteratorStack.back(); }
643 
644  // Special cases to handle various flavors of long, which tend to conflict with
645  // the int32_t or int64_t on various compiler/OS combinations. MSVC doesn't need any of this.
646  #ifndef _MSC_VER
647  private:
649  template <class T> inline
650  typename std::enable_if<sizeof(T) == sizeof(std::int32_t) && std::is_signed<T>::value, void>::type
651  loadLong(T & l){ loadValue( reinterpret_cast<std::int32_t&>( l ) ); }
652 
654  template <class T> inline
655  typename std::enable_if<sizeof(T) == sizeof(std::int64_t) && std::is_signed<T>::value, void>::type
656  loadLong(T & l){ loadValue( reinterpret_cast<std::int64_t&>( l ) ); }
657 
659  template <class T> inline
660  typename std::enable_if<sizeof(T) == sizeof(std::uint32_t) && !std::is_signed<T>::value, void>::type
661  loadLong(T & lu){ loadValue( reinterpret_cast<std::uint32_t&>( lu ) ); }
662 
664  template <class T> inline
665  typename std::enable_if<sizeof(T) == sizeof(std::uint64_t) && !std::is_signed<T>::value, void>::type
666  loadLong(T & lu){ loadValue( reinterpret_cast<std::uint64_t&>( lu ) ); }
667 
668  public:
670  template <class T> inline
671  typename std::enable_if<std::is_same<T, long>::value &&
672  sizeof(T) >= sizeof(std::int64_t) &&
673  !std::is_same<T, std::int64_t>::value, void>::type
674  loadValue( T & t ){ loadLong(t); }
675 
677  template <class T> inline
678  typename std::enable_if<std::is_same<T, unsigned long>::value &&
679  sizeof(T) >= sizeof(std::uint64_t) &&
680  !std::is_same<T, std::uint64_t>::value, void>::type
681  loadValue( T & t ){ loadLong(t); }
682  #endif // _MSC_VER
683 
684  private:
686  void stringToNumber( std::string const & str, long long & val ) { val = std::stoll( str ); }
688  void stringToNumber( std::string const & str, unsigned long long & val ) { val = std::stoull( str ); }
690  void stringToNumber( std::string const & str, long double & val ) { val = std::stold( str ); }
691 
692  public:
694  template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
695  !std::is_same<T, long>::value,
696  !std::is_same<T, unsigned long>::value,
697  !std::is_same<T, std::int64_t>::value,
698  !std::is_same<T, std::uint64_t>::value,
699  (sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long))> = traits::sfinae>
700  inline void loadValue(T & val)
701  {
702  std::string encoded;
703  loadValue( encoded );
704  stringToNumber( encoded, val );
705  }
706 
708  void loadSize(size_type & size)
709  {
710  if (itsIteratorStack.size() == 1)
711  size = itsDocument.Size();
712  else
713  size = (itsIteratorStack.rbegin() + 1)->value().Size();
714  }
715 
717 
718  private:
719  const char * itsNextName;
720  ReadStream itsReadStream;
721  std::vector<Iterator> itsIteratorStack;
722  CEREAL_RAPIDJSON_NAMESPACE::Document itsDocument;
723  };
724 
725  // ######################################################################
726  // JSONArchive prologue and epilogue functions
727  // ######################################################################
728 
729  // ######################################################################
731 
732  template <class T> inline
733  void prologue( JSONOutputArchive &, NameValuePair<T> const & )
734  { }
735 
737  template <class T> inline
738  void prologue( JSONInputArchive &, NameValuePair<T> const & )
739  { }
740 
741  // ######################################################################
743 
744  template <class T> inline
745  void epilogue( JSONOutputArchive &, NameValuePair<T> const & )
746  { }
747 
749 
750  template <class T> inline
751  void epilogue( JSONInputArchive &, NameValuePair<T> const & )
752  { }
753 
754  // ######################################################################
756 
758  template <class T> inline
759  void prologue( JSONOutputArchive & ar, SizeTag<T> const & )
760  {
761  ar.makeArray();
762  }
763 
765  template <class T> inline
766  void prologue( JSONInputArchive &, SizeTag<T> const & )
767  { }
768 
769  // ######################################################################
771 
772  template <class T> inline
773  void epilogue( JSONOutputArchive &, SizeTag<T> const & )
774  { }
775 
777  template <class T> inline
778  void epilogue( JSONInputArchive &, SizeTag<T> const & )
779  { }
780 
781  // ######################################################################
783 
787  template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
788  !traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value,
789  !traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
790  inline void prologue( JSONOutputArchive & ar, T const & )
791  {
792  ar.startNode();
793  }
794 
796  template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
797  !traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value,
798  !traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
799  inline void prologue( JSONInputArchive & ar, T const & )
800  {
801  ar.startNode();
802  }
803 
804  // ######################################################################
806 
809  template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
810  !traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value,
811  !traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
812  inline void epilogue( JSONOutputArchive & ar, T const & )
813  {
814  ar.finishNode();
815  }
816 
818  template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
819  !traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value,
820  !traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
821  inline void epilogue( JSONInputArchive & ar, T const & )
822  {
823  ar.finishNode();
824  }
825 
826  // ######################################################################
828  inline
829  void prologue( JSONOutputArchive & ar, std::nullptr_t const & )
830  {
831  ar.writeName();
832  }
833 
835  inline
836  void prologue( JSONInputArchive &, std::nullptr_t const & )
837  { }
838 
839  // ######################################################################
841  inline
842  void epilogue( JSONOutputArchive &, std::nullptr_t const & )
843  { }
844 
846  inline
847  void epilogue( JSONInputArchive &, std::nullptr_t const & )
848  { }
849 
850  // ######################################################################
852  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
853  void prologue( JSONOutputArchive & ar, T const & )
854  {
855  ar.writeName();
856  }
857 
859  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
860  void prologue( JSONInputArchive &, T const & )
861  { }
862 
863  // ######################################################################
865  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
866  void epilogue( JSONOutputArchive &, T const & )
867  { }
868 
870  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
871  void epilogue( JSONInputArchive &, T const & )
872  { }
873 
874  // ######################################################################
876  template<class CharT, class Traits, class Alloc> inline
877  void prologue(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const &)
878  {
879  ar.writeName();
880  }
881 
883  template<class CharT, class Traits, class Alloc> inline
884  void prologue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
885  { }
886 
887  // ######################################################################
889  template<class CharT, class Traits, class Alloc> inline
890  void epilogue(JSONOutputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
891  { }
892 
894  template<class CharT, class Traits, class Alloc> inline
895  void epilogue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
896  { }
897 
898  // ######################################################################
899  // Common JSONArchive serialization functions
900  // ######################################################################
902  template <class T> inline
903  void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive & ar, NameValuePair<T> const & t )
904  {
905  ar.setNextName( t.name );
906  ar( t.value );
907  }
908 
909  template <class T> inline
910  void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, NameValuePair<T> & t )
911  {
912  ar.setNextName( t.name );
913  ar( t.value );
914  }
915 
917  inline
918  void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::nullptr_t const & t)
919  {
920  ar.saveValue( t );
921  }
922 
924  inline
925  void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::nullptr_t & t)
926  {
927  ar.loadValue( t );
928  }
929 
931  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
932  void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, T const & t)
933  {
934  ar.saveValue( t );
935  }
936 
938  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
939  void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, T & t)
940  {
941  ar.loadValue( t );
942  }
943 
945  template<class CharT, class Traits, class Alloc> inline
946  void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
947  {
948  ar.saveValue( str );
949  }
950 
952  template<class CharT, class Traits, class Alloc> inline
953  void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
954  {
955  ar.loadValue( str );
956  }
957 
958  // ######################################################################
960  template <class T> inline
961  void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive &, SizeTag<T> const & )
962  {
963  // nothing to do here, we don't explicitly save the size
964  }
965 
967  template <class T> inline
968  void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, SizeTag<T> & st )
969  {
970  ar.loadSize( st.size );
971  }
972 } // namespace cereal
973 
974 // register archives for polymorphic support
976 CEREAL_REGISTER_ARCHIVE(cereal::JSONOutputArchive)
977 
978 // tie input and output archives together
979 CEREAL_SETUP_ARCHIVE_TRAITS(cereal::JSONInputArchive, cereal::JSONOutputArchive)
980 
981 #endif // CEREAL_ARCHIVES_JSON_HPP_
void saveValue(T t)
Serialize a long if it would not be caught otherwise.
Definition: json.hpp:284
static Options Default()
Default options.
Definition: json.hpp:112
void saveValue(int64_t i64)
Saves an int64 to the current node.
Definition: json.hpp:239
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:193
void saveValue(std::string const &s)
Saves a string to the current node.
Definition: json.hpp:245
#define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive)
Sets up traits that relate an input archive to an output archive.
Definition: traits.hpp:169
IndentChar
The character to use for indenting.
Definition: json.hpp:118
void saveValue(uint64_t u64)
Saves a uint64 to the current node.
Definition: json.hpp:241
void saveValue(int i)
Saves an int to the current node.
Definition: json.hpp:235
void finishNode()
Designates the most recently added node as finished.
Definition: json.hpp:201
A class containing various advanced options for the JSON archive.
Definition: json.hpp:108
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:321
void saveValue(std::nullptr_t)
Saves a nullptr to the current node.
Definition: json.hpp:249
void saveValue(char const *s)
Saves a const char * to the current node.
Definition: json.hpp:247
void loadBinaryValue(void *data, size_t size, const char *name=nullptr)
Loads some binary data, encoded as a base64 string.
Definition: json.hpp:442
Options(int precision=JSONWriter::kDefaultMaxDecimalPlaces, IndentChar indentChar=IndentChar::space, unsigned int indentLength=4)
Specify specific options for the JSONOutputArchive.
Definition: json.hpp:131
Type traits only struct used to mark an archive as human readable (text based)
Definition: traits.hpp:1299
The base input archive class.
Definition: cereal.hpp:599
const char * getNodeName() const
Retrieves the current node name.
Definition: json.hpp:595
static Options NoIndent()
Default options with no indentation.
Definition: json.hpp:115
An output archive designed to save data to JSON.
Definition: json.hpp:95
void saveValue(double d)
Saves a double to the current node.
Definition: json.hpp:243
Definition: access.hpp:40
An input archive designed to load data from JSON.
Definition: json.hpp:406
#define CEREAL_REGISTER_ARCHIVE(Archive)
Registers a specific Archive type with cereal.
Definition: cereal.hpp:141
void makeArray()
Designates that the current node should be output as an array, not an object.
Definition: json.hpp:353
void saveValue(T const &t)
Save exotic arithmetic as strings to current node.
Definition: json.hpp:301
Internal misc utilities.
Main cereal functionality.
~JSONOutputArchive() CEREAL_NOEXCEPT
Destructor, flushes the JSON.
Definition: json.hpp:162
#define CEREAL_LOAD_FUNCTION_NAME
The deserialization (load) function name to search for.
Definition: macros.hpp:85
JSONInputArchive(std::istream &stream)
Construct, reading from the provided stream.
Definition: json.hpp:422
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: json.hpp:227
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
void saveValue(unsigned u)
Saves a uint to the current node.
Definition: json.hpp:237
void finishNode()
Finishes the most recently started node.
Definition: json.hpp:587
The base output archive class.
Definition: cereal.hpp:234
void saveValue(bool b)
Saves a bool to the current node.
Definition: json.hpp:233
#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:173
void loadSize(size_type &size)
Loads the size for a SizeTag.
Definition: json.hpp:708
void startNode()
Starts a new node, going into its proper iterator.
Definition: json.hpp:576
void loadValue(T &val)
Loads a value from the current node - long double and long long overloads.
Definition: json.hpp:700
JSONOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream.
Definition: json.hpp:149
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: json.hpp:601
::type loadValue(T &t)
Loads a value from the current node - small signed overload.
Definition: json.hpp:681
An exception class thrown when things go wrong at runtime.
Definition: helpers.hpp:48