Line data Source code
1 : /*! \file json.hpp
2 : \brief JSON input and output archives */
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 : {
37 : //! An exception thrown when rapidjson fails an internal assertion
38 : /*! @ingroup Utility */
39 : struct RapidJSONException : Exception
40 0 : { RapidJSONException( const char * what_ ) : Exception( what_ ) {} };
41 : }
42 :
43 : // Inform rapidjson that assert will throw
44 : #ifndef CEREAL_RAPIDJSON_ASSERT_THROWS
45 : #define CEREAL_RAPIDJSON_ASSERT_THROWS
46 : #endif // CEREAL_RAPIDJSON_ASSERT_THROWS
47 :
48 : // Override rapidjson assertions to throw exceptions by default
49 : #ifndef CEREAL_RAPIDJSON_ASSERT
50 : #define CEREAL_RAPIDJSON_ASSERT(x) if(!(x)){ \
51 : throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); }
52 : #endif // RAPIDJSON_ASSERT
53 :
54 : // Enable support for parsing of nan, inf, -inf
55 : #ifndef CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS
56 : #define CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag
57 : #endif
58 :
59 : // Enable support for parsing of nan, inf, -inf
60 : #ifndef CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS
61 : #define CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag | kParseNanAndInfFlag
62 : #endif
63 :
64 : #include "cereal/external/rapidjson/prettywriter.h"
65 : #include "cereal/external/rapidjson/ostreamwrapper.h"
66 : #include "cereal/external/rapidjson/istreamwrapper.h"
67 : #include "cereal/external/rapidjson/document.h"
68 : #include "cereal/external/base64.hpp"
69 :
70 : #include <limits>
71 : #include <sstream>
72 : #include <stack>
73 : #include <vector>
74 : #include <string>
75 :
76 : namespace cereal
77 : {
78 : // ######################################################################
79 : //! An output archive designed to save data to JSON
80 : /*! This archive uses RapidJSON to build serialize data to JSON.
81 :
82 : JSON archives provides a human readable output but at decreased
83 : performance (both in time and space) compared to binary archives.
84 :
85 : JSON archives are only guaranteed to finish flushing their contents
86 : upon destruction and should thus be used in an RAII fashion.
87 :
88 : JSON benefits greatly from name-value pairs, which if present, will
89 : name the nodes in the output. If these are not present, each level
90 : of the output will be given an automatically generated delimited name.
91 :
92 : The precision of the output archive controls the number of decimals output
93 : for floating point numbers and should be sufficiently large (i.e. at least 20)
94 : if there is a desire to have binary equality between the numbers output and
95 : those read in. In general you should expect a loss of precision when going
96 : from floating point to text and back.
97 :
98 : JSON archives do not output the size information for any dynamically sized structure
99 : and instead infer it from the number of children for a node. This means that data
100 : can be hand edited for dynamic sized structures and will still be readable. This
101 : is accomplished through the cereal::SizeTag object, which will cause the archive
102 : to output the data as a JSON array (e.g. marked by [] instead of {}), which indicates
103 : that the container is variable sized and may be edited.
104 :
105 : \ingroup Archives */
106 : class JSONOutputArchive : public OutputArchive<JSONOutputArchive>, public traits::TextArchive
107 : {
108 : enum class NodeType { StartObject, InObject, StartArray, InArray };
109 :
110 : using WriteStream = CEREAL_RAPIDJSON_NAMESPACE::OStreamWrapper;
111 : using JSONWriter = CEREAL_RAPIDJSON_NAMESPACE::PrettyWriter<WriteStream>;
112 :
113 : public:
114 : /*! @name Common Functionality
115 : Common use cases for directly interacting with an JSONOutputArchive */
116 : //! @{
117 :
118 : //! A class containing various advanced options for the JSON archive
119 : class Options
120 : {
121 : public:
122 : //! Default options
123 3704 : static Options Default(){ return Options(); }
124 :
125 : //! Default options with no indentation
126 : static Options NoIndent(){ return Options( JSONWriter::kDefaultMaxDecimalPlaces, IndentChar::space, 0 ); }
127 :
128 3704 : //! The character to use for indenting
129 : enum class IndentChar : char
130 : {
131 : space = ' ',
132 : tab = '\t',
133 : newline = '\n',
134 : carriage_return = '\r'
135 : };
136 :
137 : //! Specify specific options for the JSONOutputArchive
138 : /*! @param precision The precision used for floating point numbers
139 : @param indentChar The type of character to indent with
140 : @param indentLength The number of indentChar to use for indentation
141 : (0 corresponds to no indentation) */
142 3704 : explicit Options( int precision = JSONWriter::kDefaultMaxDecimalPlaces,
143 : IndentChar indentChar = IndentChar::space,
144 3704 : unsigned int indentLength = 4 ) :
145 : itsPrecision( precision ),
146 : itsIndentChar( static_cast<char>(indentChar) ),
147 7408 : itsIndentLength( indentLength ) { }
148 :
149 3704 : private:
150 : friend class JSONOutputArchive;
151 : int itsPrecision;
152 3704 : char itsIndentChar;
153 : unsigned int itsIndentLength;
154 : };
155 :
156 : //! Construct, outputting to the provided stream
157 : /*! @param stream The stream to output to.
158 : @param options The JSON specific options to use. See the Options struct
159 : for the values of default parameters */
160 3704 : JSONOutputArchive(std::ostream & stream, Options const & options = Options::Default() ) :
161 : OutputArchive<JSONOutputArchive>(this),
162 : itsWriteStream(stream),
163 3704 : itsWriter(itsWriteStream),
164 3704 : itsNextName(nullptr)
165 3704 : {
166 3704 : itsWriter.SetMaxDecimalPlaces( options.itsPrecision );
167 3704 : itsWriter.SetIndent( options.itsIndentChar, options.itsIndentLength );
168 7408 : itsNameCounter.push(0);
169 7408 : itsNodeStack.push(NodeType::StartObject);
170 3704 : }
171 3704 :
172 3704 : //! Destructor, flushes the JSON
173 7408 : ~JSONOutputArchive() CEREAL_NOEXCEPT
174 7408 : {
175 7408 : if (itsNodeStack.top() == NodeType::InObject)
176 3704 : itsWriter.EndObject();
177 0 : else if (itsNodeStack.top() == NodeType::InArray)
178 3704 : itsWriter.EndArray();
179 7408 : }
180 3704 :
181 3704 : //! Saves some binary data, encoded as a base64 string, with an optional name
182 0 : /*! This will create a new node, optionally named, and insert a value that consists of
183 0 : the data encoded as a base64 string */
184 3704 : void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
185 0 : {
186 0 : setNextName( name );
187 3704 : writeName();
188 3704 :
189 3704 : auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
190 3704 : saveValue( base64string );
191 0 : };
192 3704 :
193 7408 : //! @}
194 3704 : /*! @name Internal Functionality
195 3704 : Functionality designed for use by those requiring control over the inner mechanisms of
196 0 : the JSONOutputArchive */
197 0 : //! @{
198 3704 :
199 : //! Starts a new node in the JSON output
200 : /*! The node can optionally be given a name by calling setNextName prior
201 : to creating the node
202 :
203 : Nodes only need to be started for types that are themselves objects or arrays */
204 : void startNode()
205 : {
206 : writeName();
207 : itsNodeStack.push(NodeType::StartObject);
208 : itsNameCounter.push(0);
209 : }
210 :
211 : //! Designates the most recently added node as finished
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 1359889 : // We'll also end any object/arrays we happen to be in
219 : switch(itsNodeStack.top())
220 1359889 : {
221 1359889 : case NodeType::StartArray:
222 1359889 : itsWriter.StartArray();
223 2716991 : // fall through
224 : case NodeType::InArray:
225 1357102 : itsWriter.EndArray();
226 2716991 : break;
227 1357102 : case NodeType::StartObject:
228 1357102 : itsWriter.StartObject();
229 : // fall through
230 : case NodeType::InObject:
231 1357102 : itsWriter.EndObject();
232 : break;
233 1359889 : }
234 :
235 301 : itsNodeStack.pop();
236 301 : itsNameCounter.pop();
237 : }
238 1367402 :
239 10300 : //! Sets the name for the next node created with startNode
240 10602 : void setNextName( const char * name )
241 1002 : {
242 11000 : itsNextName = name;
243 10300 : }
244 1359889 :
245 1350289 : //! Saves a bool to the current node
246 1350289 : void saveValue(bool b) { itsWriter.Bool(b); }
247 1346802 : //! Saves an int to the current node
248 1346802 : void saveValue(int i) { itsWriter.Int(i); }
249 2706691 : //! Saves a uint to the current node
250 1359889 : void saveValue(unsigned u) { itsWriter.Uint(u); }
251 1359889 : //! Saves an int64 to the current node
252 1357102 : void saveValue(int64_t i64) { itsWriter.Int64(i64); }
253 1357102 : //! Saves a uint64 to the current node
254 2099125 : void saveValue(uint64_t u64) { itsWriter.Uint64(u64); }
255 : //! Saves a double to the current node
256 742023 : void saveValue(double d) { itsWriter.Double(d); }
257 1482156 : //! Saves a string to the current node
258 : void saveValue(std::string const & s) { itsWriter.String(s.c_str(), static_cast<CEREAL_RAPIDJSON_NAMESPACE::SizeType>( s.size() )); }
259 740133 : //! Saves a const char * to the current node
260 751541 : void saveValue(char const * s) { itsWriter.String(s); }
261 : //! Saves a nullptr to the current node
262 2337544 : void saveValue(std::nullptr_t) { itsWriter.Null(); }
263 11408 :
264 86279 : private:
265 2336504 : // Some compilers/OS have difficulty disambiguating the above for various flavors of longs, so we provide
266 1301 : // special overloads to handle these cases.
267 85382 :
268 1653 : //! 32 bit signed long saving to current node
269 1301 : template <class T, traits::EnableIf<sizeof(T) == sizeof(std::int32_t),
270 2203 : std::is_signed<T>::value> = traits::sfinae> inline
271 1652 : void saveLong(T l){ saveValue( static_cast<std::int32_t>( l ) ); }
272 2063813 :
273 2203 : //! non 32 bit signed long saving to current node
274 742023 : template <class T, traits::EnableIf<sizeof(T) != sizeof(std::int32_t),
275 2060130 : std::is_signed<T>::value> = traits::sfinae> inline
276 : void saveLong(T l){ saveValue( static_cast<std::int64_t>( l ) ); }
277 740133 :
278 : //! 32 bit unsigned long saving to current node
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 :
283 : //! non 32 bit unsigned long saving to current node
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
290 : //! MSVC only long overload to current node
291 : void saveValue( unsigned long lu ){ saveLong( lu ); };
292 : #else // _MSC_VER
293 : //! Serialize a long if it would not be caught otherwise
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 :
299 : //! Serialize an unsigned long if it would not be caught otherwise
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 :
306 : //! Save exotic arithmetic as strings to current node
307 : /*! Handles long long (if distinct from other types), unsigned long (if distinct), and long double */
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 :
321 : //! Write the name of the upcoming node and prepare object/array state
322 : /*! Since writeName is called for every value that is output, regardless of
323 : whether it has a name or not, it is the place where we will do a deferred
324 : check of our node state and decide whether we are in an array or an object.
325 :
326 : The general workflow of saving to the JSON archive is:
327 :
328 600 : 1. (optional) Set the name for the next node to be created, usually done by an NVP
329 : 2. Start the node
330 600 : 3. (if there is data to save) Write the name of the node (this function)
331 1200 : 4. (if there is data to save) Save the data (with saveValue)
332 600 : 5. Finish the node
333 1200 : */
334 700 : void writeName()
335 600 : {
336 700 : NodeType const & nodeType = itsNodeStack.top();
337 200 :
338 100 : // Start up either an object or an array, depending on state
339 200 : if(nodeType == NodeType::StartArray)
340 200 : {
341 100 : itsWriter.StartArray();
342 200 : itsNodeStack.top() = NodeType::InArray;
343 200 : }
344 100 : else if(nodeType == NodeType::StartObject)
345 200 : {
346 200 : itsNodeStack.top() = NodeType::InObject;
347 100 : itsWriter.StartObject();
348 3870704 : }
349 200 :
350 3870604 : // Array types do not output names
351 3865083 : if(nodeType == NodeType::InArray) return;
352 100 :
353 7735487 : if(itsNextName == nullptr)
354 100 : {
355 9999 : std::string name = "value" + std::to_string( itsNameCounter.top()++ ) + "\0";
356 3874882 : saveValue(name);
357 : }
358 3870503 : else
359 9998 : {
360 1352493 : saveValue(itsNextName);
361 5207378 : itsNextName = nullptr;
362 : }
363 1349706 : }
364 1349706 :
365 3870504 : //! Designates that the current node should be output as an array, not an object
366 1800 : void makeArray()
367 2732009 : {
368 3866683 : itsNodeStack.top() = NodeType::StartArray;
369 5971758 : }
370 4717318 :
371 3600 : //! @}
372 5961597 :
373 1987199 : private:
374 743823 : WriteStream itsWriteStream; //!< Rapidjson write stream
375 742023 : JSONWriter itsWriter; //!< Rapidjson writer
376 1800 : char const * itsNextName; //!< The next name
377 740133 : std::stack<uint32_t> itsNameCounter; //!< Counter for creating unique names for unnamed nodes
378 740233 : std::stack<NodeType> itsNodeStack;
379 1900 : }; // JSONOutputArchive
380 10300 :
381 100 : // ######################################################################
382 10400 : //! An input archive designed to load data from JSON
383 22400 : /*! This archive uses RapidJSON to read in a JSON archive.
384 :
385 12100 : As with the output JSON archive, the preferred way to use this archive is in
386 12100 : an RAII fashion, ensuring its destruction after all data has been read.
387 5400 :
388 3600 : Input JSON should have been produced by the JSONOutputArchive. Data can
389 : only be added to dynamically sized containers (marked by JSON arrays) -
390 5400 : the input archive will determine their size by looking at the number of child nodes.
391 1800 : Only JSON originating from a JSONOutputArchive is officially supported, but data
392 0 : from other sources may work if properly formatted.
393 0 :
394 : The JSONInputArchive does not require that nodes are loaded in the same
395 0 : order they were saved by JSONOutputArchive. Using name value pairs (NVPs),
396 0 : it is possible to load in an out of order fashion or otherwise skip/select
397 : specific nodes to load.
398 :
399 : The default behavior of the input archive is to read sequentially starting
400 : with the first node and exploring its children. When a given NVP does
401 : not match the read in name for a node, the archive will search for that
402 : node at the current level and load it if it exists. After loading an out of
403 : order node, the archive will then proceed back to loading sequentially from
404 : its new position.
405 :
406 : Consider this simple example where loading of some data is skipped:
407 :
408 : @code{cpp}
409 : // imagine the input file has someData(1-9) saved in order at the top level node
410 : ar( someData1, someData2, someData3 ); // XML loads in the order it sees in the file
411 : ar( cereal::make_nvp( "hello", someData6 ) ); // NVP given does not
412 : // match expected NVP name, so we search
413 : // for the given NVP and load that value
414 : ar( someData7, someData8, someData9 ); // with no NVP given, loading resumes at its
415 : // current location, proceeding sequentially
416 : @endcode
417 :
418 : \ingroup Archives */
419 : class JSONInputArchive : public InputArchive<JSONInputArchive>, public traits::TextArchive
420 : {
421 : private:
422 : using ReadStream = CEREAL_RAPIDJSON_NAMESPACE::IStreamWrapper;
423 : typedef CEREAL_RAPIDJSON_NAMESPACE::GenericValue<CEREAL_RAPIDJSON_NAMESPACE::UTF8<>> JSONValue;
424 : typedef JSONValue::ConstMemberIterator MemberIterator;
425 : typedef JSONValue::ConstValueIterator ValueIterator;
426 : typedef CEREAL_RAPIDJSON_NAMESPACE::Document::GenericValue GenericValue;
427 :
428 : public:
429 : /*! @name Common Functionality
430 : Common use cases for directly interacting with an JSONInputArchive */
431 : //! @{
432 :
433 : //! Construct, reading from the provided stream
434 : /*! @param stream The stream to read from */
435 : JSONInputArchive(std::istream & stream) :
436 : InputArchive<JSONInputArchive>(this),
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 :
449 3704 : //! Loads some binary data, encoded as a base64 string
450 : /*! This will automatically start and finish a node to load the data, and can be called directly by
451 : users.
452 7408 :
453 : Note that this follows the same ordering rules specified in the class description in regards
454 3704 : to loading in/out of order */
455 7408 : void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
456 0 : {
457 3704 : itsNextName = name;
458 7408 :
459 3704 : std::string encoded;
460 : loadValue( encoded );
461 7408 : auto decoded = base64::decode( encoded );
462 3704 :
463 : if( size != decoded.size() )
464 3704 : throw Exception("Decoded binary data size does not match specified size");
465 :
466 : std::memcpy( data, decoded.data(), decoded.size() );
467 100 : itsNextName = nullptr;
468 : };
469 :
470 200 : private:
471 : //! @}
472 100 : /*! @name Internal Functionality
473 200 : Functionality designed for use by those requiring control over the inner mechanisms of
474 0 : the JSONInputArchive */
475 100 : //! @{
476 200 :
477 100 : //! An internal iterator that handles both array and object types
478 : /*! This class is a variant and holds both types of iterators that
479 200 : rapidJSON supports - one for arrays and one for objects. */
480 100 : class Iterator
481 : {
482 100 : 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 :
499 1353593 : //! Advance to the next node
500 1353593 : Iterator & operator++()
501 : {
502 2704399 : ++itsIndex;
503 1351506 : return *this;
504 1353593 : }
505 1350806 :
506 11000 : //! Get the value of the current node
507 1361106 : GenericValue const & value()
508 : {
509 20600 : switch(itsType)
510 10601 : {
511 10300 : case Value : return itsValueItBegin[itsIndex];
512 10300 : case Member: return itsMemberItBegin[itsIndex].value;
513 302 : default: throw cereal::Exception("JSONInputArchive internal error: null or empty iterator to object or array!");
514 3881004 : }
515 : }
516 3870704 :
517 7735887 : //! Get the name of the current node, or nullptr if it has no name
518 100 : const char * name() const
519 3865083 : {
520 3865283 : if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
521 6601782 : return itsMemberItBegin[itsIndex].name.GetString();
522 100 : else
523 6601782 : return nullptr;
524 6590487 : }
525 3114585 :
526 10077684 : //! Adjust our position such that we are at the node with the given name
527 0 : /*! @throws Exception if no such named node exists */
528 3111653 : inline void search( const char * searchName )
529 3478834 : {
530 0 : const auto len = std::strlen( searchName );
531 0 : size_t index = 0;
532 743923 : for( auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
533 : {
534 743923 : const auto currentName = it->name.GetString();
535 1485856 : if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
536 : ( std::strlen( currentName ) == len ) )
537 742133 : {
538 741933 : itsIndex = index;
539 1800 : return;
540 100 : }
541 1800 : }
542 2700 :
543 0 : throw Exception("JSON Parsing failed - provided NVP (" + std::string(searchName) + ") not found");
544 4500 : }
545 1800 :
546 3100 : private:
547 2700 : MemberIterator itsMemberItBegin, itsMemberItEnd; //!< The member iterator (object)
548 4000 : ValueIterator itsValueItBegin; //!< The value iterator (array)
549 6200 : size_t itsIndex; //!< The current index of this iterator
550 900 : enum Type {Value, Member, Null_} itsType; //!< Whether this holds values (array) or members (objects) or nothing
551 3100 : };
552 4000 :
553 1800 : //! Searches for the expectedName node if it doesn't match the actualName
554 : /*! This needs to be called before every load or node start occurs. This function will
555 900 : check to see if an NVP has been provided (with setNextName) and if so, see if that name matches the actual
556 900 : next name given. If the names do not match, it will search in the current level of the JSON for that name.
557 0 : If the name is not found, an exception will be thrown.
558 0 :
559 : Resets the NVP name after called.
560 0 :
561 : @throws Exception if an expectedName is given and not found */
562 0 : inline void search()
563 0 : {
564 0 : // The name an NVP provided with setNextName()
565 0 : if( itsNextName )
566 0 : {
567 0 : // The actual name of the current node
568 0 : auto const actualName = itsIteratorStack.back().name();
569 0 :
570 0 : // Do a search if we don't see a name coming up, or if the names don't match
571 0 : if( !actualName || std::strcmp( itsNextName, actualName ) != 0 )
572 : itsIteratorStack.back().search( itsNextName );
573 0 : }
574 0 :
575 0 : itsNextName = nullptr;
576 3871004 : }
577 :
578 0 : public:
579 7736387 : //! Starts a new node, going into its proper iterator
580 : /*! This places an iterator for the next node to be parsed onto the iterator stack. If the next
581 : node is an array, this will be a value iterator, otherwise it will be a member iterator.
582 4607506 :
583 : By default our strategy is to start with the document root node and then recursively iterate through
584 : all children in the order they show up in the document.
585 1482356 : We don't need to know NVPs to do this; we'll just blindly load in the order things appear in.
586 900 :
587 : If we were given an NVP, we will search for it if it does not match our the name of the next node
588 740233 : that would normally be loaded. This functionality is provided by search(). */
589 3871904 : void startNode()
590 3871004 : {
591 : search();
592 3865383 :
593 3865383 : if(itsIteratorStack.back().value().IsArray())
594 1800 : 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 3600 : }
598 :
599 : //! Finishes the most recently started node
600 1800 : void finishNode()
601 : {
602 : itsIteratorStack.pop_back();
603 1360189 : ++itsIteratorStack.back();
604 0 : }
605 1360189 :
606 1357402 : //! Retrieves the current node name
607 1361989 : /*! @return nullptr if no name exists */
608 1369502 : const char * getNodeName() const
609 : {
610 2709091 : return itsIteratorStack.back().name();
611 1372289 : }
612 :
613 1347102 : //! Sets the name for the next node created with startNode
614 2717291 : void setNextName( const char * name )
615 : {
616 1359889 : itsNextName = name;
617 2716991 : }
618 1359889 :
619 1357102 : //! Loads a value from the current node - small signed overload
620 1357102 : template <class T, traits::EnableIf<std::is_signed<T>::value,
621 1357102 : 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 742123 : }
629 :
630 742123 : //! Loads a value from the current node - small unsigned overload
631 1482356 : template <class T, traits::EnableIf<std::is_unsigned<T>::value,
632 : sizeof(T) < sizeof(uint64_t),
633 740233 : !std::is_same<bool, T>::value> = traits::sfinae> inline
634 740233 : void loadValue(T & val)
635 : {
636 2285056 : search();
637 :
638 2285056 : val = static_cast<T>( itsIteratorStack.back().value().GetUint() );
639 2284017 : ++itsIteratorStack.back();
640 2285056 : }
641 4569073 :
642 2285056 : //! Loads a value from the current node - bool overload
643 2352724 : void loadValue(bool & val) { search(); val = itsIteratorStack.back().value().GetBool(); ++itsIteratorStack.back(); }
644 2284017 : //! Loads a value from the current node - int64 overload
645 2352724 : void loadValue(int64_t & val) { search(); val = itsIteratorStack.back().value().GetInt64(); ++itsIteratorStack.back(); }
646 67764 : //! Loads a value from the current node - uint64 overload
647 68707 : void loadValue(uint64_t & val) { search(); val = itsIteratorStack.back().value().GetUint64(); ++itsIteratorStack.back(); }
648 144373 : //! Loads a value from the current node - float overload
649 68707 : void loadValue(float & val) { search(); val = static_cast<float>(itsIteratorStack.back().value().GetDouble()); ++itsIteratorStack.back(); }
650 749202 : //! Loads a value from the current node - double overload
651 75666 : void loadValue(double & val) { search(); val = itsIteratorStack.back().value().GetDouble(); ++itsIteratorStack.back(); }
652 749202 : //! Loads a value from the current node - string overload
653 689246 : void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
654 681838 : //! Loads a nullptr from the current node
655 1356682 : void loadValue(std::nullptr_t&) { search(); CEREAL_RAPIDJSON_ASSERT(itsIteratorStack.back().value().IsNull()); ++itsIteratorStack.back(); }
656 681838 :
657 874154 : // Special cases to handle various flavors of long, which tend to conflict with
658 675644 : // the int32_t or int64_t on various compiler/OS combinations. MSVC doesn't need any of this.
659 856645 : #ifndef _MSC_VER
660 194612 : private:
661 182555 : //! 32 bit signed long loading from current node
662 457768 : template <class T> inline
663 182602 : typename std::enable_if<sizeof(T) == sizeof(std::int32_t) && std::is_signed<T>::value, void>::type
664 277119 : loadLong(T & l){ loadValue( reinterpret_cast<std::int32_t&>( l ) ); }
665 274570 :
666 275465 : //! non 32 bit signed long loading from current node
667 190182 : template <class T> inline
668 95568 : typename std::enable_if<sizeof(T) == sizeof(std::int64_t) && std::is_signed<T>::value, void>::type
669 154167 : loadLong(T & l){ loadValue( reinterpret_cast<std::int64_t&>( l ) ); }
670 95318 :
671 154867 : //! 32 bit unsigned long loading from current node
672 60100 : template <class T> inline
673 60700 : typename std::enable_if<sizeof(T) == sizeof(std::uint32_t) && !std::is_signed<T>::value, void>::type
674 120800 : loadLong(T & lu){ loadValue( reinterpret_cast<std::uint32_t&>( lu ) ); }
675 60400 :
676 120588 : //! non 32 bit unsigned long loading from current node
677 60600 : template <class T> inline
678 120288 : typename std::enable_if<sizeof(T) == sizeof(std::uint64_t) && !std::is_signed<T>::value, void>::type
679 60987 : loadLong(T & lu){ loadValue( reinterpret_cast<std::uint64_t&>( lu ) ); }
680 60588 :
681 150752 : public:
682 61088 : //! Serialize a long if it would not be caught otherwise
683 80087 : template <class T> inline
684 89967 : typename std::enable_if<std::is_same<T, long>::value &&
685 80087 : sizeof(T) >= sizeof(std::int64_t) &&
686 20100 : !std::is_same<T, std::int64_t>::value, void>::type
687 20200 : loadValue( T & t ){ loadLong(t); }
688 40100 :
689 21100 : //! Serialize an unsigned long if it would not be caught otherwise
690 20100 : template <class T> inline
691 20100 : typename std::enable_if<std::is_same<T, unsigned long>::value &&
692 21000 : sizeof(T) >= sizeof(std::uint64_t) &&
693 : !std::is_same<T, std::uint64_t>::value, void>::type
694 400 : loadValue( T & t ){ loadLong(t); }
695 20000 : #endif // _MSC_VER
696 400 :
697 400 : private:
698 20400 : //! Convert a string to a long long
699 800 : void stringToNumber( std::string const & str, long long & val ) { val = std::stoll( str ); }
700 400 : //! Convert a string to an unsigned long long
701 500 : void stringToNumber( std::string const & str, unsigned long long & val ) { val = std::stoull( str ); }
702 20400 : //! Convert a string to a long double
703 500 : void stringToNumber( std::string const & str, long double & val ) { val = std::stold( str ); }
704 100 :
705 20100 : public:
706 200 : //! Loads a value from the current node - long double and long long overloads
707 100 : template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
708 200 : !std::is_same<T, long>::value,
709 100 : !std::is_same<T, unsigned long>::value,
710 200 : !std::is_same<T, std::int64_t>::value,
711 100 : !std::is_same<T, std::uint64_t>::value,
712 100 : (sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long))> = traits::sfinae>
713 200 : inline void loadValue(T & val)
714 100 : {
715 300 : std::string encoded;
716 100 : loadValue( encoded );
717 500 : stringToNumber( encoded, val );
718 200 : }
719 200 :
720 600 : //! Loads the size for a SizeTag
721 200 : void loadSize(size_type & size)
722 200 : {
723 200 : if (itsIteratorStack.size() == 1)
724 300 : size = itsDocument.Size();
725 : else
726 200 : size = (itsIteratorStack.rbegin() + 1)->value().Size();
727 300 : }
728 200 :
729 700 : //! @}
730 500 :
731 400 : private:
732 800 : const char * itsNextName; //!< Next name set by NVP
733 300 : ReadStream itsReadStream; //!< Rapidjson write stream
734 500 : std::vector<Iterator> itsIteratorStack; //!< 'Stack' of rapidJSON iterators
735 6500 : CEREAL_RAPIDJSON_NAMESPACE::Document itsDocument; //!< Rapidjson document
736 : };
737 6500 :
738 6200 : // ######################################################################
739 : // JSONArchive prologue and epilogue functions
740 12400 : // ######################################################################
741 6300 :
742 : // ######################################################################
743 6400 : //! Prologue for NVPs for JSON archives
744 6400 : /*! NVPs do not start or finish nodes - they just set up the names */
745 100 : template <class T> inline
746 300 : void prologue( JSONOutputArchive &, NameValuePair<T> const & )
747 100 : { }
748 100 :
749 1400 : //! Prologue for NVPs for JSON archives
750 : template <class T> inline
751 1300 : void prologue( JSONInputArchive &, NameValuePair<T> const & )
752 1300 : { }
753 :
754 2600 : // ######################################################################
755 1300 : //! Epilogue for NVPs for JSON archives
756 : /*! NVPs do not start or finish nodes - they just set up the names */
757 1300 : template <class T> inline
758 1300 : void epilogue( JSONOutputArchive &, NameValuePair<T> const & )
759 : { }
760 11427 :
761 11427 : //! Epilogue for NVPs for JSON archives
762 2950 : /*! NVPs do not start or finish nodes - they just set up the names */
763 16675 : template <class T> inline
764 13128 : void epilogue( JSONInputArchive &, NameValuePair<T> const & )
765 7154 : { }
766 7407 :
767 3659 : // ######################################################################
768 9308 : //! Prologue for deferred data for JSON archives
769 8160 : /*! Do nothing for the defer wrapper */
770 4160 : template <class T> inline
771 7712 : void prologue( JSONOutputArchive &, DeferredData<T> const & )
772 8715 : { }
773 7415 :
774 243267 : //! Prologue for deferred data for JSON archives
775 243524 : template <class T> inline
776 31176 : void prologue( JSONInputArchive &, DeferredData<T> const & )
777 261193 : { }
778 271509 :
779 59787 : // ######################################################################
780 56652 : //! Epilogue for deferred for JSON archives
781 66076 : /*! NVPs do not start or finish nodes - they just set up the names */
782 57746 : template <class T> inline
783 55950 : void epilogue( JSONOutputArchive &, DeferredData<T> const & )
784 56488 : { }
785 69158 :
786 66364 : //! Epilogue for deferred for JSON archives
787 45408 : /*! Do nothing for the defer wrapper */
788 403699 : template <class T> inline
789 412695 : void epilogue( JSONInputArchive &, DeferredData<T> const & )
790 72484 : { }
791 411008 :
792 397016 : // ######################################################################
793 66129 : //! Prologue for SizeTags for JSON archives
794 62172 : /*! SizeTags are strictly ignored for JSON, they just indicate
795 439338 : that the current node should be made into an array */
796 442015 : template <class T> inline
797 77774 : void prologue( JSONOutputArchive & ar, SizeTag<T> const & )
798 536709 : {
799 548764 : ar.makeArray();
800 126619 : }
801 186059 :
802 209921 : //! Prologue for SizeTags for JSON archives
803 150180 : template <class T> inline
804 138339 : void prologue( JSONInputArchive &, SizeTag<T> const & )
805 158898 : { }
806 149091 :
807 135852 : // ######################################################################
808 126097 : //! Epilogue for SizeTags for JSON archives
809 156473 : /*! SizeTags are strictly ignored for JSON */
810 174791 : template <class T> inline
811 233928 : void epilogue( JSONOutputArchive &, SizeTag<T> const & )
812 249747 : { }
813 156552 :
814 231916 : //! Epilogue for SizeTags for JSON archives
815 205370 : template <class T> inline
816 96081 : void epilogue( JSONInputArchive &, SizeTag<T> const & )
817 86769 : { }
818 277592 :
819 275981 : // ######################################################################
820 272583 : //! Prologue for all other types for JSON archives (except minimal types)
821 468797 : /*! Starts a new node, named either automatically or by some NVP,
822 297398 : that may be given data by the type about to be archived
823 312397 :
824 293190 : Minimal types do not start or finish nodes */
825 137084 : template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
826 137691 : !traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value,
827 302453 : !traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
828 315938 : inline void prologue( JSONOutputArchive & ar, T const & )
829 126995 : {
830 318686 : ar.startNode();
831 307978 : }
832 151600 :
833 164006 : //! Prologue for all other types for JSON archives
834 113507 : template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
835 141101 : !traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value,
836 222187 : !traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
837 181788 : inline void prologue( JSONInputArchive & ar, T const & )
838 91908 : {
839 166803 : ar.startNode();
840 364501 : }
841 281230 :
842 566911 : // ######################################################################
843 278584 : //! Epilogue for all other types other for JSON archives (except minimal types)
844 765984 : /*! Finishes the node created in the prologue
845 1063386 :
846 212194 : Minimal types do not start or finish nodes */
847 767294 : template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
848 902894 : !traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value,
849 357887 : !traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
850 431882 : inline void epilogue( JSONOutputArchive & ar, T const & )
851 498483 : {
852 428495 : ar.finishNode();
853 373689 : }
854 353588 :
855 334401 : //! Epilogue for all other types other for JSON archives
856 346301 : template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
857 383700 : !traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value,
858 238500 : !traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
859 187200 : inline void epilogue( JSONInputArchive & ar, T const & )
860 402992 : {
861 386792 : ar.finishNode();
862 54507 : }
863 270283 :
864 471133 : // ######################################################################
865 262857 : //! Prologue for arithmetic types for JSON archives
866 74925 : inline
867 272497 : void prologue( JSONOutputArchive & ar, std::nullptr_t const & )
868 266572 : {
869 60386 : ar.writeName();
870 56983 : }
871 48494 :
872 38097 : //! Prologue for arithmetic types for JSON archives
873 237096 : inline
874 289381 : void prologue( JSONInputArchive &, std::nullptr_t const & )
875 114988 : { }
876 267001 :
877 319888 : // ######################################################################
878 134293 : //! Epilogue for arithmetic types for JSON archives
879 86005 : inline
880 77106 : void epilogue( JSONOutputArchive &, std::nullptr_t const & )
881 77109 : { }
882 162011 :
883 68600 : //! Epilogue for arithmetic types for JSON archives
884 150207 : inline
885 236507 : void epilogue( JSONInputArchive &, std::nullptr_t const & )
886 91429 : { }
887 595425 :
888 167404 : // ######################################################################
889 553290 : //! Prologue for arithmetic types for JSON archives
890 976294 : template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
891 234700 : void prologue( JSONOutputArchive & ar, T const & )
892 550111 : {
893 699616 : ar.writeName();
894 385804 : }
895 183022 :
896 235309 : //! Prologue for arithmetic types for JSON archives
897 354913 : template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
898 292612 : void prologue( JSONInputArchive &, T const & )
899 174402 : { }
900 173602 :
901 303606 : // ######################################################################
902 263903 : //! Epilogue for arithmetic types for JSON archives
903 142708 : template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
904 343562 : void epilogue( JSONOutputArchive &, T const & )
905 442858 : { }
906 253912 :
907 224380 : //! Epilogue for arithmetic types for JSON archives
908 333976 : template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
909 155504 : void epilogue( JSONInputArchive &, T const & )
910 46502 : { }
911 26402 :
912 35404 : // ######################################################################
913 37204 : //! Prologue for strings for JSON archives
914 27400 : template<class CharT, class Traits, class Alloc> inline
915 28302 : void prologue(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const &)
916 25532 : {
917 29325 : ar.writeName();
918 29530 : }
919 23524 :
920 238618 : //! Prologue for strings for JSON archives
921 26794 : template<class CharT, class Traits, class Alloc> inline
922 287734 : void prologue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
923 456173 : { }
924 96289 :
925 330149 : // ######################################################################
926 277123 : //! Epilogue for strings for JSON archives
927 125562 : template<class CharT, class Traits, class Alloc> inline
928 149701 : void epilogue(JSONOutputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
929 117982 : { }
930 76282 :
931 126302 : //! Epilogue for strings for JSON archives
932 97901 : template<class CharT, class Traits, class Alloc> inline
933 37113 : void epilogue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
934 56604 : { }
935 47512 :
936 470122 : // ######################################################################
937 26406 : // Common JSONArchive serialization functions
938 490514 : // ######################################################################
939 932814 : //! Serializing NVP types to JSON
940 135206 : template <class T> inline
941 468312 : void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive & ar, NameValuePair<T> const & t )
942 689292 : {
943 268710 : ar.setNextName( t.name );
944 264010 : ar( t.value );
945 311958 : }
946 320719 :
947 520390 : template <class T> inline
948 238682 : void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, NameValuePair<T> & t )
949 275914 : {
950 491709 : ar.setNextName( t.name );
951 311713 : ar( t.value );
952 252997 : }
953 264608 :
954 342883 : //! Saving for nullptr to JSON
955 331781 : inline
956 83680 : void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::nullptr_t const & t)
957 391675 : {
958 242165 : ar.saveValue( t );
959 294057 : }
960 416389 :
961 121880 : //! Loading arithmetic from JSON
962 284701 : inline
963 260202 : void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::nullptr_t & t)
964 82404 : {
965 91912 : ar.loadValue( t );
966 97912 : }
967 56209 :
968 92206 : //! Saving for arithmetic to JSON
969 118635 : template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
970 39711 : void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, T const & t)
971 99851 : {
972 139173 : ar.saveValue( t );
973 55676 : }
974 69047 :
975 98529 : //! Loading arithmetic from JSON
976 83851 : template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
977 48692 : void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, T & t)
978 47382 : {
979 66676 : ar.loadValue( t );
980 71098 : }
981 491214 :
982 33602 : //! saving string to JSON
983 512616 : template<class CharT, class Traits, class Alloc> inline
984 945723 : void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
985 323002 : {
986 479708 : ar.saveValue( str );
987 783911 : }
988 626712 :
989 156308 : //! loading string from JSON
990 329804 : template<class CharT, class Traits, class Alloc> inline
991 465506 : void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
992 315209 : {
993 216911 : ar.loadValue( str );
994 163505 : }
995 356006 :
996 406205 : // ######################################################################
997 163403 : //! Saving SizeTags to JSON
998 453562 : template <class T> inline
999 344313 : void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive &, SizeTag<T> const & )
1000 552655 : {
1001 565955 : // nothing to do here, we don't explicitly save the size
1002 153008 : }
1003 446418 :
1004 358538 : //! Loading SizeTags from JSON
1005 68389 : template <class T> inline
1006 45652 : void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, SizeTag<T> & st )
1007 229216 : {
1008 103489 : ar.loadSize( st.size );
1009 163201 : }
1010 304856 : } // namespace cereal
1011 89702 :
1012 196381 : // register archives for polymorphic support
1013 163831 : CEREAL_REGISTER_ARCHIVE(cereal::JSONInputArchive)
1014 53207 : CEREAL_REGISTER_ARCHIVE(cereal::JSONOutputArchive)
1015 69158 :
1016 140806 : // tie input and output archives together
1017 42800 : CEREAL_SETUP_ARCHIVE_TRAITS(cereal::JSONInputArchive, cereal::JSONOutputArchive)
1018 127755 :
1019 222949 : #endif // CEREAL_ARCHIVES_JSON_HPP_
|