diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-12-02 09:01:21 +0000 |
---|---|---|
committer | <> | 2014-12-04 16:11:25 +0000 |
commit | bdab5265fcbf3f472545073a23f8999749a9f2b9 (patch) | |
tree | c6018dd03dea906f8f1fb5f105f05b71a7dc250a /include/ntp_lists.h | |
download | ntp-d4b7cd9723cce9561fa15f74b90b85a3a61b5ef8.tar.gz |
Imported from /home/lorry/working-area/delta_ntp/ntp-dev-4.2.7p482.tar.gz.ntp-dev-4.2.7p482
Diffstat (limited to 'include/ntp_lists.h')
-rw-r--r-- | include/ntp_lists.h | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/include/ntp_lists.h b/include/ntp_lists.h new file mode 100644 index 0000000..2b6e616 --- /dev/null +++ b/include/ntp_lists.h @@ -0,0 +1,443 @@ +/* + * ntp_lists.h - linked lists common code + * + * SLIST: singly-linked lists + * ========================== + * + * These macros implement a simple singly-linked list template. Both + * the listhead and per-entry next fields are declared as pointers to + * the list entry struct type. Initialization to NULL is typically + * implicit (for globals and statics) or handled by zeroing of the + * containing structure. + * + * The name of the next link field is passed as an argument to allow + * membership in several lists at once using multiple next link fields. + * + * When possible, placing the link field first in the entry structure + * allows slightly smaller code to be generated on some platforms. + * + * LINK_SLIST(listhead, pentry, nextlink) + * add entry at head + * + * LINK_TAIL_SLIST(listhead, pentry, nextlink, entrytype) + * add entry at tail. This is O(n), if this is a common + * operation the FIFO template may be more appropriate. + * + * LINK_SORT_SLIST(listhead, pentry, beforecur, nextlink, entrytype) + * add entry in sorted order. beforecur is an expression comparing + * pentry with the current list entry. The current entry can be + * referenced within beforecur as L_S_S_CUR(), which is short for + * LINK_SORT_SLIST_CUR(). beforecur is nonzero if pentry sorts + * before L_S_S_CUR(). + * + * UNLINK_HEAD_SLIST(punlinked, listhead, nextlink) + * unlink first entry and point punlinked to it, or set punlinked + * to NULL if the list is empty. + * + * UNLINK_SLIST(punlinked, listhead, ptounlink, nextlink, entrytype) + * unlink entry pointed to by ptounlink. punlinked is set to NULL + * if the entry is not found on the list, otherwise it is set to + * ptounlink. + * + * UNLINK_EXPR_SLIST(punlinked, listhead, expr, nextlink, entrytype) + * unlink entry where expression expr is nonzero. expr can refer + * to the entry being tested using UNLINK_EXPR_SLIST_CURRENT(), + * alias U_E_S_CUR(). See the implementation of UNLINK_SLIST() + * below for an example. U_E_S_CUR() is NULL iff the list is empty. + * punlinked is pointed to the removed entry or NULL if none + * satisfy expr. + * + * FIFO: singly-linked lists plus tail pointer + * =========================================== + * + * This is the same as FreeBSD's sys/queue.h STAILQ -- a singly-linked + * list implementation with tail-pointer maintenance, so that adding + * at the tail for first-in, first-out access is O(1). + * + * DECL_FIFO_ANCHOR(entrytype) + * provides the type specification portion of the declaration for + * a variable to refer to a FIFO queue (similar to listhead). The + * anchor contains the head and indirect tail pointers. Example: + * + * #include "ntp_lists.h" + * + * typedef struct myentry_tag myentry; + * struct myentry_tag { + * myentry *next_link; + * ... + * }; + * + * DECL_FIFO_ANCHOR(myentry) my_fifo; + * + * void somefunc(myentry *pentry) + * { + * LINK_FIFO(my_fifo, pentry, next_link); + * } + * + * If DECL_FIFO_ANCHOR is used with stack or heap storage, it + * should be initialized to NULL pointers using a = { NULL }; + * initializer or memset. + * + * HEAD_FIFO(anchor) + * TAIL_FIFO(anchor) + * Pointer to first/last entry, NULL if FIFO is empty. + * + * LINK_FIFO(anchor, pentry, nextlink) + * add entry at tail. + * + * UNLINK_FIFO(punlinked, anchor, nextlink) + * unlink head entry and point punlinked to it, or set punlinked + * to NULL if the list is empty. + * + * CONCAT_FIFO(q1, q2, nextlink) + * empty fifoq q2 moving its nodes to q1 following q1's existing + * nodes. + * + * DLIST: doubly-linked lists + * ========================== + * + * Elements on DLISTs always have non-NULL forward and back links, + * because both link chains are circular. The beginning/end is marked + * by the listhead, which is the same type as elements for simplicity. + * An empty list's listhead has both links set to its own address. + * + * + */ +#ifndef NTP_LISTS_H +#define NTP_LISTS_H + +#include "ntp_types.h" /* TRUE and FALSE */ +#include "ntp_assert.h" + +#ifdef DEBUG +# define NTP_DEBUG_LISTS_H +#endif + +/* + * If list debugging is not enabled, save a little time by not clearing + * an entry's link pointer when it is unlinked, as the stale pointer + * is harmless as long as it is ignored when the entry is not in a + * list. + */ +#ifndef NTP_DEBUG_LISTS_H +#define MAYBE_Z_LISTS(p) do { } while (FALSE) +#else +#define MAYBE_Z_LISTS(p) (p) = NULL +#endif + +#define LINK_SLIST(listhead, pentry, nextlink) \ +do { \ + (pentry)->nextlink = (listhead); \ + (listhead) = (pentry); \ +} while (FALSE) + +#define LINK_TAIL_SLIST(listhead, pentry, nextlink, entrytype) \ +do { \ + entrytype **pptail; \ + \ + pptail = &(listhead); \ + while (*pptail != NULL) \ + pptail = &((*pptail)->nextlink); \ + \ + (pentry)->nextlink = NULL; \ + *pptail = (pentry); \ +} while (FALSE) + +#define LINK_SORT_SLIST_CURRENT() (*ppentry) +#define L_S_S_CUR() LINK_SORT_SLIST_CURRENT() + +#define LINK_SORT_SLIST(listhead, pentry, beforecur, nextlink, \ + entrytype) \ +do { \ + entrytype **ppentry; \ + \ + ppentry = &(listhead); \ + while (TRUE) { \ + if (NULL == *ppentry || (beforecur)) { \ + (pentry)->nextlink = *ppentry; \ + *ppentry = (pentry); \ + break; \ + } \ + ppentry = &((*ppentry)->nextlink); \ + if (NULL == *ppentry) { \ + (pentry)->nextlink = NULL; \ + *ppentry = (pentry); \ + break; \ + } \ + } \ +} while (FALSE) + +#define UNLINK_HEAD_SLIST(punlinked, listhead, nextlink) \ +do { \ + (punlinked) = (listhead); \ + if (NULL != (punlinked)) { \ + (listhead) = (punlinked)->nextlink; \ + MAYBE_Z_LISTS((punlinked)->nextlink); \ + } \ +} while (FALSE) + +#define UNLINK_EXPR_SLIST_CURRENT() (*ppentry) +#define U_E_S_CUR() UNLINK_EXPR_SLIST_CURRENT() + +#define UNLINK_EXPR_SLIST(punlinked, listhead, expr, nextlink, \ + entrytype) \ +do { \ + entrytype **ppentry; \ + \ + ppentry = &(listhead); \ + \ + while (!(expr)) \ + if (*ppentry != NULL && \ + (*ppentry)->nextlink != NULL) { \ + ppentry = &((*ppentry)->nextlink); \ + } else { \ + ppentry = NULL; \ + break; \ + } \ + \ + if (ppentry != NULL) { \ + (punlinked) = *ppentry; \ + *ppentry = (punlinked)->nextlink; \ + MAYBE_Z_LISTS((punlinked)->nextlink); \ + } else { \ + (punlinked) = NULL; \ + } \ +} while (FALSE) + +#define UNLINK_SLIST(punlinked, listhead, ptounlink, nextlink, \ + entrytype) \ + UNLINK_EXPR_SLIST(punlinked, listhead, (ptounlink) == \ + U_E_S_CUR(), nextlink, entrytype) + +#define CHECK_SLIST(listhead, nextlink, entrytype) \ +do { \ + entrytype *pentry; \ + \ + for (pentry = (listhead); \ + pentry != NULL; \ + pentry = pentry->nextlink){ \ + NTP_INSIST(pentry != pentry->nextlink); \ + NTP_INSIST((listhead) != pentry->nextlink); \ + } \ +} while (FALSE) + +/* + * FIFO + */ + +#define DECL_FIFO_ANCHOR(entrytype) \ +struct { \ + entrytype * phead; /* NULL if list empty */ \ + entrytype ** pptail; /* NULL if list empty */ \ +} + +#define HEAD_FIFO(anchor) ((anchor).phead) +#define TAIL_FIFO(anchor) ((NULL == (anchor).pptail) \ + ? NULL \ + : *((anchor).pptail)) + +/* + * For DEBUG builds only, verify both or neither of the anchor pointers + * are NULL with each operation. + */ +#if !defined(NTP_DEBUG_LISTS_H) +#define CHECK_FIFO_CONSISTENCY(anchor) do { } while (FALSE) +#else +#define CHECK_FIFO_CONSISTENCY(anchor) \ + check_gen_fifo_consistency(&(anchor)) +void check_gen_fifo_consistency(void *fifo); +#endif + +/* + * generic FIFO element used to access any FIFO where each element + * begins with the link pointer + */ +typedef struct gen_node_tag gen_node; +struct gen_node_tag { + gen_node * link; +}; + +/* generic FIFO */ +typedef DECL_FIFO_ANCHOR(gen_node) gen_fifo; + + +#define LINK_FIFO(anchor, pentry, nextlink) \ +do { \ + CHECK_FIFO_CONSISTENCY(anchor); \ + \ + (pentry)->nextlink = NULL; \ + if (NULL != (anchor).pptail) { \ + (*((anchor).pptail))->nextlink = (pentry); \ + (anchor).pptail = \ + &(*((anchor).pptail))->nextlink; \ + } else { \ + (anchor).phead = (pentry); \ + (anchor).pptail = &(anchor).phead; \ + } \ + \ + CHECK_FIFO_CONSISTENCY(anchor); \ +} while (FALSE) + +#define UNLINK_FIFO(punlinked, anchor, nextlink) \ +do { \ + CHECK_FIFO_CONSISTENCY(anchor); \ + \ + (punlinked) = (anchor).phead; \ + if (NULL != (punlinked)) { \ + (anchor).phead = (punlinked)->nextlink; \ + if (NULL == (anchor).phead) \ + (anchor).pptail = NULL; \ + else if ((anchor).pptail == \ + &(punlinked)->nextlink) \ + (anchor).pptail = &(anchor).phead; \ + MAYBE_Z_LISTS((punlinked)->nextlink); \ + CHECK_FIFO_CONSISTENCY(anchor); \ + } \ +} while (FALSE) + +#define UNLINK_MID_FIFO(punlinked, anchor, tounlink, nextlink, \ + entrytype) \ +do { \ + entrytype **ppentry; \ + \ + CHECK_FIFO_CONSISTENCY(anchor); \ + \ + ppentry = &(anchor).phead; \ + \ + while ((tounlink) != *ppentry) \ + if ((*ppentry)->nextlink != NULL) { \ + ppentry = &((*ppentry)->nextlink); \ + } else { \ + ppentry = NULL; \ + break; \ + } \ + \ + if (ppentry != NULL) { \ + (punlinked) = *ppentry; \ + *ppentry = (punlinked)->nextlink; \ + if (NULL == *ppentry) \ + (anchor).pptail = NULL; \ + else if ((anchor).pptail == \ + &(punlinked)->nextlink) \ + (anchor).pptail = &(anchor).phead; \ + MAYBE_Z_LISTS((punlinked)->nextlink); \ + CHECK_FIFO_CONSISTENCY(anchor); \ + } else { \ + (punlinked) = NULL; \ + } \ +} while (FALSE) + +#define CONCAT_FIFO(f1, f2, nextlink) \ +do { \ + CHECK_FIFO_CONSISTENCY(f1); \ + CHECK_FIFO_CONSISTENCY(f2); \ + \ + if ((f2).pptail != NULL) { \ + if ((f1).pptail != NULL) { \ + (*(f1).pptail)->nextlink = (f2).phead; \ + if ((f2).pptail == &(f2).phead) \ + (f1).pptail = \ + &(*(f1).pptail)->nextlink; \ + else \ + (f1).pptail = (f2).pptail; \ + CHECK_FIFO_CONSISTENCY(f1); \ + } else { \ + (f1) = (f2); \ + } \ + MAYBE_Z_LISTS((f2).phead); \ + MAYBE_Z_LISTS((f2).pptail); \ + } \ +} while (FALSE) + +/* + * DLIST + */ +#define DECL_DLIST_LINK(entrytype, link) \ +struct { \ + entrytype * b; \ + entrytype * f; \ +} link + +#define INIT_DLIST(listhead, link) \ +do { \ + (listhead).link.f = &(listhead); \ + (listhead).link.b = &(listhead); \ +} while (FALSE) + +#define HEAD_DLIST(listhead, link) \ + ( \ + (&(listhead) != (listhead).link.f) \ + ? (listhead).link.f \ + : NULL \ + ) + +#define TAIL_DLIST(listhead, link) \ + ( \ + (&(listhead) != (listhead).link.b) \ + ? (listhead).link.b \ + : NULL \ + ) + +#define NEXT_DLIST(listhead, entry, link) \ + ( \ + (&(listhead) != (entry)->link.f) \ + ? (entry)->link.f \ + : NULL \ + ) + +#define PREV_DLIST(listhead, entry, link) \ + ( \ + (&(listhead) != (entry)->link.b) \ + ? (entry)->link.b \ + : NULL \ + ) + +#define LINK_DLIST(listhead, pentry, link) \ +do { \ + (pentry)->link.f = (listhead).link.f; \ + (pentry)->link.b = &(listhead); \ + (listhead).link.f->link.b = (pentry); \ + (listhead).link.f = (pentry); \ +} while (FALSE) + +#define LINK_TAIL_DLIST(listhead, pentry, link) \ +do { \ + (pentry)->link.b = (listhead).link.b; \ + (pentry)->link.f = &(listhead); \ + (listhead).link.b->link.f = (pentry); \ + (listhead).link.b = (pentry); \ +} while (FALSE) + +#define UNLINK_DLIST(ptounlink, link) \ +do { \ + (ptounlink)->link.b->link.f = (ptounlink)->link.f; \ + (ptounlink)->link.f->link.b = (ptounlink)->link.b; \ + MAYBE_Z_LISTS((ptounlink)->link.b); \ + MAYBE_Z_LISTS((ptounlink)->link.f); \ +} while (FALSE) + +#define ITER_DLIST_BEGIN(listhead, iter, link, entrytype) \ +{ \ + entrytype *i_dl_nextiter; \ + \ + for ((iter) = (listhead).link.f; \ + (iter) != &(listhead) \ + && ((i_dl_nextiter = (iter)->link.f), TRUE); \ + (iter) = i_dl_nextiter) { +#define ITER_DLIST_END() \ + } \ +} + +#define REV_ITER_DLIST_BEGIN(listhead, iter, link, entrytype) \ +{ \ + entrytype *i_dl_nextiter; \ + \ + for ((iter) = (listhead).link.b; \ + (iter) != &(listhead) \ + && ((i_dl_nextiter = (iter)->link.b), TRUE); \ + (iter) = i_dl_nextiter) { +#define REV_ITER_DLIST_END() \ + } \ +} + +#endif /* NTP_LISTS_H */ |