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