1 //---------------------------------------------------------------------------
2 /*
3 Sortable collection of pointers to objects
4 */
5
6 #ifndef GListHH
7 #define GListHH
8
9 #include "GBase.h"
10 //#include "assert.h"
11 #ifdef __LINE__
12 #define SLISTINDEX_ERR "GList error (%s:%d):Invalid list index: %d"
13 #define TEST_INDEX(x) \
14 if (x<0 || x>=fCount) GError(SLISTINDEX_ERR, __FILE__,__LINE__, x)
15 #else
16 #define SLISTINDEX_ERR "GList error:Invalid list index: %d"
17 #define TEST_INDEX(x) \
18 if (x<0 || x>=fCount) GError(SLISTINDEX_ERR, x, __FILE__,__LINE__)
19 #endif
20
21 #define SLISTCAPACITY_ERR "GList error: invalid capacity: %d"
22 #define SLISTCOUNT_ERR "GList error: invalid count: %d"
23 #define SLISTSORTED_ERR "Operation not allowed on a sorted list!"
24 #define SLISTUNSORTED_ERR "Operation not allowed on an unsorted list!"
25
26 // ------ macros:
27 #define BE_UNSORTED if (fCompareProc!=NULL) { GError(SLISTSORTED_ERR); return; }
28 #define BE_SORTED if (fCompareProc==NULL) { GError(SLISTUNSORTED_ERR); return; }
29
30 #define MAXLISTSIZE INT_MAX-1
31
32 #define SORTED (fCompareProc!=NULL)
33 #define UNSORTED (fCompareProc==NULL)
34 #define FREEDATA (fFreeProc!=NULL)
35 /* #define TEST_INDEX(x) assert(x>=0 && x<fCount); \
36 if (x<0 || x>=fCount) GError(SLISTINDEX_ERR, x) */
37
38
39 //template for array of objects
40 template <class OBJ> class GArray {
41 protected:
42 OBJ* fArray;
43 int fCount;
44 int fCapacity;
45 bool fUnique;
46
DefaultCompareProc(OBJ & item1,OBJ & item2)47 static int DefaultCompareProc(OBJ& item1, OBJ& item2) {
48 //the comparison operators MUST be defined for OBJ class!
49 if ( item1 > item2) return 1;
50 else return (item2 > item1) ? -1 : 0 ;
51 }
52 public:
53 typedef int CompareProc(OBJ& item1, OBJ& item2);
54 protected:
55 CompareProc* fCompareProc;
56 void idxInsert(int idx, OBJ& item);
57 void Grow();
58 void Grow(int idx, OBJ& item);
59 void qSort(int L, int R);
60 public:
61 GArray(CompareProc* cmpFunc=NULL);
62 GArray(bool sorted, bool unique=false);
63 GArray(int init_capacity, bool sorted, bool unique=false);
64 GArray(GArray<OBJ>& array); //copy constructor
65 const GArray<OBJ>& operator=(GArray& array);
66 virtual ~GArray();
67 //assignment operator
68 void setSorted(CompareProc* cmpFunc);
69 //sort the array if cmpFunc not NULL or changes
70 void Reverse(); //WARNING: will break the sort order if SORTED!
71 int Add(OBJ* item); // specific implementation if sorted
Add(OBJ & item)72 int Add(OBJ& item) { return Add(&item); } //both will CREATE a new OBJ and COPY to it
73 // using OBJ new operator=
74 void Add(GArray<OBJ>& list); //add copies of all items from another list
Get(int idx)75 OBJ& Get(int idx) {
76 TEST_INDEX(idx);
77 return fArray[idx];
78 }
operator [](int i)79 OBJ& operator[](int i) {
80 TEST_INDEX(i);
81 return fArray[i];
82 }
83 void Clear();
84 void Delete(int index);
85 void Exchange(int idx1, int idx2);
Capacity()86 int Capacity() { return fCapacity; }
Unique()87 int Unique() { return fUnique; }
88 //this will reject identical items in sorted lists only!
setUnique(bool beUnique)89 void setUnique(bool beUnique) { fUnique = beUnique; };
90 void setCapacity(int NewCapacity);
Count()91 int Count() { return fCount; }
92 void setCount(int NewCount);
93 void Sort(); //explicit sort may be requested
Sorted()94 bool Sorted() { return fCompareProc!=NULL; }
95 int IndexOf(OBJ& item);
96 //this needs the == operator to have been defined for OBJ
97 bool Found(OBJ& item, int& idx); // for sorted arrays only;
98 //search by content; if found, returns true and idx will be the index
99 //of the first item found matching for which CompareProc returns 0
100 bool Exists(OBJ& item); //same as above without existing index info
101 //unsorted only, place item at position idx:
102 void Insert(int idx, OBJ* item);
Insert(int idx,OBJ & item)103 void Insert(int idx, OBJ& item) { Insert(idx,&item); }
104 void Replace(int idx, OBJ& item); //Put, use operator= to copy
105 void Move(int curidx, int newidx);
106 };
107
108 //------- template for array of pointers to objects ---------
109 template <class OBJ> class GList {
110 protected:
111 OBJ** fList; //pointer to an array of pointers to objects
112 int fCount; //total number of entries in list
113 int fCapacity; //current allocated size
114 bool fUnique;
115 GCompareProc* fCompareProc; //a pointer to a Compare function
116 GFreeProc* fFreeProc; //useful for deleting objects
DefaultCompareProc(const pointer item1,const pointer item2)117 static int DefaultCompareProc(const pointer item1, const pointer item2) {
118 //the comparison operators MUST be defined for OBJ class!
119 if (*((OBJ*)item1) > *((OBJ*)item2)) return 1;
120 else if (*((OBJ*)item2) > *((OBJ*)item1)) return -1;
121 else return 0;
122 }
123 void Expand();
124 void Grow();
125 void QuickSort(int L, int R);
126 public:
127 void sortInsert(int idx, OBJ* item);
DefaultFreeProc(pointer item)128 static void DefaultFreeProc(pointer item) {
129 delete (OBJ*)item;
130 }
131 GList(GCompareProc* compareProc=NULL); //free by default
132 GList(GCompareProc* compareProc, //unsorted by default
133 GFreeProc *freeProc,
134 bool beUnique=false);
135 GList(bool sorted, bool free_elements=true, bool beUnique=false);
136 GList(int init_capacity, bool sorted, bool free_elements=true, bool beUnique=false);
137 GList(GList<OBJ>& list); //copy constructor?
138 GList(GList<OBJ>* list); //kind of a copy constructor
139 virtual ~GList();
140 void Reverse(); //reverse pointer array; WARNING: will break the sort order if sorted!
141 void freeItem(int idx);
142 void setSorted(GCompareProc* compareProc);
143 //sorted if compareProc not NULL; sort the list if compareProc changes !
setFreeItem(GFreeProc * freeProc)144 void setFreeItem(GFreeProc *freeProc) { fFreeProc=freeProc; }
setFreeItem(bool doFree)145 void setFreeItem(bool doFree) {
146 if (doFree) fFreeProc=DefaultFreeProc;
147 else fFreeProc=NULL;
148 }
Sorted()149 bool Sorted() { return fCompareProc!=NULL; }
setSorted(bool sorted)150 void setSorted(bool sorted) {
151 if (sorted) {
152 if (fCompareProc!=&DefaultCompareProc) {
153 fCompareProc=&DefaultCompareProc;
154 Sort();
155 }
156 }
157 else fCompareProc=NULL;
158 }
159 int Add(OBJ* item); //-- specific implementation if sorted
160 void Add(GList<OBJ>& list); //add all pointers from another list
161
162 OBJ* AddIfNew(OBJ* item, bool deleteIfFound=true, int* fidx=NULL);
163 // default: delete item if Found() (and pointers are not equal)!
164 //returns the equal (==) object if it's in the list already
165 //or the item itself if it is unique, and it addsit
166
167 // -- stack usage:
Push(OBJ * item)168 int Push(OBJ* item) { return Add(item); }
169 OBJ* Pop();// Stack use; removes and returns last item,but does NOT FREE it
170 OBJ* Shift(); //Queue use: removes and returns first item, but does NOT FREE it
171 void Clear();
172 void Delete(int index);
173 void Forget(int idx);
174 void Exchange(int idx1, int idx2);
First()175 OBJ* First() { return (fCount>0)?fList[0]:NULL; }
Last()176 OBJ* Last() { return (fCount>0)?fList[fCount-1]:NULL;}
isEmpty()177 bool isEmpty() { return fCount==0; }
notEmpty()178 bool notEmpty() { return fCount>0; }
Capacity()179 int Capacity() { return fCapacity; }
Unique()180 int Unique() { return fUnique; }
181 //this will reject identical items in sorted lists only!
setUnique(bool beUnique)182 void setUnique(bool beUnique) { fUnique = beUnique; };
183
184 void setCapacity(int NewCapacity);
Count()185 int Count() { return fCount; }
186 void setCount(int NewCount);
GetCompareProc()187 GCompareProc* GetCompareProc() {return fCompareProc;}
188 OBJ* Get(int idx);
189 OBJ* operator[](int i);
190 void Grow(int idx, OBJ* item);
191 int IndexOf(OBJ* item); //this has a specific implementation for sorted lists
192 //if list is sorted, item data is located by binary search
193 //based on the Compare function
194 //if not, a linear search is performed, but
195 //this needs the == operator to have been defined for OBJ
196 bool Found(OBJ* item, int & idx); // sorted only;
197 //search by content; if found, returns true and idx will be the index
198 //of the first item found matching for which GTCompareProc returns 0
199 bool Exists(OBJ* item); //same as above without existing index info
200 bool Exists(OBJ& item); //same as above without existing index info
201 void Insert(int idx, OBJ* item); //unsorted only, place item at position idx
202 void Move(int curidx, int newidx);
203 void Put(int idx, OBJ* item, bool re_sort=false);
204 int Remove(OBJ* item); //search for pointer, using binary search if sorted
205 int RemovePtr(OBJ* item); //always use linear search to find the pointer!
206 void Pack();
207 void Sort(); //explicit sort may be requested using this function
208 const GList<OBJ>& operator=(GList& list);
209 };
210
211
212 //basic template for a Stack of pointers
213 template <class OBJ> class GStack {
214 protected:
215 struct StackOBJ {
216 OBJ* obj;
217 StackOBJ* prev;
218 };
219 int fCount; //total number of elements in stack
220 StackOBJ* base;
221 StackOBJ* top;
222 public:
GStack(OBJ * po=NULL)223 GStack(OBJ* po=NULL) {
224 base=NULL;
225 top=NULL;
226 fCount=0;
227 if (po!=NULL) Push(po);
228 }
~GStack()229 ~GStack() {
230 while (fCount>0) Pop();
231 }
isEmpty()232 bool isEmpty() { return fCount==0; }
Size()233 int Size() { return fCount; }
Count()234 int Count() { return fCount; }
Pop()235 OBJ* Pop() {
236 if (top==NULL) return NULL;
237 fCount--;
238 StackOBJ* ctop=top;
239 if (top==base) base=NULL;
240 OBJ* r=top->obj;
241 top=top->prev;
242 GFREE(ctop);
243 return r;
244 }
Push(OBJ * o)245 OBJ* Push(OBJ* o) {
246 fCount++;
247 StackOBJ* ctop=top; //could be NULL
248 GMALLOC(top, sizeof(StackOBJ));
249 top->obj=o;
250 top->prev=ctop;
251 if (base==NULL) base=top;
252 return o;
253 }
Top()254 OBJ* Top() { return ((top==NULL)? NULL : top->obj); }
Base()255 OBJ* Base() { return ((base==NULL)? NULL : base->obj); }
256 };
257
258 //-------------------- TEMPLATE IMPLEMENTATION-------------------------------
259
GArray(GArray & array)260 template <class OBJ> GArray<OBJ>::GArray(GArray& array) { //copy constructor
261 fCount=array.fCount;
262 fCapacity=array.fCapacity;
263 if (fCapacity>0) {
264 GMALLOC(fArray, fCapacity*sizeof(OBJ));
265 }
266 fUnique=array.fUnique;
267 fCompareProc=array.fCompareProc;
268 fCount=array.fCount;
269 // uses OBJ operator=
270 for (int i=0;i<fCount;i++) fArray[i]=array[i];
271 }
272
operator =(GArray & array)273 template <class OBJ> const GArray<OBJ>& GArray<OBJ>::operator=(GArray& array) {
274 if (&array==this) return *this;
275 Clear();
276 fCount=array.fCount;
277 fUnique=array.fUnique;
278 fCapacity=array.fCapacity;
279 if (fCapacity>0) {
280 GMALLOC(fArray, fCapacity*sizeof(OBJ));
281 }
282 fCompareProc=array.fCompareProc;
283 fCount=array.fCount;
284 // uses OBJ operator=
285 for (int i=0;i<fCount;i++) {
286 fArray[i]=array[i];
287 }
288 return *this;
289 }
GArray(CompareProc * cmpFunc)290 template <class OBJ> GArray<OBJ>::GArray(CompareProc* cmpFunc) {
291 fCount=0;
292 fCapacity=0;
293 fArray=NULL;
294 fCompareProc = cmpFunc;
295 fUnique = false; //only affects sorted lists
296 }
297
GArray(bool sorted,bool unique)298 template <class OBJ> GArray<OBJ>::GArray(bool sorted, bool unique) {
299 fCount=0;
300 fCapacity=0;
301 fArray=NULL;
302 fUnique=unique;
303 fCompareProc=sorted? &DefaultCompareProc : NULL;
304 }
305
GArray(int init_capacity,bool sorted,bool unique)306 template <class OBJ> GArray<OBJ>::GArray(int init_capacity,
307 bool sorted, bool unique) {
308 fCount=0;
309 fCapacity=0;
310 fArray=NULL;
311 fUnique=unique;
312 fCompareProc=sorted? &DefaultCompareProc : NULL;
313 setCapacity(init_capacity);
314 }
315
~GArray()316 template <class OBJ> GArray<OBJ>::~GArray() {
317 Clear();//this will free the items if fFreeProc is defined
318 }
319
setCapacity(int NewCapacity)320 template <class OBJ> void GArray<OBJ>::setCapacity(int NewCapacity) {
321 if (NewCapacity < fCount || NewCapacity > MAXLISTSIZE)
322 GError(SLISTCAPACITY_ERR, NewCapacity);
323 //error: capacity not within range
324 if (NewCapacity!=fCapacity) {
325 if (NewCapacity==0) {
326 GFREE(fArray);
327 }
328 else {
329 GREALLOC(fArray, NewCapacity*sizeof(OBJ));
330 }
331 fCapacity=NewCapacity;
332 }
333 }
334
Clear()335 template <class OBJ> void GArray<OBJ>::Clear() {
336 CompareProc* fcmp=fCompareProc;
337 fCompareProc=NULL;
338 setCount(0);
339 setCapacity(0); //so the array itself is deallocated too!
340 fCompareProc=fcmp;
341 }
342
setSorted(CompareProc * cmpFunc)343 template <class OBJ> void GArray<OBJ>::setSorted(CompareProc* cmpFunc) {
344 CompareProc* old_proc=fCompareProc;
345 fCompareProc=cmpFunc;
346 if (fCompareProc!=old_proc && fCompareProc!=NULL)
347 Sort(); //new compare method
348 }
349
Grow()350 template <class OBJ> void GArray<OBJ>::Grow() {
351 int delta;
352 if (fCapacity > 64) delta = fCapacity/4;
353 else if (fCapacity > 8) delta = 16;
354 else delta = 4;
355 setCapacity(fCapacity + delta);
356 }
357
Reverse()358 template <class OBJ> void GArray<OBJ>::Reverse() {
359 int l=0;
360 int r=fCount-1;
361 OBJ c;
362 while (l<r) {
363 c=fArray[l];fArray[l]=fArray[r];
364 fArray[r]=c;
365 l++;r--;
366 }
367 }
368
Grow(int idx,OBJ & item)369 template <class OBJ> void GArray<OBJ>::Grow(int idx, OBJ& item) {
370 int delta;
371 if (fCapacity > 64) delta = fCapacity/4;
372 else if (fCapacity > 8) delta = 16;
373 else delta = 4;
374 int NewCapacity=fCapacity+delta;
375 if (NewCapacity <= fCount || NewCapacity >= MAXLISTSIZE)
376 GError(SLISTCAPACITY_ERR, NewCapacity);
377 //error: capacity not within range
378 if (NewCapacity!=fCapacity) {
379 if (NewCapacity==0)
380 GFREE(fArray);
381 else { //add the new item
382 if (idx==fCount) { //append item
383 GREALLOC(fArray, NewCapacity*sizeof(OBJ));
384 fArray[idx]=item;
385 }
386 else { //insert item at idx
387 OBJ* newList;
388 GMALLOC(newList, NewCapacity*sizeof(OBJ));
389 //copy data before idx
390 memmove(&newList[0],&fArray[0], idx*sizeof(OBJ));
391 newList[idx]=item; // operator=
392 //copy data after idx
393 memmove(&newList[idx+1],&fArray[idx], (fCount-idx)*sizeof(OBJ));
394 memset(&newList[fCount+1], 0, (NewCapacity-fCount-1)*sizeof(OBJ));
395 //data copied:
396 GFREE(fArray);
397 fArray=newList;
398 }
399 fCount++;
400 }
401 fCapacity=NewCapacity;
402 }
403 }
404
IndexOf(OBJ & item)405 template <class OBJ> int GArray<OBJ>::IndexOf(OBJ& item) {
406 int result=0;
407 if (Found(item, result)) return result;
408 else return -1;
409 }
410
Exists(OBJ & item)411 template <class OBJ> bool GArray<OBJ>::Exists(OBJ& item) {
412 int result=0;
413 if (Found(item, result)) return true;
414 else return false;
415 }
416
417
Add(OBJ * item)418 template <class OBJ> int GArray<OBJ>::Add(OBJ* item) {
419 if (item==NULL) return -1;
420 int result;
421 if (SORTED) {
422 if (Found(*item, result))
423 if (fUnique) return -1; //cannot add a duplicate!
424 //Found sets result to the position where the item should be!
425 idxInsert(result, *item);
426 }
427 else {
428 if (fUnique && Found(*item,result)) return -1; //set behaviour
429 result = fCount;
430 if (result==fCapacity) Grow();
431 fArray[result] = *item; //operator=, copies the item
432 fCount++;
433 }
434 return result;
435 }
436
Add(GArray<OBJ> & list)437 template <class OBJ> void GArray<OBJ>::Add(GArray<OBJ>& list) {
438 if (list.Count()==0) return;
439 if (SORTED) {
440 for (int i=0;i<list.fCount;i++) Add(&list[i]);
441 }
442 else { //simply copy
443 setCapacity(fCapacity+list.fCount);
444 int s=fCount;
445 for (int i=0;i<list.fCount;i++)
446 fArray[s+i]=list.fArray[i];
447 fCount+=list.fCount;
448 }
449 }
450
Found(OBJ & item,int & idx)451 template <class OBJ> bool GArray<OBJ>::Found(OBJ& item, int& idx) {
452 //search the list by using CompareProc (if defined)
453 //or == operator for a non-sortable list
454 //for sorted lists, even when the result is false, the idx is
455 //set to the closest matching object!
456 int i;
457 idx=-1;
458 if (fCount==0) { idx=0;return false;}
459 if (SORTED) { //binary search based on CompareProc
460 //do the simplest tests first:
461 if ((*fCompareProc)(fArray[0],item)>0) {
462 idx=0;
463 return false;
464 }
465 if ((*fCompareProc)(item, fArray[fCount-1])>0) {
466 idx=fCount;
467 return false;
468 }
469
470 int l=0;
471 int h = fCount - 1;
472 int c;
473 while (l <= h) {
474 i = (l + h) >> 1;
475 c = (*fCompareProc)(fArray[i], item);
476 if (c < 0) l = i + 1;
477 else {
478 h = i - 1;
479 if (c == 0) { //found!
480 idx=i;
481 return true;
482 }
483 }
484 } //while
485 idx = l;
486 return false;
487 }
488 else {//not sorted: use linear search
489 // needs == operator to compare user defined objects !
490 i=0;
491 while (i<fCount) {
492 if (fArray[i]==item) { //requires operator==
493 idx=i;
494 return true;
495 }
496 i++;
497 }
498 return false;
499 }
500 }
501
idxInsert(int idx,OBJ & item)502 template <class OBJ> void GArray<OBJ>::idxInsert(int idx, OBJ& item) {
503 //idx must be the new position this new item must have
504 //so the allowed range is [0..fCount]
505 //the old idx item all the above will be shifted to idx+1
506 if (idx<0 || idx>fCount) GError(SLISTINDEX_ERR, idx);
507 if (fCount==fCapacity) { //need to resize
508 Grow(idx, item);
509 //expand and also copy/move data and insert the new item
510 return;
511 }
512 //move data around to make room for the new item
513 if (idx<fCount)
514 memmove(&fArray[idx+1], &fArray[idx], (fCount-idx)*sizeof(OBJ));
515 fArray[idx]=item;
516 fCount++;
517 }
518
Insert(int idx,OBJ * item)519 template <class OBJ> void GArray<OBJ>::Insert(int idx, OBJ* item) {
520 //idx can be [0..fCount] so an item can be actually added
521 BE_UNSORTED; //forbid this operation on sorted data
522 idxInsert(idx, item);
523 }
524
Move(int curidx,int newidx)525 template <class OBJ> void GArray<OBJ>::Move(int curidx, int newidx) {
526 BE_UNSORTED; //cannot do this in a sorted list!
527 if (curidx!=newidx || newidx>=fCount)
528 GError(SLISTINDEX_ERR, newidx);
529
530 OBJ tmp=fArray[curidx]; //copy constructor here
531 fArray[curidx]=fArray[newidx];
532 fArray[newidx]=tmp;
533 }
534
Replace(int idx,OBJ & item)535 template <class OBJ> void GArray<OBJ>::Replace(int idx, OBJ& item) {
536 TEST_INDEX(idx);
537 fArray[idx]=item;
538 if ( SORTED ) Sort(); //re-sort !
539 }
540
Delete(int index)541 template <class OBJ> void GArray<OBJ>::Delete(int index) {
542 TEST_INDEX(index);
543 //fArray[index]=NULL;
544 fCount--;
545 if (index<fCount) //move higher elements if any
546 memmove(&fArray[index], &fArray[index+1], (fCount-index)*sizeof(OBJ));
547 }
548
setCount(int NewCount)549 template <class OBJ> void GArray<OBJ>::setCount(int NewCount) {
550 if (NewCount<0 || NewCount > MAXLISTSIZE)
551 GError(SLISTCOUNT_ERR, NewCount);
552 if (NewCount > fCapacity) setCapacity(NewCount);
553 if (NewCount > fCount)
554 memset(&fArray[fCount], 0, (NewCount - fCount) * sizeof(OBJ));
555 fCount = NewCount;
556 }
557
qSort(int l,int r)558 template <class OBJ> void GArray<OBJ>::qSort(int l, int r) {
559 int i, j;
560 OBJ p,t;
561 do {
562 i = l; j = r;
563 p = fArray[(l + r) >> 1];
564 do {
565 while (fCompareProc(fArray[i], p) < 0) i++;
566 while (fCompareProc(fArray[j], p) > 0) j--;
567 if (i <= j) {
568 t = fArray[i];
569 fArray[i] = fArray[j];
570 fArray[j] = t;
571 i++; j--;
572 }
573 } while (i <= j);
574 if (l < j) qSort(l, j);
575 l = i;
576 } while (i < r);
577 }
578
Sort()579 template <class OBJ> void GArray<OBJ>::Sort() {
580 if (fArray!=NULL && fCount>0 && fCompareProc!=NULL)
581 qSort(0, fCount-1);
582 }
583
584
585
586
587
588 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
589 //*=> GList implementation -- sortable array of pointers to OBJ
590
operator [](int i)591 template <class OBJ> OBJ* GList<OBJ>::operator[](int i) {
592 TEST_INDEX(i);
593 return fList[i];
594 }
595
GList(GList & list)596 template <class OBJ> GList<OBJ>::GList(GList& list) { //copy constructor
597 fCount=list.fCount;
598 fUnique=list.fUnique;
599 fCapacity=list.fCapacity;
600 if (fCapacity>0) {
601 GMALLOC(fList, fCapacity*sizeof(OBJ*));
602 }
603 fCompareProc=list.fCompareProc;
604 fFreeProc=list.fFreeProc;
605 fCount=list.fCount;
606 memcpy(fList, list.fList, fCount*sizeof(OBJ*));
607 //for (int i=0;i<list.Count();i++) Add(list[i]);
608 }
609
GList(GList * plist)610 template <class OBJ> GList<OBJ>::GList(GList* plist) { //another copy constructor
611 fCount=0;
612 fCapacity=plist->fCapacity;
613 if (fCapacity>0) {
614 GMALLOC(fList, fCapacity*sizeof(OBJ*));
615 }
616 fUnique=plist->fUnique;
617 fCompareProc=plist->fCompareProc;
618 fFreeProc=plist->fFreeProc;
619 fCount=plist->fCount;
620 memcpy(fList, plist->fList, fCount*sizeof(OBJ*));
621 //for (int i=0;i<list->fCount;i++) Add(plist->Get(i));
622 }
623
Add(GList<OBJ> & list)624 template <class OBJ> void GList<OBJ>::Add(GList<OBJ>& list) {
625 if (list.Count()==0) return;
626 if (SORTED) {
627 for (int i=0;i<list.Count();i++) Add(list[i]);
628 }
629 else { //simply copy
630 setCapacity(fCapacity+list.fCount);
631 memcpy( & (fList[fCount]), list.fList, list.fCount*sizeof(OBJ*));
632 fCount+=list.fCount;
633 }
634 }
635
636
GList(GCompareProc * compareProc,GFreeProc * freeProc,bool beUnique)637 template <class OBJ> GList<OBJ>::GList(GCompareProc* compareProc,
638 GFreeProc* freeProc, bool beUnique) {
639 fCount=0;
640 fCapacity=0;
641 fList=NULL;
642 fCompareProc = compareProc;
643 fFreeProc = freeProc;
644 fUnique = beUnique; //only affects sorted lists
645 }
646
GList(GCompareProc * compareProc)647 template <class OBJ> GList<OBJ>::GList(GCompareProc* compareProc) {
648 fCount=0;
649 fCapacity=0;
650 fList=NULL;
651 fCompareProc = compareProc;
652 fFreeProc = &DefaultFreeProc;
653 fUnique = false; //only affects sorted lists
654 }
655
Reverse()656 template <class OBJ> void GList<OBJ>::Reverse() {
657 int l=0;
658 int r=fCount-1;
659 OBJ* c;
660 while (l<r) {
661 c=fList[l];fList[l]=fList[r];
662 fList[r]=c;
663 l++;r--;
664 }
665 }
666
667
GList(bool sorted,bool free_elements,bool beUnique)668 template <class OBJ> GList<OBJ>::GList(bool sorted,
669 bool free_elements, bool beUnique) {
670 fCount=0;
671 fCapacity=0;
672 fList=NULL;
673 if (sorted) {
674 if (free_elements) {
675 fCompareProc=&DefaultCompareProc;
676 fFreeProc=&DefaultFreeProc;
677 fUnique=beUnique;
678 }
679 else {
680 fCompareProc=&DefaultCompareProc;
681 fFreeProc=NULL;
682 fUnique=beUnique;
683 }
684 }
685 else {
686 if (free_elements) {
687 fCompareProc=NULL;
688 fFreeProc=&DefaultFreeProc;
689 fUnique=beUnique;
690 }
691 else {
692 fCompareProc=NULL;
693 fFreeProc=NULL;
694 fUnique=beUnique;
695 }
696 }
697 }
698
GList(int init_capacity,bool sorted,bool free_elements,bool beUnique)699 template <class OBJ> GList<OBJ>::GList(int init_capacity, bool sorted,
700 bool free_elements, bool beUnique) {
701 fCount=0;
702 fCapacity=0;
703 fList=NULL;
704 if (sorted) {
705 if (free_elements) {
706 fCompareProc=&DefaultCompareProc;
707 fFreeProc=&DefaultFreeProc;
708 fUnique=beUnique;
709 }
710 else {
711 fCompareProc=&DefaultCompareProc;
712 fFreeProc=NULL;
713 fUnique=beUnique;
714 }
715 }
716 else {
717 if (free_elements) {
718 fCompareProc=NULL;
719 fFreeProc=&DefaultFreeProc;
720 fUnique=beUnique;
721 }
722 else {
723 fCompareProc=NULL;
724 fFreeProc=NULL;
725 fUnique=beUnique;
726 }
727 }
728 setCapacity(init_capacity);
729 }
730
~GList()731 template <class OBJ> GList<OBJ>::~GList() {
732 Clear();//this will free the items if fFreeProc is defined
733 }
734
setCapacity(int NewCapacity)735 template <class OBJ> void GList<OBJ>::setCapacity(int NewCapacity) {
736 if (NewCapacity < fCount || NewCapacity > MAXLISTSIZE)
737 GError(SLISTCAPACITY_ERR, NewCapacity);
738 //error: capacity not within range
739 if (NewCapacity!=fCapacity) {
740 if (NewCapacity==0)
741 GFREE(fList);
742 else
743 GREALLOC(fList, NewCapacity*sizeof(OBJ*));
744 fCapacity=NewCapacity;
745 }
746 }
747
freeItem(int idx)748 template <class OBJ> void GList<OBJ>::freeItem(int idx) {
749 TEST_INDEX(idx);
750 (*fFreeProc)(fList[idx]);
751 fList[idx]=NULL;
752 }
753
Clear()754 template <class OBJ> void GList<OBJ>::Clear() {
755 if (FREEDATA) {
756 for (int i=0; i<fCount; i++) {
757 (*fFreeProc)(fList[i]);
758 }
759 }
760 GCompareProc* fcmp=fCompareProc;
761 fCompareProc=NULL;
762 setCount(0);
763 setCapacity(0); //so the array itself is deallocated too!
764 fCompareProc=fcmp;
765 }
766
767
Exchange(int idx1,int idx2)768 template <class OBJ> void GList<OBJ>::Exchange(int idx1, int idx2) {
769 BE_UNSORTED; //cannot do that in a sorted list!
770 TEST_INDEX(idx1);
771 TEST_INDEX(idx2);
772 OBJ* item=fList[idx1];
773 fList[idx1]=fList[idx2];
774 fList[idx2]=item;
775 }
776
777
Expand()778 template <class OBJ> void GList<OBJ>::Expand()
779 {
780 if (fCount==fCapacity) Grow();
781 //return this;
782 }
783
784
Get(int idx)785 template <class OBJ> OBJ* GList<OBJ>::Get(int idx)
786 {
787 TEST_INDEX(idx);
788 return fList[idx];
789 }
790
operator =(GList & list)791 template <class OBJ> const GList<OBJ>& GList<OBJ>::operator=(GList& list) {
792 if (&list!=this) {
793 Clear();
794 fCompareProc=list.fCompareProc;
795 fFreeProc=list.fFreeProc;
796 //Attention: the object pointers are copied directly,
797 //but the actual objects are NOT duplicated
798 for (int i=0;i<list.Count();i++) Add(list[i]);
799 }
800 return *this;
801 }
802
setSorted(GCompareProc * compareProc)803 template <class OBJ> void GList<OBJ>::setSorted(GCompareProc* compareProc) {
804 GCompareProc* old_proc=fCompareProc;
805 fCompareProc=compareProc;
806 if (fCompareProc!=old_proc && fCompareProc!=NULL)
807 Sort(); //new compare method
808 }
809
Grow()810 template <class OBJ> void GList<OBJ>::Grow() {
811 int delta;
812 if (fCapacity > 64) delta = fCapacity/4;
813 else if (fCapacity > 8) delta = 16;
814 else delta = 4;
815 setCapacity(fCapacity + delta);
816 }
817
Grow(int idx,OBJ * newitem)818 template <class OBJ> void GList<OBJ>::Grow(int idx, OBJ* newitem) {
819 int delta;
820 if (fCapacity > 64) delta = fCapacity/4;
821 else if (fCapacity > 8) delta = 16;
822 else delta = 4;
823 // setCapacity(fCapacity + delta);
824 int NewCapacity=fCapacity+delta;
825 if (NewCapacity <= fCount || NewCapacity > MAXLISTSIZE)
826 GError(SLISTCAPACITY_ERR, NewCapacity);
827 //error: capacity not within range
828 if (NewCapacity!=fCapacity) {
829 if (NewCapacity==0)
830 GFREE(fList);
831 else {//add the new item
832 if (idx==fCount) {
833 GREALLOC(fList, NewCapacity*sizeof(OBJ*));
834 fList[idx]=newitem;
835 }
836 else {
837 OBJ** newList;
838 GMALLOC(newList, NewCapacity*sizeof(OBJ*));
839 //copy data before idx
840 memmove(&newList[0],&fList[0], idx*sizeof(OBJ*));
841 newList[idx]=newitem;
842 //copy data after idx
843 memmove(&newList[idx+1],&fList[idx], (fCount-idx)*sizeof(OBJ*));
844 memset(&newList[fCount+1], 0, (NewCapacity-fCount-1)*sizeof(OBJ*));
845 //data copied:
846 GFREE(fList);
847 fList=newList;
848 }
849 fCount++;
850 }
851 fCapacity=NewCapacity;
852 }
853 }
854
855
IndexOf(OBJ * item)856 template <class OBJ> int GList<OBJ>::IndexOf(OBJ* item) {
857 int result=0;
858 if (Found(item, result)) return result;
859 else return -1;
860 }
861
Exists(OBJ & item)862 template <class OBJ> bool GList<OBJ>::Exists(OBJ& item) {
863 int result=0;
864 if (Found(&item, result)) return true;
865 else return false;
866 }
867
Exists(OBJ * item)868 template <class OBJ> bool GList<OBJ>::Exists(OBJ* item) {
869 int result=0;
870 if (Found(item, result)) return true;
871 else return false;
872 }
873
Add(OBJ * item)874 template <class OBJ> int GList<OBJ>::Add(OBJ* item) {
875 int result;
876 if (item==NULL) return -1;
877 if (SORTED) {
878 if (Found(item, result))
879 if (fUnique) return -1; //duplicates forbidden
880 //Found sets result to the position where the item should be!
881 sortInsert(result, item);
882 }
883 else {
884 if (fUnique && Found(item,result)) return -1; //set behaviour
885 result = fCount;
886 if (result==fCapacity) Grow();
887 fList[result]=item;
888 fCount++;
889 }
890 return result;
891 }
892
893 //by default, it deletes the item if it has an equal in the list!
894 //returns the existing equal (==) object if it's in the list already
895 //or returns the item itself if it's unique (and adds it)
AddIfNew(OBJ * item,bool deleteIfFound,int * fidx)896 template <class OBJ> OBJ* GList<OBJ>::AddIfNew(OBJ* item,
897 bool deleteIfFound, int* fidx) {
898 int r;
899 if (Found(item, r)) {
900 if (deleteIfFound && (pointer)item != (pointer)fList[r]) delete item;
901 if (fidx!=NULL) *fidx=r;
902 return fList[r]; //found
903 }
904 //not found:
905 if (SORTED) {
906 //Found() set result to the position where the item should be inserted:
907 sortInsert(r, item);
908 }
909 else {
910 r = fCount;
911 if (r==fCapacity) Grow();
912 fList[r]=item;
913 fCount++;
914 }
915 if (fidx!=NULL) *fidx=r;
916 return item;
917 }
918
Found(OBJ * item,int & idx)919 template <class OBJ> bool GList<OBJ>::Found(OBJ* item, int& idx) {
920 //search the list by using CompareProc (if defined)
921 //or == operator for a non-sortable list
922 //for sorted lists, even when the result is false, the idx is
923 //set to the closest matching object!
924 int i;
925 idx=-1;
926 if (fCount==0) { idx=0;return false;}
927 if (SORTED) { //binary search based on CompareProc
928 //do the simple test first:
929
930 if ((*fCompareProc)(fList[0],item)>0) {
931 idx=0;
932 return false;
933 }
934 if ((*fCompareProc)(item, fList[fCount-1])>0) {
935 idx=fCount;
936 return false;
937 }
938
939 int l, h, c;
940 l = 0;
941 h = fCount - 1;
942 while (l <= h) {
943 i = (l + h) >> 1;
944 c = (*fCompareProc)(fList[i], item);
945 if (c < 0) l = i + 1;
946 else {
947 h = i - 1;
948 if (c == 0) {
949 idx=i;
950 return true;
951 }
952 }
953 } //while
954 idx = l;
955 return false;
956 }
957 else {//not sorted: use linear search
958 // needs == operator to compare user defined objects !
959 i=0;
960 while (i<fCount) {
961 if (*fList[i]==*item) {
962 idx=i;
963 return true;
964 }
965 i++;
966 }
967 return false;
968 }
969 }
970
sortInsert(int idx,OBJ * item)971 template <class OBJ> void GList<OBJ>::sortInsert(int idx, OBJ* item) {
972 //idx must be the new position this new item must have
973 //so the allowed range is [0..fCount]
974 //the old idx item all the above will be shifted to idx+1
975 if (idx<0 || idx>fCount) GError(SLISTINDEX_ERR, idx);
976 if (fCount==fCapacity) {
977 Grow(idx, item);
978 //expand and also copy/move data and insert the new item
979 return;
980 }
981 //room still left, just move data around and insert the new one
982 if (idx<fCount) //copy/move pointers only!
983 memmove(&fList[idx+1], &fList[idx], (fCount-idx)*sizeof(OBJ*));
984 fList[idx]=item;
985 fCount++;
986 }
987
Insert(int idx,OBJ * item)988 template <class OBJ> void GList<OBJ>::Insert(int idx, OBJ* item) {
989 //idx can be [0..fCount] so an item can be actually added
990 BE_UNSORTED; //cannot do that with a sorted list!
991 if (idx<0 || idx>fCount) GError(SLISTINDEX_ERR, idx);
992 if (fCount==fCapacity) {
993 Grow(idx, item);
994 return;
995 }
996 if (idx<fCount)
997 memmove(&fList[idx+1], &fList[idx], (fCount-idx)*sizeof(OBJ*));
998 fList[idx]=item;
999 fCount++;
1000 }
1001
Move(int curidx,int newidx)1002 template <class OBJ> void GList<OBJ>::Move(int curidx, int newidx) {
1003 BE_UNSORTED; //cannot do that in a sorted list!
1004 if (curidx!=newidx || newidx>=fCount)
1005 GError(SLISTINDEX_ERR, newidx);
1006 OBJ* p;
1007 p=Get(curidx);
1008 //this is a delete:
1009 fCount--;
1010 if (curidx<fCount)
1011 memmove(&fList[curidx], &fList[curidx+1], (fCount-curidx)*sizeof(OBJ*));
1012 //-this was instead of delete
1013 Insert(newidx, p);
1014 }
1015
1016
Put(int idx,OBJ * item,bool re_sort)1017 template <class OBJ> void GList<OBJ>::Put(int idx, OBJ* item, bool re_sort) {
1018 //WARNING: this will never free the replaced item!!!
1019 TEST_INDEX(idx);
1020 fList[idx]=item;
1021 if (SORTED && item!=NULL && re_sort) Sort(); //re-sort
1022 }
1023
Forget(int idx)1024 template <class OBJ> void GList<OBJ>::Forget(int idx) {
1025 TEST_INDEX(idx);
1026 fList[idx]=NULL;
1027 }
1028
Delete(int index)1029 template <class OBJ> void GList<OBJ>::Delete(int index) {
1030 TEST_INDEX(index);
1031 if (fFreeProc!=NULL && fList[index]!=NULL) {
1032 (*fFreeProc)(fList[index]); //freeItem
1033 }
1034 fList[index]=NULL;
1035 fCount--;
1036 if (index<fCount) //move higher elements if any
1037 memmove(&fList[index], &fList[index+1], (fCount-index)*sizeof(OBJ*));
1038 }
1039
1040 //Stack usage:
Pop()1041 template <class OBJ> OBJ* GList<OBJ>::Pop() {
1042 if (fCount<=0) return NULL;
1043 fCount--;
1044 OBJ* o=fList[fCount];
1045 fList[fCount]=NULL;
1046 return o;
1047 }
1048
1049 //Queue usage:
Shift()1050 template <class OBJ> OBJ* GList<OBJ>::Shift() {
1051 if (fCount<=0) return NULL;
1052 fCount--;
1053 OBJ* o=fList[0];
1054 if (fCount>0)
1055 memmove(&fList[0], &fList[1], (fCount)*sizeof(OBJ*));
1056 fList[fCount]=NULL; //not that it matters..
1057 return o;
1058 }
1059
Remove(OBJ * item)1060 template <class OBJ> int GList<OBJ>::Remove(OBJ* item) {
1061 //removes an item if it's in our list
1062 int result=IndexOf(item);
1063 if (result>=0) Delete(result);
1064 return result;
1065 }
1066
1067 //linear search for the pointer
RemovePtr(OBJ * item)1068 template <class OBJ> int GList<OBJ>::RemovePtr(OBJ* item) {
1069 int i;
1070 if (item==NULL) return -1;
1071 for (i=0;i<fCount;i++)
1072 if (fList[i]==item) break;
1073 if (i==fCount) return -1; //not found
1074 Delete(i);
1075 return i;
1076 }
1077
1078
Pack()1079 template <class OBJ> void GList<OBJ>::Pack() {//also frees items!
1080 for (int i=fCount-1; i>=0; i--)
1081 if (fList[i]==NULL) Delete(i); //also shift contents of fList accordingly
1082 }
1083
setCount(int NewCount)1084 template <class OBJ> void GList<OBJ>::setCount(int NewCount) {
1085 if (NewCount<0 || NewCount > MAXLISTSIZE)
1086 GError(SLISTCOUNT_ERR, NewCount);
1087 if (NewCount > fCapacity) setCapacity(NewCount);
1088 if (NewCount > fCount)
1089 memset(fList[fCount], 0, (NewCount - fCount) * sizeof(OBJ*));
1090 fCount = NewCount;
1091 }
1092
QuickSort(int L,int R)1093 template <class OBJ> void GList<OBJ>::QuickSort(int L, int R) {
1094 int I, J;
1095 OBJ* P;
1096 OBJ* T;
1097 do {
1098 I = L;
1099 J = R;
1100 P = fList[(L + R) >> 1];
1101 do {
1102 while (fCompareProc(fList[I], P) < 0) I++;
1103 while (fCompareProc(fList[J], P) > 0) J--;
1104 if (I <= J) {
1105 T = fList[I];
1106 fList[I] = fList[J];
1107 fList[J] = T;
1108 I++;
1109 J--;
1110 }
1111 }
1112 while (I <= J);
1113 if (L < J) QuickSort(L, J);
1114 L = I;
1115 }
1116 while (I < R);
1117
1118 }
1119
Sort()1120 template <class OBJ> void GList<OBJ>::Sort() {
1121 if (fList!=NULL && fCount>0 && fCompareProc!=NULL)
1122 QuickSort(0, fCount-1);
1123 }
1124
1125 //---------------------------------------------------------------------------
1126 #endif
1127