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