1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre
5  *			Copyright (c) Telecom ParisTech 2000-2012
6  *					All rights reserved
7  *
8  *  This file is part of GPAC / common tools sub-project
9  *
10  *  GPAC is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU Lesser General Public License as published by
12  *  the Free Software Foundation; either version 2, or (at your option)
13  *  any later version.
14  *
15  *  GPAC is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; see the file COPYING.  If not, write to
22  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25 
26 #include <gpac/list.h>
27 
28 /* GF_List modes, ONLY ONE CAN BE DEFINED
29 
30 	linked-list
31 	#define GF_LIST_LINKED
32 
33 	double navigation linked-list
34 	#define GF_LIST_DOUBLE_LINKED
35 
36 	single step memory array
37 	#define GF_LIST_ARRAY
38 
39 	multi-step memory array without gf_realloc on remove, using the GF_LIST_REALLOC macro
40 	GF_LIST_ARRAY_GROW
41 */
42 
43 /*after some tuning, this seems to be the fastest mode on WINCE*/
44 #ifdef _WIN32_WCE
45 #define GF_LIST_LINKED
46 #else
47 #define GF_LIST_ARRAY_GROW
48 #endif
49 
50 #define GF_LIST_REALLOC(a) (a = a ? (3*a/2) : 10)
51 //#define GF_LIST_REALLOC(a) (a++)
52 
53 
54 #if defined(GF_LIST_LINKED)
55 
56 typedef struct tagIS
57 {
58 	struct tagIS *next;
59 	void *data;
60 } ItemSlot;
61 
62 struct _tag_array
63 {
64 	struct tagIS *head;
65 	struct tagIS *tail;
66 	u32 entryCount;
67 	s32 foundEntryNumber;
68 	struct tagIS *foundEntry;
69 };
70 
71 
72 GF_EXPORT
gf_list_new()73 GF_List * gf_list_new()
74 {
75 	GF_List *nlist = (GF_List *) gf_malloc(sizeof(GF_List));
76 	if (! nlist) return NULL;
77 	nlist->head = nlist->foundEntry = NULL;
78 	nlist->tail = NULL;
79 	nlist->foundEntryNumber = -1;
80 	nlist->entryCount = 0;
81 	return nlist;
82 }
83 
84 GF_EXPORT
gf_list_del(GF_List * ptr)85 void gf_list_del(GF_List *ptr)
86 {
87 	if (!ptr) return;
88 	while (ptr->entryCount) gf_list_rem(ptr, 0);
89 	gf_free(ptr);
90 }
91 
92 GF_EXPORT
gf_list_reset(GF_List * ptr)93 void gf_list_reset(GF_List *ptr)
94 {
95 	while (ptr && ptr->entryCount) gf_list_rem(ptr, 0);
96 }
97 
98 GF_EXPORT
gf_list_add(GF_List * ptr,void * item)99 GF_Err gf_list_add(GF_List *ptr, void* item)
100 {
101 	ItemSlot *entry;
102 	if (! ptr) return GF_BAD_PARAM;
103 	entry = (ItemSlot *) gf_malloc(sizeof(ItemSlot));
104 	if (!entry) return GF_OUT_OF_MEM;
105 	entry->data = item;
106 	entry->next = NULL;
107 	if (! ptr->head) {
108 		ptr->head = entry;
109 		ptr->entryCount = 1;
110 	} else {
111 		ptr->entryCount += 1;
112 		ptr->tail->next = entry;
113 	}
114 	ptr->tail = entry;
115 	ptr->foundEntryNumber = ptr->entryCount - 1;
116 	ptr->foundEntry = entry;
117 	return GF_OK;
118 }
119 
120 GF_EXPORT
gf_list_count(const GF_List * ptr)121 u32 gf_list_count(const GF_List *ptr)
122 {
123 	if (!ptr) return 0;
124 	return ptr->entryCount;
125 }
126 
127 GF_EXPORT
gf_list_get(GF_List * ptr,u32 itemNumber)128 void *gf_list_get(GF_List *ptr, u32 itemNumber)
129 {
130 	ItemSlot *entry;
131 	u32 i;
132 
133 	if (!ptr || (itemNumber >= ptr->entryCount) ) return NULL;
134 
135 	if (!ptr->foundEntry || (itemNumber < (u32) ptr->foundEntryNumber) ) {
136 		ptr->foundEntryNumber = 0;
137 		ptr->foundEntry = ptr->head;
138 	}
139 	entry = ptr->foundEntry;
140 	for (i = ptr->foundEntryNumber; i < itemNumber; i++ ) {
141 		entry = entry->next;
142 	}
143 	ptr->foundEntryNumber = itemNumber;
144 	ptr->foundEntry = entry;
145 	return (void *) entry->data;
146 }
147 
148 GF_EXPORT
gf_list_last(GF_List * ptr)149 void *gf_list_last(GF_List *ptr)
150 {
151 	ItemSlot *entry;
152 	if (!ptr || !ptr->entryCount) return NULL;
153 	entry = ptr->head;
154 	while (entry->next) entry = entry->next;
155 	return entry->data;
156 }
157 
158 GF_EXPORT
gf_list_rem(GF_List * ptr,u32 itemNumber)159 GF_Err gf_list_rem(GF_List *ptr, u32 itemNumber)
160 {
161 	ItemSlot *tmp, *tmp2;
162 	u32 i;
163 
164 	/* !! if head is null (empty list)*/
165 	if ( (! ptr) || (! ptr->head) || (ptr->head && !ptr->entryCount) || (itemNumber >= ptr->entryCount) )
166 		return GF_BAD_PARAM;
167 
168 	/*we delete the head*/
169 	if (! itemNumber) {
170 		tmp = ptr->head;
171 		ptr->head = ptr->head->next;
172 		ptr->entryCount --;
173 		ptr->foundEntry = ptr->head;
174 		ptr->foundEntryNumber = 0;
175 		gf_free(tmp);
176 		/*that was the last entry, reset the tail*/
177 		if (!ptr->entryCount) {
178 			ptr->tail = ptr->head = ptr->foundEntry = NULL;
179 			ptr->foundEntryNumber = -1;
180 		}
181 		return GF_OK;
182 	}
183 
184 	tmp = ptr->head;
185 	i = 0;
186 	while (i < itemNumber - 1) {
187 		tmp = tmp->next;
188 		i++;
189 	}
190 	tmp2 = tmp->next;
191 	tmp->next = tmp2->next;
192 	/*if we deleted the last entry, update the tail !!!*/
193 	if (! tmp->next || (ptr->tail == tmp2) ) {
194 		ptr->tail = tmp;
195 		tmp->next = NULL;
196 	}
197 
198 	gf_free(tmp2);
199 	ptr->entryCount --;
200 	ptr->foundEntry = ptr->head;
201 	ptr->foundEntryNumber = 0;
202 
203 	return GF_OK;
204 }
205 
206 GF_EXPORT
gf_list_rem_last(GF_List * ptr)207 GF_Err gf_list_rem_last(GF_List *ptr)
208 {
209 	return gf_list_rem(ptr, ptr->entryCount-1);
210 }
211 
212 GF_EXPORT
gf_list_insert(GF_List * ptr,void * item,u32 position)213 GF_Err gf_list_insert(GF_List *ptr, void *item, u32 position)
214 {
215 	u32 i;
216 	ItemSlot *tmp, *tmp2;
217 
218 	if (!ptr || !item) return GF_BAD_PARAM;
219 	/*if last entry or first of an empty array...*/
220 	if (position >= ptr->entryCount) return gf_list_add(ptr, item);
221 
222 	tmp2 = (ItemSlot *) gf_malloc(sizeof(ItemSlot));
223 	tmp2->data = item;
224 	tmp2->next = NULL;
225 	/*special case for the head*/
226 	if (position == 0) {
227 		tmp2->next = ptr->head;
228 		ptr->head = tmp2;
229 		ptr->entryCount ++;
230 		ptr->foundEntry = tmp2;
231 		ptr->foundEntryNumber = 0;
232 		return GF_OK;
233 	}
234 	tmp = ptr->head;
235 	for (i = 1; i < position; i++) {
236 		tmp = tmp->next;
237 		if (!tmp)
238 			break;
239 	}
240 	tmp2->next = tmp->next;
241 	tmp->next = tmp2;
242 	ptr->entryCount ++;
243 	ptr->foundEntry = tmp2;
244 	ptr->foundEntryNumber = i;
245 	return GF_OK;
246 }
247 
248 #elif defined(GF_LIST_DOUBLE_LINKED)
249 
250 
251 typedef struct tagIS
252 {
253 	struct tagIS *next;
254 	struct tagIS *prev;
255 	void *data;
256 } ItemSlot;
257 
258 struct _tag_array
259 {
260 	struct tagIS *head;
261 	struct tagIS *tail;
262 	u32 entryCount;
263 	s32 foundEntryNumber;
264 	struct tagIS *foundEntry;
265 };
266 
267 
268 GF_EXPORT
gf_list_new()269 GF_List * gf_list_new()
270 {
271 	GF_List *nlist = (GF_List *) gf_malloc(sizeof(GF_List));
272 	if (! nlist) return NULL;
273 	nlist->head = nlist->foundEntry = NULL;
274 	nlist->tail = NULL;
275 	nlist->foundEntryNumber = -1;
276 	nlist->entryCount = 0;
277 	return nlist;
278 }
279 
280 GF_EXPORT
gf_list_del(GF_List * ptr)281 void gf_list_del(GF_List *ptr)
282 {
283 	if (!ptr) return;
284 	while (ptr->entryCount) {
285 		gf_list_rem(ptr, 0);
286 	}
287 	gf_free(ptr);
288 }
289 
290 GF_EXPORT
gf_list_reset(GF_List * ptr)291 void gf_list_reset(GF_List *ptr)
292 {
293 	while (ptr && ptr->entryCount) gf_list_rem(ptr, 0);
294 }
295 
296 GF_EXPORT
gf_list_add(GF_List * ptr,void * item)297 GF_Err gf_list_add(GF_List *ptr, void* item)
298 {
299 	ItemSlot *entry;
300 	if (! ptr) return GF_BAD_PARAM;
301 	entry = (ItemSlot *) gf_malloc(sizeof(ItemSlot));
302 	if (!entry) return GF_OUT_OF_MEM;
303 	entry->data = item;
304 	entry->next = entry->prev = NULL;
305 
306 	if (! ptr->head) {
307 		ptr->head = entry;
308 		ptr->entryCount = 1;
309 	} else {
310 		ptr->entryCount += 1;
311 		entry->prev = ptr->tail;
312 		ptr->tail->next = entry;
313 	}
314 	ptr->tail = entry;
315 	ptr->foundEntryNumber = ptr->entryCount - 1;
316 	ptr->foundEntry = entry;
317 	return GF_OK;
318 }
319 
320 
321 GF_EXPORT
gf_list_count(GF_List * ptr)322 u32 gf_list_count(GF_List *ptr)
323 {
324 	if (! ptr) return 0;
325 	return ptr->entryCount;
326 }
327 
328 GF_EXPORT
gf_list_get(GF_List * ptr,u32 itemNumber)329 void *gf_list_get(GF_List *ptr, u32 itemNumber)
330 {
331 	ItemSlot *entry;
332 	u32 i;
333 
334 	if (!ptr || !ptr->head || (itemNumber >= ptr->entryCount) ) return NULL;
335 
336 	if (!itemNumber) {
337 		ptr->foundEntry = ptr->head;
338 		ptr->foundEntryNumber = 0;
339 		return ptr->head->data;
340 	}
341 
342 	entry = ptr->foundEntry;
343 	if ( itemNumber < (u32) ptr->foundEntryNumber ) {
344 		for (i = ptr->foundEntryNumber; i > itemNumber; i-- ) {
345 			entry = entry->prev;
346 		}
347 	} else {
348 		for (i = ptr->foundEntryNumber; i < itemNumber; i++ ) {
349 			entry = entry->next;
350 		}
351 	}
352 	ptr->foundEntryNumber = itemNumber;
353 	ptr->foundEntry = entry;
354 	return (void *) entry->data;
355 }
356 
357 GF_EXPORT
gf_list_last(GF_List * ptr)358 void *gf_list_last(GF_List *ptr)
359 {
360 	if(!ptr || !ptr->tail) return NULL;
361 	return ptr->tail->data;
362 }
363 
364 GF_EXPORT
gf_list_rem(GF_List * ptr,u32 itemNumber)365 GF_Err gf_list_rem(GF_List *ptr, u32 itemNumber)
366 {
367 	ItemSlot *tmp;
368 	u32 i;
369 
370 	/* !! if head is null (empty list)*/
371 	if ( (! ptr) || (! ptr->head) || (ptr->head && !ptr->entryCount) || (itemNumber >= ptr->entryCount) )
372 		return GF_BAD_PARAM;
373 
374 	/*we delete the head*/
375 	if (! itemNumber) {
376 		tmp = ptr->head;
377 		ptr->head = ptr->head->next;
378 
379 		ptr->entryCount --;
380 		ptr->foundEntry = ptr->head;
381 		ptr->foundEntryNumber = 0;
382 		gf_free(tmp);
383 
384 		/*that was the last entry, reset the tail*/
385 		if (!ptr->entryCount) {
386 			ptr->tail = ptr->head = ptr->foundEntry = NULL;
387 			ptr->foundEntryNumber = -1;
388 		} else {
389 			ptr->head->prev = NULL;
390 		}
391 		return GF_OK;
392 	}
393 	else if (itemNumber==ptr->entryCount-1) {
394 		tmp = ptr->tail;
395 		ptr->tail = tmp->prev;
396 		ptr->tail->next = NULL;
397 		ptr->entryCount--;
398 		if (ptr->foundEntry==tmp) {
399 			ptr->foundEntry = ptr->tail;
400 			ptr->foundEntryNumber = ptr->entryCount-1;
401 		}
402 		gf_free(tmp);
403 		return GF_OK;
404 	}
405 
406 	tmp = ptr->foundEntry;
407 	if ( itemNumber < (u32) ptr->foundEntryNumber ) {
408 		for (i = ptr->foundEntryNumber; i > itemNumber; i-- ) {
409 			tmp = tmp->prev;
410 		}
411 	} else {
412 		for (i = ptr->foundEntryNumber; i < itemNumber; i++ ) {
413 			tmp = tmp->next;
414 		}
415 	}
416 	tmp->prev->next = tmp->next;
417 	tmp->next->prev = tmp->prev;
418 	if (tmp==ptr->foundEntry) ptr->foundEntry = tmp->next;
419 	gf_free(tmp);
420 	ptr->entryCount--;
421 	return GF_OK;
422 }
423 
424 GF_EXPORT
gf_list_rem_last(GF_List * ptr)425 GF_Err gf_list_rem_last(GF_List *ptr)
426 {
427 	return gf_list_rem(ptr, ptr->entryCount-1);
428 }
429 
430 GF_EXPORT
gf_list_insert(GF_List * ptr,void * item,u32 position)431 GF_Err gf_list_insert(GF_List *ptr, void *item, u32 position)
432 {
433 	u32 i;
434 	ItemSlot *tmp, *tmp2;
435 
436 	if (!ptr || !item) return GF_BAD_PARAM;
437 	/*if last entry or first of an empty array...*/
438 	if (position >= ptr->entryCount) return gf_list_add(ptr, item);
439 	tmp2 = (ItemSlot *) gf_malloc(sizeof(ItemSlot));
440 	tmp2->data = item;
441 	tmp2->next = tmp2->prev = NULL;
442 	/*special case for the head*/
443 	if (position == 0) {
444 		ptr->head->prev = tmp2;
445 		tmp2->next = ptr->head;
446 		ptr->head = tmp2;
447 		ptr->entryCount ++;
448 		ptr->foundEntry = tmp2;
449 		ptr->foundEntryNumber = 0;
450 		return GF_OK;
451 	}
452 
453 	tmp = ptr->foundEntry;
454 	if ( position < (u32) ptr->foundEntryNumber ) {
455 		for (i = ptr->foundEntryNumber; i >= position; i-- ) {
456 			tmp = tmp->prev;
457 		}
458 		tmp = tmp->prev;
459 	} else {
460 		for (i = ptr->foundEntryNumber; i < position; i++ ) {
461 			tmp = tmp->next;
462 		}
463 	}
464 	tmp2->next = tmp->next;
465 	tmp2->next->prev = tmp2;
466 	tmp2->prev = tmp;
467 	tmp2->prev->next = tmp2;
468 	ptr->entryCount ++;
469 	ptr->foundEntry = tmp2;
470 	ptr->foundEntryNumber = position;
471 	return GF_OK;
472 }
473 
474 #elif defined(GF_LIST_ARRAY)
475 
476 struct _tag_array
477 {
478 	void **slots;
479 	u32 entryCount;
480 };
481 
482 
483 GF_EXPORT
gf_list_new()484 GF_List * gf_list_new()
485 {
486 	GF_List *nlist = (GF_List *) gf_malloc(sizeof(GF_List));
487 	if (! nlist) return NULL;
488 	nlist->slots = NULL;
489 	nlist->entryCount = 0;
490 	return nlist;
491 }
492 
493 GF_EXPORT
gf_list_del(GF_List * ptr)494 void gf_list_del(GF_List *ptr)
495 {
496 	if (!ptr) return;
497 	gf_free(ptr->slots);
498 	gf_free(ptr);
499 }
500 
501 GF_EXPORT
gf_list_add(GF_List * ptr,void * item)502 GF_Err gf_list_add(GF_List *ptr, void* item)
503 {
504 	if (! ptr) return GF_BAD_PARAM;
505 
506 	ptr->slots = (void **) gf_realloc(ptr->slots, (ptr->entryCount+1)*sizeof(void*));
507 	if (!ptr->slots) {
508 		return GF_OUT_OF_MEM;
509 	}
510 	ptr->slots[ptr->entryCount] = item;
511 	ptr->entryCount ++;
512 	return GF_OK;
513 }
514 
515 GF_EXPORT
gf_list_count(GF_List * ptr)516 u32 gf_list_count(GF_List *ptr)
517 {
518 	return ptr ? ptr->entryCount : 0;
519 }
520 
521 GF_EXPORT
gf_list_get(GF_List * ptr,u32 itemNumber)522 void *gf_list_get(GF_List *ptr, u32 itemNumber)
523 {
524 	if(!ptr || (itemNumber >= ptr->entryCount)) return NULL;
525 	return ptr->slots[itemNumber];
526 }
527 
528 GF_EXPORT
gf_list_last(GF_List * ptr)529 void *gf_list_last(GF_List *ptr)
530 {
531 	if(!ptr || !ptr->entryCount) return NULL;
532 	return ptr->slots[ptr->entryCount-1];
533 }
534 
535 
536 /*WARNING: itemNumber is from 0 to entryCount - 1*/
537 GF_EXPORT
gf_list_rem(GF_List * ptr,u32 itemNumber)538 GF_Err gf_list_rem(GF_List *ptr, u32 itemNumber)
539 {
540 	u32 i;
541 	if ( !ptr || !ptr->slots || !ptr->entryCount) return GF_BAD_PARAM;
542 	i = ptr->entryCount - itemNumber - 1;
543 	if (i) memmove(&ptr->slots[itemNumber], & ptr->slots[itemNumber +1], sizeof(void *)*i);
544 	ptr->slots[ptr->entryCount-1] = NULL;
545 	ptr->entryCount -= 1;
546 	ptr->slots = (void **) gf_realloc(ptr->slots, sizeof(void*)*ptr->entryCount);
547 	return GF_OK;
548 }
549 
550 GF_EXPORT
gf_list_rem_last(GF_List * ptr)551 GF_Err gf_list_rem_last(GF_List *ptr)
552 {
553 	if ( !ptr || !ptr->slots || !ptr->entryCount) return GF_BAD_PARAM;
554 	ptr->entryCount -= 1;
555 	ptr->slots = (void **) gf_realloc(ptr->slots, sizeof(void*)*ptr->entryCount);
556 	return GF_OK;
557 }
558 
559 
560 /*WARNING: position is from 0 to entryCount - 1*/
561 GF_EXPORT
gf_list_insert(GF_List * ptr,void * item,u32 position)562 GF_Err gf_list_insert(GF_List *ptr, void *item, u32 position)
563 {
564 	u32 i;
565 	if (!ptr || !item) return GF_BAD_PARAM;
566 	/*if last entry or first of an empty array...*/
567 	if (position >= ptr->entryCount) return gf_list_add(ptr, item);
568 	ptr->slots = (void **) gf_realloc(ptr->slots, (ptr->entryCount+1)*sizeof(void*));
569 	i = ptr->entryCount - position;
570 	memmove(&ptr->slots[position + 1], &ptr->slots[position], sizeof(void *)*i);
571 	ptr->entryCount++;
572 	ptr->slots[position] = item;
573 	return GF_OK;
574 }
575 
576 GF_EXPORT
gf_list_reset(GF_List * ptr)577 void gf_list_reset(GF_List *ptr)
578 {
579 	if (ptr) {
580 		ptr->entryCount = 0;
581 		gf_free(ptr->slots);
582 		ptr->slots = NULL;
583 	}
584 }
585 
586 #else	/*GF_LIST_ARRAY_GROW*/
587 
588 
589 struct _tag_array
590 {
591 	void **slots;
592 	u32 entryCount;
593 	u32 allocSize;
594 };
595 
596 GF_EXPORT
gf_list_new()597 GF_List * gf_list_new()
598 {
599 	GF_List *nlist;
600 
601 	nlist = (GF_List *) gf_malloc(sizeof(GF_List));
602 	if (! nlist) return NULL;
603 
604 	nlist->slots = NULL;
605 	nlist->entryCount = 0;
606 	nlist->allocSize = 0;
607 	return nlist;
608 }
609 
610 GF_EXPORT
gf_list_del(GF_List * ptr)611 void gf_list_del(GF_List *ptr)
612 {
613 	if (!ptr) return;
614 	gf_free(ptr->slots);
615 	gf_free(ptr);
616 }
617 
realloc_chain(GF_List * ptr)618 static void realloc_chain(GF_List *ptr)
619 {
620 	GF_LIST_REALLOC(ptr->allocSize);
621 	ptr->slots = (void**)gf_realloc(ptr->slots, ptr->allocSize*sizeof(void*));
622 }
623 
624 GF_EXPORT
gf_list_add(GF_List * ptr,void * item)625 GF_Err gf_list_add(GF_List *ptr, void* item)
626 {
627 	if (! ptr) return GF_BAD_PARAM;
628 	if (! item)
629 		return GF_BAD_PARAM;
630 	if (ptr->allocSize==ptr->entryCount) realloc_chain(ptr);
631 	if (!ptr->slots) return GF_OUT_OF_MEM;
632 
633 	ptr->slots[ptr->entryCount] = item;
634 	ptr->entryCount ++;
635 	return GF_OK;
636 }
637 
638 GF_EXPORT
gf_list_count(const GF_List * ptr)639 u32 gf_list_count(const GF_List *ptr)
640 {
641 	if (!ptr) return 0;
642 	return ptr->entryCount;
643 }
644 
645 GF_EXPORT
gf_list_get(GF_List * ptr,u32 itemNumber)646 void *gf_list_get(GF_List *ptr, u32 itemNumber)
647 {
648 	if(!ptr || (itemNumber >= ptr->entryCount))
649 		return NULL;
650 	return ptr->slots[itemNumber];
651 }
652 
653 GF_EXPORT
gf_list_last(GF_List * ptr)654 void *gf_list_last(GF_List *ptr)
655 {
656 	if(!ptr || !ptr->entryCount) return NULL;
657 	return ptr->slots[ptr->entryCount-1];
658 }
659 
660 
661 /*WARNING: itemNumber is from 0 to entryCount - 1*/
662 GF_EXPORT
gf_list_rem(GF_List * ptr,u32 itemNumber)663 GF_Err gf_list_rem(GF_List *ptr, u32 itemNumber)
664 {
665 	u32 i;
666 	if ( !ptr || !ptr->slots || !ptr->entryCount) return GF_BAD_PARAM;
667 	if (ptr->entryCount < itemNumber) return GF_BAD_PARAM;
668 
669 	i = ptr->entryCount - itemNumber - 1;
670 	if (i) memmove(&ptr->slots[itemNumber], & ptr->slots[itemNumber +1], sizeof(void *)*i);
671 	ptr->slots[ptr->entryCount-1] = NULL;
672 	ptr->entryCount -= 1;
673 	return GF_OK;
674 }
675 
676 GF_EXPORT
gf_list_rem_last(GF_List * ptr)677 GF_Err gf_list_rem_last(GF_List *ptr)
678 {
679 	if ( !ptr || !ptr->slots || !ptr->entryCount) return GF_BAD_PARAM;
680 	ptr->slots[ptr->entryCount-1] = NULL;
681 	ptr->entryCount -= 1;
682 	return GF_OK;
683 }
684 
685 /*WARNING: position is from 0 to entryCount - 1*/
686 GF_EXPORT
gf_list_insert(GF_List * ptr,void * item,u32 position)687 GF_Err gf_list_insert(GF_List *ptr, void *item, u32 position)
688 {
689 	u32 i;
690 	if (!ptr || !item) return GF_BAD_PARAM;
691 	/*if last entry or first of an empty array...*/
692 	if (position >= ptr->entryCount) return gf_list_add(ptr, item);
693 	if (ptr->allocSize==ptr->entryCount) realloc_chain(ptr);
694 
695 	i = ptr->entryCount - position;
696 	memmove(&ptr->slots[position + 1], &ptr->slots[position], sizeof(void *)*i);
697 	ptr->entryCount++;
698 	ptr->slots[position] = item;
699 	return GF_OK;
700 }
701 
702 GF_EXPORT
gf_list_reset(GF_List * ptr)703 void gf_list_reset(GF_List *ptr)
704 {
705 	if (ptr) ptr->entryCount = 0;
706 }
707 
708 #endif
709 
710 GF_EXPORT
gf_list_find(GF_List * ptr,void * item)711 s32 gf_list_find(GF_List *ptr, void *item)
712 {
713 	u32 i, count;
714 	count = gf_list_count(ptr);
715 	for (i=0; i<count; i++) {
716 		if (gf_list_get(ptr, i) == item) return (s32) i;
717 	}
718 	return -1;
719 }
720 
721 GF_EXPORT
gf_list_del_item(GF_List * ptr,void * item)722 s32 gf_list_del_item(GF_List *ptr, void *item)
723 {
724 	s32 i = gf_list_find(ptr, item);
725 	if (i>=0) gf_list_rem(ptr, (u32) i);
726 	return i;
727 }
728 
729 GF_EXPORT
gf_list_enum(GF_List * ptr,u32 * pos)730 void *gf_list_enum(GF_List *ptr, u32 *pos)
731 {
732 	void *res;
733 	if (!ptr || !pos) return NULL;
734 	res = gf_list_get(ptr, *pos);
735 	(*pos)++;
736 	return res;
737 }
738 
739 //unused
740 #if 0
741 GF_EXPORT
742 void *gf_list_rev_enum(GF_List *ptr, u32 *pos) {
743 	void *res;
744 	if (!ptr || !pos) return NULL;
745 	res = gf_list_get(ptr, gf_list_count (ptr) - *pos - 1 );
746 	(*pos)++;
747 	return res;
748 }
749 #endif
750 
751 GF_EXPORT
gf_list_swap(GF_List * l1,GF_List * l2)752 GF_Err gf_list_swap(GF_List *l1, GF_List *l2)
753 {
754 	GF_Err e;
755 	u32 count = gf_list_count(l1);
756 	if (!l1 || !l2) return GF_BAD_PARAM;
757 	if (l1 == l2) return GF_OK;
758 
759 	while (gf_list_count(l2)) {
760 		void *ptr = gf_list_get(l2, 0);
761 		e = gf_list_rem(l2, 0);
762 		if (e) return e;
763 		e = gf_list_add(l1, ptr);
764 		if (e) return e;
765 	}
766 	while (count) {
767 		void *ptr = gf_list_get(l1, 0);
768 		e = gf_list_rem(l1, 0);
769 		if (e) return e;
770 		count--;
771 		e = gf_list_add(l2, ptr);
772 		if (e) return e;
773 	}
774 	return GF_OK;
775 }
776 
777 GF_EXPORT
gf_list_transfer(GF_List * dst,GF_List * src)778 GF_Err gf_list_transfer(GF_List *dst, GF_List *src)
779 {
780 	GF_Err e;
781 	if (!dst || !src) return GF_BAD_PARAM;
782 	if (dst == src) return GF_OK;
783 
784 	while (gf_list_count(src)) {
785 		void *ptr = gf_list_get(src, 0);
786 		e = gf_list_rem(src, 0);
787 		if (e) return e;
788 		e = gf_list_add(dst, ptr);
789 		if (e) return e;
790 	}
791 	return GF_OK;
792 }
793 
794 GF_EXPORT
gf_list_clone(GF_List * ptr)795 GF_List* gf_list_clone(GF_List *ptr) {
796 	GF_List* new_list;
797 	u32 i = 0;
798 	void* item;
799 	if (!ptr) return NULL;
800 	new_list = gf_list_new();
801 	while ((item = gf_list_enum(ptr, &i)))
802 		gf_list_add(new_list, item);
803 
804 	return new_list;
805 }
806 
807 //unused
808 #if 0
809 void gf_list_reverse(GF_List *ptr) {
810 	GF_List* saved_order;
811 	void* item;
812 	u32 i = 0;
813 	if (!ptr) return;
814 	saved_order = gf_list_clone(ptr);
815 	gf_list_reset(ptr);
816 
817 	while ((item = gf_list_enum(saved_order, &i))) {
818 		gf_list_insert(ptr, item, 0);
819 	}
820 
821 	gf_list_del(saved_order);
822 }
823 #endif
824 
825 GF_EXPORT
gf_list_pop_front(GF_List * ptr)826 void* gf_list_pop_front(GF_List *ptr) {
827 	void * item;
828 	if (!ptr) return NULL;
829 
830 	item = gf_list_get(ptr, 0);
831 	gf_list_rem(ptr, 0);
832 
833 	return item;
834 }
835 
836 GF_EXPORT
gf_list_pop_back(GF_List * ptr)837 void* gf_list_pop_back(GF_List *ptr) {
838 	void * item;
839 	if (!ptr) return NULL;
840 
841 	item = gf_list_last(ptr);
842 	gf_list_rem_last(ptr);
843 
844 	return item;
845 }
846