wordreference/libjson/_internal/Source/internalJSONNode.h

504 lines
16 KiB
C++

#ifndef INTERNAL_JSONNODE_H
#define INTERNAL_JSONNODE_H
#include "JSONDebug.h"
#include "JSONChildren.h"
#include "JSONMemory.h"
#include "JSONGlobals.h"
#ifdef JSON_DEBUG
#include <climits> //to check int value
#endif
#include "JSONSharedString.h"
#ifdef JSON_LESS_MEMORY
#ifdef __GNUC__
#pragma pack(push, 1)
#elif _MSC_VER
#pragma pack(push, internalJSONNode_pack, 1)
#endif
#endif
/*
This class is the work horse of libjson, it handles all of the
functinality of JSONNode. This object is reference counted for
speed and memory reasons.
If JSON_REF_COUNT is not on, this internal structure still has an important
purpose, as it can be passed around by JSONNoders that are flagged as temporary
*/
class JSONNode; //forward declaration
#ifndef JSON_LIBRARY
#define DECL_SET_INTEGER(type) void Set(type) json_nothrow json_write_priority; void Set(unsigned type) json_nothrow json_write_priority;
#define DECL_CAST_OP(type) operator type() const json_nothrow; operator unsigned type() const json_nothrow;
#endif
#ifdef JSON_MUTEX_CALLBACKS
#define initializeMutex(x) ,mylock(x)
#else
#define initializeMutex(x)
#endif
#if defined(JSON_PREPARSE) || !defined(JSON_READ_PRIORITY)
#define SetFetched(b) (void)0
#define Fetch() (void)0
#define initializeFetch(x)
#else
#define initializeFetch(x) ,fetched(x)
#endif
#ifdef JSON_REF_COUNT
#define initializeRefCount(x) ,refcount(x)
#else
#define initializeRefCount(x)
#endif
#ifdef JSON_COMMENTS
#define initializeComment(x) ,_comment(x)
#else
#define initializeComment(x)
#endif
#ifdef JSON_LESS_MEMORY
#define CHILDREN _value.Children
#define DELETE_CHILDREN()\
if (isContainer()){\
jsonChildren::deleteChildren(CHILDREN);\
}
#define CHILDREN_TO_NULL() (void)0
#define initializeChildren(x)
#else
#define CHILDREN Children
#define DELETE_CHILDREN()\
if (CHILDREN != 0) jsonChildren::deleteChildren(CHILDREN);
#define CHILDREN_TO_NULL() CHILDREN = 0
#define makeNotContainer() (void)0
#define makeContainer() if (!CHILDREN) CHILDREN = jsonChildren::newChildren()
#define initializeChildren(x) ,CHILDREN(x)
#endif
class internalJSONNode {
public:
LIBJSON_OBJECT(internalJSONNode);
internalJSONNode(char mytype = JSON_NULL) json_nothrow json_hot;
#ifdef JSON_READ_PRIORITY
internalJSONNode(const json_string & unparsed) json_nothrow json_hot;
internalJSONNode(const json_string & name_t, const json_string & value_t) json_nothrow json_read_priority;
#endif
internalJSONNode(const internalJSONNode & orig) json_nothrow json_hot;
internalJSONNode & operator = (const internalJSONNode &) json_nothrow json_hot;
~internalJSONNode(void) json_nothrow json_hot;
static internalJSONNode * newInternal(char mytype = JSON_NULL) json_hot;
#ifdef JSON_READ_PRIORITY
static internalJSONNode * newInternal(const json_string & unparsed) json_hot;
static internalJSONNode * newInternal(const json_string & name_t, const json_string & value_t) json_hot;
#endif
static internalJSONNode * newInternal(const internalJSONNode & orig) json_hot; //not copyable, only by this class
static void deleteInternal(internalJSONNode * ptr) json_nothrow json_hot;
json_index_t size(void) const json_nothrow json_read_priority;
bool empty(void) const json_nothrow;
unsigned char type(void) const json_nothrow json_read_priority;
json_string name(void) const json_nothrow json_read_priority;
void setname(const json_string & newname) json_nothrow json_write_priority;
#ifdef JSON_COMMENTS
void setcomment(const json_string & comment) json_nothrow;
json_string getcomment(void) const json_nothrow;
#endif
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
void preparse(void) json_nothrow;
#endif
#ifdef JSON_LIBRARY
void push_back(JSONNode * node) json_nothrow;
#else
void push_back(const JSONNode & node) json_nothrow;
#endif
void reserve(json_index_t siz) json_nothrow;
void push_front(const JSONNode & node) json_nothrow;
JSONNode * pop_back(json_index_t pos) json_nothrow;
JSONNode * pop_back(const json_string & name_t) json_nothrow;
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
JSONNode * pop_back_nocase(const json_string & name_t) json_nothrow;
#endif
JSONNode * at(json_index_t pos) json_nothrow;
//These return ** because pop_back needs them
JSONNode ** at(const json_string & name_t) json_nothrow;
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
JSONNode ** at_nocase(const json_string & name_t) json_nothrow;
#endif
void Set(const json_string & val) json_nothrow json_write_priority;
#ifdef JSON_LIBRARY
void Set(json_number val) json_nothrow json_write_priority;
void Set(json_int_t val) json_nothrow json_write_priority;
operator json_int_t() const json_nothrow;
operator json_number() const json_nothrow;
#else
DECL_SET_INTEGER(char)
DECL_SET_INTEGER(short)
DECL_SET_INTEGER(int)
DECL_SET_INTEGER(long)
#ifndef JSON_ISO_STRICT
DECL_SET_INTEGER(long long)
void Set(long double val) json_nothrow json_write_priority;
#endif
void Set(float val) json_nothrow json_write_priority;
void Set(double val) json_nothrow json_write_priority;
DECL_CAST_OP(char)
DECL_CAST_OP(short)
DECL_CAST_OP(int)
DECL_CAST_OP(long)
#ifndef JSON_ISO_STRICT
DECL_CAST_OP(long long)
operator long double() const json_nothrow;
#endif
operator float() const json_nothrow;
operator double() const json_nothrow;
#endif
operator json_string()const json_nothrow;
operator bool() const json_nothrow;
void Set(bool val) json_nothrow;
bool IsEqualTo(const json_string & val) const json_nothrow;
bool IsEqualTo(bool val) const json_nothrow;
bool IsEqualTo(const internalJSONNode * val) const json_nothrow;
template<typename T>
bool IsEqualToNum(T val) const json_nothrow;
internalJSONNode * incRef(void) json_nothrow;
#ifdef JSON_REF_COUNT
void decRef(void) json_nothrow json_hot;
bool hasNoReferences(void) json_nothrow json_hot;
#endif
internalJSONNode * makeUnique(void) json_nothrow json_hot;
JSONNode ** begin(void) const json_nothrow;
JSONNode ** end(void) const json_nothrow;
bool Fetched(void) const json_nothrow json_hot;
#ifdef JSON_MUTEX_CALLBACKS
void _set_mutex(void * mutex, bool unset = true) json_nothrow json_cold;
void _unset_mutex(void) json_nothrow json_cold;
#endif
#ifdef JSON_WRITE_PRIORITY
void DumpRawString(json_string & output) const json_nothrow json_write_priority;
void WriteName(bool formatted, bool arrayChild, json_string & output) const json_nothrow json_write_priority;
#ifdef JSON_ARRAY_SIZE_ON_ONE_LINE
void WriteChildrenOneLine(unsigned int indent, json_string & output) const json_nothrow json_write_priority;
#endif
void WriteChildren(unsigned int indent, json_string & output) const json_nothrow json_write_priority;
void WriteComment(unsigned int indent, json_string & output) const json_nothrow json_write_priority;
void Write(unsigned int indent, bool arrayChild, json_string & output) const json_nothrow json_write_priority;
#endif
inline bool isContainer(void) const json_nothrow {
return (_type == JSON_NODE || _type == JSON_ARRAY);
}
inline bool isNotContainer(void) const json_nothrow {
return (_type != JSON_NODE && _type != JSON_ARRAY);
}
#ifdef JSON_LESS_MEMORY
inline void makeNotContainer(void){
if (isContainer()){
jsonChildren::deleteChildren(CHILDREN);
}
}
inline void makeContainer(void){
if (isNotContainer()){
CHILDREN = jsonChildren::newChildren();
}
}
#endif
void Nullify(void) const json_nothrow;
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
void SetFetched(bool val) const json_nothrow json_hot;
void Fetch(void) const json_nothrow json_hot; //it's const because it doesn't change the VALUE of the function
#endif
#ifdef JSON_READ_PRIORITY
void FetchString(void) const json_nothrow json_read_priority;
void FetchNode(void) const json_nothrow json_read_priority;
void FetchArray(void) const json_nothrow json_read_priority;
#endif
void FetchNumber(void) const json_nothrow json_read_priority;
#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS
static bool AreEqualNoCase(const json_char * ch_one, const json_char * ch_two) json_nothrow json_read_priority;
#endif
inline void clearname(void) json_nothrow {
clearString(_name);
}
#ifdef JSON_DEBUG
#ifndef JSON_LIBRARY
JSONNode Dump(size_t & totalmemory) const json_nothrow;
JSONNode DumpMutex(void) const json_nothrow;
#endif
#endif
mutable unsigned char _type BITS(3);
json_string _name;
mutable bool _name_encoded BITS(1); //must be above name due to initialization list order
mutable json_string _string; //these are both mutable because the string can change when it's fetched
mutable bool _string_encoded BITS(1);
//the value of the json
union value_union_t {
bool _bool BITS(1);
json_number _number;
#ifdef JSON_LESS_MEMORY
jsonChildren * Children;
#endif
};
mutable value_union_t _value; //internal structure changes depending on type
#ifdef JSON_MUTEX_CALLBACKS
void * mylock;
#endif
#ifdef JSON_REF_COUNT
size_t refcount PACKED(20);
#endif
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
mutable bool fetched BITS(1);
#endif
#ifdef JSON_COMMENTS
json_string _comment;
#endif
#ifndef JSON_LESS_MEMORY
jsonChildren * CHILDREN;
#endif
};
inline internalJSONNode::internalJSONNode(char mytype) json_nothrow : _type(mytype), _name(), _name_encoded(), _string(), _string_encoded(), _value()
initializeMutex(0)
initializeRefCount(1)
initializeFetch(true)
initializeComment(json_global(EMPTY_JSON_STRING))
initializeChildren((_type == JSON_NODE || _type == JSON_ARRAY) ? jsonChildren::newChildren() : 0){
LIBJSON_CTOR;
#ifdef JSON_LESS_MEMORY
//if not less memory, its in the initialization list
if (isContainer()){
CHILDREN = jsonChildren::newChildren();
}
#endif
}
inline internalJSONNode * internalJSONNode::incRef(void) json_nothrow {
#ifdef JSON_REF_COUNT
++refcount;
return this;
#else
return makeUnique();
#endif
}
inline json_index_t internalJSONNode::size(void) const json_nothrow {
if (isNotContainer()) return 0;
Fetch();
return CHILDREN -> size();
}
inline bool internalJSONNode::empty(void) const json_nothrow {
if (isNotContainer()) return true;
Fetch();
return CHILDREN -> empty();
}
inline unsigned char internalJSONNode::type(void) const json_nothrow {
return _type;
}
inline json_string internalJSONNode::name(void) const json_nothrow {
return _name;
}
inline void internalJSONNode::setname(const json_string & newname) json_nothrow {
#ifdef JSON_LESS_MEMORY
JSON_ASSERT(newname.capacity() == newname.length(), JSON_TEXT("name object too large"));
#endif
_name = newname;
_name_encoded = true;
}
#ifdef JSON_COMMENTS
inline void internalJSONNode::setcomment(const json_string & comment) json_nothrow {
_comment = comment;
}
inline json_string internalJSONNode::getcomment(void) const json_nothrow {
return _comment;
}
#endif
inline bool internalJSONNode::IsEqualTo(const json_string & val) const json_nothrow {
if (type() != JSON_STRING) return false;
Fetch();
return _string == val;
}
inline bool internalJSONNode::IsEqualTo(bool val) const json_nothrow {
if (type() != JSON_BOOL) return false;
Fetch();
return val == _value._bool;
}
template<typename T>
inline bool internalJSONNode::IsEqualToNum(T val) const json_nothrow {
if (type() != JSON_NUMBER) return false;
Fetch();
return (json_number)val == _value._number;
}
#ifdef JSON_REF_COUNT
inline void internalJSONNode::decRef(void) json_nothrow {
JSON_ASSERT(refcount != 0, JSON_TEXT("decRef on a 0 refcount internal"));
--refcount;
}
inline bool internalJSONNode::hasNoReferences(void) json_nothrow {
return refcount == 0;
}
#endif
inline internalJSONNode * internalJSONNode::makeUnique(void) json_nothrow {
#ifdef JSON_REF_COUNT
if (refcount > 1){
decRef();
return newInternal(*this);
}
JSON_ASSERT(refcount == 1, JSON_TEXT("makeUnique on a 0 refcount internal"));
return this;
#else
return newInternal(*this);
#endif
}
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
inline void internalJSONNode::SetFetched(bool val) const json_nothrow {
fetched = val;
}
#endif
inline bool internalJSONNode::Fetched(void) const json_nothrow {
#if !defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY)
return fetched;
#else
return true;
#endif
}
inline JSONNode ** internalJSONNode::begin(void) const json_nothrow {
JSON_ASSERT_SAFE(isContainer(), json_global(ERROR_NON_CONTAINER) + JSON_TEXT("begin"), return 0;);
Fetch();
return CHILDREN -> begin();
}
inline JSONNode ** internalJSONNode::end(void) const json_nothrow {
JSON_ASSERT_SAFE(isContainer(), json_global(ERROR_NON_CONTAINER) + JSON_TEXT("end"), return 0;);
Fetch();
return CHILDREN -> end();
}
inline JSONNode * internalJSONNode::at(json_index_t pos) json_nothrow {
JSON_ASSERT_SAFE(isContainer(), JSON_TEXT("calling at on non-container type"), return 0;);
Fetch();
return (*CHILDREN)[pos];
}
#if defined(JSON_LESS_MEMORY) && defined(__GNUC__)
inline void internalJSONNode::reserve(json_index_t __attribute__((unused)) siz) json_nothrow
#else
inline void internalJSONNode::reserve(json_index_t siz) json_nothrow
#endif
{
JSON_ASSERT_SAFE(isContainer(), json_global(ERROR_NON_CONTAINER) + JSON_TEXT("reserve"), return;);
Fetch();
jsonChildren::reserve2(CHILDREN, siz);
}
/*
cast operators
*/
#ifndef JSON_LIBRARY
#ifdef JSON_ISO_STRICT
#define BASE_CONVERT_TYPE long
#else
#define BASE_CONVERT_TYPE long long
#endif
#define IMP_SMALLER_INT_CAST_OP(_type, type_max, type_min)\
inline internalJSONNode::operator _type() const json_nothrow {\
JSON_ASSERT(_value._number > type_min, _string + json_global(ERROR_LOWER_RANGE) + JSON_TEXT(#_type));\
JSON_ASSERT(_value._number < type_max, _string + json_global(ERROR_UPPER_RANGE) + JSON_TEXT(#_type));\
JSON_ASSERT(_value._number == (json_number)((_type)(_value._number)), json_string(JSON_TEXT("(")) + json_string(JSON_TEXT(#_type)) + json_string(JSON_TEXT(") will truncate ")) + _string);\
return (_type)static_cast<BASE_CONVERT_TYPE>(*this);\
}
IMP_SMALLER_INT_CAST_OP(char, CHAR_MAX, CHAR_MIN)
IMP_SMALLER_INT_CAST_OP(unsigned char, UCHAR_MAX, 0)
IMP_SMALLER_INT_CAST_OP(short, SHRT_MAX, SHRT_MIN)
IMP_SMALLER_INT_CAST_OP(unsigned short, USHRT_MAX, 0)
IMP_SMALLER_INT_CAST_OP(int, INT_MAX, INT_MIN)
IMP_SMALLER_INT_CAST_OP(unsigned int, UINT_MAX, 0)
#ifndef JSON_ISO_STRICT
IMP_SMALLER_INT_CAST_OP(long, LONG_MAX, LONG_MIN)
IMP_SMALLER_INT_CAST_OP(unsigned long, ULONG_MAX, 0)
#endif
#endif
inline internalJSONNode::operator json_string() const json_nothrow {
Fetch();
return _string;
}
#ifndef JSON_LIBRARY
#ifndef JSON_ISO_STRICT
inline internalJSONNode::operator float() const json_nothrow {
return static_cast<float>(static_cast<long double>(*this));
}
inline internalJSONNode::operator double() const json_nothrow {
return static_cast<double>(static_cast<long double>(*this));
}
#else
inline internalJSONNode::operator float() const json_nothrow {
return static_cast<float>(static_cast<double>(*this));
}
#endif
#endif
#ifdef JSON_LESS_MEMORY
#ifdef __GNUC__
#pragma pack(pop)
#elif _MSC_VER
#pragma pack(pop, internalJSONNode_pack,)
#endif
#endif
#endif