#ifndef JSONCHILDREN_H #define JSONCHILDREN_H #include "JSONMemory.h" #include "JSONDebug.h" //for JSON_ASSERT macro #ifdef JSON_LESS_MEMORY #ifdef __GNUC__ #pragma pack(push, 1) #elif _MSC_VER #pragma pack(push, jsonChildren, 1) #endif #endif #define json_foreach(chldrn, itrtr)\ JSONNode ** itrtr = chldrn -> begin();\ for(JSONNode ** itrtr##_end = chldrn -> end(); itrtr != itrtr##_end; ++itrtr) /* This class is essentially a vector that has been heavily optimized for the specific purpose of holding JSONNode children. It acts the same way as a vector, it has a automatically expanding array. On destruction, this container automatically destroys everything contained in it as well, so that you libjson doesn't have to do that. T is JSONNode*, I can't define it that way directly because JSONNode uses this container, and because the container deletes the children automatically, forward declaration can't be used */ class JSONNode; //forward declaration #ifdef JSON_LESS_MEMORY #define childrenVirtual virtual #else #define childrenVirtual #endif class jsonChildren { public: LIBJSON_OBJECT(jsonChildren); //starts completely empty and the array is not allocated jsonChildren(void) json_nothrow : array(0), mysize(0), mycapacity(0) { LIBJSON_CTOR; } #ifdef JSON_LESS_MEMORY jsonChildren(JSONNode** ar, json_index_t si, json_index_t ca) json_nothrow : array(ar), mysize(si), mycapacity(ca) { LIBJSON_CTOR; } #endif //deletes the array and everything that is contained within it (using delete) childrenVirtual ~jsonChildren(void) json_nothrow { if (json_unlikely(array != 0)){ //the following function calls are safe, but take more time than a check here deleteAll(); libjson_free(array); } LIBJSON_DTOR; } //increase the size of the array void inc(json_index_t amount) json_nothrow; void inc(void) json_nothrow; //Adds something to the vector, doubling the array if necessary void push_back(JSONNode * item) json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null push_back")); inc(); array[mysize++] = item; } //Adds something to the front of the vector, doubling the array if necessary void push_front(JSONNode * item) json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null push_front")); inc(); std::memmove(array + 1, array, mysize++ * sizeof(JSONNode *)); array[0] = item; } //gets an item out of the vector by it's position inline JSONNode * operator[] (json_index_t position) const json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null []")); JSON_ASSERT(position < mysize, JSON_TEXT("Using [] out of bounds")); JSON_ASSERT(position < mycapacity, JSON_TEXT("Using [] out of bounds")); JSON_ASSERT(array != 0, JSON_TEXT("Array is null")); return array[position]; } //returns the allocated capacity, but keep in mind that some might not be valid inline json_index_t capacity() const json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null capacity")); return mycapacity; } //returns the number of valid objects within the vector inline json_index_t size() const json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null size")); return mysize; } //tests whether or not the vector is empty inline bool empty() const json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null empty")); return mysize == 0; } //clears (and deletes) everything from the vector and sets it's size to 0 inline void clear() json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null clear")); if (json_likely(array != 0)){ //don't bother clearing anything if there is nothing in it JSON_ASSERT(mycapacity != 0, JSON_TEXT("mycapacity is not zero, but array is null")); deleteAll(); mysize = 0; } JSON_ASSERT(mysize == 0, JSON_TEXT("mysize is not zero after clear")); } //returns the beginning of the array inline JSONNode ** begin(void) const json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null begin")); return array; } //returns the end of the array inline JSONNode ** end(void) const json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null end")); return array + mysize; } //makes sure that even after shirnking and expanding, the iterator is in same relative position template struct iteratorKeeper { public: LIBJSON_OBJECT(jsonChildren::iteratorKeeper); iteratorKeeper(jsonChildren * pthis, JSONNode ** & position) json_nothrow : myRelativeOffset(reverse ? (json_index_t)(pthis -> array + (size_t)pthis -> mysize - position) : (json_index_t)(position - pthis -> array)), myChildren(pthis), myPos(position){ LIBJSON_CTOR; } ~iteratorKeeper(void) json_nothrow { LIBJSON_DTOR; if (reverse){ myPos = myChildren -> array + myChildren -> mysize - myRelativeOffset; } else { myPos = myChildren -> array + myRelativeOffset; } } private: iteratorKeeper(const iteratorKeeper &); iteratorKeeper & operator = (const iteratorKeeper &); json_index_t myRelativeOffset; jsonChildren * myChildren; JSONNode ** & myPos; }; //This function DOES NOT delete the item it points to inline void erase(JSONNode ** & position) json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null erase")); JSON_ASSERT(array != 0, JSON_TEXT("erasing something from a null array 1")); JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array 1")); JSON_ASSERT(position <= array + mysize, JSON_TEXT("erasing out of bounds 1")); std::memmove(position, position + 1, (mysize-- - (position - array) - 1) * sizeof(JSONNode *)); iteratorKeeper ik(this, position); shrink(); } //This function DOES NOT delete the item it points to inline void erase(JSONNode ** & position, json_index_t number) json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null erase 2")); doerase(position, number); iteratorKeeper ik(this, position); shrink(); } //This function DOES NOT delete the item it points to inline void erase(JSONNode ** position, json_index_t number, JSONNode ** & starter) json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null erase 3")); doerase(position, number); iteratorKeeper ik(this, starter); shrink(); } #ifdef JSON_LIBRARY void insert(JSONNode ** & position, JSONNode * item) json_nothrow{ #else void insert(JSONNode ** & position, JSONNode * item, bool reverse = false) json_nothrow { #endif JSON_ASSERT(this != 0, JSON_TEXT("Children is null insert")); //position isnt relative to array because of realloc JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 1")); JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 1")); #ifndef JSON_LIBRARY if (reverse){ iteratorKeeper ik(this, position); inc(); } else #endif { iteratorKeeper ik(this, position); inc(); } std::memmove(position + 1, position, (mysize++ - (position - array)) * sizeof(JSONNode *)); *position = item; } void insert(JSONNode ** & position, JSONNode ** items, json_index_t num) json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null insert 2")); JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 2")); JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 2")); { iteratorKeeper ik(this, position); inc(num); } const size_t ptrs = ((JSONNode **)(array + mysize)) - position; std::memmove(position + num, position, ptrs * sizeof(JSONNode *)); std::memcpy(position, items, num * sizeof(JSONNode *)); mysize += num; } inline void reserve(json_index_t amount) json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null reserve")); JSON_ASSERT(array == 0, JSON_TEXT("reserve is not meant to expand a preexisting array")); JSON_ASSERT(mycapacity == 0, JSON_TEXT("reservec is not meant to expand a preexisting array")); JSON_ASSERT(mysize == 0, JSON_TEXT("reserves is not meant to expand a preexisting array")); array = json_malloc(mycapacity = amount); } //it is static because mine might change pointers entirely static void reserve2(jsonChildren *& mine, json_index_t amount) json_nothrow; //shrinks the array to only as large as it needs to be to hold everything within it inline childrenVirtual void shrink() json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null shrink")); if (json_unlikely(mysize == 0)){ //size is zero, we should completely free the array libjson_free(array); //free does checks for a null pointer, so don't bother checking array = 0; #ifdef JSON_LESS_MEMORY } else { //need to shrink it, using realloc JSON_ASSERT(array != 0, JSON_TEXT("shrinking a null array that is not size 0")); array = json_realloc(array, mysize); #endif } mycapacity = mysize; } inline static void deleteChildren(jsonChildren * ptr) json_nothrow { #ifdef JSON_MEMORY_CALLBACKS ptr -> ~jsonChildren(); libjson_free(ptr); #else delete ptr; #endif } inline static jsonChildren * newChildren(void) { #ifdef JSON_MEMORY_CALLBACKS return new(json_malloc(1)) jsonChildren(); #else return new jsonChildren(); #endif } JSONNode ** array; //the expandable array json_index_t mysize; //the number of valid items json_index_t mycapacity; //the number of possible items JSON_PROTECTED //to make sure it's not copyable jsonChildren(const jsonChildren &); jsonChildren & operator = (const jsonChildren &); void deleteAll(void) json_nothrow json_hot; //implemented in JSONNode.cpp void doerase(JSONNode ** position, json_index_t number) json_nothrow; }; #ifdef JSON_LESS_MEMORY class jsonChildren_Reserved : public jsonChildren { public: LIBJSON_OBJECT(jsonChildren_Reserved); jsonChildren_Reserved(jsonChildren * orig, json_index_t siz) json_nothrow : jsonChildren(orig -> array, orig -> mysize, orig -> mycapacity), myreserved(siz) { orig -> array = 0; deleteChildren(orig); LIBJSON_CTOR; } jsonChildren_Reserved(const jsonChildren_Reserved & orig) json_nothrow : jsonChildren(orig.array, orig.mysize, orig.mycapacity), myreserved(orig.myreserved){ LIBJSON_COPY_CTOR; } inline virtual ~jsonChildren_Reserved() json_nothrow { LIBJSON_DTOR; }; inline virtual void shrink() json_nothrow { JSON_ASSERT(this != 0, JSON_TEXT("Children is null shrink reserved")); if (json_unlikely(mysize == 0)){ //size is zero, we should completely free the array libjson_free(array); //free does checks for a null pointer, so don't bother checking array = 0; } else if (mysize > myreserved){ JSON_ASSERT(array != 0, JSON_TEXT("shrinking a null array that is not size 0")); array = json_realloc(array, mysize); } } #ifdef JSON_LESS_MEMORY inline static jsonChildren * newChildren_Reserved(jsonChildren * orig, json_index_t siz) json_nothrow { #ifdef JSON_MEMORY_CALLBACKS return new(json_malloc(1)) jsonChildren_Reserved(orig, siz); #else return new jsonChildren_Reserved(orig, siz); #endif } #endif JSON_PRIVATE jsonChildren_Reserved & operator = (const jsonChildren_Reserved &); json_index_t myreserved; }; #endif #ifdef JSON_LESS_MEMORY #ifdef __GNUC__ #pragma pack(pop) #elif _MSC_VER #pragma pack(pop, jsonChildren) #endif #endif #endif