1 /********************************************************************************
2 *                                                                               *
3 *                            O b j e c t   L i s t                              *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1997,2020 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify          *
9 * it under the terms of the GNU Lesser General Public License as published by   *
10 * the Free Software Foundation; either version 3 of the License, or             *
11 * (at your option) any later version.                                           *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
16 * GNU Lesser General Public License for more details.                           *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public License      *
19 * along with this program.  If not, see <http://www.gnu.org/licenses/>          *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "FXArray.h"
25 #include "FXHash.h"
26 #include "FXStream.h"
27 #include "FXObject.h"
28 #include "FXStream.h"
29 #include "FXElement.h"
30 #include "FXObjectList.h"
31 
32 /*
33   Notes:
34   - A list of pointers to objects.
35   - The list may be serialized; this means contents of all objects referenced
36     from the list may be saved or loaded through the serialization mechanism.
37   - Serialization is limited to 2^31 objects only, due to serialization format
38     using a 32-bit int for compatibility with 32 bit systems.
39 */
40 
41 
42 // Size rounded up to nearest multiple of ROUNDVAL
43 #define ROUNDVAL    16
44 
45 // Round up to nearest ROUNDVAL
46 #define ROUNDUP(n)  (((n)+ROUNDVAL-1)&-ROUNDVAL)
47 
48 // Special empty object list value
49 #define EMPTY       ((FXObject**)(__objectlist__empty__+1))
50 
51 using namespace FX;
52 
53 /*******************************************************************************/
54 
55 namespace FX {
56 
57 
58 // Empty object list valie
59 extern const FXival __objectlist__empty__[];
60 const FXival __objectlist__empty__[2]={0,0};
61 
62 
63 // Change number of items in list
no(FXival num)64 FXbool FXObjectList::no(FXival num){
65   if(__likely(num!=no())){
66     if(0<num){
67       FXptr p;
68       if(ptr!=EMPTY){
69         if(__unlikely((p=::realloc(((FXival*)ptr)-1,sizeof(FXival)+sizeof(FXObject*)*ROUNDUP(num)))==NULL)) return false;
70         }
71       else{
72         if(__unlikely((p=::malloc(sizeof(FXival)+sizeof(FXObject*)*ROUNDUP(num)))==NULL)) return false;
73         }
74       ptr=(FXObject**)(((FXival*)p)+1);
75       *(((FXival*)ptr)-1)=num;
76       }
77     else{
78       if(ptr!=EMPTY){
79         ::free(((FXival*)ptr)-1);
80         ptr=EMPTY;
81         }
82       }
83     }
84   return true;
85   }
86 
87 
88 // Default constructor
FXObjectList()89 FXObjectList::FXObjectList():ptr(EMPTY){
90   }
91 
92 
93 // Copy constructor
FXObjectList(const FXObjectList & other)94 FXObjectList::FXObjectList(const FXObjectList& other):ptr(EMPTY){
95   FXival num=other.no();
96   if(__likely(0<num && no(num))){
97     copyElms(ptr,other.ptr,num);
98     }
99   }
100 
101 
102 // Construct and init with single object
FXObjectList(FXObject * object)103 FXObjectList::FXObjectList(FXObject* object):ptr(EMPTY){
104   if(__likely(no(1))){
105     ptr[0]=object;
106     }
107   }
108 
109 
110 // Construct and init with n copies of object
FXObjectList(FXObject * object,FXival n)111 FXObjectList::FXObjectList(FXObject* object,FXival n):ptr(EMPTY){
112   if(__likely(0<n && no(n))){
113     fillElms(ptr,object,n);
114     }
115   }
116 
117 
118 // Construct and init with list of objects
FXObjectList(FXObject ** objects,FXival n)119 FXObjectList::FXObjectList(FXObject** objects,FXival n):ptr(EMPTY){
120   if(__likely(0<n && no(n))){
121     copyElms(ptr,objects,n);
122     }
123   }
124 
125 
126 // Assignment operator
operator =(const FXObjectList & other)127 FXObjectList& FXObjectList::operator=(const FXObjectList& other){
128   if(__likely(ptr!=other.ptr && no(other.no()))){
129     copyElms(ptr,other.ptr,other.no());
130     }
131   return *this;
132   }
133 
134 
135 // Adopt objects from src, leaving src empty
adopt(FXObjectList & other)136 FXObjectList& FXObjectList::adopt(FXObjectList& other){
137   if(__likely(ptr!=other.ptr)){
138     swap(ptr,other.ptr);
139     other.clear();
140     }
141   return *this;
142   }
143 
144 
145 // Find object in list, searching forward; return position or -1
find(const FXObject * object,FXival pos) const146 FXival FXObjectList::find(const FXObject* object,FXival pos) const {
147   FXival p=FXMAX(0,pos);
148   while(p<no()){
149     if(ptr[p]==object){ return p; }
150     ++p;
151     }
152   return -1;
153   }
154 
155 
156 // Find object in list, searching backward; return position or -1
rfind(const FXObject * object,FXival pos) const157 FXival FXObjectList::rfind(const FXObject* object,FXival pos) const {
158   FXival p=FXMIN(pos,no()-1);
159   while(0<=p){
160     if(ptr[p]==object){ return p; }
161     --p;
162     }
163   return -1;
164   }
165 
166 
167 // Assign object p to list
assign(FXObject * object)168 FXbool FXObjectList::assign(FXObject* object){
169   if(__likely(no(1))){
170     ptr[0]=object;
171     return true;
172     }
173   return false;
174   }
175 
176 
177 // Assign n copies of object to list
assign(FXObject * object,FXival n)178 FXbool FXObjectList::assign(FXObject* object,FXival n){
179   if(__likely(no(n))){
180     fillElms(ptr,object,n);
181     return true;
182     }
183   return false;
184   }
185 
186 
187 // Assign n objects to list
assign(FXObject ** objects,FXival n)188 FXbool FXObjectList::assign(FXObject** objects,FXival n){
189   if(__likely(no(n))){
190     moveElms(ptr,objects,n);
191     return true;
192     }
193   return false;
194   }
195 
196 
197 // Assign objects to list
assign(const FXObjectList & objects)198 FXbool FXObjectList::assign(const FXObjectList& objects){
199   return assign(objects.ptr,objects.no());
200   }
201 
202 
203 // Insert an object
insert(FXival pos,FXObject * object)204 FXbool FXObjectList::insert(FXival pos,FXObject* object){
205   FXival num=no();
206   if(__likely(no(num+1))){
207     moveElms(ptr+pos+1,ptr+pos,num-pos);
208     ptr[pos]=object;
209     return true;
210     }
211   return false;
212   }
213 
214 
215 // Insert n copies of object at specified position
insert(FXival pos,FXObject * object,FXival n)216 FXbool FXObjectList::insert(FXival pos,FXObject* object,FXival n){
217   FXival num=no();
218   if(__likely(no(num+n))){
219     moveElms(ptr+pos+n,ptr+pos,num-pos);
220     fillElms(ptr+pos,object,n);
221     return true;
222     }
223   return false;
224   }
225 
226 
227 // Insert n objects at specified position
insert(FXival pos,FXObject ** objects,FXival n)228 FXbool FXObjectList::insert(FXival pos,FXObject** objects,FXival n){
229   FXival num=no();
230   if(__likely(no(num+n))){
231     moveElms(ptr+pos+n,ptr+pos,num-pos);
232     copyElms(ptr+pos,objects,n);
233     return true;
234     }
235   return false;
236   }
237 
238 
239 // Insert objects at specified position
insert(FXival pos,const FXObjectList & objects)240 FXbool FXObjectList::insert(FXival pos,const FXObjectList& objects){
241   return insert(pos,objects.ptr,objects.no());
242   }
243 
244 
245 // Prepend an object
prepend(FXObject * object)246 FXbool FXObjectList::prepend(FXObject* object){
247   FXival num=no();
248   if(__likely(no(num+1))){
249     moveElms(ptr+1,ptr,num);
250     ptr[0]=object;
251     return true;
252     }
253   return false;
254   }
255 
256 
257 // Prepend n copies of object
prepend(FXObject * object,FXival n)258 FXbool FXObjectList::prepend(FXObject* object,FXival n){
259   FXival num=no();
260   if(__likely(no(num+n))){
261     moveElms(ptr+n,ptr,num);
262     fillElms(ptr,object,n);
263     return true;
264     }
265   return false;
266   }
267 
268 
269 // Prepend n objects
prepend(FXObject ** objects,FXival n)270 FXbool FXObjectList::prepend(FXObject** objects,FXival n){
271   FXival num=no();
272   if(__likely(no(num+n))){
273     moveElms(ptr+n,ptr,num);
274     copyElms(ptr,objects,n);
275     return true;
276     }
277   return false;
278   }
279 
280 
281 // Prepend objects
prepend(const FXObjectList & objects)282 FXbool FXObjectList::prepend(const FXObjectList& objects){
283   return prepend(objects.ptr,objects.no());
284   }
285 
286 
287 // Append an object
append(FXObject * object)288 FXbool FXObjectList::append(FXObject* object){
289   FXival num=no();
290   if(__likely(no(num+1))){
291     ptr[num]=object;
292     return true;
293     }
294   return false;
295   }
296 
297 
298 // Append n copies of object
append(FXObject * object,FXival n)299 FXbool FXObjectList::append(FXObject* object,FXival n){
300   FXival num=no();
301   if(__likely(no(num+n))){
302     fillElms(ptr+num,object,n);
303     return true;
304     }
305   return false;
306   }
307 
308 
309 // Append n objects
append(FXObject ** objects,FXival n)310 FXbool FXObjectList::append(FXObject** objects,FXival n){
311   FXival num=no();
312   if(__likely(no(num+n))){
313     copyElms(ptr+num,objects,n);
314     return true;
315     }
316   return false;
317   }
318 
319 
320 // Append objects
append(const FXObjectList & objects)321 FXbool FXObjectList::append(const FXObjectList& objects){
322   return append(objects.ptr,objects.no());
323   }
324 
325 
326 // Replace element
replace(FXival pos,FXObject * object)327 FXbool FXObjectList::replace(FXival pos,FXObject* object){
328   ptr[pos]=object;
329   return true;
330   }
331 
332 
333 // Replaces the m objects at pos with n copies of object
replace(FXival pos,FXival m,FXObject * object,FXival n)334 FXbool FXObjectList::replace(FXival pos,FXival m,FXObject* object,FXival n){
335   FXival num=no();
336   if(__unlikely(m<n)){
337     if(__unlikely(!no(num-m+n))) return false;
338     moveElms(ptr+pos+n,ptr+pos+m,num-pos-n);
339     }
340   else if(__unlikely(m>n)){
341     moveElms(ptr+pos+n,ptr+pos+m,num-pos-m);
342     if(__unlikely(!no(num-m+n))) return false;
343     }
344   fillElms(ptr+pos,object,n);
345   return true;
346   }
347 
348 
349 // Replaces the m objects at pos with n objects
replace(FXival pos,FXival m,FXObject ** objects,FXival n)350 FXbool FXObjectList::replace(FXival pos,FXival m,FXObject** objects,FXival n){
351   FXival num=no();
352   if(__unlikely(m<n)){
353     if(__unlikely(!no(num-m+n))) return false;
354     moveElms(ptr+pos+n,ptr+pos+m,num-pos-n);
355     }
356   else if(__unlikely(m>n)){
357     moveElms(ptr+pos+n,ptr+pos+m,num-pos-m);
358     if(__unlikely(!no(num-m+n))) return false;
359     }
360   copyElms(ptr+pos,objects,n);
361   return true;
362   }
363 
364 
365 // Replace the m objects at pos with objects
replace(FXival pos,FXival m,const FXObjectList & objects)366 FXbool FXObjectList::replace(FXival pos,FXival m,const FXObjectList& objects){
367   return replace(pos,m,objects.ptr,objects.no());
368   }
369 
370 
371 // Remove object at pos
erase(FXival pos)372 FXbool FXObjectList::erase(FXival pos){
373   FXival num=no();
374   moveElms(ptr+pos,ptr+pos+1,num-pos-1);
375   return no(num-1);
376   }
377 
378 
379 // Remove n objects at pos
erase(FXival pos,FXival n)380 FXbool FXObjectList::erase(FXival pos,FXival n){
381   FXival num=no();
382   moveElms(ptr+pos,ptr+pos+n,num-n-pos);
383   return no(num-n);
384   }
385 
386 
387 // Remove object
remove(const FXObject * object)388 FXbool FXObjectList::remove(const FXObject* object){
389   FXival pos;
390   if(0<=(pos=find(object))){
391     return erase(pos);
392     }
393   return false;
394   }
395 
396 
397 // Push object to end
push(FXObject * object)398 FXbool FXObjectList::push(FXObject* object){
399   return append(object);
400   }
401 
402 
403 // Pop object from end
pop()404 FXbool FXObjectList::pop(){
405   return no(no()-1);
406   }
407 
408 
409 // Clear the list
clear()410 void FXObjectList::clear(){
411   no(0);
412   }
413 
414 
415 // Save to stream; children may be NULL
save(FXStream & store) const416 void FXObjectList::save(FXStream& store) const {
417   FXint num;
418   num=no();
419   store << num;
420   for(FXint i=0; i<num; i++){
421     store << ptr[i];
422     }
423   }
424 
425 
426 // Load from stream; children may be NULL
load(FXStream & store)427 void FXObjectList::load(FXStream& store){
428   FXint num;
429   store >> num;
430   if(!no(num)) return;
431   for(FXint i=0; i<num; i++){
432     store >> ptr[i];
433     }
434   }
435 
436 
437 // Free up nicely
~FXObjectList()438 FXObjectList::~FXObjectList(){
439   clear();
440   }
441 
442 }
443