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