/* Lisp style linked lists. Allocation failures abort the whole process. Mark A. Sheldon Copyright 2005 */ #include #include #include /* Client interface in linked_list.h duplicates these type defitions, except that struct node is omitted and a list_t is said to be void * */ #define NIL NULL typedef void * DATA; struct node { DATA car; /* Data */ struct node *cdr; /* Next */ }; typedef struct node *list_t; inline int nullp(list_t l) { return l == NIL; } list_t cons(DATA car, list_t cdr) { list_t new_node; if ( (new_node = (list_t) malloc(sizeof(struct node))) == NULL ) { perror("cons"); exit(errno); } new_node->cdr = cdr; new_node->car = car; return new_node; } inline DATA car(list_t l) { return l->car; } inline list_t cdr(list_t l) { return l->cdr; } inline void set_cdr(list_t l, list_t new_cdr) { l->cdr = new_cdr; } static list_t postpend_internal(list_t new_node, list_t current, list_t whole) { if (nullp(cdr(current))) { set_cdr(current, new_node); return whole; } return postpend_internal(new_node, cdr(current), whole); } list_t postpend(DATA new_elt, list_t l) { list_t new_node = cons(new_elt, NIL); if (nullp(l)) return new_node; return postpend_internal(new_node, l, l); } static list_t reverse_iter(list_t l, list_t accumulator) { if (nullp(l)) return accumulator; else return reverse_iter(cdr(l), cons(car(l), accumulator)); } list_t reverse(list_t l) { return reverse_iter(l, NIL); } void list_foreach(void (*fn)(DATA), list_t l) { for ( ; !nullp(l); l = cdr(l)) (*fn)(car(l)); } void destroy_node(list_t l) { if (nullp(l)) return; set_cdr(l, NIL); free(car(l)); free(l); } void destroy_spine(list_t l) { if (nullp(l)) return; destroy_spine(cdr(l)); free(l); } void destroy_list(list_t l) { if (nullp(l)) return; free(car(l)); destroy_list(cdr(l)); free(l); }