/* List.c: generic linear lists */ #include "List.h" #include "private.h" #include "pools.h" #ifndef NOPOOLS static POOL *listPool = (POOL *)NULL; #define NEWLIST() (LIST *)NewPoolCell(sizeof(LIST), 0, "GDT list cells", &listPool) #define DISPOSELIST(ptr) Dispose((unsigned char *)(ptr), &listPool) #else /*NOPOOLS*/ #define NEWLIST() (LIST *)Alloc(sizeof(LIST)) #define DISPOSELIST(ptr) Free((char *)ptr, sizeof(LIST)) #endif /*NOPOOLS*/ #ifndef NOLISTMACROS void *__plistel__; /* wordt gebruikt in de ListNext() macro */ #endif /*NOLISTMACROS*/ #ifdef NOLISTMACROS /* creeert een lege lijst */ LIST *ListCreate(void) { return (LIST *)NULL; } #endif /*NOLISTMACROS*/ /* voegt het element vooraan aan de lijst toe, geeft de nieuwe wijzer naar * de lijst terug */ LIST *ListAdd(LIST *list, void *pelement) { LIST *newlist; /* weiger NULL-pointers in de lijst */ if (pelement == (void *)NULL) return list; newlist = NEWLIST(); newlist->pelement = pelement; newlist->next = list; return newlist; } /* telt het aantal elementen in de lijst */ int ListCount(LIST *list) { int count = 0; while (list) { count++; list = list->next; } return count; } /* geeft het index-ste element uit de lijst terug of NULL als er * geen index elementen in de lijst zijn. index telt vanaf 0. */ void *ListGet(LIST *list, int index) { while (list && index > 0) { list = list->next; index--; } if (!list) return (void *)NULL; else return list->pelement; } #ifdef NOLISTMACROS /* het eerste argument is het adres van een LIST *. * Aanvankelijk moet deze LIST * naar het begin van een lijst wijzen. * Bij herhaaldelijke oproepen zal de lijst doorlopen worden. * De functie geeft bij herhaaldelijk oproepen een na een alle * elementen van de lijst terug. Indien de lijst doorlopen is, * wordt een NULL wijzer teruggegeven */ void *ListNext(LIST **list) { void *pelement = (void *)NULL; if (*list) { pelement = (*list)->pelement; *list = (*list)->next; } else pelement = (void *)NULL; return pelement; } #endif /*NOLISTMACROS*/ /* voegt twee lijsten samen: de elementen van lijst list2 komen voor de elementen van * lijst list1. Een wijzer naar de verlengde lijst list1 wordt teruggegeven. */ LIST *ListMerge(LIST *list1, LIST *list2) { void *pelement = (void *)NULL; while ((pelement = ListNext(&list2))) list1 = ListAdd(list1, pelement); return list1; } /* dupliceert een lijst: de elementen zelf worden niet gedupliceerd */ LIST *ListDuplicate(LIST *list) { LIST *newlist = (LIST *)NULL; void *pelement = (void *)NULL; while ((pelement = ListNext(&list))) newlist = ListAdd(newlist, pelement); return newlist; } /* verwijdert een element uit de lijst. Geeft een pointer naar de gewijzigde * lijst terug */ LIST *ListRemove(LIST *list, void *pelement) { LIST *p, *q; /* als de lijst ledig is */ if (!list) { GdtError("ListRemove", "attempt to remove an element from an empty list"); return list; /* voor het geval we ooit besluiten tolerant te zijn */ } /* als het eerste element verwijderd moet worden */ if (pelement == list->pelement) { p = list->next; DISPOSELIST(list); return p; } /* chasing pointers: */ q = list; p = list->next; while (p && p->pelement != pelement) { q = p; p = p->next; } /* als p de NULL pointer is komt het te verwijderen element niet in de lijst * voor: fout */ if (!p) { GdtError("ListRemove", "attempt to remove a nonexisting element from a list"); return list; } /* in het andere geval is p een wijzer naar de lijst-cel die eruit gehaald moet * worden */ else { q->next = p->next; DISPOSELIST(p); } /* geef een (ongewijzigde) wijzer naar de gewijzigde lijst terug */ return list; } /* Iterates over the list, conditionally removing elements. Elements are * removed if the routine 'func' returns nonzero. They are kept in the list * if the routine returns zero. 'func' is reponsible for disposing memory * pointed to from the list if an element needs to be deleted as * this routine only disposes of the LIST structure pointing to the * actual element. Returns the updated list. */ LIST *ListIterateRemove(LIST *list, int (*func)(void *)) { LIST *p, *q; /* check the first element of the list */ while (list && func(list->pelement) != 0) { /* the first element needs to be deleted. */ p = list; list = list->next; DISPOSELIST(p); } if (!list) return list; /* return the empty list */ /* the other situation: the list contains at least one element and the first * element is not to be deleted. Chasing pointers... (the first element of * the list remains unchanged). */ q = list; p = list->next; while (p) { if (func(p->pelement) != 0) { /* delete the element */ q->next = p->next; DISPOSELIST(p); p = q->next; } else { /* don't delete the element */ q = p; p = p->next; } } return list; } #ifdef NOLISTMACROS /* iterator: voer de procedure uit vooral alle elementen van de lijst. * De procedure heeft als argument een wijzer naar een element */ void ListIterate(LIST *list, void (*proc)(void *)) { void *pelement; while (list) { pelement = list->pelement; list = list->next; proc(pelement); } } #endif /*NOLISTMACROS*/ #ifdef NOLISTMACROS /* iterator: voer de procedure uit vooral alle elementen van de lijst. * De procedure heeft twee argumenten: eerst een wijzer naar * het element, dan een wijzer naar andere data de gelijk is voor alle * elementen */ void ListIterate1A(LIST *list, void (*proc)(void *, void *), void *extra) { void *pelement; while (list) { pelement = list->pelement; list = list->next; proc(pelement, extra); } } #endif /*NOLISTMACROS*/ #ifdef NOLISTMACROS /* iterator: voer de procedure uit vooral alle elementen van de lijst. * De procedure heeft twee argumenten: eerst een wijzer naar * data die gelijk is voor alle elementen, dan een wijzer naar het element */ void ListIterate1B(LIST *list, void (*proc)(void *, void *), void *extra) { void *pelement; while (list) { pelement = list->pelement; list = list->next; proc(extra, pelement); } } #endif /*NOLISTMACROS*/ /* een volledige lijst vernietigen: vernietigt niet de elementen! */ void ListDestroy(LIST *list) { LIST *p; while (list) { p = list->next; DISPOSELIST(list); list = p; } } #ifdef TEST #include static int odd(void *bla) { int num = (int)bla; return (num%2 == 1); } static void print(void *bla) { fprintf(stderr, "%d ", (int)bla); } int main(int argc, char **argv) { LIST *list = ListCreate(); int n; fprintf(stderr, "ListIterateRemove() test: removes all odd number from a list:\n\n"); fprintf(stderr, "Enter a series of integer numbers. Terminate the list with a 0 (zero):\n"); scanf("%d", &n); while (n != 0) { list = ListAdd(list, (void *)n); scanf("%d", &n); } fprintf(stderr, "The list you entered is (reversed and without terminating zero):\n"); ListIterate(list, print); fprintf(stderr, "\n"); fprintf(stderr, "Now removing all odd numbers ... \n"); list = ListIterateRemove(list, odd); fprintf(stderr, "The result should contain all even numbers of the list:\n"); ListIterate(list, print); fprintf(stderr, "\n"); return 0; } #endif /*TEST*/