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.