2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): none yet.
25 * ***** END GPL LICENSE BLOCK *****
29 /** \file blender/blenlib/intern/listbase.c
32 * Manipulations on ListBase structs
39 #include "MEM_guardedalloc.h"
41 #include "DNA_listBase.h"
43 #include "BLI_listbase.h"
45 #include "BLI_strict_flags.h"
50 * moves the entire contents of \a src onto the end of \a dst.
52 void BLI_movelisttolist(ListBase *dst, ListBase *src)
54 if (src->first == NULL) return;
56 if (dst->first == NULL) {
57 dst->first = src->first;
58 dst->last = src->last;
61 ((Link *)dst->last)->next = src->first;
62 ((Link *)src->first)->prev = dst->last;
63 dst->last = src->last;
65 src->first = src->last = NULL;
69 * Prepends \a vlink (assumed to begin with a Link) onto listbase.
71 void BLI_addhead(ListBase *listbase, void *vlink)
75 if (link == NULL) return;
77 link->next = listbase->first;
80 if (listbase->first) ((Link *)listbase->first)->prev = link;
81 if (listbase->last == NULL) listbase->last = link;
82 listbase->first = link;
87 * Appends \a vlink (assumed to begin with a Link) onto listbase.
89 void BLI_addtail(ListBase *listbase, void *vlink)
93 if (link == NULL) return;
96 link->prev = listbase->last;
98 if (listbase->last) ((Link *)listbase->last)->next = link;
99 if (listbase->first == NULL) listbase->first = link;
100 listbase->last = link;
105 * Removes \a vlink from \a listbase. Assumes it is linked into there!
107 void BLI_remlink(ListBase *listbase, void *vlink)
111 if (link == NULL) return;
113 if (link->next) link->next->prev = link->prev;
114 if (link->prev) link->prev->next = link->next;
116 if (listbase->last == link) listbase->last = link->prev;
117 if (listbase->first == link) listbase->first = link->next;
121 * Checks that \a vlink is linked into listbase, removing it from there if so.
123 bool BLI_remlink_safe(ListBase *listbase, void *vlink)
125 if (BLI_findindex(listbase, vlink) != -1) {
126 BLI_remlink(listbase, vlink);
135 * Swaps \a vlinka and \a vlinkb in the list. Assumes they are both already in the list!
137 void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
139 Link *linka = vlinka;
140 Link *linkb = vlinkb;
142 if (!linka || !linkb)
145 if (linkb->next == linka) {
146 SWAP(Link *, linka, linkb);
149 if (linka->next == linkb) {
150 linka->next = linkb->next;
151 linkb->prev = linka->prev;
155 else { /* Non-contiguous items, we can safely swap. */
156 SWAP(Link *, linka->prev, linkb->prev);
157 SWAP(Link *, linka->next, linkb->next);
160 /* Update neighbors of linka and linkb. */
161 if (linka->prev) linka->prev->next = linka;
162 if (linka->next) linka->next->prev = linka;
163 if (linkb->prev) linkb->prev->next = linkb;
164 if (linkb->next) linkb->next->prev = linkb;
166 if (listbase->last == linka) listbase->last = linkb;
167 else if (listbase->last == linkb) listbase->last = linka;
168 if (listbase->first == linka) listbase->first = linkb;
169 else if (listbase->first == linkb) listbase->first = linka;
173 * Removes the head from \a listbase and returns it.
175 void *BLI_pophead(ListBase *listbase)
178 if ((link = listbase->first)) {
179 BLI_remlink(listbase, link);
186 * Removes the tail from \a listbase and returns it.
188 void *BLI_poptail(ListBase *listbase)
191 if ((link = listbase->last)) {
192 BLI_remlink(listbase, link);
198 * Removes \a vlink from listbase and disposes of it. Assumes it is linked into there!
200 void BLI_freelinkN(ListBase *listbase, void *vlink)
204 if (link == NULL) return;
206 BLI_remlink(listbase, link);
211 * Assigns all #Link.prev pointers from #Link.next
213 static void listbase_double_from_single(Link *iter, ListBase *listbase)
216 listbase->first = iter;
220 } while ((iter = iter->next));
221 listbase->last = prev;
224 #define SORT_IMPL_LINKTYPE Link
227 #define SORT_IMPL_FUNC listbase_sort_fn
228 #include "list_sort_impl.h"
229 #undef SORT_IMPL_FUNC
232 #define SORT_IMPL_USE_THUNK
233 #define SORT_IMPL_FUNC listbase_sort_fn_r
234 #include "list_sort_impl.h"
235 #undef SORT_IMPL_FUNC
236 #undef SORT_IMPL_USE_THUNK
238 #undef SORT_IMPL_LINKTYPE
241 * Sorts the elements of listbase into the order defined by cmp
242 * (which should return 1 if its first arg should come after its second arg).
243 * This uses insertion sort, so NOT ok for large list.
245 void BLI_listbase_sort(ListBase *listbase, int (*cmp)(const void *, const void *))
247 if (listbase->first != listbase->last) {
248 Link *head = listbase->first;
249 head = listbase_sort_fn(head, cmp);
250 listbase_double_from_single(head, listbase);
254 void BLI_listbase_sort_r(ListBase *listbase, int (*cmp)(void *, const void *, const void *), void *thunk)
256 if (listbase->first != listbase->last) {
257 Link *head = listbase->first;
258 head = listbase_sort_fn_r(head, cmp, thunk);
259 listbase_double_from_single(head, listbase);
264 * Inserts \a vnewlink immediately following \a vprevlink in \a listbase.
265 * Or, if \a vprevlink is NULL, puts \a vnewlink at the front of the list.
267 void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
269 Link *prevlink = vprevlink;
270 Link *newlink = vnewlink;
272 /* newlink before nextlink */
273 if (newlink == NULL) return;
276 if (listbase->first == NULL) {
277 listbase->first = newlink;
278 listbase->last = newlink;
282 /* insert at head of list */
283 if (prevlink == NULL) {
284 newlink->prev = NULL;
285 newlink->next = listbase->first;
286 newlink->next->prev = newlink;
287 listbase->first = newlink;
292 if (listbase->last == prevlink) {
293 listbase->last = newlink;
296 newlink->next = prevlink->next;
297 newlink->prev = prevlink;
298 prevlink->next = newlink;
300 newlink->next->prev = newlink;
305 * Inserts \a vnewlink immediately preceding \a vnextlink in listbase.
306 * Or, if \a vnextlink is NULL, puts \a vnewlink at the end of the list.
308 void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
310 Link *nextlink = vnextlink;
311 Link *newlink = vnewlink;
313 /* newlink before nextlink */
314 if (newlink == NULL) return;
317 if (listbase->first == NULL) {
318 listbase->first = newlink;
319 listbase->last = newlink;
323 /* insert at end of list */
324 if (nextlink == NULL) {
325 newlink->prev = listbase->last;
326 newlink->next = NULL;
327 ((Link *)listbase->last)->next = newlink;
328 listbase->last = newlink;
332 /* at beginning of list */
333 if (listbase->first == nextlink) {
334 listbase->first = newlink;
337 newlink->next = nextlink;
338 newlink->prev = nextlink->prev;
339 nextlink->prev = newlink;
341 newlink->prev->next = newlink;
347 * Insert a link in place of another, without changing it's position in the list.
349 * Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`.
350 * - `vreplacelink` *must* be in the list.
351 * - `vnewlink` *must not* be in the list.
353 void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
355 Link *l_old = vreplacelink;
356 Link *l_new = vnewlink;
358 /* update adjacent links */
359 if (l_old->next != NULL) {
360 l_old->next->prev = l_new;
362 if (l_old->prev != NULL) {
363 l_old->prev->next = l_new;
366 /* set direct links */
367 l_new->next = l_old->next;
368 l_new->prev = l_old->prev;
371 if (listbase->first == l_old) {
372 listbase->first = l_new;
374 if (listbase->last == l_old) {
375 listbase->last = l_new;
380 * Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
381 * item if new position would exceed list (could optionally move to head/tail).
383 * \param step: Absolute value defines step size, sign defines direction. E.g pass -1
384 * to move \a vlink before previous, or 1 to move behind next.
385 * \return If position of \a vlink has changed.
387 bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
391 const bool is_up = step < 0;
396 BLI_assert(BLI_findindex(listbase, link) != -1);
398 /* find link to insert before/after */
399 for (int i = 0; i < ABS(step); i++) {
400 hook = is_up ? hook->prev : hook->next;
407 BLI_remlink(listbase, vlink);
409 BLI_insertlinkbefore(listbase, hook, vlink);
412 BLI_insertlinkafter(listbase, hook, vlink);
419 * Removes and disposes of the entire contents of listbase using direct free(3).
421 void BLI_freelist(ListBase *listbase)
425 link = listbase->first;
432 BLI_listbase_clear(listbase);
436 * Removes and disposes of the entire contents of \a listbase using guardedalloc.
438 void BLI_freelistN(ListBase *listbase)
442 link = listbase->first;
449 BLI_listbase_clear(listbase);
453 * Returns the number of elements in \a listbase, up until (and including count_max)
455 * \note Use to avoid redundant looping.
457 int BLI_listbase_count_ex(const ListBase *listbase, const int count_max)
462 for (link = listbase->first; link && count != count_max; link = link->next) {
470 * Returns the number of elements in \a listbase.
472 int BLI_listbase_count(const ListBase *listbase)
477 for (link = listbase->first; link; link = link->next) {
485 * Returns the nth element of \a listbase, numbering from 0.
487 void *BLI_findlink(const ListBase *listbase, int number)
492 link = listbase->first;
493 while (link != NULL && number != 0) {
503 * Returns the nth-last element of \a listbase, numbering from 0.
505 void *BLI_rfindlink(const ListBase *listbase, int number)
510 link = listbase->last;
511 while (link != NULL && number != 0) {
521 * Returns the position of \a vlink within \a listbase, numbering from 0, or -1 if not found.
523 int BLI_findindex(const ListBase *listbase, const void *vlink)
528 if (vlink == NULL) return -1;
530 link = listbase->first;
543 * Finds the first element of \a listbase which contains the null-terminated
544 * string \a id at the specified offset, returning NULL if not found.
546 void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
551 for (link = listbase->first; link; link = link->next) {
552 id_iter = ((const char *)link) + offset;
554 if (id[0] == id_iter[0] && STREQ(id, id_iter)) {
561 /* same as above but find reverse */
563 * Finds the last element of \a listbase which contains the
564 * null-terminated string \a id at the specified offset, returning NULL if not found.
566 void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset)
571 for (link = listbase->last; link; link = link->prev) {
572 id_iter = ((const char *)link) + offset;
574 if (id[0] == id_iter[0] && STREQ(id, id_iter)) {
583 * Finds the first element of \a listbase which contains a pointer to the
584 * null-terminated string \a id at the specified offset, returning NULL if not found.
586 void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int offset)
591 for (link = listbase->first; link; link = link->next) {
592 /* exact copy of BLI_findstring(), except for this line */
593 id_iter = *((const char **)(((const char *)link) + offset));
595 if (id[0] == id_iter[0] && STREQ(id, id_iter)) {
602 /* same as above but find reverse */
604 * Finds the last element of \a listbase which contains a pointer to the
605 * null-terminated string \a id at the specified offset, returning NULL if not found.
607 void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int offset)
612 for (link = listbase->last; link; link = link->prev) {
613 /* exact copy of BLI_rfindstring(), except for this line */
614 id_iter = *((const char **)(((const char *)link) + offset));
616 if (id[0] == id_iter[0] && STREQ(id, id_iter)) {
625 * Finds the first element of listbase which contains the specified pointer value
626 * at the specified offset, returning NULL if not found.
628 void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
631 const void *ptr_iter;
633 for (link = listbase->first; link; link = link->next) {
634 /* exact copy of BLI_findstring(), except for this line */
635 ptr_iter = *((const void **)(((const char *)link) + offset));
637 if (ptr == ptr_iter) {
644 /* same as above but find reverse */
646 * Finds the last element of listbase which contains the specified pointer value
647 * at the specified offset, returning NULL if not found.
649 void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
652 const void *ptr_iter;
654 for (link = listbase->last; link; link = link->prev) {
655 /* exact copy of BLI_rfindstring(), except for this line */
656 ptr_iter = *((const void **)(((const char *)link) + offset));
658 if (ptr == ptr_iter) {
667 * Returns the 1-based index of the first element of listbase which contains the specified
668 * null-terminated string at the specified offset, or -1 if not found.
670 int BLI_findstringindex(const ListBase *listbase, const char *id, const int offset)
676 link = listbase->first;
678 id_iter = ((const char *)link) + offset;
680 if (id[0] == id_iter[0] && STREQ(id, id_iter))
690 * Sets dst to a duplicate of the entire contents of src. dst may be the same as src.
692 void BLI_duplicatelist(ListBase *dst, const ListBase *src)
694 struct Link *dst_link, *src_link;
696 /* in this order, to ensure it works if dst == src */
697 src_link = src->first;
698 dst->first = dst->last = NULL;
701 dst_link = MEM_dupallocN(src_link);
702 BLI_addtail(dst, dst_link);
704 src_link = src_link->next;
708 void BLI_listbase_reverse(ListBase *lb)
710 struct Link *curr = lb->first;
711 struct Link *prev = NULL;
712 struct Link *next = NULL;
721 /* swap first/last */
723 lb->first = lb->last;
728 * \param vlink Link to make first.
730 void BLI_listbase_rotate_first(ListBase *lb, void *vlink)
733 ((Link *)lb->first)->prev = lb->last;
734 ((Link *)lb->last)->next = lb->first;
737 lb->last = ((Link *)vlink)->prev;
739 ((Link *)lb->first)->prev = NULL;
740 ((Link *)lb->last)->next = NULL;
744 * \param vlink Link to make last.
746 void BLI_listbase_rotate_last(ListBase *lb, void *vlink)
749 ((Link *)lb->first)->prev = lb->last;
750 ((Link *)lb->last)->next = lb->first;
752 lb->first = ((Link *)vlink)->next;
755 ((Link *)lb->first)->prev = NULL;
756 ((Link *)lb->last)->next = NULL;
759 /* create a generic list node containing link to provided data */
760 LinkData *BLI_genericNodeN(void *data)
767 /* create new link, and make it hold the given data */
768 ld = MEM_callocN(sizeof(LinkData), __func__);