4 * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "alpm_list.h"
27 /* check exported library symbols with: nm -C -D <lib> */
28 #define SYMEXPORT __attribute__((visibility("default")))
29 #define SYMHIDDEN __attribute__((visibility("internal")))
32 * @addtogroup alpm_list List Functions
33 * @brief Functions to manipulate alpm_list_t lists.
35 * These functions are designed to create, destroy, and modify lists of
36 * type alpm_list_t. This is an internal list type used by libalpm that is
37 * publicly exposed for use by frontends if desired.
44 * @brief Free a list, but not the contained data.
46 * @param list the list to free
48 void SYMEXPORT
alpm_list_free(alpm_list_t
*list
)
50 alpm_list_t
*it
= list
;
53 alpm_list_t
*tmp
= it
->next
;
60 * @brief Free the internal data of a list structure.
62 * @param list the list to free
63 * @param fn a free function for the internal data
65 void SYMEXPORT
alpm_list_free_inner(alpm_list_t
*list
, alpm_list_fn_free fn
)
67 alpm_list_t
*it
= list
;
81 * @brief Add a new item to the end of the list.
83 * @param list the list to add to
84 * @param data the new item to be added to the list
86 * @return the resultant list
88 alpm_list_t SYMEXPORT
*alpm_list_add(alpm_list_t
*list
, void *data
)
90 alpm_list_t
*ptr
, *lp
;
92 ptr
= calloc(1, sizeof(alpm_list_t
));
100 /* Special case: the input list is empty */
106 lp
= alpm_list_last(list
);
115 * @brief Add items to a list in sorted order.
117 * @param list the list to add to
118 * @param data the new item to be added to the list
119 * @param fn the comparison function to use to determine order
121 * @return the resultant list
123 alpm_list_t SYMEXPORT
*alpm_list_add_sorted(alpm_list_t
*list
, void *data
, alpm_list_fn_cmp fn
)
126 return alpm_list_add(list
, data
);
128 alpm_list_t
*add
= NULL
, *prev
= NULL
, *next
= list
;
130 add
= calloc(1, sizeof(alpm_list_t
));
136 /* Find insertion point. */
138 if(fn(add
->data
, next
->data
) <= 0) break;
143 /* Insert the add node to the list */
144 if(prev
== NULL
) { /* special case: we insert add as the first element */
145 add
->prev
= list
->prev
; /* list != NULL */
149 } else if(next
== NULL
) { /* another special case: add last element */
166 * @brief Join two lists.
167 * The two lists must be independent. Do not free the original lists after
168 * calling this function, as this is not a copy operation. The list pointers
169 * passed in should be considered invalid after calling this function.
171 * @param first the first list
172 * @param second the second list
174 * @return the resultant joined list
176 alpm_list_t SYMEXPORT
*alpm_list_join(alpm_list_t
*first
, alpm_list_t
*second
)
186 /* tmp is the last element of the first list */
188 /* link the first list to the second */
190 /* link the second list to the first */
191 first
->prev
= second
->prev
;
192 /* set the back reference to the tail */
199 * @brief Merge the two sorted sublists into one sorted list.
201 * @param left the first list
202 * @param right the second list
203 * @param fn comparison function for determining merge order
205 * @return the resultant list
207 alpm_list_t SYMEXPORT
*alpm_list_mmerge(alpm_list_t
*left
, alpm_list_t
*right
, alpm_list_fn_cmp fn
)
209 alpm_list_t
*newlist
, *lp
;
216 if(fn(left
->data
, right
->data
) <= 0) {
224 newlist
->prev
= NULL
;
225 newlist
->next
= NULL
;
228 while((left
!= NULL
) && (right
!= NULL
)) {
229 if(fn(left
->data
, right
->data
) <= 0) {
246 else if(right
!= NULL
) {
251 /* Find our tail pointer
252 * TODO maintain this in the algorithm itself */
254 while(lp
&& lp
->next
) {
263 * @brief Sort a list of size `n` using mergesort algorithm.
265 * @param list the list to sort
266 * @param n the size of the list
267 * @param fn the comparison function for determining order
269 * @return the resultant list
271 alpm_list_t SYMEXPORT
*alpm_list_msort(alpm_list_t
*list
, size_t n
, alpm_list_fn_cmp fn
)
274 alpm_list_t
*left
= list
;
275 alpm_list_t
*lastleft
= alpm_list_nth(list
, n
/2 - 1);
276 alpm_list_t
*right
= lastleft
->next
;
277 /* terminate first list */
278 lastleft
->next
= NULL
;
280 left
= alpm_list_msort(left
, n
/2, fn
);
281 right
= alpm_list_msort(right
, n
- (n
/2), fn
);
282 list
= alpm_list_mmerge(left
, right
, fn
);
288 * @brief Remove an item from the list.
289 * item is not freed; this is the responsibility of the caller.
291 * @param haystack the list to remove the item from
292 * @param item the item to remove from the list
294 * @return the resultant list
296 alpm_list_t SYMEXPORT
*alpm_list_remove_item(alpm_list_t
*haystack
,
299 if(haystack
== NULL
|| item
== NULL
) {
303 if(item
== haystack
) {
304 /* Special case: removing the head node which has a back reference to
306 haystack
= item
->next
;
308 haystack
->prev
= item
->prev
;
311 } else if(item
== haystack
->prev
) {
312 /* Special case: removing the tail node, so we need to fix the back
313 * reference on the head node. We also know tail != head. */
315 /* i->next should always be null */
316 item
->prev
->next
= item
->next
;
317 haystack
->prev
= item
->prev
;
321 /* Normal case, non-head and non-tail node */
323 item
->next
->prev
= item
->prev
;
326 item
->prev
->next
= item
->next
;
335 * @brief Remove an item from the list.
337 * @param haystack the list to remove the item from
338 * @param needle the data member of the item we're removing
339 * @param fn the comparison function for searching
340 * @param data output parameter containing data of the removed item
342 * @return the resultant list
344 alpm_list_t SYMEXPORT
*alpm_list_remove(alpm_list_t
*haystack
,
345 const void *needle
, alpm_list_fn_cmp fn
, void **data
)
347 alpm_list_t
*i
= haystack
;
358 if(i
->data
== NULL
) {
362 if(fn(i
->data
, needle
) == 0) {
363 haystack
= alpm_list_remove_item(haystack
, i
);
379 * @brief Remove a string from a list.
381 * @param haystack the list to remove the item from
382 * @param needle the data member of the item we're removing
383 * @param data output parameter containing data of the removed item
385 * @return the resultant list
387 alpm_list_t SYMEXPORT
*alpm_list_remove_str(alpm_list_t
*haystack
,
388 const char *needle
, char **data
)
390 return alpm_list_remove(haystack
, (const void *)needle
,
391 (alpm_list_fn_cmp
)strcmp
, (void **)data
);
395 * @brief Create a new list without any duplicates.
397 * This does NOT copy data members.
399 * @param list the list to copy
401 * @return a new list containing non-duplicate items
403 alpm_list_t SYMEXPORT
*alpm_list_remove_dupes(const alpm_list_t
*list
)
405 const alpm_list_t
*lp
= list
;
406 alpm_list_t
*newlist
= NULL
;
408 if(!alpm_list_find_ptr(newlist
, lp
->data
)) {
409 newlist
= alpm_list_add(newlist
, lp
->data
);
417 * @brief Copy a string list, including data.
419 * @param list the list to copy
421 * @return a copy of the original list
423 alpm_list_t SYMEXPORT
*alpm_list_strdup(const alpm_list_t
*list
)
425 const alpm_list_t
*lp
= list
;
426 alpm_list_t
*newlist
= NULL
;
428 newlist
= alpm_list_add(newlist
, strdup(lp
->data
));
435 * @brief Copy a list, without copying data.
437 * @param list the list to copy
439 * @return a copy of the original list
441 alpm_list_t SYMEXPORT
*alpm_list_copy(const alpm_list_t
*list
)
443 const alpm_list_t
*lp
= list
;
444 alpm_list_t
*newlist
= NULL
;
446 newlist
= alpm_list_add(newlist
, lp
->data
);
453 * @brief Copy a list and copy the data.
454 * Note that the data elements to be copied should not contain pointers
455 * and should also be of constant size.
457 * @param list the list to copy
458 * @param size the size of each data element
460 * @return a copy of the original list, data copied as well
462 alpm_list_t SYMEXPORT
*alpm_list_copy_data(const alpm_list_t
*list
,
465 const alpm_list_t
*lp
= list
;
466 alpm_list_t
*newlist
= NULL
;
468 void *newdata
= calloc(1, size
);
470 memcpy(newdata
, lp
->data
, size
);
471 newlist
= alpm_list_add(newlist
, newdata
);
479 * @brief Create a new list in reverse order.
481 * @param list the list to copy
483 * @return a new list in reverse order
485 alpm_list_t SYMEXPORT
*alpm_list_reverse(alpm_list_t
*list
)
487 const alpm_list_t
*lp
;
488 alpm_list_t
*newlist
= NULL
, *backup
;
494 lp
= alpm_list_last(list
);
495 /* break our reverse circular list */
500 newlist
= alpm_list_add(newlist
, lp
->data
);
503 list
->prev
= backup
; /* restore tail pointer */
510 * @brief Get the first element of a list.
512 * @param list the list
514 * @return the first element in the list
516 inline alpm_list_t SYMEXPORT
*alpm_list_first(const alpm_list_t
*list
)
519 return (alpm_list_t
*)list
;
526 * @brief Return nth element from list (starting from 0).
528 * @param list the list
529 * @param n the index of the item to find (n < alpm_list_count(list) IS needed)
531 * @return an alpm_list_t node for index `n`
533 alpm_list_t SYMEXPORT
*alpm_list_nth(const alpm_list_t
*list
, size_t n
)
535 const alpm_list_t
*i
= list
;
539 return (alpm_list_t
*)i
;
543 * @brief Get the next element of a list.
545 * @param node the list node
547 * @return the next element, or NULL when no more elements exist
549 inline alpm_list_t SYMEXPORT
*alpm_list_next(const alpm_list_t
*node
)
559 * @brief Get the last item in the list.
561 * @param list the list
563 * @return the last element in the list
565 alpm_list_t SYMEXPORT
*alpm_list_last(const alpm_list_t
*list
)
575 * @brief Get the data member of a list node.
577 * @param node the list node
579 * @return the contained data, or NULL if none
581 void SYMEXPORT
*alpm_list_getdata(const alpm_list_t
*node
)
583 if(node
== NULL
) return NULL
;
590 * @brief Get the number of items in a list.
592 * @param list the list
594 * @return the number of list items
596 size_t SYMEXPORT
alpm_list_count(const alpm_list_t
*list
)
599 const alpm_list_t
*lp
= list
;
608 * @brief Find an item in a list.
610 * @param needle the item to search
611 * @param haystack the list
612 * @param fn the comparison function for searching (!= NULL)
614 * @return `needle` if found, NULL otherwise
616 void SYMEXPORT
*alpm_list_find(const alpm_list_t
*haystack
, const void *needle
,
619 const alpm_list_t
*lp
= haystack
;
621 if(lp
->data
&& fn(lp
->data
, needle
) == 0) {
629 /* trivial helper function for alpm_list_find_ptr */
630 static int ptr_cmp(const void *p
, const void *q
)
636 * @brief Find an item in a list.
638 * Search for the item whose data matches that of the `needle`.
640 * @param needle the data to search for (== comparison)
641 * @param haystack the list
643 * @return `needle` if found, NULL otherwise
645 void SYMEXPORT
*alpm_list_find_ptr(const alpm_list_t
*haystack
,
648 return alpm_list_find(haystack
, needle
, ptr_cmp
);
652 * @brief Find a string in a list.
654 * @param needle the string to search for
655 * @param haystack the list
657 * @return `needle` if found, NULL otherwise
659 char SYMEXPORT
*alpm_list_find_str(const alpm_list_t
*haystack
,
662 return (char *)alpm_list_find(haystack
, (const void *)needle
,
663 (alpm_list_fn_cmp
)strcmp
);
667 * @brief Find the differences between list `left` and list `right`
669 * The two lists must be sorted. Items only in list `left` are added to the
670 * `onlyleft` list. Items only in list `right` are added to the `onlyright`
673 * @param left the first list
674 * @param right the second list
675 * @param fn the comparison function
676 * @param onlyleft pointer to the first result list
677 * @param onlyright pointer to the second result list
680 void SYMEXPORT
alpm_list_diff_sorted(const alpm_list_t
*left
,
681 const alpm_list_t
*right
, alpm_list_fn_cmp fn
,
682 alpm_list_t
**onlyleft
, alpm_list_t
**onlyright
)
684 const alpm_list_t
*l
= left
;
685 const alpm_list_t
*r
= right
;
687 if(!onlyleft
&& !onlyright
) {
691 while(l
!= NULL
&& r
!= NULL
) {
692 int cmp
= fn(l
->data
, r
->data
);
695 *onlyleft
= alpm_list_add(*onlyleft
, l
->data
);
701 *onlyright
= alpm_list_add(*onlyright
, r
->data
);
711 *onlyleft
= alpm_list_add(*onlyleft
, l
->data
);
717 *onlyright
= alpm_list_add(*onlyright
, r
->data
);
725 * @brief Find the items in list `lhs` that are not present in list `rhs`.
727 * @param lhs the first list
728 * @param rhs the second list
729 * @param fn the comparison function
731 * @return a list containing all items in `lhs` not present in `rhs`
733 alpm_list_t SYMEXPORT
*alpm_list_diff(const alpm_list_t
*lhs
,
734 const alpm_list_t
*rhs
, alpm_list_fn_cmp fn
)
736 alpm_list_t
*left
, *right
;
737 alpm_list_t
*ret
= NULL
;
739 left
= alpm_list_copy(lhs
);
740 left
= alpm_list_msort(left
, alpm_list_count(left
), fn
);
741 right
= alpm_list_copy(rhs
);
742 right
= alpm_list_msort(right
, alpm_list_count(right
), fn
);
744 alpm_list_diff_sorted(left
, right
, fn
, &ret
, NULL
);
746 alpm_list_free(left
);
747 alpm_list_free(right
);
753 /* vim: set ts=2 sw=2 noet: */