The headers <ddslib/dllist.h> and <ddslib/dllist.hh> provide some
macros for managing structures in multiple doubly
linked lists. Rather than defining a container
type, you just get a macro to declare a structure
member to maintain the structure's position in a
list. For example, if you want to build two
independent lists of struct
foo objects:
struct foo {
dllist_elem(struct foo) by_size, by_date;
unsigned size;
time_t date;
};
Another macro defines a list header pointing to first and last members:
typedef dllist_hdr(struct foo) foo_list_t; foo_list_t size_list = dllist_HDRINIT, date_list = dllist_HDRINIT;
In a non-dynamic context, dllist_HDRINIT may be used to initialize
to an empty list. In any context, dllist_init(&size_list) will do the
same.
To add an element at the beginning or end of a
list, use dllist_prepend or
dllist_append, specifying the
structure member to use to record the element in the
list:
struct foo *elem = malloc(sizeof *elem); dllist_append(&size_list, by_size, elem);
You can insert before or after another element
with dllist_insertbefore or
dllist_insertafter:
struct foo *previous; // already exists struct foo *elem = malloc(sizeof *elem); dllist_insertafter(&size_list, by_size, previous, elem);
These work even if the reference pointer is null.
The macros do no memory (de-)allocation, only linking, so you can use them with statically allocated elements too.
To iterate, use dllist_first or dllist_last to initialize, and
dllist_next or dllist_prev with the name of the member to
increment:
for (struct foo *ptr = dllist_first(&size_list);
ptr != NULL;
ptr = dllist_next(by_size, ptr)) {
...
}
To remove from a list:
dllist_unlink(&size_list, by_size, elem);
There are similar macros to work with closed lists:
typedef dllist_loophdr(struct foo) foo_list_t; foo_list_t size_list = dllist_LOOPHDRINIT; dllist_loopinit(&size_list); dllist_loopinsert(&size_list, by_size, elem); dllist_loopinsertafter(by_size, elem, previous); dllist_loopinsertbefore(by_size, elem, next); dllist_loopunlink(&size_list, by_size, elem);
For closed lists, there are also macros to split and join lists:
dllist_loopsplit(&l1, &l2, by_size, elem1, elem2); dllist_loopjoin(&l1, &l2, by_size, elem1, elem2);
To split, l2 must be an
empty list, and elem1 and
elem2 must be members of
l1. Everything from
elem1 upto but excluding
elem2 will be removed from
l1, and become the new
contents of l2.
To join, elem1 must belong
to l1, and elem2 to l2.
elem1's previous element
becomes the head of the list, and elem2 becomes its next element.
elem1 becomes the next element
of elem2's previous element.
Finally, the two elements swap previous elements, and
l2 is left empty.