1: /*
2: * ntp_lists.h - linked lists common code
3: *
4: * SLIST: singly-linked lists
5: * ==========================
6: *
7: * These macros implement a simple singly-linked list template. Both
8: * the listhead and per-entry next fields are declared as pointers to
9: * the list entry struct type. Initialization to NULL is typically
10: * implicit (for globals and statics) or handled by zeroing of the
11: * containing structure.
12: *
13: * The name of the next link field is passed as an argument to allow
14: * membership in several lists at once using multiple next link fields.
15: *
16: * When possible, placing the link field first in the entry structure
17: * allows slightly smaller code to be generated on some platforms.
18: *
19: * LINK_SLIST(listhead, pentry, nextlink)
20: * add entry at head
21: *
22: * LINK_TAIL_SLIST(listhead, pentry, nextlink, entrytype)
23: * add entry at tail. This is O(n), if this is a common
24: * operation the FIFO template may be more appropriate.
25: *
26: * LINK_SORT_SLIST(listhead, pentry, beforecur, nextlink, entrytype)
27: * add entry in sorted order. beforecur is an expression comparing
28: * pentry with the current list entry. The current entry can be
29: * referenced within beforecur as L_S_S_CUR(), which is short for
30: * LINK_SORT_SLIST_CUR(). beforecur is nonzero if pentry sorts
31: * before L_S_S_CUR().
32: *
33: * UNLINK_HEAD_SLIST(punlinked, listhead, nextlink)
34: * unlink first entry and point punlinked to it, or set punlinked
35: * to NULL if the list is empty.
36: *
37: * UNLINK_SLIST(punlinked, listhead, ptounlink, nextlink, entrytype)
38: * unlink entry pointed to by ptounlink. punlinked is set to NULL
39: * if the entry is not found on the list, otherwise it is set to
40: * ptounlink.
41: *
42: * UNLINK_EXPR_SLIST(punlinked, listhead, expr, nextlink, entrytype)
43: * unlink entry where expression expr is nonzero. expr can refer
44: * to the entry being tested using UNLINK_EXPR_SLIST_CURRENT(),
45: * alias U_E_S_CUR(). See the implementation of UNLINK_SLIST()
46: * below for an example. U_E_S_CUR() is NULL iff the list is empty.
47: * punlinked is pointed to the removed entry or NULL if none
48: * satisfy expr.
49: *
50: * FIFO: singly-linked lists plus tail pointer
51: * ===========================================
52: *
53: * This is the same as FreeBSD's sys/queue.h STAILQ -- a singly-linked
54: * list implementation with tail-pointer maintenance, so that adding
55: * at the tail for first-in, first-out access is O(1).
56: *
57: * DECL_FIFO_ANCHOR(entrytype)
58: * provides the type specification portion of the declaration for
59: * a variable to refer to a FIFO queue (similar to listhead). The
60: * anchor contains the head and indirect tail pointers. Example:
61: *
62: * #include "ntp_lists.h"
63: *
64: * typedef struct myentry_tag myentry;
65: * struct myentry_tag {
66: * myentry *next_link;
67: * ...
68: * };
69: *
70: * DECL_FIFO_ANCHOR(myentry) my_fifo;
71: *
72: * void somefunc(myentry *pentry)
73: * {
74: * LINK_FIFO(my_fifo, pentry, next_link);
75: * }
76: *
77: * If DECL_FIFO_ANCHOR is used with stack or heap storage, it
78: * should be initialized to NULL pointers using a = { NULL };
79: * initializer or memset.
80: *
81: * HEAD_FIFO(anchor)
82: * TAIL_FIFO(anchor)
83: * Pointer to first/last entry, NULL if FIFO is empty.
84: *
85: * LINK_FIFO(anchor, pentry, nextlink)
86: * add entry at tail.
87: *
88: * UNLINK_FIFO(punlinked, anchor, nextlink)
89: * unlink head entry and point punlinked to it, or set punlinked
90: * to NULL if the list is empty.
91: *
92: * CONCAT_FIFO(q1, q2, nextlink)
93: * empty fifoq q2 moving its nodes to q1 following q1's existing
94: * nodes.
95: *
96: * DLIST: doubly-linked lists
97: * ==========================
98: *
99: * Elements on DLISTs always have non-NULL forward and back links,
100: * because both link chains are circular. The beginning/end is marked
101: * by the listhead, which is the same type as elements for simplicity.
102: * An empty list's listhead has both links set to its own address.
103: *
104: *
105: */
106: #ifndef NTP_LISTS_H
107: #define NTP_LISTS_H
108:
109: #include "ntp_types.h" /* TRUE and FALSE */
110: #include "ntp_assert.h"
111:
112: #ifdef DEBUG
113: # define NTP_DEBUG_LISTS_H
114: #endif
115:
116: /*
117: * If list debugging is not enabled, save a little time by not clearing
118: * an entry's link pointer when it is unlinked, as the stale pointer
119: * is harmless as long as it is ignored when the entry is not in a
120: * list.
121: */
122: #ifndef NTP_DEBUG_LISTS_H
123: #define MAYBE_Z_LISTS(p) do { } while (FALSE)
124: #else
125: #define MAYBE_Z_LISTS(p) (p) = NULL
126: #endif
127:
128: #define LINK_SLIST(listhead, pentry, nextlink) \
129: do { \
130: (pentry)->nextlink = (listhead); \
131: (listhead) = (pentry); \
132: } while (FALSE)
133:
134: #define LINK_TAIL_SLIST(listhead, pentry, nextlink, entrytype) \
135: do { \
136: entrytype **pptail; \
137: \
138: pptail = &(listhead); \
139: while (*pptail != NULL) \
140: pptail = &((*pptail)->nextlink); \
141: \
142: (pentry)->nextlink = NULL; \
143: *pptail = (pentry); \
144: } while (FALSE)
145:
146: #define LINK_SORT_SLIST_CURRENT() (*ppentry)
147: #define L_S_S_CUR() LINK_SORT_SLIST_CURRENT()
148:
149: #define LINK_SORT_SLIST(listhead, pentry, beforecur, nextlink, \
150: entrytype) \
151: do { \
152: entrytype **ppentry; \
153: \
154: ppentry = &(listhead); \
155: while (TRUE) { \
156: if (NULL == *ppentry || (beforecur)) { \
157: (pentry)->nextlink = *ppentry; \
158: *ppentry = (pentry); \
159: break; \
160: } \
161: ppentry = &((*ppentry)->nextlink); \
162: if (NULL == *ppentry) { \
163: (pentry)->nextlink = NULL; \
164: *ppentry = (pentry); \
165: break; \
166: } \
167: } \
168: } while (FALSE)
169:
170: #define UNLINK_HEAD_SLIST(punlinked, listhead, nextlink) \
171: do { \
172: (punlinked) = (listhead); \
173: if (NULL != (punlinked)) { \
174: (listhead) = (punlinked)->nextlink; \
175: MAYBE_Z_LISTS((punlinked)->nextlink); \
176: } \
177: } while (FALSE)
178:
179: #define UNLINK_EXPR_SLIST_CURRENT() (*ppentry)
180: #define U_E_S_CUR() UNLINK_EXPR_SLIST_CURRENT()
181:
182: #define UNLINK_EXPR_SLIST(punlinked, listhead, expr, nextlink, \
183: entrytype) \
184: do { \
185: entrytype **ppentry; \
186: \
187: ppentry = &(listhead); \
188: \
189: while (!(expr)) \
190: if (*ppentry != NULL && \
191: (*ppentry)->nextlink != NULL) { \
192: ppentry = &((*ppentry)->nextlink); \
193: } else { \
194: ppentry = NULL; \
195: break; \
196: } \
197: \
198: if (ppentry != NULL) { \
199: (punlinked) = *ppentry; \
200: *ppentry = (punlinked)->nextlink; \
201: MAYBE_Z_LISTS((punlinked)->nextlink); \
202: } else { \
203: (punlinked) = NULL; \
204: } \
205: } while (FALSE)
206:
207: #define UNLINK_SLIST(punlinked, listhead, ptounlink, nextlink, \
208: entrytype) \
209: UNLINK_EXPR_SLIST(punlinked, listhead, (ptounlink) == \
210: U_E_S_CUR(), nextlink, entrytype)
211:
212: #define CHECK_SLIST(listhead, nextlink, entrytype) \
213: do { \
214: entrytype *pentry; \
215: \
216: for (pentry = (listhead); \
217: pentry != NULL; \
218: pentry = pentry->nextlink){ \
219: NTP_INSIST(pentry != pentry->nextlink); \
220: NTP_INSIST((listhead) != pentry->nextlink); \
221: } \
222: } while (FALSE)
223:
224: /*
225: * FIFO
226: */
227:
228: #define DECL_FIFO_ANCHOR(entrytype) \
229: struct { \
230: entrytype * phead; /* NULL if list empty */ \
231: entrytype ** pptail; /* NULL if list empty */ \
232: }
233:
234: #define HEAD_FIFO(anchor) ((anchor).phead)
235: #define TAIL_FIFO(anchor) ((NULL == (anchor).pptail) \
236: ? NULL \
237: : *((anchor).pptail))
238:
239: /*
240: * For DEBUG builds only, verify both or neither of the anchor pointers
241: * are NULL with each operation.
242: */
243: #if !defined(NTP_DEBUG_LISTS_H)
244: #define CHECK_FIFO_CONSISTENCY(anchor) do { } while (FALSE)
245: #else
246: #define CHECK_FIFO_CONSISTENCY(anchor) \
247: check_gen_fifo_consistency(&(anchor))
248: void check_gen_fifo_consistency(void *fifo);
249: #endif
250:
251: /*
252: * generic FIFO element used to access any FIFO where each element
253: * begins with the link pointer
254: */
255: typedef struct gen_node_tag gen_node;
256: struct gen_node_tag {
257: gen_node * link;
258: };
259:
260: /* generic FIFO */
261: typedef DECL_FIFO_ANCHOR(gen_node) gen_fifo;
262:
263:
264: #define LINK_FIFO(anchor, pentry, nextlink) \
265: do { \
266: CHECK_FIFO_CONSISTENCY(anchor); \
267: \
268: (pentry)->nextlink = NULL; \
269: if (NULL != (anchor).pptail) { \
270: (*((anchor).pptail))->nextlink = (pentry); \
271: (anchor).pptail = \
272: &(*((anchor).pptail))->nextlink; \
273: } else { \
274: (anchor).phead = (pentry); \
275: (anchor).pptail = &(anchor).phead; \
276: } \
277: \
278: CHECK_FIFO_CONSISTENCY(anchor); \
279: } while (FALSE)
280:
281: #define UNLINK_FIFO(punlinked, anchor, nextlink) \
282: do { \
283: CHECK_FIFO_CONSISTENCY(anchor); \
284: \
285: (punlinked) = (anchor).phead; \
286: if (NULL != (punlinked)) { \
287: (anchor).phead = (punlinked)->nextlink; \
288: if (NULL == (anchor).phead) \
289: (anchor).pptail = NULL; \
290: else if ((anchor).pptail == \
291: &(punlinked)->nextlink) \
292: (anchor).pptail = &(anchor).phead; \
293: MAYBE_Z_LISTS((punlinked)->nextlink); \
294: CHECK_FIFO_CONSISTENCY(anchor); \
295: } \
296: } while (FALSE)
297:
298: #define UNLINK_MID_FIFO(punlinked, anchor, tounlink, nextlink, \
299: entrytype) \
300: do { \
301: entrytype **ppentry; \
302: \
303: CHECK_FIFO_CONSISTENCY(anchor); \
304: \
305: ppentry = &(anchor).phead; \
306: \
307: while ((tounlink) != *ppentry) \
308: if ((*ppentry)->nextlink != NULL) { \
309: ppentry = &((*ppentry)->nextlink); \
310: } else { \
311: ppentry = NULL; \
312: break; \
313: } \
314: \
315: if (ppentry != NULL) { \
316: (punlinked) = *ppentry; \
317: *ppentry = (punlinked)->nextlink; \
318: if (NULL == *ppentry) \
319: (anchor).pptail = NULL; \
320: else if ((anchor).pptail == \
321: &(punlinked)->nextlink) \
322: (anchor).pptail = &(anchor).phead; \
323: MAYBE_Z_LISTS((punlinked)->nextlink); \
324: CHECK_FIFO_CONSISTENCY(anchor); \
325: } else { \
326: (punlinked) = NULL; \
327: } \
328: } while (FALSE)
329:
330: #define CONCAT_FIFO(f1, f2, nextlink) \
331: do { \
332: CHECK_FIFO_CONSISTENCY(f1); \
333: CHECK_FIFO_CONSISTENCY(f2); \
334: \
335: if ((f2).pptail != NULL) { \
336: if ((f1).pptail != NULL) { \
337: (*(f1).pptail)->nextlink = (f2).phead; \
338: if ((f2).pptail == &(f2).phead) \
339: (f1).pptail = \
340: &(*(f1).pptail)->nextlink; \
341: else \
342: (f1).pptail = (f2).pptail; \
343: CHECK_FIFO_CONSISTENCY(f1); \
344: } else { \
345: (f1) = (f2); \
346: } \
347: MAYBE_Z_LISTS((f2).phead); \
348: MAYBE_Z_LISTS((f2).pptail); \
349: } \
350: } while (FALSE)
351:
352: /*
353: * DLIST
354: */
355: #define DECL_DLIST_LINK(entrytype, link) \
356: struct { \
357: entrytype * b; \
358: entrytype * f; \
359: } link
360:
361: #define INIT_DLIST(listhead, link) \
362: do { \
363: (listhead).link.f = &(listhead); \
364: (listhead).link.b = &(listhead); \
365: } while (FALSE)
366:
367: #define HEAD_DLIST(listhead, link) \
368: ( \
369: (&(listhead) != (listhead).link.f) \
370: ? (listhead).link.f \
371: : NULL \
372: )
373:
374: #define TAIL_DLIST(listhead, link) \
375: ( \
376: (&(listhead) != (listhead).link.b) \
377: ? (listhead).link.b \
378: : NULL \
379: )
380:
381: #define NEXT_DLIST(listhead, entry, link) \
382: ( \
383: (&(listhead) != (entry)->link.f) \
384: ? (entry)->link.f \
385: : NULL \
386: )
387:
388: #define PREV_DLIST(listhead, entry, link) \
389: ( \
390: (&(listhead) != (entry)->link.b) \
391: ? (entry)->link.b \
392: : NULL \
393: )
394:
395: #define LINK_DLIST(listhead, pentry, link) \
396: do { \
397: (pentry)->link.f = (listhead).link.f; \
398: (pentry)->link.b = &(listhead); \
399: (listhead).link.f->link.b = (pentry); \
400: (listhead).link.f = (pentry); \
401: } while (FALSE)
402:
403: #define LINK_TAIL_DLIST(listhead, pentry, link) \
404: do { \
405: (pentry)->link.b = (listhead).link.b; \
406: (pentry)->link.f = &(listhead); \
407: (listhead).link.b->link.f = (pentry); \
408: (listhead).link.b = (pentry); \
409: } while (FALSE)
410:
411: #define UNLINK_DLIST(ptounlink, link) \
412: do { \
413: (ptounlink)->link.b->link.f = (ptounlink)->link.f; \
414: (ptounlink)->link.f->link.b = (ptounlink)->link.b; \
415: MAYBE_Z_LISTS((ptounlink)->link.b); \
416: MAYBE_Z_LISTS((ptounlink)->link.f); \
417: } while (FALSE)
418:
419: #define ITER_DLIST_BEGIN(listhead, iter, link, entrytype) \
420: { \
421: entrytype *i_dl_nextiter; \
422: \
423: for ((iter) = (listhead).link.f; \
424: (iter) != &(listhead) \
425: && ((i_dl_nextiter = (iter)->link.f), TRUE); \
426: (iter) = i_dl_nextiter) {
427: #define ITER_DLIST_END() \
428: } \
429: }
430:
431: #define REV_ITER_DLIST_BEGIN(listhead, iter, link, entrytype) \
432: { \
433: entrytype *i_dl_nextiter; \
434: \
435: for ((iter) = (listhead).link.b; \
436: (iter) != &(listhead) \
437: && ((i_dl_nextiter = (iter)->link.b), TRUE); \
438: (iter) = i_dl_nextiter) {
439: #define REV_ITER_DLIST_END() \
440: } \
441: }
442:
443: #endif /* NTP_LISTS_H */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>