json.hpp
Go to the documentation of this file.
/*
Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CEREAL_ARCHIVES_JSON_HPP_
#define CEREAL_ARCHIVES_JSON_HPP_
#include "cereal/cereal.hpp"
#include "cereal/details/util.hpp"
namespace cereal
{
struct RapidJSONException : Exception
{ RapidJSONException( const char * what_ ) : Exception( what_ ) {} };
}
// Inform rapidjson that assert will throw
#ifndef CEREAL_RAPIDJSON_ASSERT_THROWS
#define CEREAL_RAPIDJSON_ASSERT_THROWS
#endif // CEREAL_RAPIDJSON_ASSERT_THROWS
// Override rapidjson assertions to throw exceptions by default
#ifndef CEREAL_RAPIDJSON_ASSERT
#define CEREAL_RAPIDJSON_ASSERT(x) if(!(x)){ \
throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); }
#endif // RAPIDJSON_ASSERT
// Enable support for parsing of nan, inf, -inf
#ifndef CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS
#define CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag
#endif
// Enable support for parsing of nan, inf, -inf
#ifndef CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS
#define CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag | kParseNanAndInfFlag
#endif
#include "cereal/external/rapidjson/prettywriter.h"
#include "cereal/external/rapidjson/ostreamwrapper.h"
#include "cereal/external/rapidjson/istreamwrapper.h"
#include "cereal/external/rapidjson/document.h"
#include "cereal/external/base64.hpp"
#include <limits>
#include <sstream>
#include <stack>
#include <vector>
#include <string>
namespace cereal
{
// ######################################################################
class JSONOutputArchive : public OutputArchive<JSONOutputArchive>, public traits::TextArchive
{
enum class NodeType { StartObject, InObject, StartArray, InArray };
using WriteStream = CEREAL_RAPIDJSON_NAMESPACE::OStreamWrapper;
using JSONWriter = CEREAL_RAPIDJSON_NAMESPACE::PrettyWriter<WriteStream>;
public:
class Options
{
public:
static Options Default(){ return Options(); }
static Options NoIndent(){ return Options( JSONWriter::kDefaultMaxDecimalPlaces, IndentChar::space, 0 ); }
enum class IndentChar : char
{
space = ' ',
tab = '\t',
newline = '\n',
carriage_return = '\r'
};
explicit Options( int precision = JSONWriter::kDefaultMaxDecimalPlaces,
IndentChar indentChar = IndentChar::space,
unsigned int indentLength = 4 ) :
itsPrecision( precision ),
itsIndentChar( static_cast<char>(indentChar) ),
itsIndentLength( indentLength ) { }
private:
friend class JSONOutputArchive;
int itsPrecision;
char itsIndentChar;
unsigned int itsIndentLength;
};
JSONOutputArchive(std::ostream & stream, Options const & options = Options::Default() ) :
OutputArchive<JSONOutputArchive>(this),
itsWriteStream(stream),
itsWriter(itsWriteStream),
itsNextName(nullptr)
{
itsWriter.SetMaxDecimalPlaces( options.itsPrecision );
itsWriter.SetIndent( options.itsIndentChar, options.itsIndentLength );
itsNameCounter.push(0);
itsNodeStack.push(NodeType::StartObject);
}
~JSONOutputArchive() CEREAL_NOEXCEPT
{
if (itsNodeStack.top() == NodeType::InObject)
itsWriter.EndObject();
else if (itsNodeStack.top() == NodeType::InArray)
itsWriter.EndArray();
}
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
{
setNextName( name );
writeName();
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
saveValue( base64string );
};
void startNode()
{
writeName();
itsNodeStack.push(NodeType::StartObject);
itsNameCounter.push(0);
}
void finishNode()
{
// if we ended up serializing an empty object or array, writeName
// will never have been called - so start and then immediately end
// the object/array.
//
// We'll also end any object/arrays we happen to be in
switch(itsNodeStack.top())
{
case NodeType::StartArray:
itsWriter.StartArray();
// fall through
case NodeType::InArray:
itsWriter.EndArray();
break;
case NodeType::StartObject:
itsWriter.StartObject();
// fall through
case NodeType::InObject:
itsWriter.EndObject();
break;
}
itsNodeStack.pop();
itsNameCounter.pop();
}
void setNextName( const char * name )
{
itsNextName = name;
}
void saveValue(bool b) { itsWriter.Bool(b); }
void saveValue(int i) { itsWriter.Int(i); }
void saveValue(unsigned u) { itsWriter.Uint(u); }
void saveValue(int64_t i64) { itsWriter.Int64(i64); }
void saveValue(uint64_t u64) { itsWriter.Uint64(u64); }
void saveValue(double d) { itsWriter.Double(d); }
void saveValue(std::string const & s) { itsWriter.String(s.c_str(), static_cast<CEREAL_RAPIDJSON_NAMESPACE::SizeType>( s.size() )); }
void saveValue(char const * s) { itsWriter.String(s); }
void saveValue(std::nullptr_t) { itsWriter.Null(); }
private:
// Some compilers/OS have difficulty disambiguating the above for various flavors of longs, so we provide
// special overloads to handle these cases.
template <class T, traits::EnableIf<sizeof(T) == sizeof(std::int32_t),
std::is_signed<T>::value> = traits::sfinae> inline
void saveLong(T l){ saveValue( static_cast<std::int32_t>( l ) ); }
template <class T, traits::EnableIf<sizeof(T) != sizeof(std::int32_t),
std::is_signed<T>::value> = traits::sfinae> inline
void saveLong(T l){ saveValue( static_cast<std::int64_t>( l ) ); }
template <class T, traits::EnableIf<sizeof(T) == sizeof(std::int32_t),
std::is_unsigned<T>::value> = traits::sfinae> inline
void saveLong(T lu){ saveValue( static_cast<std::uint32_t>( lu ) ); }
template <class T, traits::EnableIf<sizeof(T) != sizeof(std::int32_t),
std::is_unsigned<T>::value> = traits::sfinae> inline
void saveLong(T lu){ saveValue( static_cast<std::uint64_t>( lu ) ); }
public:
#if defined(_MSC_VER) && _MSC_VER < 1916
void saveValue( unsigned long lu ){ saveLong( lu ); };
#else // _MSC_VER
template <class T, traits::EnableIf<std::is_same<T, long>::value,
!std::is_same<T, int>::value,
!std::is_same<T, std::int64_t>::value> = traits::sfinae> inline
void saveValue( T t ){ saveLong( t ); }
template <class T, traits::EnableIf<std::is_same<T, unsigned long>::value,
!std::is_same<T, unsigned>::value,
!std::is_same<T, std::uint64_t>::value> = traits::sfinae> inline
void saveValue( T t ){ saveLong( t ); }
#endif // _MSC_VER
template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
!std::is_same<T, long>::value,
!std::is_same<T, unsigned long>::value,
!std::is_same<T, std::int64_t>::value,
!std::is_same<T, std::uint64_t>::value,
(sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long))> = traits::sfinae> inline
void saveValue(T const & t)
{
std::stringstream ss; ss.precision( std::numeric_limits<long double>::max_digits10 );
ss << t;
saveValue( ss.str() );
}
void writeName()
{
NodeType const & nodeType = itsNodeStack.top();
// Start up either an object or an array, depending on state
if(nodeType == NodeType::StartArray)
{
itsWriter.StartArray();
itsNodeStack.top() = NodeType::InArray;
}
else if(nodeType == NodeType::StartObject)
{
itsNodeStack.top() = NodeType::InObject;
itsWriter.StartObject();
}
// Array types do not output names
if(nodeType == NodeType::InArray) return;
if(itsNextName == nullptr)
{
std::string name = "value" + std::to_string( itsNameCounter.top()++ ) + "\0";
saveValue(name);
}
else
{
saveValue(itsNextName);
itsNextName = nullptr;
}
}
void makeArray()
{
itsNodeStack.top() = NodeType::StartArray;
}
private:
WriteStream itsWriteStream;
JSONWriter itsWriter;
char const * itsNextName;
std::stack<uint32_t> itsNameCounter;
std::stack<NodeType> itsNodeStack;
}; // JSONOutputArchive
// ######################################################################
class JSONInputArchive : public InputArchive<JSONInputArchive>, public traits::TextArchive
{
private:
using ReadStream = CEREAL_RAPIDJSON_NAMESPACE::IStreamWrapper;
typedef CEREAL_RAPIDJSON_NAMESPACE::GenericValue<CEREAL_RAPIDJSON_NAMESPACE::UTF8<>> JSONValue;
typedef JSONValue::ConstMemberIterator MemberIterator;
typedef JSONValue::ConstValueIterator ValueIterator;
typedef CEREAL_RAPIDJSON_NAMESPACE::Document::GenericValue GenericValue;
public:
JSONInputArchive(std::istream & stream) :
InputArchive<JSONInputArchive>(this),
itsNextName( nullptr ),
itsReadStream(stream)
{
itsDocument.ParseStream<>(itsReadStream);
if (itsDocument.IsArray())
itsIteratorStack.emplace_back(itsDocument.Begin(), itsDocument.End());
else
itsIteratorStack.emplace_back(itsDocument.MemberBegin(), itsDocument.MemberEnd());
}
~JSONInputArchive() CEREAL_NOEXCEPT = default;
void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
{
itsNextName = name;
std::string encoded;
loadValue( encoded );
auto decoded = base64::decode( encoded );
if( size != decoded.size() )
throw Exception("Decoded binary data size does not match specified size");
std::memcpy( data, decoded.data(), decoded.size() );
itsNextName = nullptr;
};
private:
class Iterator
{
public:
Iterator() : itsIndex( 0 ), itsType(Null_) {}
Iterator(MemberIterator begin, MemberIterator end) :
itsMemberItBegin(begin), itsMemberItEnd(end), itsIndex(0), itsSize(std::distance(begin, end)), itsType(Member)
{
if( itsSize == 0 )
itsType = Null_;
}
Iterator(ValueIterator begin, ValueIterator end) :
itsValueItBegin(begin), itsIndex(0), itsSize(std::distance(begin, end)), itsType(Value)
{
if( itsSize == 0 )
itsType = Null_;
}
Iterator & operator++()
{
++itsIndex;
return *this;
}
GenericValue const & value()
{
if( itsIndex >= itsSize )
throw cereal::Exception("No more objects in input");
switch(itsType)
{
case Value : return itsValueItBegin[itsIndex];
case Member: return itsMemberItBegin[itsIndex].value;
default: throw cereal::Exception("JSONInputArchive internal error: null or empty iterator to object or array!");
}
}
const char * name() const
{
if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
return itsMemberItBegin[itsIndex].name.GetString();
else
return nullptr;
}
inline void search( const char * searchName )
{
const auto len = std::strlen( searchName );
size_t index = 0;
for( auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
{
const auto currentName = it->name.GetString();
if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
( std::strlen( currentName ) == len ) )
{
itsIndex = index;
return;
}
}
throw Exception("JSON Parsing failed - provided NVP (" + std::string(searchName) + ") not found");
}
private:
MemberIterator itsMemberItBegin, itsMemberItEnd;
ValueIterator itsValueItBegin;
size_t itsIndex, itsSize;
enum Type {Value, Member, Null_} itsType;
};
inline void search()
{
// store pointer to itsNextName locally and reset to nullptr in case search() throws
auto localNextName = itsNextName;
itsNextName = nullptr;
// The name an NVP provided with setNextName()
if( localNextName )
{
// The actual name of the current node
auto const actualName = itsIteratorStack.back().name();
// Do a search if we don't see a name coming up, or if the names don't match
if( !actualName || std::strcmp( localNextName, actualName ) != 0 )
itsIteratorStack.back().search( localNextName );
}
}
public:
void startNode()
{
search();
if(itsIteratorStack.back().value().IsArray())
itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
else
itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
}
void finishNode()
{
itsIteratorStack.pop_back();
++itsIteratorStack.back();
}
const char * getNodeName() const
{
return itsIteratorStack.back().name();
}
void setNextName( const char * name )
{
itsNextName = name;
}
template <class T, traits::EnableIf<std::is_signed<T>::value,
sizeof(T) < sizeof(int64_t)> = traits::sfinae> inline
void loadValue(T & val)
{
search();
val = static_cast<T>( itsIteratorStack.back().value().GetInt() );
++itsIteratorStack.back();
}
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
sizeof(T) < sizeof(uint64_t),
!std::is_same<bool, T>::value> = traits::sfinae> inline
void loadValue(T & val)
{
search();
val = static_cast<T>( itsIteratorStack.back().value().GetUint() );
++itsIteratorStack.back();
}
void loadValue(bool & val) { search(); val = itsIteratorStack.back().value().GetBool(); ++itsIteratorStack.back(); }
void loadValue(int64_t & val) { search(); val = itsIteratorStack.back().value().GetInt64(); ++itsIteratorStack.back(); }
void loadValue(uint64_t & val) { search(); val = itsIteratorStack.back().value().GetUint64(); ++itsIteratorStack.back(); }
void loadValue(float & val) { search(); val = static_cast<float>(itsIteratorStack.back().value().GetDouble()); ++itsIteratorStack.back(); }
void loadValue(double & val) { search(); val = itsIteratorStack.back().value().GetDouble(); ++itsIteratorStack.back(); }
void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
void loadValue(std::nullptr_t&) { search(); CEREAL_RAPIDJSON_ASSERT(itsIteratorStack.back().value().IsNull()); ++itsIteratorStack.back(); }
// Special cases to handle various flavors of long, which tend to conflict with
// the int32_t or int64_t on various compiler/OS combinations. MSVC doesn't need any of this.
#ifndef _MSC_VER
private:
template <class T> inline
typename std::enable_if<sizeof(T) == sizeof(std::int32_t) && std::is_signed<T>::value, void>::type
loadLong(T & l){ loadValue( reinterpret_cast<std::int32_t&>( l ) ); }
template <class T> inline
typename std::enable_if<sizeof(T) == sizeof(std::int64_t) && std::is_signed<T>::value, void>::type
loadLong(T & l){ loadValue( reinterpret_cast<std::int64_t&>( l ) ); }
template <class T> inline
typename std::enable_if<sizeof(T) == sizeof(std::uint32_t) && !std::is_signed<T>::value, void>::type
loadLong(T & lu){ loadValue( reinterpret_cast<std::uint32_t&>( lu ) ); }
template <class T> inline
typename std::enable_if<sizeof(T) == sizeof(std::uint64_t) && !std::is_signed<T>::value, void>::type
loadLong(T & lu){ loadValue( reinterpret_cast<std::uint64_t&>( lu ) ); }
public:
template <class T> inline
typename std::enable_if<std::is_same<T, long>::value &&
sizeof(T) >= sizeof(std::int64_t) &&
!std::is_same<T, std::int64_t>::value, void>::type
loadValue( T & t ){ loadLong(t); }
template <class T> inline
typename std::enable_if<std::is_same<T, unsigned long>::value &&
sizeof(T) >= sizeof(std::uint64_t) &&
!std::is_same<T, std::uint64_t>::value, void>::type
loadValue( T & t ){ loadLong(t); }
#endif // _MSC_VER
private:
void stringToNumber( std::string const & str, long long & val ) { val = std::stoll( str ); }
void stringToNumber( std::string const & str, unsigned long long & val ) { val = std::stoull( str ); }
void stringToNumber( std::string const & str, long double & val ) { val = std::stold( str ); }
public:
template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
!std::is_same<T, long>::value,
!std::is_same<T, unsigned long>::value,
!std::is_same<T, std::int64_t>::value,
!std::is_same<T, std::uint64_t>::value,
(sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long))> = traits::sfinae>
inline void loadValue(T & val)
{
std::string encoded;
loadValue( encoded );
stringToNumber( encoded, val );
}
void loadSize(size_type & size)
{
if (itsIteratorStack.size() == 1)
size = itsDocument.Size();
else
size = (itsIteratorStack.rbegin() + 1)->value().Size();
}
private:
const char * itsNextName;
ReadStream itsReadStream;
std::vector<Iterator> itsIteratorStack;
CEREAL_RAPIDJSON_NAMESPACE::Document itsDocument;
};
// ######################################################################
// JSONArchive prologue and epilogue functions
// ######################################################################
// ######################################################################
template <class T> inline
void prologue( JSONOutputArchive &, NameValuePair<T> const & )
{ }
template <class T> inline
void prologue( JSONInputArchive &, NameValuePair<T> const & )
{ }
// ######################################################################
template <class T> inline
void epilogue( JSONOutputArchive &, NameValuePair<T> const & )
{ }
template <class T> inline
void epilogue( JSONInputArchive &, NameValuePair<T> const & )
{ }
// ######################################################################
template <class T> inline
void prologue( JSONOutputArchive &, DeferredData<T> const & )
{ }
template <class T> inline
void prologue( JSONInputArchive &, DeferredData<T> const & )
{ }
// ######################################################################
template <class T> inline
void epilogue( JSONOutputArchive &, DeferredData<T> const & )
{ }
template <class T> inline
void epilogue( JSONInputArchive &, DeferredData<T> const & )
{ }
// ######################################################################
template <class T> inline
void prologue( JSONOutputArchive & ar, SizeTag<T> const & )
{
ar.makeArray();
}
template <class T> inline
void prologue( JSONInputArchive &, SizeTag<T> const & )
{ }
// ######################################################################
template <class T> inline
void epilogue( JSONOutputArchive &, SizeTag<T> const & )
{ }
template <class T> inline
void epilogue( JSONInputArchive &, SizeTag<T> const & )
{ }
// ######################################################################
template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
!traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value,
!traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
inline void prologue( JSONOutputArchive & ar, T const & )
{
ar.startNode();
}
template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
!traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value,
!traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
inline void prologue( JSONInputArchive & ar, T const & )
{
ar.startNode();
}
// ######################################################################
template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
!traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value,
!traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
inline void epilogue( JSONOutputArchive & ar, T const & )
{
ar.finishNode();
}
template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
!traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value,
!traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
inline void epilogue( JSONInputArchive & ar, T const & )
{
ar.finishNode();
}
// ######################################################################
inline
void prologue( JSONOutputArchive & ar, std::nullptr_t const & )
{
ar.writeName();
}
inline
void prologue( JSONInputArchive &, std::nullptr_t const & )
{ }
// ######################################################################
inline
void epilogue( JSONOutputArchive &, std::nullptr_t const & )
{ }
inline
void epilogue( JSONInputArchive &, std::nullptr_t const & )
{ }
// ######################################################################
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void prologue( JSONOutputArchive & ar, T const & )
{
ar.writeName();
}
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void prologue( JSONInputArchive &, T const & )
{ }
// ######################################################################
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void epilogue( JSONOutputArchive &, T const & )
{ }
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void epilogue( JSONInputArchive &, T const & )
{ }
// ######################################################################
template<class CharT, class Traits, class Alloc> inline
void prologue(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const &)
{
ar.writeName();
}
template<class CharT, class Traits, class Alloc> inline
void prologue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
{ }
// ######################################################################
template<class CharT, class Traits, class Alloc> inline
void epilogue(JSONOutputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
{ }
template<class CharT, class Traits, class Alloc> inline
void epilogue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
{ }
// ######################################################################
// Common JSONArchive serialization functions
// ######################################################################
template <class T> inline
void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive & ar, NameValuePair<T> const & t )
{
ar.setNextName( t.name );
ar( t.value );
}
template <class T> inline
void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, NameValuePair<T> & t )
{
ar.setNextName( t.name );
ar( t.value );
}
inline
void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::nullptr_t const & t)
{
ar.saveValue( t );
}
inline
void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::nullptr_t & t)
{
ar.loadValue( t );
}
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, T const & t)
{
ar.saveValue( t );
}
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, T & t)
{
ar.loadValue( t );
}
template<class CharT, class Traits, class Alloc> inline
void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
{
ar.saveValue( str );
}
template<class CharT, class Traits, class Alloc> inline
void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
{
ar.loadValue( str );
}
// ######################################################################
template <class T> inline
void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive &, SizeTag<T> const & )
{
// nothing to do here, we don't explicitly save the size
}
template <class T> inline
void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, SizeTag<T> & st )
{
ar.loadSize( st.size );
}
} // namespace cereal
// register archives for polymorphic support
CEREAL_REGISTER_ARCHIVE(cereal::JSONInputArchive)
CEREAL_REGISTER_ARCHIVE(cereal::JSONOutputArchive)
// tie input and output archives together
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::JSONInputArchive, cereal::JSONOutputArchive)
#endif // CEREAL_ARCHIVES_JSON_HPP_
cereal::InputArchive
The base input archive class.
Definition: cereal.hpp:710
cereal::JSONInputArchive::loadValue
::type loadValue(T &t)
Loads a value from the current node - small signed overload.
Definition: json.hpp:699
cereal::prologue
void prologue(JSONOutputArchive &, NameValuePair< T > const &)
Prologue for NVPs for JSON archives.
Definition: json.hpp:751
cereal::JSONInputArchive::loadSize
void loadSize(size_type &size)
Loads the size for a SizeTag.
Definition: json.hpp:726
cereal::JSONOutputArchive::saveValue
void saveValue(T t)
Serialize a long if it would not be caught otherwise.
Definition: json.hpp:297
cereal::JSONOutputArchive::saveValue
void saveValue(T const &t)
Save exotic arithmetic as strings to current node.
Definition: json.hpp:314
cereal::JSONOutputArchive::saveValue
void saveValue(char const *s)
Saves a const char * to the current node.
Definition: json.hpp:260
cereal::JSONOutputArchive::Options::IndentChar
IndentChar
The character to use for indenting.
Definition: json.hpp:129
cereal::JSONInputArchive::loadBinaryValue
void loadBinaryValue(void *data, size_t size, const char *name=nullptr)
Loads some binary data, encoded as a base64 string.
Definition: json.hpp:455
cereal::JSONOutputArchive::finishNode
void finishNode()
Designates the most recently added node as finished.
Definition: json.hpp:212
cereal::JSONOutputArchive::saveValue
void saveValue(bool b)
Saves a bool to the current node.
Definition: json.hpp:246
cereal::JSONOutputArchive::Options
A class containing various advanced options for the JSON archive.
Definition: json.hpp:119
cereal::JSONOutputArchive::~JSONOutputArchive
~JSONOutputArchive() CEREAL_NOEXCEPT
Destructor, flushes the JSON.
Definition: json.hpp:173
cereal::JSONOutputArchive::saveValue
void saveValue(int64_t i64)
Saves an int64 to the current node.
Definition: json.hpp:252
cereal::JSONOutputArchive::startNode
void startNode()
Starts a new node in the JSON output.
Definition: json.hpp:204
cereal::JSONOutputArchive
An output archive designed to save data to JSON.
Definition: json.hpp:106
cereal::JSONOutputArchive::setNextName
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: json.hpp:240
cereal::JSONOutputArchive::saveValue
void saveValue(uint64_t u64)
Saves a uint64 to the current node.
Definition: json.hpp:254
cereal::JSONOutputArchive::Options::Options
Options(int precision=JSONWriter::kDefaultMaxDecimalPlaces, IndentChar indentChar=IndentChar::space, unsigned int indentLength=4)
Specify specific options for the JSONOutputArchive.
Definition: json.hpp:142
cereal::JSONOutputArchive::JSONOutputArchive
JSONOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream.
Definition: json.hpp:160
CEREAL_LOAD_FUNCTION_NAME
#define CEREAL_LOAD_FUNCTION_NAME
The deserialization (load) function name to search for.
Definition: macros.hpp:85
cereal::JSONOutputArchive::Options::Default
static Options Default()
Default options.
Definition: json.hpp:123
cereal::JSONInputArchive::finishNode
void finishNode()
Finishes the most recently started node.
Definition: json.hpp:605
CEREAL_REGISTER_ARCHIVE
#define CEREAL_REGISTER_ARCHIVE(Archive)
Registers a specific Archive type with cereal.
Definition: cereal.hpp:195
cereal::NameValuePair
For holding name value pairs.
Definition: helpers.hpp:139
cereal::traits::TextArchive
Type traits only struct used to mark an archive as human readable (text based)
Definition: traits.hpp:1321
cereal::OutputArchive
The base output archive class.
Definition: cereal.hpp:318
cereal::JSONOutputArchive::writeName
void writeName()
Write the name of the upcoming node and prepare object/array state.
Definition: json.hpp:334
cereal::JSONInputArchive::setNextName
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: json.hpp:619
cereal::JSONInputArchive::loadValue
void loadValue(T &val)
Loads a value from the current node - long double and long long overloads.
Definition: json.hpp:718
CEREAL_SAVE_FUNCTION_NAME
#define CEREAL_SAVE_FUNCTION_NAME
The serialization (save) function name to search for.
Definition: macros.hpp:92
cereal::JSONInputArchive::JSONInputArchive
JSONInputArchive(std::istream &stream)
Construct, reading from the provided stream.
Definition: json.hpp:435
cereal::JSONOutputArchive::saveValue
void saveValue(std::string const &s)
Saves a string to the current node.
Definition: json.hpp:258
CEREAL_SETUP_ARCHIVE_TRAITS
#define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive)
Sets up traits that relate an input archive to an output archive.
Definition: traits.hpp:169
cereal::JSONInputArchive::startNode
void startNode()
Starts a new node, going into its proper iterator.
Definition: json.hpp:594
CEREAL_NOEXCEPT
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
cereal::JSONInputArchive
An input archive designed to load data from JSON.
Definition: json.hpp:419
cereal::JSONInputArchive::getNodeName
const char * getNodeName() const
Retrieves the current node name.
Definition: json.hpp:613
cereal::JSONOutputArchive::saveBinaryValue
void saveBinaryValue(const void *data, size_t size, const char *name=nullptr)
Saves some binary data, encoded as a base64 string, with an optional name.
Definition: json.hpp:184
cereal::JSONOutputArchive::saveValue
void saveValue(std::nullptr_t)
Saves a nullptr to the current node.
Definition: json.hpp:262
cereal::RapidJSONException
An exception thrown when rapidjson fails an internal assertion.
Definition: json.hpp:39
cereal::epilogue
void epilogue(JSONOutputArchive &, NameValuePair< T > const &)
Epilogue for NVPs for JSON archives.
Definition: json.hpp:763
EnableIf
typename detail::EnableIfHelper< Conditions... >::type EnableIf
Provides a way to enable a function if conditions are met.
Definition: traits.hpp:116
cereal::JSONOutputArchive::saveValue
void saveValue(int i)
Saves an int to the current node.
Definition: json.hpp:248
cereal::JSONOutputArchive::makeArray
void makeArray()
Designates that the current node should be output as an array, not an object.
Definition: json.hpp:366
cereal.hpp
Main cereal functionality.
cereal::SizeTag
A wrapper around size metadata.
Definition: helpers.hpp:312
cereal::Exception
An exception class thrown when things go wrong at runtime.
Definition: helpers.hpp:48
cereal::JSONOutputArchive::saveValue
void saveValue(unsigned u)
Saves a uint to the current node.
Definition: json.hpp:250
cereal::DeferredData
A wrapper around data that should be serialized after all non-deferred data.
Definition: helpers.hpp:232
cereal::JSONOutputArchive::saveValue
void saveValue(double d)
Saves a double to the current node.
Definition: json.hpp:256
cereal::size_type
CEREAL_SIZE_TYPE size_type
The size type used by cereal.
Definition: helpers.hpp:61
cereal::JSONOutputArchive::Options::NoIndent
static Options NoIndent()
Default options with no indentation.
Definition: json.hpp:126
util.hpp
Internal misc utilities.