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 the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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"
34
35namespace 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
76namespace 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
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
205 {
206 writeName();
207 itsNodeStack.push(NodeType::StartObject);
208 itsNameCounter.push(0);
209 }
210
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#if defined(_MSC_VER) && _MSC_VER < 1916
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, int>::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, unsigned>::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
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
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
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), itsSize(std::distance(begin, end)), itsType(Member)
487 {
488 if( itsSize == 0 )
489 itsType = Null_;
490 }
491
492 Iterator(ValueIterator begin, ValueIterator end) :
493 itsValueItBegin(begin), itsIndex(0), itsSize(std::distance(begin, end)), itsType(Value)
494 {
495 if( itsSize == 0 )
496 itsType = Null_;
497 }
498
500 Iterator & operator++()
501 {
502 ++itsIndex;
503 return *this;
504 }
505
507 GenericValue const & value()
508 {
509 if( itsIndex >= itsSize )
510 throw cereal::Exception("No more objects in input");
511
512 switch(itsType)
513 {
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!");
517 }
518 }
519
521 const char * name() const
522 {
523 if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
524 return itsMemberItBegin[itsIndex].name.GetString();
525 else
526 return nullptr;
527 }
528
530
531 inline void search( const char * searchName )
532 {
533 const auto len = std::strlen( searchName );
534 size_t index = 0;
535 for( auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
536 {
537 const auto currentName = it->name.GetString();
538 if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
539 ( std::strlen( currentName ) == len ) )
540 {
541 itsIndex = index;
542 return;
543 }
544 }
545
546 throw Exception("JSON Parsing failed - provided NVP (" + std::string(searchName) + ") not found");
547 }
548
549 private:
550 MemberIterator itsMemberItBegin, itsMemberItEnd;
551 ValueIterator itsValueItBegin;
552 size_t itsIndex, itsSize;
553 enum Type {Value, Member, Null_} itsType;
554 };
555
557
565 inline void search()
566 {
567 // store pointer to itsNextName locally and reset to nullptr in case search() throws
568 auto localNextName = itsNextName;
569 itsNextName = nullptr;
570
571 // The name an NVP provided with setNextName()
572 if( localNextName )
573 {
574 // The actual name of the current node
575 auto const actualName = itsIteratorStack.back().name();
576
577 // Do a search if we don't see a name coming up, or if the names don't match
578 if( !actualName || std::strcmp( localNextName, actualName ) != 0 )
579 itsIteratorStack.back().search( localNextName );
580 }
581 }
582
583 public:
585
595 {
596 search();
597
598 if(itsIteratorStack.back().value().IsArray())
599 itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
600 else
601 itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
602 }
603
606 {
607 itsIteratorStack.pop_back();
608 ++itsIteratorStack.back();
609 }
610
612
613 const char * getNodeName() const
614 {
615 return itsIteratorStack.back().name();
616 }
617
619 void setNextName( const char * name )
620 {
621 itsNextName = name;
622 }
623
625 template <class T, traits::EnableIf<std::is_signed<T>::value,
626 sizeof(T) < sizeof(int64_t)> = traits::sfinae> inline
627 void loadValue(T & val)
628 {
629 search();
630
631 val = static_cast<T>( itsIteratorStack.back().value().GetInt() );
632 ++itsIteratorStack.back();
633 }
634
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
639 void loadValue(T & val)
640 {
641 search();
642
643 val = static_cast<T>( itsIteratorStack.back().value().GetUint() );
644 ++itsIteratorStack.back();
645 }
646
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(); }
661
662 // Special cases to handle various flavors of long, which tend to conflict with
663 // the int32_t or int64_t on various compiler/OS combinations. MSVC doesn't need any of this.
664 #ifndef _MSC_VER
665 private:
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 ) ); }
670
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 ) ); }
675
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 ) ); }
680
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 ) ); }
685
686 public:
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
692 loadValue( T & t ){ loadLong(t); }
693
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
699 loadValue( T & t ){ loadLong(t); }
700 #endif // _MSC_VER
701
702 private:
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 ); }
709
710 public:
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>
718 inline void loadValue(T & val)
719 {
720 std::string encoded;
721 loadValue( encoded );
722 stringToNumber( encoded, val );
723 }
724
726 void loadSize(size_type & size)
727 {
728 if (itsIteratorStack.size() == 1)
729 size = itsDocument.Size();
730 else
731 size = (itsIteratorStack.rbegin() + 1)->value().Size();
732 }
733
735
736 private:
737 const char * itsNextName;
738 ReadStream itsReadStream;
739 std::vector<Iterator> itsIteratorStack;
740 RAPIDJSON_NAMESPACE::Document itsDocument;
741 };
742
743 // ######################################################################
744 // JSONArchive prologue and epilogue functions
745 // ######################################################################
746
747 // ######################################################################
749
750 template <class T> inline
752 { }
753
755 template <class T> inline
757 { }
758
759 // ######################################################################
761
762 template <class T> inline
764 { }
765
767
768 template <class T> inline
770 { }
771
772 // ######################################################################
774
775 template <class T> inline
777 { }
778
780 template <class T> inline
782 { }
783
784 // ######################################################################
786
787 template <class T> inline
789 { }
790
792
793 template <class T> inline
795 { }
796
797 // ######################################################################
799
801 template <class T> inline
803 {
804 ar.makeArray();
805 }
806
808 template <class T> inline
810 { }
811
812 // ######################################################################
814
815 template <class T> inline
817 { }
818
820 template <class T> inline
822 { }
823
824 // ######################################################################
826
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>
833 inline void prologue( JSONOutputArchive & ar, T const & )
834 {
835 ar.startNode();
836 }
837
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>
842 inline void prologue( JSONInputArchive & ar, T const & )
843 {
844 ar.startNode();
845 }
846
847 // ######################################################################
849
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>
855 inline void epilogue( JSONOutputArchive & ar, T const & )
856 {
857 ar.finishNode();
858 }
859
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>
864 inline void epilogue( JSONInputArchive & ar, T const & )
865 {
866 ar.finishNode();
867 }
868
869 // ######################################################################
871 inline
872 void prologue( JSONOutputArchive & ar, std::nullptr_t const & )
873 {
874 ar.writeName();
875 }
876
878 inline
879 void prologue( JSONInputArchive &, std::nullptr_t const & )
880 { }
881
882 // ######################################################################
884 inline
885 void epilogue( JSONOutputArchive &, std::nullptr_t const & )
886 { }
887
889 inline
890 void epilogue( JSONInputArchive &, std::nullptr_t const & )
891 { }
892
893 // ######################################################################
895 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
896 void prologue( JSONOutputArchive & ar, T const & )
897 {
898 ar.writeName();
899 }
900
902 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
903 void prologue( JSONInputArchive &, T const & )
904 { }
905
906 // ######################################################################
908 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
909 void epilogue( JSONOutputArchive &, T const & )
910 { }
911
913 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
914 void epilogue( JSONInputArchive &, T const & )
915 { }
916
917 // ######################################################################
919 template<class CharT, class Traits, class Alloc> inline
920 void prologue(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const &)
921 {
922 ar.writeName();
923 }
924
926 template<class CharT, class Traits, class Alloc> inline
927 void prologue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
928 { }
929
930 // ######################################################################
932 template<class CharT, class Traits, class Alloc> inline
933 void epilogue(JSONOutputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
934 { }
935
937 template<class CharT, class Traits, class Alloc> inline
938 void epilogue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
939 { }
940
941 // ######################################################################
942 // Common JSONArchive serialization functions
943 // ######################################################################
945 template <class T> inline
947 {
948 ar.setNextName( t.name );
949 ar( t.value );
950 }
951
952 template <class T> inline
953 void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, NameValuePair<T> & t )
954 {
955 ar.setNextName( t.name );
956 ar( t.value );
957 }
958
960 inline
961 void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::nullptr_t const & t)
962 {
963 ar.saveValue( t );
964 }
965
967 inline
968 void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::nullptr_t & t)
969 {
970 ar.loadValue( t );
971 }
972
974 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
976 {
977 ar.saveValue( t );
978 }
979
981 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
983 {
984 ar.loadValue( t );
985 }
986
988 template<class CharT, class Traits, class Alloc> inline
989 void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
990 {
991 ar.saveValue( str );
992 }
993
995 template<class CharT, class Traits, class Alloc> inline
996 void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
997 {
998 ar.loadValue( str );
999 }
1000
1001 // ######################################################################
1003 template <class T> inline
1005 {
1006 // nothing to do here, we don't explicitly save the size
1007 }
1008
1010 template <class T> inline
1012 {
1013 ar.loadSize( st.size );
1014 }
1015} // namespace cereal
1016
1017// register archives for polymorphic support
1020
1021// tie input and output archives together
1023
1024#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:711
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:699
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:726
const char * getNodeName() const
Retrieves the current node name.
Definition: json.hpp:613
void startNode()
Starts a new node, going into its proper iterator.
Definition: json.hpp:594
void loadValue(T &val)
Loads a value from the current node - long double and long long overloads.
Definition: json.hpp:718
void finishNode()
Finishes the most recently started node.
Definition: json.hpp:605
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: json.hpp:619
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
Internal misc utilities.