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 withou 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 	}
111 	else {
112 		ptr->entryCount += 1;
113 		ptr->tail->next = entry;
114 	}
115 	ptr->tail = entry;
116 	ptr->foundEntryNumber = ptr->entryCount - 1;
117 	ptr->foundEntry = entry;
118 	return GF_OK;
119 }
120 
121 GF_EXPORT
gf_list_count(const GF_List * ptr)122 u32 gf_list_count(const GF_List *ptr)
123 {
124 	if (!ptr) return 0;
125 	return ptr->entryCount;
126 }
127 
128 GF_EXPORT
gf_list_get(GF_List * ptr,u32 itemNumber)129 void *gf_list_get(GF_List *ptr, u32 itemNumber)
130 {
131 	ItemSlot *entry;
132 	u32 i;
133 
134 	if (!ptr || (itemNumber >= ptr->entryCount)) return NULL;
135 
136 	if (!ptr->foundEntry || (itemNumber < (u32)ptr->foundEntryNumber)) {
137 		ptr->foundEntryNumber = 0;
138 		ptr->foundEntry = ptr->head;
139 	}
140 	entry = ptr->foundEntry;
141 	for (i = ptr->foundEntryNumber; i < itemNumber; i++) {
142 		entry = entry->next;
143 	}
144 	ptr->foundEntryNumber = itemNumber;
145 	ptr->foundEntry = entry;
146 	return (void *)entry->data;
147 }
148 
149 GF_EXPORT
gf_list_last(GF_List * ptr)150 void *gf_list_last(GF_List *ptr)
151 {
152 	ItemSlot *entry;
153 	if (!ptr || !ptr->entryCount) return NULL;
154 	entry = ptr->head;
155 	while (entry->next) entry = entry->next;
156 	return entry->data;
157 }
158 
159 GF_EXPORT
gf_list_rem(GF_List * ptr,u32 itemNumber)160 GF_Err gf_list_rem(GF_List *ptr, u32 itemNumber)
161 {
162 	ItemSlot *tmp, *tmp2;
163 	u32 i;
164 
165 	/* !! if head is null (empty list)*/
166 	if ((!ptr) || (!ptr->head) || (ptr->head && !ptr->entryCount) || (itemNumber >= ptr->entryCount))
167 		return GF_BAD_PARAM;
168 
169 	/*we delete the head*/
170 	if (!itemNumber) {
171 		tmp = ptr->head;
172 		ptr->head = ptr->head->next;
173 		ptr->entryCount--;
174 		ptr->foundEntry = ptr->head;
175 		ptr->foundEntryNumber = 0;
176 		gf_free(tmp);
177 		/*that was the last entry, reset the tail*/
178 		if (!ptr->entryCount) {
179 			ptr->tail = ptr->head = ptr->foundEntry = NULL;
180 			ptr->foundEntryNumber = -1;
181 		}
182 		return GF_OK;
183 	}
184 
185 	tmp = ptr->head;
186 	i = 0;
187 	while (i < itemNumber - 1) {
188 		tmp = tmp->next;
189 		i++;
190 	}
191 	tmp2 = tmp->next;
192 	tmp->next = tmp2->next;
193 	/*if we deleted the last entry, update the tail !!!*/
194 	if (!tmp->next || (ptr->tail == tmp2)) {
195 		ptr->tail = tmp;
196 		tmp->next = NULL;
197 	}
198 
199 	gf_free(tmp2);
200 	ptr->entryCount--;
201 	ptr->foundEntry = ptr->head;
202 	ptr->foundEntryNumber = 0;
203 
204 	return GF_OK;
205 }
206 
207 GF_EXPORT
gf_list_rem_last(GF_List * ptr)208 GF_Err gf_list_rem_last(GF_List *ptr)
209 {
210 	return gf_list_rem(ptr, ptr->entryCount - 1);
211 }
212 
213 GF_EXPORT
gf_list_insert(GF_List * ptr,void * item,u32 position)214 GF_Err gf_list_insert(GF_List *ptr, void *item, u32 position)
215 {
216 	u32 i;
217 	ItemSlot *tmp, *tmp2;
218 
219 	if (!ptr || !item) return GF_BAD_PARAM;
220 	/*if last entry or first of an empty array...*/
221 	if (position >= ptr->entryCount) return gf_list_add(ptr, item);
222 
223 	tmp2 = (ItemSlot *)gf_malloc(sizeof(ItemSlot));
224 	tmp2->data = item;
225 	tmp2->next = NULL;
226 	/*special case for the head*/
227 	if (position == 0) {
228 		tmp2->next = ptr->head;
229 		ptr->head = tmp2;
230 		ptr->entryCount++;
231 		ptr->foundEntry = tmp2;
232 		ptr->foundEntryNumber = 0;
233 		return GF_OK;
234 	}
235 	tmp = ptr->head;
236 	for (i = 1; i < position; i++) {
237 		tmp = tmp->next;
238 		if (!tmp)
239 			break;
240 	}
241 	tmp2->next = tmp->next;
242 	tmp->next = tmp2;
243 	ptr->entryCount++;
244 	ptr->foundEntry = tmp2;
245 	ptr->foundEntryNumber = i;
246 	return GF_OK;
247 }
248 
249 #elif defined(GF_LIST_DOUBLE_LINKED)
250 
251 
252 typedef struct tagIS
253 {
254 	struct tagIS *next;
255 	struct tagIS *prev;
256 	void *data;
257 } ItemSlot;
258 
259 struct _tag_array
260 {
261 	struct tagIS *head;
262 	struct tagIS *tail;
263 	u32 entryCount;
264 	s32 foundEntryNumber;
265 	struct tagIS *foundEntry;
266 };
267 
268 
269 GF_EXPORT
gf_list_new()270 GF_List * gf_list_new()
271 {
272 	GF_List *nlist = (GF_List *)gf_malloc(sizeof(GF_List));
273 	if (!nlist) return NULL;
274 	nlist->head = nlist->foundEntry = NULL;
275 	nlist->tail = NULL;
276 	nlist->foundEntryNumber = -1;
277 	nlist->entryCount = 0;
278 	return nlist;
279 }
280 
281 GF_EXPORT
gf_list_del(GF_List * ptr)282 void gf_list_del(GF_List *ptr)
283 {
284 	if (!ptr) return;
285 	while (ptr->entryCount) {
286 		gf_list_rem(ptr, 0);
287 	}
288 	gf_free(ptr);
289 }
290 
291 GF_EXPORT
gf_list_reset(GF_List * ptr)292 void gf_list_reset(GF_List *ptr)
293 {
294 	while (ptr && ptr->entryCount) gf_list_rem(ptr, 0);
295 }
296 
297 GF_EXPORT
gf_list_add(GF_List * ptr,void * item)298 GF_Err gf_list_add(GF_List *ptr, void* item)
299 {
300 	ItemSlot *entry;
301 	if (!ptr) return GF_BAD_PARAM;
302 	entry = (ItemSlot *)gf_malloc(sizeof(ItemSlot));
303 	if (!entry) return GF_OUT_OF_MEM;
304 	entry->data = item;
305 	entry->next = entry->prev = NULL;
306 
307 	if (!ptr->head) {
308 		ptr->head = entry;
309 		ptr->entryCount = 1;
310 	}
311 	else {
312 		ptr->entryCount += 1;
313 		entry->prev = ptr->tail;
314 		ptr->tail->next = entry;
315 	}
316 	ptr->tail = entry;
317 	ptr->foundEntryNumber = ptr->entryCount - 1;
318 	ptr->foundEntry = entry;
319 	return GF_OK;
320 }
321 
322 
323 GF_EXPORT
gf_list_count(GF_List * ptr)324 u32 gf_list_count(GF_List *ptr)
325 {
326 	if (!ptr) return 0;
327 	return ptr->entryCount;
328 }
329 
330 GF_EXPORT
gf_list_get(GF_List * ptr,u32 itemNumber)331 void *gf_list_get(GF_List *ptr, u32 itemNumber)
332 {
333 	ItemSlot *entry;
334 	u32 i;
335 
336 	if (!ptr || !ptr->head || (itemNumber >= ptr->entryCount)) return NULL;
337 
338 	if (!itemNumber) {
339 		ptr->foundEntry = ptr->head;
340 		ptr->foundEntryNumber = 0;
341 		return ptr->head->data;
342 	}
343 
344 	entry = ptr->foundEntry;
345 	if (itemNumber < (u32)ptr->foundEntryNumber) {
346 		for (i = ptr->foundEntryNumber; i > itemNumber; i--) {
347 			entry = entry->prev;
348 		}
349 	}
350 	else {
351 		for (i = ptr->foundEntryNumber; i < itemNumber; i++) {
352 			entry = entry->next;
353 		}
354 	}
355 	ptr->foundEntryNumber = itemNumber;
356 	ptr->foundEntry = entry;
357 	return (void *)entry->data;
358 }
359 
360 GF_EXPORT
gf_list_last(GF_List * ptr)361 void *gf_list_last(GF_List *ptr)
362 {
363 	if (!ptr || !ptr->tail) return NULL;
364 	return ptr->tail->data;
365 }
366 
367 GF_EXPORT
gf_list_rem(GF_List * ptr,u32 itemNumber)368 GF_Err gf_list_rem(GF_List *ptr, u32 itemNumber)
369 {
370 	ItemSlot *tmp;
371 	u32 i;
372 
373 	/* !! if head is null (empty list)*/
374 	if ((!ptr) || (!ptr->head) || (ptr->head && !ptr->entryCount) || (itemNumber >= ptr->entryCount))
375 		return GF_BAD_PARAM;
376 
377 	/*we delete the head*/
378 	if (!itemNumber) {
379 		tmp = ptr->head;
380 		ptr->head = ptr->head->next;
381 
382 		ptr->entryCount--;
383 		ptr->foundEntry = ptr->head;
384 		ptr->foundEntryNumber = 0;
385 		gf_free(tmp);
386 
387 		/*that was the last entry, reset the tail*/
388 		if (!ptr->entryCount) {
389 			ptr->tail = ptr->head = ptr->foundEntry = NULL;
390 			ptr->foundEntryNumber = -1;
391 		}
392 		else {
393 			ptr->head->prev = NULL;
394 		}
395 		return GF_OK;
396 	}
397 	else if (itemNumber == ptr->entryCount - 1) {
398 		tmp = ptr->tail;
399 		ptr->tail = tmp->prev;
400 		ptr->tail->next = NULL;
401 		ptr->entryCount--;
402 		if (ptr->foundEntry == tmp) {
403 			ptr->foundEntry = ptr->tail;
404 			ptr->foundEntryNumber = ptr->entryCount - 1;
405 		}
406 		gf_free(tmp);
407 		return GF_OK;
408 	}
409 
410 	tmp = ptr->foundEntry;
411 	if (itemNumber < (u32)ptr->foundEntryNumber) {
412 		for (i = ptr->foundEntryNumber; i > itemNumber; i--) {
413 			tmp = tmp->prev;
414 		}
415 	}
416 	else {
417 		for (i = ptr->foundEntryNumber; i < itemNumber; i++) {
418 			tmp = tmp->next;
419 		}
420 	}
421 	tmp->prev->next = tmp->next;
422 	tmp->next->prev = tmp->prev;
423 	if (tmp == ptr->foundEntry) ptr->foundEntry = tmp->next;
424 	gf_free(tmp);
425 	ptr->entryCount--;
426 	return GF_OK;
427 }
428 
429 GF_EXPORT
gf_list_rem_last(GF_List * ptr)430 GF_Err gf_list_rem_last(GF_List *ptr)
431 {
432 	return gf_list_rem(ptr, ptr->entryCount - 1);
433 }
434 
435 GF_EXPORT
gf_list_insert(GF_List * ptr,void * item,u32 position)436 GF_Err gf_list_insert(GF_List *ptr, void *item, u32 position)
437 {
438 	u32 i;
439 	ItemSlot *tmp, *tmp2;
440 
441 	if (!ptr || !item) return GF_BAD_PARAM;
442 	/*if last entry or first of an empty array...*/
443 	if (position >= ptr->entryCount) return gf_list_add(ptr, item);
444 	tmp2 = (ItemSlot *)gf_malloc(sizeof(ItemSlot));
445 	tmp2->data = item;
446 	tmp2->next = tmp2->prev = NULL;
447 	/*special case for the head*/
448 	if (position == 0) {
449 		ptr->head->prev = tmp2;
450 		tmp2->next = ptr->head;
451 		ptr->head = tmp2;
452 		ptr->entryCount++;
453 		ptr->foundEntry = tmp2;
454 		ptr->foundEntryNumber = 0;
455 		return GF_OK;
456 	}
457 
458 	tmp = ptr->foundEntry;
459 	if (position < (u32)ptr->foundEntryNumber) {
460 		for (i = ptr->foundEntryNumber; i >= position; i--) {
461 			tmp = tmp->prev;
462 		}
463 		tmp = tmp->prev;
464 	}
465 	else {
466 		for (i = ptr->foundEntryNumber; i < position; i++) {
467 			tmp = tmp->next;
468 		}
469 	}
470 	tmp2->next = tmp->next;
471 	tmp2->next->prev = tmp2;
472 	tmp2->prev = tmp;
473 	tmp2->prev->next = tmp2;
474 	ptr->entryCount++;
475 	ptr->foundEntry = tmp2;
476 	ptr->foundEntryNumber = position;
477 	return GF_OK;
478 }
479 
480 #elif defined(GF_LIST_ARRAY)
481 
482 struct _tag_array
483 {
484 	void **slots;
485 	u32 entryCount;
486 };
487 
488 
489 GF_EXPORT
gf_list_new()490 GF_List * gf_list_new()
491 {
492 	GF_List *nlist = (GF_List *)gf_malloc(sizeof(GF_List));
493 	if (!nlist) return NULL;
494 	nlist->slots = NULL;
495 	nlist->entryCount = 0;
496 	return nlist;
497 }
498 
499 GF_EXPORT
gf_list_del(GF_List * ptr)500 void gf_list_del(GF_List *ptr)
501 {
502 	if (!ptr) return;
503 	gf_free(ptr->slots);
504 	gf_free(ptr);
505 }
506 
507 GF_EXPORT
gf_list_add(GF_List * ptr,void * item)508 GF_Err gf_list_add(GF_List *ptr, void* item)
509 {
510 	if (!ptr) return GF_BAD_PARAM;
511 
512 	ptr->entryCount++;
513 	ptr->slots = (void **)gf_realloc(ptr->slots, ptr->entryCount * sizeof(void*));
514 	if (!ptr->slots) {
515 		ptr->entryCount = 0;
516 		return GF_OUT_OF_MEM;
517 	}
518 	ptr->slots[ptr->entryCount - 1] = item;
519 	return GF_OK;
520 }
521 
522 GF_EXPORT
gf_list_count(GF_List * ptr)523 u32 gf_list_count(GF_List *ptr)
524 {
525 	return ptr ? ptr->entryCount : 0;
526 }
527 
528 GF_EXPORT
gf_list_get(GF_List * ptr,u32 itemNumber)529 void *gf_list_get(GF_List *ptr, u32 itemNumber)
530 {
531 	if (!ptr || (itemNumber >= ptr->entryCount)) return NULL;
532 	return ptr->slots[itemNumber];
533 }
534 
535 GF_EXPORT
gf_list_last(GF_List * ptr)536 void *gf_list_last(GF_List *ptr)
537 {
538 	if (!ptr || !ptr->entryCount) return NULL;
539 	return ptr->slots[ptr->entryCount - 1];
540 }
541 
542 
543 /*WARNING: itemNumber is from 0 to entryCount - 1*/
544 GF_EXPORT
gf_list_rem(GF_List * ptr,u32 itemNumber)545 GF_Err gf_list_rem(GF_List *ptr, u32 itemNumber)
546 {
547 	u32 i;
548 	if (!ptr || !ptr->slots || !ptr->entryCount) return GF_BAD_PARAM;
549 	i = ptr->entryCount - itemNumber - 1;
550 	if (i) memmove(&ptr->slots[itemNumber], &ptr->slots[itemNumber + 1], sizeof(void *)*i);
551 	ptr->slots[ptr->entryCount - 1] = NULL;
552 	ptr->entryCount -= 1;
553 	ptr->slots = (void **)gf_realloc(ptr->slots, sizeof(void*)*ptr->entryCount);
554 	return GF_OK;
555 }
556 
557 GF_EXPORT
gf_list_rem_last(GF_List * ptr)558 GF_Err gf_list_rem_last(GF_List *ptr)
559 {
560 	if (!ptr || !ptr->slots || !ptr->entryCount) return GF_BAD_PARAM;
561 	ptr->entryCount -= 1;
562 	ptr->slots = (void **)gf_realloc(ptr->slots, sizeof(void*)*ptr->entryCount);
563 	return GF_OK;
564 }
565 
566 
567 /*WARNING: position is from 0 to entryCount - 1*/
568 GF_EXPORT
gf_list_insert(GF_List * ptr,void * item,u32 position)569 GF_Err gf_list_insert(GF_List *ptr, void *item, u32 position)
570 {
571 	u32 i;
572 	if (!ptr || !item) return GF_BAD_PARAM;
573 	/*if last entry or first of an empty array...*/
574 	if (position >= ptr->entryCount) return gf_list_add(ptr, item);
575 	ptr->slots = (void **)gf_realloc(ptr->slots, (ptr->entryCount + 1) * sizeof(void*));
576 	i = ptr->entryCount - position;
577 	memmove(&ptr->slots[position + 1], &ptr->slots[position], sizeof(void *)*i);
578 	ptr->entryCount++;
579 	ptr->slots[position] = item;
580 	return GF_OK;
581 }
582 
583 GF_EXPORT
gf_list_reset(GF_List * ptr)584 void gf_list_reset(GF_List *ptr)
585 {
586 	if (ptr) {
587 		ptr->entryCount = 0;
588 		gf_free(ptr->slots);
589 		ptr->slots = NULL;
590 	}
591 }
592 
593 #else	/*GF_LIST_ARRAY_GROW*/
594 
595 
596 struct _tag_array
597 {
598 	void **slots;
599 	u32 entryCount;
600 	u32 allocSize;
601 };
602 
603 GF_EXPORT
gf_list_new()604 GF_List * gf_list_new()
605 {
606 	GF_List *nlist;
607 
608 	nlist = (GF_List *)gf_malloc(sizeof(GF_List));
609 	if (!nlist) return NULL;
610 
611 	nlist->slots = NULL;
612 	nlist->entryCount = 0;
613 	nlist->allocSize = 0;
614 	return nlist;
615 }
616 
617 GF_EXPORT
gf_list_del(GF_List * ptr)618 void gf_list_del(GF_List *ptr)
619 {
620 	if (!ptr) return;
621 	gf_free(ptr->slots);
622 	gf_free(ptr);
623 }
624 
realloc_chain(GF_List * ptr)625 static void realloc_chain(GF_List *ptr)
626 {
627 	GF_LIST_REALLOC(ptr->allocSize);
628 	ptr->slots = (void**)gf_realloc(ptr->slots, ptr->allocSize * sizeof(void*));
629 }
630 
631 GF_EXPORT
gf_list_add(GF_List * ptr,void * item)632 GF_Err gf_list_add(GF_List *ptr, void* item)
633 {
634 	if (!ptr) return GF_BAD_PARAM;
635 	if (ptr->allocSize == ptr->entryCount) realloc_chain(ptr);
636 	if (!ptr->slots) return GF_OUT_OF_MEM;
637 
638 	ptr->slots[ptr->entryCount] = item;
639 	ptr->entryCount++;
640 	return GF_OK;
641 }
642 
643 GF_EXPORT
gf_list_count(const GF_List * ptr)644 u32 gf_list_count(const GF_List *ptr)
645 {
646 	if (!ptr) return 0;
647 	return ptr->entryCount;
648 }
649 
650 GF_EXPORT
gf_list_get(GF_List * ptr,u32 itemNumber)651 void *gf_list_get(GF_List *ptr, u32 itemNumber)
652 {
653 	if (!ptr || (itemNumber >= ptr->entryCount)) return NULL;
654 	return ptr->slots[itemNumber];
655 }
656 
657 GF_EXPORT
gf_list_last(GF_List * ptr)658 void *gf_list_last(GF_List *ptr)
659 {
660 	if (!ptr || !ptr->entryCount) return NULL;
661 	return ptr->slots[ptr->entryCount - 1];
662 }
663 
664 
665 /*WARNING: itemNumber is from 0 to entryCount - 1*/
666 GF_EXPORT
gf_list_rem(GF_List * ptr,u32 itemNumber)667 GF_Err gf_list_rem(GF_List *ptr, u32 itemNumber)
668 {
669 	u32 i;
670 	if (!ptr || !ptr->slots || !ptr->entryCount) return GF_BAD_PARAM;
671 	i = ptr->entryCount - itemNumber - 1;
672 	if (i) memmove(&ptr->slots[itemNumber], &ptr->slots[itemNumber + 1], sizeof(void *)*i);
673 	ptr->slots[ptr->entryCount - 1] = NULL;
674 	ptr->entryCount -= 1;
675 	return GF_OK;
676 }
677 
678 GF_EXPORT
gf_list_rem_last(GF_List * ptr)679 GF_Err gf_list_rem_last(GF_List *ptr)
680 {
681 	if (!ptr || !ptr->slots || !ptr->entryCount) return GF_BAD_PARAM;
682 	ptr->slots[ptr->entryCount - 1] = NULL;
683 	ptr->entryCount -= 1;
684 	return GF_OK;
685 }
686 
687 /*WARNING: position is from 0 to entryCount - 1*/
688 GF_EXPORT
gf_list_insert(GF_List * ptr,void * item,u32 position)689 GF_Err gf_list_insert(GF_List *ptr, void *item, u32 position)
690 {
691 	u32 i;
692 	if (!ptr || !item) return GF_BAD_PARAM;
693 	/*if last entry or first of an empty array...*/
694 	if (position >= ptr->entryCount) return gf_list_add(ptr, item);
695 	if (ptr->allocSize == ptr->entryCount) realloc_chain(ptr);
696 
697 	i = ptr->entryCount - position;
698 	memmove(&ptr->slots[position + 1], &ptr->slots[position], sizeof(void *)*i);
699 	ptr->entryCount++;
700 	ptr->slots[position] = item;
701 	return GF_OK;
702 }
703 
704 GF_EXPORT
gf_list_reset(GF_List * ptr)705 void gf_list_reset(GF_List *ptr)
706 {
707 	if (ptr) ptr->entryCount = 0;
708 }
709 
710 #endif
711 
712 GF_EXPORT
gf_list_find(GF_List * ptr,void * item)713 s32 gf_list_find(GF_List *ptr, void *item)
714 {
715 	u32 i, count;
716 	count = gf_list_count(ptr);
717 	for (i = 0; i<count; i++) {
718 		if (gf_list_get(ptr, i) == item) return (s32)i;
719 	}
720 	return -1;
721 }
722 
723 GF_EXPORT
gf_list_del_item(GF_List * ptr,void * item)724 s32 gf_list_del_item(GF_List *ptr, void *item)
725 {
726 	s32 i = gf_list_find(ptr, item);
727 	if (i >= 0) gf_list_rem(ptr, (u32)i);
728 	return i;
729 }
730 
731 GF_EXPORT
gf_list_enum(GF_List * ptr,u32 * pos)732 void *gf_list_enum(GF_List *ptr, u32 *pos)
733 {
734 	void *res;
735 	if (!ptr || !pos) return NULL;
736 	res = gf_list_get(ptr, *pos);
737 	(*pos)++;
738 	return res;
739 }
740 
741 GF_EXPORT
gf_list_rev_enum(GF_List * ptr,u32 * pos)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 
750 GF_EXPORT
gf_list_swap(GF_List * l1,GF_List * l2)751 GF_Err gf_list_swap(GF_List *l1, GF_List *l2)
752 {
753 	GF_Err e;
754 	u32 count = gf_list_count(l1);
755 	if (!l1 || !l2) return GF_BAD_PARAM;
756 	if (l1 == l2) return GF_OK;
757 
758 	while (gf_list_count(l2)) {
759 		void *ptr = gf_list_get(l2, 0);
760 		e = gf_list_rem(l2, 0);
761 		if (e) return e;
762 		e = gf_list_add(l1, ptr);
763 		if (e) return e;
764 	}
765 	while (count) {
766 		void *ptr = gf_list_get(l1, 0);
767 		e = gf_list_rem(l1, 0);
768 		if (e) return e;
769 		count--;
770 		e = gf_list_add(l2, ptr);
771 		if (e) return e;
772 	}
773 	return GF_OK;
774 }
775 
776 GF_EXPORT
gf_list_transfer(GF_List * l1,GF_List * l2)777 GF_Err gf_list_transfer(GF_List *l1, GF_List *l2)
778 {
779 	GF_Err e;
780 	if (!l1 || !l2) return GF_BAD_PARAM;
781 	if (l1 == l2) return GF_OK;
782 
783 	while (gf_list_count(l2)) {
784 		void *ptr = gf_list_get(l2, 0);
785 		e = gf_list_rem(l2, 0);
786 		if (e) return e;
787 		e = gf_list_add(l1, ptr);
788 		if (e) return e;
789 	}
790 	return GF_OK;
791 }
792 
793 GF_EXPORT
gf_list_clone(GF_List * ptr)794 GF_List* gf_list_clone(GF_List *ptr) {
795 	GF_List* new_list;
796 	u32 i = 0;
797 	void* item;
798 	if (!ptr) return NULL;
799 	new_list = gf_list_new();
800 	while ((item = gf_list_enum(ptr, &i)))
801 		gf_list_add(new_list, item);
802 
803 	return new_list;
804 }
805 
806 GF_EXPORT
gf_list_reverse(GF_List * ptr)807 void gf_list_reverse(GF_List *ptr) {
808 	GF_List* saved_order;
809 	void* item;
810 	u32 i = 0;
811 	if (!ptr) return;
812 	saved_order = gf_list_clone(ptr);
813 	gf_list_reset(ptr);
814 
815 	while ((item = gf_list_enum(saved_order, &i))) {
816 		gf_list_insert(ptr, item, 0);
817 	}
818 
819 	gf_list_del(saved_order);
820 }
821 
822 GF_EXPORT
gf_list_pop_front(GF_List * ptr)823 void* gf_list_pop_front(GF_List *ptr) {
824 	void * item;
825 	if (!ptr) return NULL;
826 
827 	item = gf_list_get(ptr, 0);
828 	gf_list_rem(ptr, 0);
829 
830 	return item;
831 }
832 
833 GF_EXPORT
gf_list_pop_back(GF_List * ptr)834 void* gf_list_pop_back(GF_List *ptr) {
835 	void * item;
836 	if (!ptr) return NULL;
837 
838 	item = gf_list_last(ptr);
839 	gf_list_rem_last(ptr);
840 
841 	return item;
842 }
843