123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/time.h>
- #include <time.h>
- #if 0
- #include <dmalloc.h>
- #endif
- #include <grass/gis.h>
- #include <grass/glocale.h>
- #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;
- }
|