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

Generated by: LCOV version 1.13