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.