The R Project SVN R-packages

Rev

Blame | Last modification | View Log | Download | RSS feed

#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);

    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