diff --git a/include/mini-clist.h b/include/mini-clist.h new file mode 100644 index 000000000..899e20c17 --- /dev/null +++ b/include/mini-clist.h @@ -0,0 +1,92 @@ +/* + * list.h : list manipulation macros and structures. + * (C) 2002-2006 - Willy Tarreau - willy@ant-computing.com + * + */ + +#ifndef __MINI_CLIST_H__ +#define __MINI_CLIST_H__ + +/* these are circular or bidirectionnal lists only. Each list pointer points to + * another list pointer in a structure, and not the structure itself. The + * pointer to the next element MUST be the first one so that the list is easily + * cast as a single linked list or pointer. + */ +struct list { + struct list *n; /* next */ + struct list *p; /* prev */ +}; + +#define LIST_INIT(l) ((l)->n = (l)->p = (l)) + +/* dual linked lists : + * Start = (struct list *) pointer to the next elem's prev list entry + * For each element : + * - prev = pointer to previous element's next (or start). Cannot be NULL + * - next = pointer to next element's prev. NULL = end. + * + */ + +/****** circular lists ********/ + +/* adds an element at the beginning of a list ; returns the element */ +#define LIST_ADD(lh, el) ({ (el)->n = (lh)->n; (el)->n->p = (lh)->n = (el); (el)->p = (lh); (el); }) + +/* adds an element at the end of a list ; returns the element */ +#define LIST_ADDQ(lh, el) ({ (el)->p = (lh)->p; (el)->p->n = (lh)->p = (el); (el)->n = (lh); (el); }) + +/* removes an element from a list and returns it */ +#define LIST_DEL(el) ({ typeof(el) __ret = (el); (el)->n->p = (el)->p; (el)->p->n = (el)->n; (__ret); }) + +/* returns a pointer of type to a structure containing a list head called + * at address . Note that can be the result of a function or macro + * since it's used only once. + * Example: LIST_ELEM(cur_node->args.next, struct node *, args) + */ +#define LIST_ELEM(lh, pt, el) ((pt)(((void *)(lh)) - ((void *)&((pt)NULL)->el))) + +/* checks if the list head is empty or not */ +#define LIST_ISEMPTY(lh) ((lh)->n == (lh)) + +/* returns a pointer of type to a structure following the element + * which contains list head , which is known as element in + * struct pt. + * Example: LIST_NEXT(args, struct node *, list) + */ +#define LIST_NEXT(lh, pt, el) (LIST_ELEM((lh)->n, pt, el)) + + +/* returns a pointer of type to a structure preceeding the element + * which contains list head , which is known as element in + * struct pt. + */ +#define LIST_PREV(lh, pt, el) (LIST_ELEM((lh)->p, pt, el)) + +/* + * iterates through a list of items of type "" which are + * linked via a "struct list" member named . The head of the + * list is stored at a location designed by , which should be a + * "struct list *". A variable of type "" will + * be used as temporary end of list pointer. It can be derived from + * since this one is only used before. + * Example: FOREACH_ITEM(cur_node, &node->args, node, struct node *, neigh) { ... }; + */ +#define FOREACH_ITEM(iterator, list_head, end_item, struct_type, struct_member) \ + iterator = end_item = LIST_ELEM(list_head, struct_type, struct_member); \ + while (((iterator) = LIST_ELEM((iterator)->struct_member.n, \ + struct_type, struct_member)) != (end_item)) + +/* + * idem except that this one is safe against deletion, but it needs a backup + * pointer of the element after the iterator. + * Example: FOREACH_ITEM_SAFE(cur_node, backup, &node->args, node, struct node *, neigh) { ... }; + */ +#define FOREACH_ITEM_SAFE(iterator, backup, list_head, end_item, struct_type, struct_member) \ + end_item = LIST_ELEM(list_head, struct_type, struct_member); \ + iterator = LIST_ELEM((end_item)->struct_member.n, struct_type, struct_member); \ + if ((iterator) != (end_item)) \ + backup = LIST_ELEM((iterator)->struct_member.n, struct_type, struct_member); \ + for ( ; (iterator) != (end_item); (iterator) = (backup), \ + backup = LIST_ELEM((iterator)->struct_member.n, struct_type, struct_member)) + +#endif /* __MINI_CLIST_H__ */