So, a design question is how to keep track of the dlist nodes that have been malloc()'d, but not used. There are pretty much two ways to do this:
Dlist make_dl() { Dlist d; d = dl_malloc(); d->flink = d; d->blink = d; d->val = (void *) 0; return d; } dl_insert_b(node, val) /* Inserts to the end of a list */ Dlist node; void *val; { Dlist last_node, new; new = dl_malloc(); new->val = val; last_node = node->blink; node->blink = new; last_node->flink = new; new->blink = last_node; new->flink = node; }Now, the free list approach to dl_malloc() is for you to maintain your own free list of dlist nodes. So, I keep a global variable called dl_free_list, which is initially NULL. Then when dl_malloc() is called, it checks to see if dl_free_list is NULL. If so, it malloc()s 1000 dlist nodes, chains them all together using the flink field of the Dlist struct, and makes dl_free_list the head of the list. Then it simply carves off one node and returns it. The code for this is below:
static Dlist dl_free_list = NULL; static Dlist dl_malloc() { int i; Dlist d; if (dl_free_list == NULL) { dl_free_list = (Dlist) malloc(sizeof(struct dlist)*1000); if (dl_free_list == NULL) { perror("malloc"); exit(1); } for (i = 0; i < 999; i++) { dl_free_list[i].flink = dl_free_list+(i+1); } dl_free_list[999].flink = NULL; } d = dl_free_list; dl_free_list = d->flink; return d; }The nice thing about this approach is that when you call dl_delete_node, you can put the node back onto the free list:
dl_delete_node(item) Dlist item; { item->flink->blink = item->blink; /* First unhook the item from the dlist */ item->blink->flink = item->flink; item->flink = dl_free_list; /* Then put it on the free list */ dl_free_list = item; }That's it.
Now, if you used the array approach, you need two global variables -- an array of dlist nodes, and an index to the first free element of the array. When you call dl_malloc() it simply increments the index and returns the dlist that the old value of the index pointed to. When the index hits 1000, you have to malloc() a new array of dlist structs. Here's the code for this:
static Dlist dl_array; static int dl_index = 1000; static Dlist dl_malloc() { Dlist d; if (dl_index == 1000) { dl_array = (Dlist) malloc(sizeof(struct dlist)*1000); if (dl_array == NULL) { perror("malloc"); exit(1); } dl_index = 0; } d = dl_array+index; index++; return d; }The problem with this implementation is that you can't do anything with dl_delete_node unless you add some additional structure. You could make a free list out of these, and then modify dl_malloc() to use the free list first and then the array if the free list is empty. That would be a nice solution to this problem.