LCOV - code coverage report

Current view: | top level - cereal/archives - json.hpp (source / functions) |  |  | Hit | Total | Coverage
Test: | coverage.info |  | Lines: | 237 | 245 | 96.7 %
Date: | 2022-01-16 21:05:07 |  | Functions: | 1817 | 1866 | 97.4 %

              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 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"
          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             :           //! 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        3704 :             itsIndentLength( indentLength ) { }
         148             :
         149             :         private:
         150             :           friend class JSONOutputArchive;
         151             :           int itsPrecision;
         152             :           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             :       {
         166        3704 :         itsWriter.SetMaxDecimalPlaces( options.itsPrecision );
         167        3704 :         itsWriter.SetIndent( options.itsIndentChar, options.itsIndentLength );
         168        3704 :         itsNameCounter.push(0);
         169        3704 :         itsNodeStack.push(NodeType::StartObject);
         170        3704 :       }
         171             :
         172             :       //! Destructor, flushes the JSON
         173        3704 :       ~JSONOutputArchive() CEREAL_NOEXCEPT
         174        3704 :       {
         175        3704 :         if (itsNodeStack.top() == NodeType::InObject)
         176        3704 :           itsWriter.EndObject();
         177           0 :         else if (itsNodeStack.top() == NodeType::InArray)
         178           0 :           itsWriter.EndArray();
         179        3704 :       }
         180             :
         181             :       //! Saves some binary data, encoded as a base64 string, with an optional name
         182             :       /*! This will create a new node, optionally named, and insert a value that consists of
         183             :           the data encoded as a base64 string */
         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             :
         193             :       //! @}
         194             :       /*! @name Internal Functionality
         195             :           Functionality designed for use by those requiring control over the inner mechanisms of
         196             :           the JSONOutputArchive */
         197             :       //! @{
         198             :
         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     1359429 :       void startNode()
         205             :       {
         206     1359429 :         writeName();
         207     1359429 :         itsNodeStack.push(NodeType::StartObject);
         208     1359429 :         itsNameCounter.push(0);
         209     1359429 :       }
         210             :
         211             :       //! Designates the most recently added node as finished
         212     1359429 :       void finishNode()
         213             :       {
         214             :         // if we ended up serializing an empty object or array, writeName
         215             :         // will never have been called - so start and then immediately end
         216             :         // the object/array.
         217             :         //
         218             :         // We'll also end any object/arrays we happen to be in
         219     1359429 :         switch(itsNodeStack.top())
         220             :         {
         221         303 :           case NodeType::StartArray:
         222         303 :             itsWriter.StartArray();
         223             :             // fall through
         224       10300 :           case NodeType::InArray:
         225       10300 :             itsWriter.EndArray();
         226       10300 :             break;
         227         700 :           case NodeType::StartObject:
         228         700 :             itsWriter.StartObject();
         229             :             // fall through
         230     1349129 :           case NodeType::InObject:
         231     1349129 :             itsWriter.EndObject();
         232     1349129 :             break;
         233             :         }
         234             :
         235     1359429 :         itsNodeStack.pop();
         236     1359429 :         itsNameCounter.pop();
         237     1359429 :       }
         238             :
         239             :       //! Sets the name for the next node created with startNode
         240      741633 :       void setNextName( const char * name )
         241             :       {
         242      741633 :         itsNextName = name;
         243      741633 :       }
         244             :
         245             :       //! Saves a bool to the current node
         246       11408 :       void saveValue(bool b)                { itsWriter.Bool(b);                                                         }
         247             :       //! Saves an int to the current node
         248     2337099 :       void saveValue(int i)                 { itsWriter.Int(i);                                                          }
         249             :       //! Saves a uint to the current node
         250       86209 :       void saveValue(unsigned u)            { itsWriter.Uint(u);                                                         }
         251             :       //! Saves an int64 to the current node
         252        1301 :       void saveValue(int64_t i64)           { itsWriter.Int64(i64);                                                      }
         253             :       //! Saves a uint64 to the current node
         254        1645 :       void saveValue(uint64_t u64)          { itsWriter.Uint64(u64);                                                     }
         255             :       //! Saves a double to the current node
         256        2203 :       void saveValue(double d)              { itsWriter.Double(d);                                                       }
         257             :       //! Saves a string to the current node
         258     2063291 :       void saveValue(std::string const & s) { itsWriter.String(s.c_str(), static_cast<CEREAL_RAPIDJSON_NAMESPACE::SizeType>( s.size() )); }
         259             :       //! Saves a const char * to the current node
         260      741633 :       void saveValue(char const * s)        { itsWriter.String(s);                                                       }
         261             :       //! Saves a nullptr to the current node
         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             :
         268             :       //! 32 bit signed long saving to current node
         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             :
         273             :       //! non 32 bit signed long saving to current node
         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             :
         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             : #if defined(_MSC_VER) && _MSC_VER < 1916
         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, int>::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, 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             :
         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         600 :       void saveValue(T const & t)
         315             :       {
         316         600 :         std::stringstream ss; ss.precision( std::numeric_limits<long double>::max_digits10 );
         317         600 :         ss << t;
         318         600 :         saveValue( ss.str() );
         319         600 :       }
         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             :             1. (optional) Set the name for the next node to be created, usually done by an NVP
         329             :             2. Start the node
         330             :             3. (if there is data to save) Write the name of the node (this function)
         331             :             4. (if there is data to save) Save the data (with saveValue)
         332             :             5. Finish the node
         333             :           */
         334     3871259 :       void writeName()
         335             :       {
         336     3871259 :         NodeType const & nodeType = itsNodeStack.top();
         337             :
         338             :         // Start up either an object or an array, depending on state
         339     3871259 :         if(nodeType == NodeType::StartArray)
         340             :         {
         341        9997 :           itsWriter.StartArray();
         342        9997 :           itsNodeStack.top() = NodeType::InArray;
         343             :         }
         344     3861262 :         else if(nodeType == NodeType::StartObject)
         345             :         {
         346     1352133 :           itsNodeStack.top() = NodeType::InObject;
         347     1352133 :           itsWriter.StartObject();
         348             :         }
         349             :
         350             :         // Array types do not output names
         351     3871259 :         if(nodeType == NodeType::InArray) return;
         352             :
         353     2732959 :         if(itsNextName == nullptr)
         354             :         {
         355     5973978 :           std::string name = "value" + std::to_string( itsNameCounter.top()++ ) + "\0";
         356     1991326 :           saveValue(name);
         357             :         }
         358             :         else
         359             :         {
         360      741633 :           saveValue(itsNextName);
         361      741633 :           itsNextName = nullptr;
         362             :         }
         363             :       }
         364             :
         365             :       //! Designates that the current node should be output as an array, not an object
         366       10300 :       void makeArray()
         367             :       {
         368       10300 :         itsNodeStack.top() = NodeType::StartArray;
         369       10300 :       }
         370             :
         371             :       //! @}
         372             :
         373             :     private:
         374             :       WriteStream itsWriteStream;          //!< Rapidjson write stream
         375             :       JSONWriter itsWriter;                //!< Rapidjson writer
         376             :       char const * itsNextName;            //!< The next name
         377             :       std::stack<uint32_t> itsNameCounter; //!< Counter for creating unique names for unnamed nodes
         378             :       std::stack<NodeType> itsNodeStack;
         379             :   }; // JSONOutputArchive
         380             :
         381             :   // ######################################################################
         382             :   //! An input archive designed to load data from JSON
         383             :   /*! This archive uses RapidJSON to read in a JSON archive.
         384             :
         385             :       As with the output JSON archive, the preferred way to use this archive is in
         386             :       an RAII fashion, ensuring its destruction after all data has been read.
         387             :
         388             :       Input JSON should have been produced by the JSONOutputArchive.  Data can
         389             :       only be added to dynamically sized containers (marked by JSON arrays) -
         390             :       the input archive will determine their size by looking at the number of child nodes.
         391             :       Only JSON originating from a JSONOutputArchive is officially supported, but data
         392             :       from other sources may work if properly formatted.
         393             :
         394             :       The JSONInputArchive does not require that nodes are loaded in the same
         395             :       order they were saved by JSONOutputArchive.  Using name value pairs (NVPs),
         396             :       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        3804 :       JSONInputArchive(std::istream & stream) :
         436             :         InputArchive<JSONInputArchive>(this),
         437             :         itsNextName( nullptr ),
         438        3804 :         itsReadStream(stream)
         439             :       {
         440        3804 :         itsDocument.ParseStream<>(itsReadStream);
         441        3804 :         if (itsDocument.IsArray())
         442           0 :           itsIteratorStack.emplace_back(itsDocument.Begin(), itsDocument.End());
         443             :         else
         444        3804 :           itsIteratorStack.emplace_back(itsDocument.MemberBegin(), itsDocument.MemberEnd());
         445        3804 :       }
         446             :
         447        3804 :       ~JSONInputArchive() CEREAL_NOEXCEPT = default;
         448             :
         449             :       //! 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             :
         453             :           Note that this follows the same ordering rules specified in the class description in regards
         454             :           to loading in/out of order */
         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:
         471             :       //! @}
         472             :       /*! @name Internal Functionality
         473             :           Functionality designed for use by those requiring control over the inner mechanisms of
         474             :           the JSONInputArchive */
         475             :       //! @{
         476             :
         477             :       //! An internal iterator that handles both array and object types
         478             :       /*! This class is a variant and holds both types of iterators that
         479             :           rapidJSON supports - one for arrays and one for objects. */
         480             :       class Iterator
         481             :       {
         482             :         public:
         483             :           Iterator() : itsIndex( 0 ), itsType(Null_) {}
         484             :
         485     1353233 :           Iterator(MemberIterator begin, MemberIterator end) :
         486     1353233 :             itsMemberItBegin(begin), itsMemberItEnd(end), itsIndex(0), itsSize(std::distance(begin, end)), itsType(Member)
         487             :           {
         488     1353233 :             if( itsSize == 0 )
         489         700 :               itsType = Null_;
         490     1353233 :           }
         491             :
         492       10300 :           Iterator(ValueIterator begin, ValueIterator end) :
         493       10300 :             itsValueItBegin(begin), itsIndex(0), itsSize(std::distance(begin, end)), itsType(Value)
         494             :           {
         495       10300 :             if( itsSize == 0 )
         496         303 :               itsType = Null_;
         497       10300 :           }
         498             :
         499             :           //! Advance to the next node
         500     3871459 :           Iterator & operator++()
         501             :           {
         502     3871459 :             ++itsIndex;
         503     3871459 :             return *this;
         504             :           }
         505             :
         506             :           //! Get the value of the current node
         507     6601521 :           GenericValue const & value()
         508             :           {
         509     6601521 :             if( itsIndex >= itsSize )
         510           0 :               throw cereal::Exception("No more objects in input");
         511             :
         512     6601521 :             switch(itsType)
         513             :             {
         514     3113900 :               case Value : return itsValueItBegin[itsIndex];
         515     3487617 :               case Member: return itsMemberItBegin[itsIndex].value;
         516           0 :               default: throw cereal::Exception("JSONInputArchive internal error: null or empty iterator to object or array!");
         517             :             }
         518             :           }
         519             :
         520             :           //! Get the name of the current node, or nullptr if it has no name
         521      741733 :           const char * name() const
         522             :           {
         523      741733 :             if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
         524      741633 :               return itsMemberItBegin[itsIndex].name.GetString();
         525             :             else
         526         100 :               return nullptr;
         527             :           }
         528             :
         529             :           //! Adjust our position such that we are at the node with the given name
         530             :           /*! @throws Exception if no such named node exists */
         531         900 :           inline void search( const char * searchName )
         532             :           {
         533         900 :             const auto len = std::strlen( searchName );
         534         900 :             size_t index = 0;
         535        3100 :             for( auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
         536             :             {
         537        3100 :               const auto currentName = it->name.GetString();
         538        3100 :               if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
         539         900 :                   ( std::strlen( currentName ) == len ) )
         540             :               {
         541         900 :                 itsIndex = index;
         542         900 :                 return;
         543             :               }
         544             :             }
         545             :
         546           0 :             throw Exception("JSON Parsing failed - provided NVP (" + std::string(searchName) + ") not found");
         547             :           }
         548             :
         549             :         private:
         550             :           MemberIterator itsMemberItBegin, itsMemberItEnd; //!< The member iterator (object)
         551             :           ValueIterator itsValueItBegin;                   //!< The value iterator (array)
         552             :           size_t itsIndex, itsSize;                        //!< The current index of this iterator
         553             :           enum Type {Value, Member, Null_} itsType;        //!< Whether this holds values (array) or members (objects) or nothing
         554             :       };
         555             :
         556             :       //! Searches for the expectedName node if it doesn't match the actualName
         557             :       /*! This needs to be called before every load or node start occurs.  This function will
         558             :           check to see if an NVP has been provided (with setNextName) and if so, see if that name matches the actual
         559             :           next name given.  If the names do not match, it will search in the current level of the JSON for that name.
         560             :           If the name is not found, an exception will be thrown.
         561             :
         562             :           Resets the NVP name after called.
         563             :
         564             :           @throws Exception if an expectedName is given and not found */
         565     3871759 :       inline void search()
         566             :       {
         567             :         // store pointer to itsNextName locally and reset to nullptr in case search() throws
         568     3871759 :         auto localNextName = itsNextName;
         569     3871759 :         itsNextName = nullptr;
         570             :
         571             :         // The name an NVP provided with setNextName()
         572     3871759 :         if( localNextName )
         573             :         {
         574             :           // The actual name of the current node
         575      741733 :           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      741733 :           if( !actualName || std::strcmp( localNextName, actualName ) != 0 )
         579         900 :             itsIteratorStack.back().search( localNextName );
         580             :         }
         581     3871759 :       }
         582             :
         583             :     public:
         584             :       //! Starts a new node, going into its proper iterator
         585             :       /*! This places an iterator for the next node to be parsed onto the iterator stack.  If the next
         586             :           node is an array, this will be a value iterator, otherwise it will be a member iterator.
         587             :
         588             :           By default our strategy is to start with the document root node and then recursively iterate through
         589             :           all children in the order they show up in the document.
         590             :           We don't need to know NVPs to do this; we'll just blindly load in the order things appear in.
         591             :
         592             :           If we were given an NVP, we will search for it if it does not match our the name of the next node
         593             :           that would normally be loaded.  This functionality is provided by search(). */
         594     1359729 :       void startNode()
         595             :       {
         596     1359729 :         search();
         597             :
         598     1359729 :         if(itsIteratorStack.back().value().IsArray())
         599       10300 :           itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
         600             :         else
         601     1349429 :           itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
         602     1359729 :       }
         603             :
         604             :       //! Finishes the most recently started node
         605     1359429 :       void finishNode()
         606             :       {
         607     1359429 :         itsIteratorStack.pop_back();
         608     1359429 :         ++itsIteratorStack.back();
         609     1359429 :       }
         610             :
         611             :       //! Retrieves the current node name
         612             :       /*! @return nullptr if no name exists */
         613             :       const char * getNodeName() const
         614             :       {
         615             :         return itsIteratorStack.back().name();
         616             :       }
         617             :
         618             :       //! Sets the name for the next node created with startNode
         619      741733 :       void setNextName( const char * name )
         620             :       {
         621      741733 :         itsNextName = name;
         622      741733 :       }
         623             :
         624             :       //! Loads a value from the current node - small signed overload
         625             :       template <class T, traits::EnableIf<std::is_signed<T>::value,
         626             :                                           sizeof(T) < sizeof(int64_t)> = traits::sfinae> inline
         627     2285007 :       void loadValue(T & val)
         628             :       {
         629     2285007 :         search();
         630             :
         631     2285007 :         val = static_cast<T>( itsIteratorStack.back().value().GetInt() );
         632     2285007 :         ++itsIteratorStack.back();
         633     2285007 :       }
         634             :
         635             :       //! Loads a value from the current node - small unsigned overload
         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      138501 :       void loadValue(T & val)
         640             :       {
         641      138501 :         search();
         642             :
         643      138501 :         val = static_cast<T>( itsIteratorStack.back().value().GetUint() );
         644      138501 :         ++itsIteratorStack.back();
         645      138501 :       }
         646             :
         647             :       //! Loads a value from the current node - bool overload
         648       11408 :       void loadValue(bool & val)        { search(); val = itsIteratorStack.back().value().GetBool(); ++itsIteratorStack.back(); }
         649             :       //! Loads a value from the current node - int64 overload
         650        1301 :       void loadValue(int64_t & val)     { search(); val = itsIteratorStack.back().value().GetInt64(); ++itsIteratorStack.back(); }
         651             :       //! Loads a value from the current node - uint64 overload
         652        1645 :       void loadValue(uint64_t & val)    { search(); val = itsIteratorStack.back().value().GetUint64(); ++itsIteratorStack.back(); }
         653             :       //! Loads a value from the current node - float overload
         654         800 :       void loadValue(float & val)       { search(); val = static_cast<float>(itsIteratorStack.back().value().GetDouble()); ++itsIteratorStack.back(); }
         655             :       //! Loads a value from the current node - double overload
         656        1403 :       void loadValue(double & val)      { search(); val = itsIteratorStack.back().value().GetDouble(); ++itsIteratorStack.back(); }
         657             :       //! Loads a value from the current node - string overload
         658       71965 :       void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
         659             :       //! Loads a nullptr from the current node
         660             :       void loadValue(std::nullptr_t&)   { search(); CEREAL_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:
         666             :       //! 32 bit signed long loading from current node
         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             :
         671             :       //! non 32 bit signed long loading from current node
         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             :
         676             :       //! 32 bit unsigned long loading from current node
         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             :
         681             :       //! non 32 bit unsigned long loading from current node
         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:
         687             :       //! Serialize a long if it would not be caught otherwise
         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             :
         694             :       //! Serialize an unsigned long if it would not be caught otherwise
         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:
         703             :       //! Convert a string to a long long
         704         100 :       void stringToNumber( std::string const & str, long long & val ) { val = std::stoll( str ); }
         705             :       //! Convert a string to an unsigned long long
         706         200 :       void stringToNumber( std::string const & str, unsigned long long & val ) { val = std::stoull( str ); }
         707             :       //! Convert a string to a long double
         708         300 :       void stringToNumber( std::string const & str, long double & val ) { val = std::stold( str ); }
         709             :
         710             :     public:
         711             :       //! Loads a value from the current node - long double and long long overloads
         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         600 :       inline void loadValue(T & val)
         719             :       {
         720        1200 :         std::string encoded;
         721         600 :         loadValue( encoded );
         722         600 :         stringToNumber( encoded, val );
         723         600 :       }
         724             :
         725             :       //! Loads the size for a SizeTag
         726       10300 :       void loadSize(size_type & size)
         727             :       {
         728       10300 :         if (itsIteratorStack.size() == 1)
         729           0 :           size = itsDocument.Size();
         730             :         else
         731       10300 :           size = (itsIteratorStack.rbegin() + 1)->value().Size();
         732       10300 :       }
         733             :
         734             :       //! @}
         735             :
         736             :     private:
         737             :       const char * itsNextName;               //!< Next name set by NVP
         738             :       ReadStream itsReadStream;               //!< Rapidjson write stream
         739             :       std::vector<Iterator> itsIteratorStack; //!< 'Stack' of rapidJSON iterators
         740             :       CEREAL_RAPIDJSON_NAMESPACE::Document itsDocument; //!< Rapidjson document
         741             :   };
         742             :
         743             :   // ######################################################################
         744             :   // JSONArchive prologue and epilogue functions
         745             :   // ######################################################################
         746             :
         747             :   // ######################################################################
         748             :   //! Prologue for NVPs for JSON archives
         749             :   /*! NVPs do not start or finish nodes - they just set up the names */
         750             :   template <class T> inline
         751      741633 :   void prologue( JSONOutputArchive &, NameValuePair<T> const & )
         752      741633 :   { }
         753             :
         754             :   //! Prologue for NVPs for JSON archives
         755             :   template <class T> inline
         756      741733 :   void prologue( JSONInputArchive &, NameValuePair<T> const & )
         757      741733 :   { }
         758             :
         759             :   // ######################################################################
         760             :   //! Epilogue for NVPs for JSON archives
         761             :   /*! NVPs do not start or finish nodes - they just set up the names */
         762             :   template <class T> inline
         763      741633 :   void epilogue( JSONOutputArchive &, NameValuePair<T> const & )
         764      741633 :   { }
         765             :
         766             :   //! Epilogue for NVPs for JSON archives
         767             :   /*! NVPs do not start or finish nodes - they just set up the names */
         768             :   template <class T> inline
         769      741533 :   void epilogue( JSONInputArchive &, NameValuePair<T> const & )
         770      741533 :   { }
         771             :
         772             :   // ######################################################################
         773             :   //! Prologue for deferred data for JSON archives
         774             :   /*! Do nothing for the defer wrapper */
         775             :   template <class T> inline
         776        1000 :   void prologue( JSONOutputArchive &, DeferredData<T> const & )
         777        1000 :   { }
         778             :
         779             :   //! Prologue for deferred data for JSON archives
         780             :   template <class T> inline
         781        1000 :   void prologue( JSONInputArchive &, DeferredData<T> const & )
         782        1000 :   { }
         783             :
         784             :   // ######################################################################
         785             :   //! Epilogue for deferred for JSON archives
         786             :   /*! NVPs do not start or finish nodes - they just set up the names */
         787             :   template <class T> inline
         788        1000 :   void epilogue( JSONOutputArchive &, DeferredData<T> const & )
         789        1000 :   { }
         790             :
         791             :   //! Epilogue for deferred for JSON archives
         792             :   /*! Do nothing for the defer wrapper */
         793             :   template <class T> inline
         794        1000 :   void epilogue( JSONInputArchive &, DeferredData<T> const & )
         795        1000 :   { }
         796             :
         797             :   // ######################################################################
         798             :   //! Prologue for SizeTags for JSON archives
         799             :   /*! SizeTags are strictly ignored for JSON, they just indicate
         800             :       that the current node should be made into an array */
         801             :   template <class T> inline
         802       10300 :   void prologue( JSONOutputArchive & ar, SizeTag<T> const & )
         803             :   {
         804       10300 :     ar.makeArray();
         805       10300 :   }
         806             :
         807             :   //! Prologue for SizeTags for JSON archives
         808             :   template <class T> inline
         809       10300 :   void prologue( JSONInputArchive &, SizeTag<T> const & )
         810       10300 :   { }
         811             :
         812             :   // ######################################################################
         813             :   //! Epilogue for SizeTags for JSON archives
         814             :   /*! SizeTags are strictly ignored for JSON */
         815             :   template <class T> inline
         816       10300 :   void epilogue( JSONOutputArchive &, SizeTag<T> const & )
         817       10300 :   { }
         818             :
         819             :   //! Epilogue for SizeTags for JSON archives
         820             :   template <class T> inline
         821       10300 :   void epilogue( JSONInputArchive &, SizeTag<T> const & )
         822       10300 :   { }
         823             :
         824             :   // ######################################################################
         825             :   //! Prologue for all other types for JSON archives (except minimal types)
         826             :   /*! Starts a new node, named either automatically or by some NVP,
         827             :       that may be given data by the type about to be archived
         828             :
         829             :       Minimal types do not start or finish nodes */
         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     1359429 :   inline void prologue( JSONOutputArchive & ar, T const & )
         834             :   {
         835     1359429 :     ar.startNode();
         836     1359429 :   }
         837             :
         838             :   //! Prologue for all other types for JSON archives
         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     1359729 :   inline void prologue( JSONInputArchive & ar, T const & )
         843             :   {
         844     1359729 :     ar.startNode();
         845     1359729 :   }
         846             :
         847             :   // ######################################################################
         848             :   //! Epilogue for all other types other for JSON archives (except minimal types)
         849             :   /*! Finishes the node created in the prologue
         850             :
         851             :       Minimal types do not start or finish nodes */
         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     1359429 :   inline void epilogue( JSONOutputArchive & ar, T const & )
         856             :   {
         857     1359429 :     ar.finishNode();
         858     1359429 :   }
         859             :
         860             :   //! Epilogue for all other types other for JSON archives
         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     1359429 :   inline void epilogue( JSONInputArchive & ar, T const & )
         865             :   {
         866     1359429 :     ar.finishNode();
         867     1359429 :   }
         868             :
         869             :   // ######################################################################
         870             :   //! Prologue for arithmetic types for JSON archives
         871             :   inline
         872             :   void prologue( JSONOutputArchive & ar, std::nullptr_t const & )
         873             :   {
         874             :     ar.writeName();
         875             :   }
         876             :
         877             :   //! Prologue for arithmetic types for JSON archives
         878             :   inline
         879             :   void prologue( JSONInputArchive &, std::nullptr_t const & )
         880             :   { }
         881             :
         882             :   // ######################################################################
         883             :   //! Epilogue for arithmetic types for JSON archives
         884             :   inline
         885             :   void epilogue( JSONOutputArchive &, std::nullptr_t const & )
         886             :   { }
         887             :
         888             :   //! Epilogue for arithmetic types for JSON archives
         889             :   inline
         890             :   void epilogue( JSONInputArchive &, std::nullptr_t const & )
         891             :   { }
         892             :
         893             :   // ######################################################################
         894             :   //! Prologue for arithmetic types for JSON archives
         895             :   template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
         896     2440465 :   void prologue( JSONOutputArchive & ar, T const & )
         897             :   {
         898     2440465 :     ar.writeName();
         899     2440465 :   }
         900             :
         901             :   //! Prologue for arithmetic types for JSON archives
         902             :   template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
         903     2440665 :   void prologue( JSONInputArchive &, T const & )
         904     2440665 :   { }
         905             :
         906             :   // ######################################################################
         907             :   //! Epilogue for arithmetic types for JSON archives
         908             :   template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
         909     2440465 :   void epilogue( JSONOutputArchive &, T const & )
         910     2440465 :   { }
         911             :
         912             :   //! Epilogue for arithmetic types for JSON archives
         913             :   template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
         914     2440665 :   void epilogue( JSONInputArchive &, T const & )
         915     2440665 :   { }
         916             :
         917             :   // ######################################################################
         918             :   //! Prologue for strings for JSON archives
         919             :   template<class CharT, class Traits, class Alloc> inline
         920       71365 :   void prologue(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const &)
         921             :   {
         922       71365 :     ar.writeName();
         923       71365 :   }
         924             :
         925             :   //! Prologue for strings for JSON archives
         926             :   template<class CharT, class Traits, class Alloc> inline
         927       71365 :   void prologue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
         928       71365 :   { }
         929             :
         930             :   // ######################################################################
         931             :   //! Epilogue for strings for JSON archives
         932             :   template<class CharT, class Traits, class Alloc> inline
         933       71365 :   void epilogue(JSONOutputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
         934       71365 :   { }
         935             :
         936             :   //! Epilogue for strings for JSON archives
         937             :   template<class CharT, class Traits, class Alloc> inline
         938       71365 :   void epilogue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
         939       71365 :   { }
         940             :
         941             :   // ######################################################################
         942             :   // Common JSONArchive serialization functions
         943             :   // ######################################################################
         944             :   //! Serializing NVP types to JSON
         945             :   template <class T> inline
         946      741633 :   void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive & ar, NameValuePair<T> const & t )
         947             :   {
         948      741633 :     ar.setNextName( t.name );
         949      741633 :     ar( t.value );
         950      741633 :   }
         951             :
         952             :   template <class T> inline
         953      741733 :   void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, NameValuePair<T> & t )
         954             :   {
         955      741733 :     ar.setNextName( t.name );
         956      741733 :     ar( t.value );
         957      741533 :   }
         958             :
         959             :   //! Saving for nullptr to JSON
         960             :   inline
         961             :   void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::nullptr_t const & t)
         962             :   {
         963             :     ar.saveValue( t );
         964             :   }
         965             :
         966             :   //! Loading arithmetic from JSON
         967             :   inline
         968             :   void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::nullptr_t & t)
         969             :   {
         970             :     ar.loadValue( t );
         971             :   }
         972             :
         973             :   //! Saving for arithmetic to JSON
         974             :   template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
         975     2440465 :   void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, T const & t)
         976             :   {
         977     2440465 :     ar.saveValue( t );
         978     2440465 :   }
         979             :
         980             :   //! Loading arithmetic from JSON
         981             :   template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
         982     2440665 :   void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, T & t)
         983             :   {
         984     2440665 :     ar.loadValue( t );
         985     2440665 :   }
         986             :
         987             :   //! saving string to JSON
         988             :   template<class CharT, class Traits, class Alloc> inline
         989       71365 :   void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
         990             :   {
         991       71365 :     ar.saveValue( str );
         992       71365 :   }
         993             :
         994             :   //! loading string from JSON
         995             :   template<class CharT, class Traits, class Alloc> inline
         996       71365 :   void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
         997             :   {
         998       71365 :     ar.loadValue( str );
         999       71365 :   }
        1000             :
        1001             :   // ######################################################################
        1002             :   //! Saving SizeTags to JSON
        1003             :   template <class T> inline
        1004       10300 :   void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive &, SizeTag<T> const & )
        1005             :   {
        1006             :     // nothing to do here, we don't explicitly save the size
        1007       10300 :   }
        1008             :
        1009             :   //! Loading SizeTags from JSON
        1010             :   template <class T> inline
        1011       10300 :   void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, SizeTag<T> & st )
        1012             :   {
        1013       10300 :     ar.loadSize( st.size );
        1014       10300 :   }
        1015             : } // namespace cereal
        1016             :
        1017             : // register archives for polymorphic support
        1018             : CEREAL_REGISTER_ARCHIVE(cereal::JSONInputArchive)
        1019             : CEREAL_REGISTER_ARCHIVE(cereal::JSONOutputArchive)
        1020             :
        1021             : // tie input and output archives together
        1022             : CEREAL_SETUP_ARCHIVE_TRAITS(cereal::JSONInputArchive, cereal::JSONOutputArchive)
        1023             :
        1024             : #endif // CEREAL_ARCHIVES_JSON_HPP_

Generated by: LCOV version 1.14