#include #include #include #include #if 0 #include #endif #include #include #include "list.h" LIST *listitem(size_t size); LIST *listadd(LIST * head, LIST * elt, cmpfunc cmp); LIST *listaddnth(LIST * head, LIST * elt, int nth); LIST *listprep(LIST * head, LIST * elt); LIST *listapp(LIST * head, LIST * elt); LIST *listunlink(LIST * head, LIST * elt); LIST *listunlinknth(LIST * head, int nth); LIST *listdel(LIST * head, LIST * elt, freefunc func); LIST *listdelnth(LIST * head, int nth, freefunc func); int listcnt(LIST * head); LIST *listdup(LIST * head, cpyfunc cpy, size_t size); LIST *listsplit(LIST * head, LIST * elt); LIST *listsplitnth(LIST * head, int nth); LIST *listjoin(LIST * head, LIST * tail); LIST *listsort(LIST * head, cmpfunc cmp); LIST *listrev(LIST * head); LIST *listshuffle(LIST * head); LIST *listdelall(LIST * head, freefunc func); LIST **list2array(LIST * head); LIST *array2list(LIST ** array); void listforeach(LIST * head, actfunc action); int listidx(LIST * head, LIST * elt); LIST *listlast(LIST * head); LIST *listnth(LIST * head, int nth); LIST *listfind(LIST * head, LIST * elt, cmpfunc cmp); LIST *listfinddatum(LIST * head, void *datum, cmpfunc cmp); LIST *listbsearch(LIST * head, LIST * elt, cmpfunc cmp); LIST *listbsearchdatum(LIST * head, const void *data, cmpfunc cmp); static LIST *_listbsearch(LIST * min, int max, LIST * elt, cmpfunc cmp); static LIST *_listbsearchdatum(LIST * min, int max, const void *datum, cmpfunc cmp); /* * listitem() allocate memory for a list item */ LIST *listitem(size_t size) { LIST *item; item = G_calloc(1, size); if (!item) { G_fatal_error(_("Out of memory")); exit(1); } return item; } /* * listadd() insert item before first greater * (cmp == NULL) -> listapp() * This is VERY slow. Rather than a lineal search, we should * try to implement a listbapprox() function. */ LIST *listadd(LIST * head, LIST * elt, cmpfunc cmp) { LIST *item, *prev = NULL; if (elt) elt->next = NULL; if (!elt) return head; if (!head) return elt; if (!cmp) return listapp(head, elt); for (item = head; item; item = item->next) { /* * cmp (sample, each): * Answers if each is smaller/equal/greater than sample */ if ((*cmp) (elt, item) > 0) break; prev = item; } if (!prev) { elt->next = head; head = elt; } else { elt->next = prev->next; prev->next = elt; } return head; } /* * listaddnth() make new item the nth of the list * (nth <= 0) -> listprep(), (nth > listcnt()) -> listapp() */ LIST *listaddnth(LIST * head, LIST * elt, int nth) { LIST *item, *prev = NULL; int i; if (elt) elt->next = NULL; if (!head) return elt; if (!elt) return head; if (nth < 1) { elt->next = head; return elt; } for (i = 0, item = head; item && i < nth; item = item->next, i++) prev = item; elt->next = prev->next; prev->next = elt; return head; } /* * listprep() prepend item on list */ inline LIST *listprep(LIST * head, LIST * elt) { if (elt && elt->next) elt->next = NULL; if (!head) return elt; if (!elt) return head; elt->next = head; return elt; } /* * listapp() append item to list */ LIST *listapp(LIST * head, LIST * elt) { LIST *item; if (elt) elt->next = NULL; if (!head) return elt; if (!elt) return head; for (item = head; item && item->next; item = item->next) ; item->next = elt; return head; } /* * listunlink() unlink item from list */ LIST *listunlink(LIST * head, LIST * elt) { LIST *item; if (!head) return NULL; if (!elt) return head; if (head == elt) { head = elt->next; elt->next = NULL; return head; } for (item = head; item && item->next != elt; item = item->next) ; if (item->next == elt) { item->next = elt->next; elt->next = NULL; } return head; } /* * listunlinknth() unlink nth element from list * listunlinknth (head, 0) == (car (list)) */ LIST *listunlinknth(LIST * head, int nth) { LIST *item, *elt; int i; if (!head) return NULL; if (nth < 0) return head; if (nth == 0) { item = head->next; head->next = NULL; return item; } for (i = 0, item = head; item && item->next && i < nth - 1; item = item->next, i++) ; if (item->next) { elt = item->next; item->next = elt->next; elt->next = NULL; } return head; } /* * listdel() unlink and free element from list */ LIST *listdel(LIST * head, LIST * elt, freefunc func) { if (!elt) return head; if (head) head = listunlink(head, elt); if (func) (*func) (elt); G_free(elt); return head; } /* * listdelnth() unlink and free nth element from list */ LIST *listdelnth(LIST * head, int nth, freefunc func) { LIST *item, *elt; int i; if (!head || nth < 0) return NULL; if (nth == 0) { elt = head; head = head->next; listdel(NULL, elt, func); return head; } for (i = 0, item = head; item && item->next && i < nth - 1; item = item->next, i++) ; if (item && item->next) { elt = item->next; item->next = elt->next; listdel(NULL, elt, func); } return head; } /* * listcnt() cound elements in list */ inline int listcnt(LIST * head) { LIST *item; int n = 0; for (item = head; item; item = item->next) n++; return n; } /* * listdup() duplicate list * if cpy is NULL, create same number of empty items */ LIST *listdup(LIST * head, cpyfunc cpy, size_t size) { LIST *newhead = NULL, *last = NULL, *item, *elt; for (item = head; item; item = item->next) { elt = listitem(size); if (cpy) (*cpy) (elt, item); if (!newhead) newhead = last = elt; else { last->next = elt; last = elt; } } return newhead; } /* * listsplit() make elt the head of a taillist */ LIST *listsplit(LIST * head, LIST * elt) { LIST *item; if (!head || !elt) return elt; if (head == elt) return NULL; for (item = head; item && item->next != elt; item = item->next) ; if (item->next == elt) item->next = NULL; return elt; } /* * listsplitnth() make nth element the head of a taillist */ LIST *listsplitnth(LIST * head, int nth) { LIST *item, *tail = NULL; int i; if (!head || nth < 1) return NULL; for (i = 0, item = head; item && i < nth - 1; item = item->next, i++) ; if (item && item->next) { tail = item->next; item->next = NULL; } return tail; } /* * listjoin() joint two lists */ LIST *listjoin(LIST * head, LIST * tail) { LIST *item; if (!head) return tail; if (!tail) return head; for (item = head; item && item->next; item = item->next) ; if (item) item->next = tail; return head; } /* * listsort() Quick sort on list */ LIST *listsort(LIST * head, cmpfunc cmp) { LIST *high = NULL, *low = NULL, *item, *next; if (!head || !head->next) return head; for (item = head; item;) { next = item->next; if ((*cmp) (item, head) < 0) { item->next = low; low = item; } else { item->next = high; high = item; } item = next; } high = listsort(high, cmp); low = listsort(low, cmp); head = listjoin(high, low); return head; } /* * listrev() reverse order the list */ LIST *listrev(LIST * head) { LIST *newhead = NULL, *item, *next; for (item = head; item;) { next = item->next; newhead = listprep(newhead, item); item = next; } return newhead; } /* * listshuffle() */ LIST *listshuffle(LIST * head) { LIST **array, *newhead = NULL; int n, i = 0, val; struct timeval tv; gettimeofday(&tv, NULL); srandom(tv.tv_usec); n = listcnt(head); array = list2array(head); while (i < n) { val = random() % n; if (array[val]) { newhead = listprep(newhead, array[val]); array[val] = NULL; i++; } } G_free(array); return newhead; } /* * listdelall() free the whole list */ LIST *listdelall(LIST * head, freefunc func) { LIST *item, *next; for (item = head; item;) { next = item->next; if (func) (*func) (item); G_free(item); item = next; } return NULL; } /* * list2array() build an array with members of list * array is allocated and needs to be G_free ()ed, list not changed. */ LIST **list2array(LIST * head) { LIST **array, *item; int n, i; n = listcnt(head); if (!n) return NULL; array = (LIST **) G_calloc(n + 1, sizeof(LIST *)); if (!array) { G_fatal_error(_("Out of memory")); exit(1); } for (i = 0, item = head; item; item = item->next, i++) array[i] = item; return array; } /* * array2list() link the elements of an array in order */ LIST *array2list(LIST ** array) { LIST *head = NULL, *item = NULL; int i; if (array) head = item = array[0]; for (i = 1; array && array[i]; i++) { item->next = array[i]; item = item->next; } item->next = NULL; return head; } /* * listforeach() execute action on each item */ inline void listforeach(LIST * head, actfunc action) { LIST *item; if (!head || !action) return; for (item = head; item; item = item->next) (*action) (item); } /* * listidx() find offset of item from head * head is offset (index) zero. */ int listidx(LIST * head, LIST * elt) { LIST *item; int i; if (!elt) return -1; for (i = 0, item = head; item; item = item->next, i++) if (item == elt) break; if (!item) return -1; return i; } /* * listlast() find last item in list. */ inline LIST *listlast(LIST * head) { LIST *item; for (item = head; item && item->next; item = item->next) ; return item; } /* * listnth() find nth item in list. */ LIST *listnth(LIST * head, int nth) { LIST *item; int i; if (!head || nth < 0) return NULL; for (i = 0, item = head; item; item = item->next, i++) if (i == nth) break; return item; } /* * listfind() linear search giving structure as sample */ LIST *listfind(LIST * head, LIST * elt, cmpfunc cmp) { LIST *item; for (item = head; item; item = item->next) if (!(*cmp) (elt, item)) break; return item; } /* * listfinddatum() linear search giving sample by pointer */ LIST *listfinddatum(LIST * head, void *datum, cmpfunc cmp) { LIST *item; for (item = head; item; item = item->next) if (!(*cmp) (datum, item)) break; return item; } static LIST *_listbsearch(LIST * min, int max, LIST * elt, cmpfunc cmp) { LIST *item; int i, n, result; if (!min) return NULL; n = max / 2; for (i = 0, item = min; item && i < n; item = item->next, i++) ; result = (*cmp) (item, elt); if (result == 0) return item; if (n == 0) { if (max == 1 && item->next && !(*cmp) (item->next, elt)) return item->next; return NULL; } if (result < 0) item = _listbsearch(min, n, elt, cmp); else item = _listbsearch(item->next, max - n - 1, elt, cmp); return item; } /* * listbsearch() binary search with struct as sample */ LIST *listbsearch(LIST * head, LIST * elt, cmpfunc cmp) { LIST *item; int n, max, result; if (!head || !elt || !cmp) return NULL; max = listcnt(head); n = max / 2; item = listnth(head, n); result = (*cmp) (item, elt); if (result == 0) return item; if (result < 0) item = _listbsearch(head, n, elt, cmp); else item = _listbsearch(item->next, max - n - 1, elt, cmp); return item; } static LIST *_listbsearchdatum(LIST * min, int max, const void *datum, cmpfunc cmp) { LIST *elt; int i, n, result; if (!min) return NULL; n = max / 2; for (i = 0, elt = min; elt && i < n; elt = elt->next, i++) ; result = (*cmp) (datum, elt); if (result == 0) return elt; if (n == 0) { if (max == 1 && elt->next && !(*cmp) (datum, elt->next)) return elt->next; return NULL; } if (result < 0) elt = _listbsearchdatum(min, n, datum, cmp); else elt = _listbsearchdatum(elt->next, max - n - 1, datum, cmp); return elt; } /* * listbsearchdatum() binary search for sample by ptr */ LIST *listbsearchdatum(LIST * head, const void *datum, cmpfunc cmp) { LIST *elt; int n, max, result; if (!head || !datum || !cmp) return NULL; max = listcnt(head); n = max / 2; elt = listnth(head, n); result = (*cmp) (datum, elt); if (result == 0) return elt; if (result < 0) elt = _listbsearchdatum(head, n, datum, cmp); else elt = _listbsearchdatum(elt->next, max - n - 1, datum, cmp); return elt; }