#ifndef VJSON_H_INCLUDED
#define VJSON_H_INCLUDED
#include <string.h>
#include <stdint.h>
#include <stddef.h>
#include <inttypes.h>
#include <string>
#include <vector>
#include <map>
#ifdef VJSON_VALVE
#include <tier0/dbg.h>
#ifdef DBGFLAG_VALIDATE
#include <tier0/validator.h>
#endif
#include <tier0/memdbgoff.h>
#define VJSON_ASSERT Assert
#endif
#ifndef VJSON_ASSERT
#include <assert.h>
#define VJSON_ASSERT assert
#endif
#ifndef VJSON_DEFAULT_INDENT
#define VJSON_DEFAULT_INDENT "\t"
#endif
namespace vjson {
enum EValueType
{
kNull,
kObject, kArray, kString,
kDouble,
kNumber = kDouble, kBool,
kDeleted, };
enum EResult
{
kOK,
kWrongType, kNotArray, kBadIndex, kNotObject, kBadKey, };
class Value; class Object; class Array;
struct PrintOptions; struct ParseContext;
struct ObjectKeyLess
{
bool operator()( const std::string &l, const std::string &r ) const { return strcmp( l.c_str(), r.c_str() ) < 0; }
bool operator()( const std::string &l, const char *r ) const { return strcmp( l.c_str(), r ) < 0; }
bool operator()( const char *l, const std::string &r ) const { return strcmp( l, r.c_str() ) < 0; }
};
using RawObject = std::map<std::string, Value, ObjectKeyLess>; using RawArray = std::vector<Value>; using ObjectItem = RawObject::value_type; template<typename T> struct TypeTraits {};
template<> struct TypeTraits<std::nullptr_t> { static constexpr EValueType kType = kNull; using AsReturnType = void; using AsReturnTypeConst = void; };
template<> struct TypeTraits<bool> { static constexpr EValueType kType = kBool; using AsReturnType = bool&; using AsReturnTypeConst = const bool&; };
template<> struct TypeTraits<double> { static constexpr EValueType kType = kDouble; using AsReturnType = double&; using AsReturnTypeConst = const double&; };
template<> struct TypeTraits<int> { static constexpr EValueType kType = kNumber; using AsReturnType = int; using AsReturnTypeConst = int; };
template<> struct TypeTraits<const char *> { static constexpr EValueType kType = kString; using AsReturnType = const char *; using AsReturnTypeConst = const char *; };
template<> struct TypeTraits<std::string> { static constexpr EValueType kType = kString; using AsReturnType = std::string &; using AsReturnTypeConst = const std::string &; };
template<> struct TypeTraits<Object> { static constexpr EValueType kType = kObject; using AsReturnType = Object &; using AsReturnTypeConst = const Object &; };
template<> struct TypeTraits<Array> { static constexpr EValueType kType = kArray; using AsReturnType = Array &; using AsReturnTypeConst = const Array &; };
template<typename T, typename V, typename A, typename R> struct ArrayIter;
template<typename T> using ConstArrayIter = ArrayIter<T, const Value, const RawArray, typename TypeTraits<T>::AsReturnTypeConst >;
template<typename T> using MutableArrayIter = ArrayIter<T, Value, RawArray, typename TypeTraits<T>::AsReturnType >;
template<typename T, typename A, typename I> struct ArrayRange;
template<typename T> using ConstArrayRange = ArrayRange< T, const RawArray, ConstArrayIter<T> >;
template<typename T> using MutableArrayRange = ArrayRange< T, RawArray, MutableArrayIter<T> >;
struct PrintOptions
{
const char *indent = VJSON_DEFAULT_INDENT;
};
struct ParseContext
{
bool allow_trailing_comma = false;
bool allow_cpp_comments = false;
std::string error_message;
int error_line = 0;
int error_byte_offset = 0;
};
extern const Value &GetStaticNullValue();
extern const Array &GetStaticEmptyArray();
extern const Object &GetStaticEmptyObject();
class Value
{
public:
Value() : _type( kNull ) {}
explicit Value( EValueType type );
Value( const Value &x ) { InternalConstruct( x ); }
Value( Value &&x ) { InternalConstruct( std::forward<Value>( x ) ); }
~Value() { InternalDestruct(); }
Value( bool x ) : _type( kBool ) { _bool = x; }
Value( double x ) : _type( kDouble ) { _double = x; }
Value( int x ) : _type( kDouble ) { _double = (double)x; }
Value( const char * x );
Value( const std::string &x );
Value( std::string && x );
Value( std::nullptr_t ) = delete;
Value( const RawObject & x );
Value( RawObject && x );
Value( const RawArray & x );
Value( RawArray && x );
Value &operator=( const Value & x );
Value &operator=( Value && x );
Value &operator=( bool x ) { InternalDestruct(); _type = kBool; _bool = x; return *this; }
Value &operator=( double x ) { InternalDestruct(); _type = kDouble; _double = x; return *this; }
Value &operator=( int x ) { InternalDestruct(); _type = kDouble; _double = (double)x; return *this; }
Value &operator=( const char * x );
Value &operator=( const std::string &x );
Value &operator=( std::string && x );
Value &operator=( std::nullptr_t ) { SetNull(); return *this; }
Value &operator=( const RawArray & x );
Value &operator=( RawArray && x );
Value &operator=( const RawObject & x );
Value &operator=( RawObject && x );
void SetNull() { InternalDestruct(); _type = kNull; }
void SetEmptyObject();
void SetEmptyArray();
void SetUint64AsString( uint64_t x );
template <typename T> void SetArray( const T *begin, const T *end );
template <typename T> void SetArray( size_t n, const T *begin ) { SetArray( begin, begin+n ); }
template <typename T> void SetArray( std::initializer_list<T> x ) { SetArray( x.begin(), x.end() ); };
const char * AsCString ( const char * defaultVal ) const { return _type == kString ? _string.c_str() : defaultVal; }
std::string AsString ( const char * defaultVal ) const { return _type == kString ? _string : std::string( defaultVal ); } std::string AsString ( const std::string &defaultVal ) const { return _type == kString ? _string : defaultVal; } std::string AsString ( std::string && defaultVal ) const { return _type == kString ? _string : std::forward<std::string>(defaultVal); } bool AsBool ( bool defaultVal ) const { return _type == kBool ? _bool : defaultVal; } double AsDouble ( double defaultVal ) const { return _type == kDouble ? _double : defaultVal; }
int AsInt ( int defaultVal ) const { return _type == kDouble ? (int)_double : defaultVal; }
const Object *AsObjectPtr ( ) const { return _type == kObject ? (const Object *)this : nullptr; } Object *AsObjectPtr ( ) { return _type == kObject ? ( Object *)this : nullptr; }
const Array *AsArrayPtr ( ) const { return _type == kArray ? (const Array *)this : nullptr; } Array *AsArrayPtr ( ) { return _type == kArray ? ( Array *)this : nullptr; }
const Object &AsObjectOrEmpty( ) const { return _type == kObject ? *(const Object *)this : GetStaticEmptyObject(); } const Array &AsArrayOrEmpty ( ) const { return _type == kArray ? *(const Array *)this : GetStaticEmptyArray(); }
EResult TryInterpret( std::string &outVal ) const;
EResult TryInterpret( bool &outVal ) const;
EResult TryInterpret( double &outVal ) const;
EResult TryInterpret( int &outVal ) const;
EResult TryInterpret( uint64_t &outVal ) const;
std::string InterpretAsString( const char * defaultVal ) const { std::string result; if ( TryInterpret( result ) != kOK ) result = defaultVal; return result; }
std::string InterpretAsString( const std::string &defaultVal ) const { std::string result; if ( TryInterpret( result ) != kOK ) result = defaultVal; return result; }
std::string InterpretAsString( std::string && defaultVal ) const { std::string result( std::forward<std::string>( defaultVal ) ); TryInterpret( result ); return result; }
bool InterpretAsBool ( bool defaultVal ) const { TryInterpret( defaultVal ); return defaultVal; }
double InterpretAsDouble( double defaultVal ) const { TryInterpret( defaultVal ); return defaultVal; }
int InterpretAsInt ( int defaultVal ) const { TryInterpret( defaultVal ); return defaultVal; }
uint64_t InterpretAsUint64( uint64_t defaultVal ) const { TryInterpret( defaultVal ); return defaultVal; }
const char * GetCString() const { VJSON_ASSERT( _type == kString ); return _string.c_str(); }
const std::string &GetString () const { VJSON_ASSERT( _type == kString ); return _string; }
std::string & GetString () { VJSON_ASSERT( _type == kString ); return _string; }
const bool & GetBool () const { VJSON_ASSERT( _type == kBool ); return _bool; }
bool & GetBool () { VJSON_ASSERT( _type == kBool ); return _bool; }
const double & GetDouble () const { VJSON_ASSERT( _type == kDouble ); return _double; }
double & GetDouble () { VJSON_ASSERT( _type == kDouble ); return _double; }
int GetInt () const { VJSON_ASSERT( _type == kDouble ); return (int)_double; }
const Object & GetObject () const { VJSON_ASSERT( _type == kObject ); return *(const Object*)this; }
Object & GetObject () { VJSON_ASSERT( _type == kObject ); return *(Object*)this; }
const Array & GetArray () const { VJSON_ASSERT( _type == kArray ); return *(const Array*)(this); }
Array & GetArray () { VJSON_ASSERT( _type == kArray ); return *(Array*)this; }
template<typename T> typename TypeTraits<T>::AsReturnTypeConst Get() const;
template<typename T> typename TypeTraits<T>::AsReturnType Get();
bool IsNull() const { return _type == kNull; }
bool IsObject() const { return _type == kObject; }
bool IsArray() const { return _type == kArray; }
bool IsString() const { return _type == kString; }
bool IsNumber() const { return _type == kDouble; }
bool IsDouble() const { return _type == kDouble; }
bool IsBool() const { return _type == kBool; }
template<typename T> bool Is() const;
EValueType Type() const { return _type; }
template <typename T, typename K> EResult SetAtKey( K&& key, T&& value );
template <typename K> EResult EraseAtKey( K&& key );
bool HasKey( const std::string &key ) const { return ValuePtrAtKey( key ) != nullptr; }
bool HasKey( const char *key ) const { return ValuePtrAtKey( key ) != nullptr; }
int ObjectLen () const { return _type == kObject ? (int)_object.size() : 0; }
size_t ObjectSize() const { return _type == kObject ? _object.size() : 0; }
Value *ValuePtrAtKey( const std::string &key );
const Value *ValuePtrAtKey( const std::string &key ) const { return const_cast<Value*>(this)->ValuePtrAtKey( key ); }
Value *ValuePtrAtKey( const char * key );
const Value *ValuePtrAtKey( const char * key ) const { return const_cast<Value*>(this)->ValuePtrAtKey( key ); }
template <typename K> const Value &AtKey( K&& key ) const { const Value *t = ValuePtrAtKey( key ); return t ? *t : GetStaticNullValue(); }
template <typename K> const char * CStringAtKey ( K&& key, const char * defaultVal ) const { const Value *t = InternalAtKey( key, kString ); return t ? t->_string.c_str() : defaultVal; }
template <typename K> std::string StringAtKey ( K&& key, const char * defaultVal ) const { const Value *t = InternalAtKey( key, kString ); return t ? t->_string : std::string( defaultVal ); } template <typename K> std::string StringAtKey ( K&& key, const std::string &defaultVal ) const { const Value *t = InternalAtKey( key, kString ); return t ? t->_string : defaultVal; } template <typename K> std::string StringAtKey ( K&& key, std::string && defaultVal ) const { const Value *t = InternalAtKey( key, kString ); return t ? t->_string : std::forward<std::string>( defaultVal ); } template <typename K> bool BoolAtKey ( K&& key, bool defaultVal ) const { const Value *t = InternalAtKey( key, kBool ); return t ? t->_bool : defaultVal; } template <typename K> double DoubleAtKey ( K&& key, double defaultVal ) const { const Value *t = InternalAtKey( key, kDouble ); return t ? t->_double : defaultVal; }
template <typename K> int IntAtKey ( K&& key, int defaultVal ) const { const Value *t = InternalAtKey( key, kDouble ); return t ? (int)t->_double : defaultVal; }
template <typename K> const Object *ObjectPtrAtKey ( K&& key ) const { return (const Object *)InternalAtKey( key, kObject ); }
template <typename K> Object * ObjectPtrAtKey ( K&& key ) { return ( Object *)InternalAtKey( key, kObject ); }
template <typename K> const Array * ArrayPtrAtKey ( K&& key ) const { return (const Array *)InternalAtKey( key, kArray ); }
template <typename K> Array * ArrayPtrAtKey ( K&& key ) { return ( Array *)InternalAtKey( key, kArray ); }
template <typename K> const Array &ArrayAtKeyOrEmpty ( K&& key ) const { const Array *t = (const Array *)InternalAtKey( key, kArray ); return t ? *t : GetStaticEmptyArray(); }
template <typename K> const Object &ObjectAtKeyOrEmpty( K&& key ) const { const Object *t = (const Object *)InternalAtKey( key, kObject ); return t ? *t : GetStaticEmptyObject(); }
template <typename K, typename T> EResult TryInterpretAtKey( K&& key, T &outResult ) const;
template <typename K> std::string InterpretAsStringAtKey( K&& key, const char * defaultVal ) const { std::string result; if ( TryInterpretAtKey( std::forward<K>(key), result ) != kOK ) return defaultVal; return result; }
template <typename K> std::string InterpretAsStringAtKey( K&& key, const std::string &defaultVal ) const { std::string result; if ( TryInterpretAtKey( std::forward<K>(key), result ) != kOK ) return defaultVal; return result; }
template <typename K> std::string InterpretAsStringAtKey( K&& key, std::string && defaultVal ) const { std::string result( std::forward<std::string>( defaultVal ) ); TryInterpretAtKey( std::forward<K>(key), result ); return result; }
template <typename K> bool InterpretAsBoolAtKey ( K&& key, bool defaultVal ) const { TryInterpretAtKey( std::forward<K>(key), defaultVal ); return defaultVal; }
template <typename K> double InterpretAsDoubleAtKey( K&& key, double defaultVal ) const { TryInterpretAtKey( std::forward<K>(key), defaultVal ); return defaultVal; }
template <typename K> int InterpretAsIntAtKey ( K&& key, int defaultVal ) const { TryInterpretAtKey( std::forward<K>(key), defaultVal ); return defaultVal; }
template <typename K> uint64_t InterpretAsUint64AtKey( K&& key, uint64_t defaultVal ) const { TryInterpretAtKey( std::forward<K>(key), defaultVal ); return defaultVal; }
int ArrayLen () const { return _type == kArray ? (int)_array.size() : 0; }
size_t ArraySize() const { return _type == kArray ? _array.size() : 0; }
const Value &AtIndex( size_t idx ) const { return ( _type == kArray && idx < _array.size() ) ? _array[idx] : GetStaticNullValue(); }
const Value *ValuePtrAtIndex( size_t idx ) const { return ( _type == kArray && idx < _array.size() ) ? &_array[idx] : nullptr; }
Value * ValuePtrAtIndex( size_t idx ) { return ( _type == kArray && idx < _array.size() ) ? &_array[idx] : nullptr; }
const char * CStringAtIndex ( size_t idx, const char * defaultVal ) const { const Value *t = InternalAtIndex( idx, kString ); return t ? t->_string.c_str() : defaultVal; }
std::string StringAtIndex ( size_t idx, const char * defaultVal ) const { const Value *t = InternalAtIndex( idx, kString ); return t ? t->_string : std::string( defaultVal ); } std::string StringAtIndex ( size_t idx, const std::string &defaultVal ) const { const Value *t = InternalAtIndex( idx, kString ); return t ? t->_string : defaultVal; } std::string StringAtIndex ( size_t idx, std::string && defaultVal ) const { const Value *t = InternalAtIndex( idx, kString ); return t ? t->_string : std::forward<std::string>( defaultVal ); } bool BoolAtIndex ( size_t idx, bool defaultVal ) const { const Value *t = InternalAtIndex( idx, kBool ); return t ? t->_bool : defaultVal; } double DoubleAtIndex ( size_t idx, double defaultVal ) const { const Value *t = InternalAtIndex( idx, kDouble ); return t ? t->_double : defaultVal; }
int IntAtIndex ( size_t idx, int defaultVal ) const { const Value *t = InternalAtIndex( idx, kDouble ); return t ? (int)t->_double : defaultVal; }
const Object *ObjectPtrAtIndex ( size_t idx ) const { return (const Object *)InternalAtIndex( idx, kObject ); }
Object * ObjectPtrAtIndex ( size_t idx ) { return ( Object *)InternalAtIndex( idx, kObject ); }
const Array * ArrayPtrAtIndex ( size_t idx ) const { return (const Array *)InternalAtIndex( idx, kArray ); }
Array * ArrayPtrAtIndex ( size_t idx ) { return ( Array *)InternalAtIndex( idx, kArray ); }
const Array &ArrayAtIndexOrEmpty ( size_t idx ) const { const Array *t = (const Array *)InternalAtIndex( idx, kArray ); return t ? *t : GetStaticEmptyArray(); }
const Object &ObjectAtIndexOrEmpty( size_t idx ) const { const Object *t = (const Object *)InternalAtIndex( idx, kObject ); return t ? *t : GetStaticEmptyObject(); }
template <typename T> EResult TryInterpretAtIndex( size_t idx, T &outResult ) const;
std::string InterpretAsStringAtIndex( size_t idx, const char * defaultVal ) const { std::string result; if ( TryInterpretAtIndex( idx, result ) != kOK ) result = defaultVal; return result; }
std::string InterpretAsStringAtIndex( size_t idx, const std::string &defaultVal ) const { std::string result; if ( TryInterpretAtIndex( idx, result ) != kOK ) result = defaultVal; return result; }
std::string InterpretAsStringAtIndex( size_t idx, std::string && defaultVal ) const { std::string result( std::forward<std::string>( defaultVal ) ); TryInterpretAtIndex( idx, result ); return result; }
bool InterpretAsBoolAtIndex ( size_t idx, bool defaultVal ) const { TryInterpretAtIndex( idx, defaultVal ); return defaultVal; }
double InterpretAsDoubleAtIndex( size_t idx, double defaultVal ) const { TryInterpretAtIndex( idx, defaultVal ); return defaultVal; }
int InterpretAsIntAtIndex ( size_t idx, int defaultVal ) const { TryInterpretAtIndex( idx, defaultVal ); return defaultVal; }
uint64_t InterpretAsUint64AtIndex( size_t idx, uint64_t defaultVal ) const { TryInterpretAtIndex( idx, defaultVal ); return defaultVal; }
inline bool ParseJSON( const char *c_str, ParseContext *ctx = nullptr ) { return ParseJSON( c_str, c_str + strlen(c_str), ctx ); }
inline bool ParseJSON( const std::string &s, ParseContext *ctx = nullptr ) { return ParseJSON( s.c_str(), s.c_str() + s.length(), ctx ); }
bool ParseJSON( const char *begin, const char *end, ParseContext *ctx = nullptr );
std::string PrintJSON( const PrintOptions &opt = PrintOptions{} ) const;
#if defined(VJSON_VALVE) && defined(DBGFLAG_VALIDATE)
void Validate( CValidator &validator, const char *pchName ) const;
#endif
protected:
EValueType _type;
union
{
double _double;
bool _bool;
RawObject _object;
RawArray _array;
std::string _string;
struct { char x[8]; } _dummy;
};
void InternalDestruct();
void InternalConstruct( const Value &x );
void InternalConstruct( Value &&x );
Value *InternalAtIndex( size_t idx, EValueType t ) const;
Value *InternalAtKey( const std::string &key, EValueType t ) const;
Value *InternalAtKey( const char *key, EValueType t ) const;
};
class Object : public Value
{
public:
Object() : Value( kObject ) {}
Object( const Object &x ) : Value( x ) {}
Object( Object &&x ) : Value( std::forward<Object>(x) ) {}
Object &operator=( const Object & x ) { VJSON_ASSERT( x._type == kObject ); Value::operator=(x); return *this; }
Object &operator=( Object && x ) { VJSON_ASSERT( x._type == kObject ); Value::operator=(std::forward<Object>(x)); return *this; }
Object &operator=( const RawObject & x ) { Value::operator=(x); return *this; }
Object &operator=( RawObject && x ) { Value::operator=(std::forward<RawObject>(x)); return *this; }
inline bool ParseJSON( const char *c_str, ParseContext *ctx = nullptr ) { return ParseJSON( c_str, c_str + strlen(c_str), ctx ); }
inline bool ParseJSON( const std::string &s, ParseContext *ctx = nullptr ) { return ParseJSON( s.c_str(), s.c_str() + s.length(), ctx ); }
bool ParseJSON( const char *begin, const char *end, ParseContext *ctx = nullptr );
int ObjectLen() const { VJSON_ASSERT( _type == kObject ); return (int)_object.size(); }
size_t ObjectSize() const { VJSON_ASSERT( _type == kObject ); return _object.size(); }
int Len() const { VJSON_ASSERT( _type == kObject ); return (int)_object.size(); }
size_t size() const { VJSON_ASSERT( _type == kObject ); return _object.size(); }
template <typename K> Value &operator[]( K &&key ) { VJSON_ASSERT( _type == kObject ); return _object[ std::forward<K>( key ) ]; }
bool empty() const { VJSON_ASSERT( _type == kObject ); return _object.empty(); }
void clear() { VJSON_ASSERT( _type == kObject ); _object.clear(); }
inline RawObject &Raw() { VJSON_ASSERT( _type == kObject ); return _object; }
inline RawObject const &Raw() const { VJSON_ASSERT( _type == kObject ); return _object; }
RawObject::iterator begin() { VJSON_ASSERT( _type == kObject ); return _object.begin(); }
RawObject::iterator end() { VJSON_ASSERT( _type == kObject ); return _object.end(); }
RawObject::const_iterator begin() const { VJSON_ASSERT( _type == kObject ); return _object.begin(); }
RawObject::const_iterator end() const { VJSON_ASSERT( _type == kObject ); return _object.end(); }
};
class Array : public Value
{
public:
Array() : Value( kArray ) {}
Array( const Array &x ) : Value( x ) {}
Array( Array &&x ) : Value( std::forward<Array>(x) ) {}
Array( const RawArray &x ) : Value( x ) {}
Array( RawArray && x ) : Value( std::forward<RawArray>( x ) ) {}
Array &operator=( const Array & x ) { VJSON_ASSERT( x._type == kArray ); Value::operator=(x); return *this; }
Array &operator=( Array && x ) { VJSON_ASSERT( x._type == kArray ); Value::operator=(std::forward<Array>(x)); return *this; }
Array &operator=( const RawArray & x ) { Value::operator=(x); return *this; }
Array &operator=( RawArray && x ) { Value::operator=(std::forward<Array>(x)); return *this; }
int ArrayLen() const { VJSON_ASSERT( _type == kArray ); return (int)_array.size(); }
size_t ArraySize() const { VJSON_ASSERT( _type == kArray ); return _array.size(); }
int Len() const { VJSON_ASSERT( _type == kArray ); return (int)_array.size(); }
size_t size() const { VJSON_ASSERT( _type == kArray ); return _array.size(); }
Value &operator[]( size_t idx ) { VJSON_ASSERT( _type == kArray ); return _array[idx]; }
const Value &operator[]( size_t idx ) const { VJSON_ASSERT( _type == kArray ); return _array[idx]; }
bool empty() const { VJSON_ASSERT( _type == kArray ); return _array.empty(); }
void clear() { VJSON_ASSERT( _type == kArray ); _array.clear(); }
Value &push_back() { VJSON_ASSERT( _type == kArray ); _array.push_back( Value{} ); return _array[ _array.size()-1 ]; }
template< typename Arg > Value &push_back( Arg &&a ) { VJSON_ASSERT( _type == kArray ); _array.push_back( std::forward<Arg>( a ) ); return _array[ _array.size()-1 ]; }
const RawArray &Raw() const { VJSON_ASSERT( _type == kArray ); return _array; }
RawArray &Raw() { VJSON_ASSERT( _type == kArray ); return _array; }
Value * begin() { VJSON_ASSERT( _type == kArray ); return _array.data(); }
Value * end() { VJSON_ASSERT( _type == kArray ); return _array.data() + _array.size(); }
const Value *begin() const { VJSON_ASSERT( _type == kArray ); return _array.data(); }
const Value *end() const { VJSON_ASSERT( _type == kArray ); return _array.data() + _array.size(); }
template <typename T> ConstArrayRange<T> Iter() const;
template <typename T> MutableArrayRange<T> Iter();
};
template<> inline bool Value::Is<std::nullptr_t>() const { return _type == kNull; }
template<> inline bool Value::Is<Object>() const { return _type == kObject; }
template<> inline bool Value::Is<Array>() const { return _type == kArray; }
template<> inline bool Value::Is<const char *>() const { return _type == kString; }
template<> inline bool Value::Is<std::string>() const { return _type == kString; }
template<> inline bool Value::Is<double>() const { return _type == kDouble; }
template<> inline bool Value::Is<bool>() const { return _type == kBool; }
template<> inline const char * Value::Get<const char *>() const { VJSON_ASSERT( _type == kString ); return _string.c_str(); }
template<> inline const char * Value::Get<const char *>() { VJSON_ASSERT( _type == kString ); return _string.c_str(); }
template<> inline const std::string &Value::Get<std::string>() const { VJSON_ASSERT( _type == kString ); return _string; }
template<> inline std::string & Value::Get<std::string>() { VJSON_ASSERT( _type == kString ); return _string; }
template<> inline const bool & Value::Get<bool>() const { VJSON_ASSERT( _type == kBool ); return _bool; } template<> inline bool & Value::Get<bool>() { VJSON_ASSERT( _type == kBool ); return _bool; } template<> inline const double & Value::Get<double>() const { VJSON_ASSERT( _type == kDouble ); return _double; }
template<> inline double & Value::Get<double>() { VJSON_ASSERT( _type == kDouble ); return _double; }
template<> inline int Value::Get<int>() const { VJSON_ASSERT( _type == kDouble ); return (int)_double; }
template<> inline int Value::Get<int>() { VJSON_ASSERT( _type == kDouble ); return (int)_double; }
template<> inline const Object & Value::Get<Object>() const { VJSON_ASSERT( _type == kObject ); return *(const Object*)this; }
template<> inline Object & Value::Get<Object>() { VJSON_ASSERT( _type == kObject ); return *(Object*)this; }
template<> inline const Array & Value::Get<Array>() const { VJSON_ASSERT( _type == kArray ); return *(const Array*)(this); }
template<> inline Array & Value::Get<Array>() { VJSON_ASSERT( _type == kArray ); return *(Array*)this; }
template <typename T, typename K>
inline EResult Value::SetAtKey( K&& key, T&& value )
{
if ( _type != kObject ) return kNotObject;
_object[ std::forward<K>( key ) ] = std::forward<T>( value );
return kOK;
}
template <typename K>
EResult Value::EraseAtKey( K&& key )
{
if ( _type != kObject ) return kNotObject;
if ( _object.erase( std::forward<K>( key ) ) == 0 ) return kBadKey;
return kOK;
}
template <typename K, typename T>
EResult Value::TryInterpretAtKey( K&& key, T &outResult ) const
{
if ( _type != kObject ) return kNotObject;
auto it = _object.find( key );
if ( it == _object.end() ) return kBadKey;
return it->second.TryInterpret( outResult );
}
template <typename T>
EResult Value::TryInterpretAtIndex( size_t idx, T &outResult ) const
{
if ( _type != kArray ) return kNotArray;
if ( idx >= _array.size() ) return kBadIndex;
return _array[ idx ].TryInterpret( outResult );
}
template <typename T>
void Value::SetArray( const T *begin, const T *end )
{
VJSON_ASSERT( begin <= end );
InternalDestruct();
_type = kArray;
new (&_array) RawArray( begin, end );
}
template<typename T, typename V, typename A, typename R>
struct ArrayIter {
A &array_ref;
V *cur_ptr;
R operator*() const { return this->cur_ptr->template Get<T>(); }
void operator++() {
VJSON_ASSERT( this->cur_ptr < this->end() ); ++this->cur_ptr; this->Next();
}
template<typename XV, typename XA, typename XR>
bool operator!=(const ArrayIter<T,XV,XA,XR> &x ) const {
VJSON_ASSERT( &this->array_ref == &x.array_ref ); VJSON_ASSERT( this->cur_ptr <= this->end() && x.cur_ptr <= this->end() ); return this->cur_ptr != x.cur_ptr;
}
void Next() {
auto e = this->end();
while ( this->cur_ptr < e && this->cur_ptr->Type() != TypeTraits<T>::kType )
++this->cur_ptr;
}
V *end() const { return this->array_ref.data() + this->array_ref.size(); }
};
template<typename T, typename A, typename I> struct ArrayRange
{
A &array_ref;
I begin() const { I beg{array_ref,array_ref.data()}; beg.Next(); return beg; }
I end() const { return I{array_ref,array_ref.data()+array_ref.size()}; }
};
template <typename T> ConstArrayRange<T> Array::Iter() const { return ConstArrayRange<T>{this->_array}; }
template <typename T> MutableArrayRange<T> Array::Iter() { return MutableArrayRange<T>{this->_array}; }
}
#ifdef VJSON_VALVE
#include <tier0/memdbgon.h>
#endif
#endif