1 #ifndef JSONCHILDREN_H 2 #define JSONCHILDREN_H 3 4 #include "JSONMemory.h" 5 #include "JSONDebug.h" //for JSON_ASSERT macro 6 7 #ifdef JSON_LESS_MEMORY 8 #ifdef __GNUC__ 9 #pragma pack(push, 1) 10 #elif _MSC_VER 11 #pragma pack(push, jsonChildren, 1) 12 #endif 13 #endif 14 15 #define json_foreach(chldrn, itrtr)\ 16 JSONNode ** itrtr = chldrn -> begin();\ 17 for(JSONNode ** itrtr##_end = chldrn -> end(); itrtr != itrtr##_end; ++itrtr) 18 19 /* 20 This class is essentially a vector that has been heavily optimized for the specific purpose 21 of holding JSONNode children. It acts the same way as a vector, it has a automatically 22 expanding array. On destruction, this container automatically destroys everything contained 23 in it as well, so that you libjson doesn't have to do that. 24 25 T is JSONNode*, I can't define it that way directly because JSONNode uses this container, and because 26 the container deletes the children automatically, forward declaration can't be used 27 */ 28 29 class JSONNode; //forward declaration 30 31 #ifdef JSON_LESS_MEMORY 32 #define childrenVirtual virtual 33 #else 34 #define childrenVirtual 35 #endif 36 37 class jsonChildren { 38 public: 39 LIBJSON_OBJECT(jsonChildren); 40 //starts completely empty and the array is not allocated jsonChildren(void)41 jsonChildren(void) json_nothrow : array(0), mysize(0), mycapacity(0) { 42 LIBJSON_CTOR; 43 } 44 45 #ifdef JSON_LESS_MEMORY jsonChildren(JSONNode ** ar,json_index_t si,json_index_t ca)46 jsonChildren(JSONNode** ar, json_index_t si, json_index_t ca) json_nothrow : array(ar), mysize(si), mycapacity(ca) { 47 LIBJSON_CTOR; 48 } 49 #endif 50 51 //deletes the array and everything that is contained within it (using delete) ~jsonChildren(void)52 childrenVirtual ~jsonChildren(void) json_nothrow { 53 if (json_unlikely(array != 0)){ //the following function calls are safe, but take more time than a check here 54 deleteAll(); 55 libjson_free<JSONNode*>(array); 56 } 57 LIBJSON_DTOR; 58 } 59 60 //increase the size of the array 61 void inc(json_index_t amount) json_nothrow; 62 void inc(void) json_nothrow; 63 64 //Adds something to the vector, doubling the array if necessary push_back(JSONNode * item)65 void push_back(JSONNode * item) json_nothrow { 66 JSON_ASSERT(this != 0, JSON_TEXT("Children is null push_back")); 67 inc(); 68 array[mysize++] = item; 69 } 70 71 //Adds something to the front of the vector, doubling the array if necessary push_front(JSONNode * item)72 void push_front(JSONNode * item) json_nothrow { 73 JSON_ASSERT(this != 0, JSON_TEXT("Children is null push_front")); 74 inc(); 75 std::memmove(array + 1, array, mysize++ * sizeof(JSONNode *)); 76 array[0] = item; 77 } 78 79 //gets an item out of the vector by it's position 80 inline JSONNode * operator[] (json_index_t position) const json_nothrow { 81 JSON_ASSERT(this != 0, JSON_TEXT("Children is null []")); 82 JSON_ASSERT(position < mysize, JSON_TEXT("Using [] out of bounds")); 83 JSON_ASSERT(position < mycapacity, JSON_TEXT("Using [] out of bounds")); 84 JSON_ASSERT(array != 0, JSON_TEXT("Array is null")); 85 return array[position]; 86 } 87 88 //returns the allocated capacity, but keep in mind that some might not be valid capacity()89 inline json_index_t capacity() const json_nothrow { 90 JSON_ASSERT(this != 0, JSON_TEXT("Children is null capacity")); 91 return mycapacity; 92 } 93 94 //returns the number of valid objects within the vector size()95 inline json_index_t size() const json_nothrow { 96 JSON_ASSERT(this != 0, JSON_TEXT("Children is null size")); 97 return mysize; 98 } 99 100 //tests whether or not the vector is empty empty()101 inline bool empty() const json_nothrow { 102 JSON_ASSERT(this != 0, JSON_TEXT("Children is null empty")); 103 return mysize == 0; 104 } 105 106 //clears (and deletes) everything from the vector and sets it's size to 0 clear()107 inline void clear() json_nothrow { 108 JSON_ASSERT(this != 0, JSON_TEXT("Children is null clear")); 109 if (json_likely(array != 0)){ //don't bother clearing anything if there is nothing in it 110 JSON_ASSERT(mycapacity != 0, JSON_TEXT("mycapacity is not zero, but array is null")); 111 deleteAll(); 112 mysize = 0; 113 } 114 JSON_ASSERT(mysize == 0, JSON_TEXT("mysize is not zero after clear")); 115 } 116 117 //returns the beginning of the array begin(void)118 inline JSONNode ** begin(void) const json_nothrow { 119 JSON_ASSERT(this != 0, JSON_TEXT("Children is null begin")); 120 return array; 121 } 122 123 //returns the end of the array end(void)124 inline JSONNode ** end(void) const json_nothrow { 125 JSON_ASSERT(this != 0, JSON_TEXT("Children is null end")); 126 return array + mysize; 127 } 128 129 //makes sure that even after shirnking and expanding, the iterator is in same relative position 130 template <bool reverse> 131 struct iteratorKeeper { 132 public: 133 LIBJSON_OBJECT(jsonChildren::iteratorKeeper); iteratorKeeperiteratorKeeper134 iteratorKeeper(jsonChildren * pthis, JSONNode ** & position) json_nothrow : 135 myRelativeOffset(reverse ? (json_index_t)(pthis -> array + (size_t)pthis -> mysize - position) : (json_index_t)(position - pthis -> array)), 136 myChildren(pthis), 137 myPos(position){ 138 LIBJSON_CTOR; 139 } 140 ~iteratorKeeperiteratorKeeper141 ~iteratorKeeper(void) json_nothrow { 142 LIBJSON_DTOR; 143 if (reverse){ 144 myPos = myChildren -> array + myChildren -> mysize - myRelativeOffset; 145 } else { 146 myPos = myChildren -> array + myRelativeOffset; 147 } 148 } 149 private: 150 iteratorKeeper(const iteratorKeeper &); 151 iteratorKeeper & operator = (const iteratorKeeper &); 152 153 json_index_t myRelativeOffset; 154 jsonChildren * myChildren; 155 JSONNode ** & myPos; 156 }; 157 158 //This function DOES NOT delete the item it points to erase(JSONNode ** & position)159 inline void erase(JSONNode ** & position) json_nothrow { 160 JSON_ASSERT(this != 0, JSON_TEXT("Children is null erase")); 161 JSON_ASSERT(array != 0, JSON_TEXT("erasing something from a null array 1")); 162 JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array 1")); 163 JSON_ASSERT(position <= array + mysize, JSON_TEXT("erasing out of bounds 1")); 164 std::memmove(position, position + 1, (mysize-- - (position - array) - 1) * sizeof(JSONNode *)); 165 iteratorKeeper<false> ik(this, position); 166 shrink(); 167 } 168 169 //This function DOES NOT delete the item it points to erase(JSONNode ** & position,json_index_t number)170 inline void erase(JSONNode ** & position, json_index_t number) json_nothrow { 171 JSON_ASSERT(this != 0, JSON_TEXT("Children is null erase 2")); 172 doerase(position, number); 173 iteratorKeeper<false> ik(this, position); 174 shrink(); 175 } 176 177 178 //This function DOES NOT delete the item it points to erase(JSONNode ** position,json_index_t number,JSONNode ** & starter)179 inline void erase(JSONNode ** position, json_index_t number, JSONNode ** & starter) json_nothrow { 180 JSON_ASSERT(this != 0, JSON_TEXT("Children is null erase 3")); 181 doerase(position, number); 182 iteratorKeeper<false> ik(this, starter); 183 shrink(); 184 } 185 186 #ifdef JSON_LIBRARY insert(JSONNode ** & position,JSONNode * item)187 void insert(JSONNode ** & position, JSONNode * item) json_nothrow{ 188 #else 189 void insert(JSONNode ** & position, JSONNode * item, bool reverse = false) json_nothrow { 190 #endif 191 JSON_ASSERT(this != 0, JSON_TEXT("Children is null insert")); 192 //position isnt relative to array because of realloc 193 JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 1")); 194 JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 1")); 195 #ifndef JSON_LIBRARY 196 if (reverse){ 197 iteratorKeeper<true> ik(this, position); 198 inc(); 199 } else 200 #endif 201 { 202 iteratorKeeper<false> ik(this, position); 203 inc(); 204 } 205 206 std::memmove(position + 1, position, (mysize++ - (position - array)) * sizeof(JSONNode *)); 207 *position = item; 208 } 209 210 void insert(JSONNode ** & position, JSONNode ** items, json_index_t num) json_nothrow { 211 JSON_ASSERT(this != 0, JSON_TEXT("Children is null insert 2")); 212 JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 2")); 213 JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 2")); 214 { 215 iteratorKeeper<false> ik(this, position); 216 inc(num); 217 } 218 const size_t ptrs = ((JSONNode **)(array + mysize)) - position; 219 std::memmove(position + num, position, ptrs * sizeof(JSONNode *)); 220 std::memcpy(position, items, num * sizeof(JSONNode *)); 221 mysize += num; 222 } 223 224 inline void reserve(json_index_t amount) json_nothrow { 225 JSON_ASSERT(this != 0, JSON_TEXT("Children is null reserve")); 226 JSON_ASSERT(array == 0, JSON_TEXT("reserve is not meant to expand a preexisting array")); 227 JSON_ASSERT(mycapacity == 0, JSON_TEXT("reservec is not meant to expand a preexisting array")); 228 JSON_ASSERT(mysize == 0, JSON_TEXT("reserves is not meant to expand a preexisting array")); 229 array = json_malloc<JSONNode*>(mycapacity = amount); 230 } 231 232 //it is static because mine might change pointers entirely 233 static void reserve2(jsonChildren *& mine, json_index_t amount) json_nothrow; 234 235 //shrinks the array to only as large as it needs to be to hold everything within it 236 inline childrenVirtual void shrink() json_nothrow { 237 JSON_ASSERT(this != 0, JSON_TEXT("Children is null shrink")); 238 if (json_unlikely(mysize == 0)){ //size is zero, we should completely free the array 239 libjson_free<JSONNode*>(array); //free does checks for a null pointer, so don't bother checking 240 array = 0; 241 #ifdef JSON_LESS_MEMORY 242 } else { //need to shrink it, using realloc 243 JSON_ASSERT(array != 0, JSON_TEXT("shrinking a null array that is not size 0")); 244 array = json_realloc<JSONNode*>(array, mysize); 245 #endif 246 } 247 mycapacity = mysize; 248 } 249 250 251 inline static void deleteChildren(jsonChildren * ptr) json_nothrow { 252 #ifdef JSON_MEMORY_CALLBACKS 253 ptr -> ~jsonChildren(); 254 libjson_free<jsonChildren>(ptr); 255 #else 256 delete ptr; 257 #endif 258 } 259 260 inline static jsonChildren * newChildren(void) { 261 #ifdef JSON_MEMORY_CALLBACKS 262 return new(json_malloc<jsonChildren>(1)) jsonChildren(); 263 #else 264 return new jsonChildren(); 265 #endif 266 } 267 268 JSONNode ** array; //the expandable array 269 270 json_index_t mysize; //the number of valid items 271 json_index_t mycapacity; //the number of possible items 272 JSON_PROTECTED 273 //to make sure it's not copyable 274 jsonChildren(const jsonChildren &); 275 jsonChildren & operator = (const jsonChildren &); 276 277 void deleteAll(void) json_nothrow json_hot; //implemented in JSONNode.cpp 278 void doerase(JSONNode ** position, json_index_t number) json_nothrow; 279 }; 280 281 #ifdef JSON_LESS_MEMORY 282 class jsonChildren_Reserved : public jsonChildren { 283 public: 284 LIBJSON_OBJECT(jsonChildren_Reserved); jsonChildren_Reserved(jsonChildren * orig,json_index_t siz)285 jsonChildren_Reserved(jsonChildren * orig, json_index_t siz) json_nothrow : jsonChildren(orig -> array, orig -> mysize, orig -> mycapacity), myreserved(siz) { 286 orig -> array = 0; 287 deleteChildren(orig); 288 LIBJSON_CTOR; 289 } jsonChildren_Reserved(const jsonChildren_Reserved & orig)290 jsonChildren_Reserved(const jsonChildren_Reserved & orig) json_nothrow : jsonChildren(orig.array, orig.mysize, orig.mycapacity), myreserved(orig.myreserved){ 291 LIBJSON_COPY_CTOR; 292 } ~jsonChildren_Reserved()293 inline virtual ~jsonChildren_Reserved() json_nothrow { 294 LIBJSON_DTOR; 295 }; shrink()296 inline virtual void shrink() json_nothrow { 297 JSON_ASSERT(this != 0, JSON_TEXT("Children is null shrink reserved")); 298 if (json_unlikely(mysize == 0)){ //size is zero, we should completely free the array 299 libjson_free<JSONNode*>(array); //free does checks for a null pointer, so don't bother checking 300 array = 0; 301 } else if (mysize > myreserved){ 302 JSON_ASSERT(array != 0, JSON_TEXT("shrinking a null array that is not size 0")); 303 array = json_realloc<JSONNode*>(array, mysize); 304 } 305 } 306 307 #ifdef JSON_LESS_MEMORY newChildren_Reserved(jsonChildren * orig,json_index_t siz)308 inline static jsonChildren * newChildren_Reserved(jsonChildren * orig, json_index_t siz) json_nothrow { 309 #ifdef JSON_MEMORY_CALLBACKS 310 return new(json_malloc<jsonChildren_Reserved>(1)) jsonChildren_Reserved(orig, siz); 311 #else 312 return new jsonChildren_Reserved(orig, siz); 313 #endif 314 } 315 #endif 316 JSON_PRIVATE 317 jsonChildren_Reserved & operator = (const jsonChildren_Reserved &); 318 json_index_t myreserved; 319 }; 320 #endif 321 322 #ifdef JSON_LESS_MEMORY 323 #ifdef __GNUC__ 324 #pragma pack(pop) 325 #elif _MSC_VER 326 #pragma pack(pop, jsonChildren) 327 #endif 328 #endif 329 #endif 330