1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 #ifndef LWRES_LIST_H
13 #define LWRES_LIST_H 1
14 
15 /*! \file lwres/list.h */
16 
17 #define LWRES_LIST(type) struct { type *head, *tail; }
18 #define LWRES_LIST_INIT(list) \
19 	do { (list).head = NULL; (list).tail = NULL; } while (0)
20 
21 #define LWRES_LINK(type) struct { type *prev, *next; }
22 #define LWRES_LINK_INIT(elt, link) \
23 	do { \
24 		(elt)->link.prev = (void *)(-1); \
25 		(elt)->link.next = (void *)(-1); \
26 	} while (0)
27 #define LWRES_LINK_LINKED(elt, link) \
28 	((void *)((elt)->link.prev) != (void *)(-1))
29 
30 #define LWRES_LIST_HEAD(list) ((list).head)
31 #define LWRES_LIST_TAIL(list) ((list).tail)
32 #define LWRES_LIST_EMPTY(list) LWRES_TF((list).head == NULL)
33 
34 #define LWRES_LIST_PREPEND(list, elt, link) \
35 	do { \
36 		if ((list).head != NULL) \
37 			(list).head->link.prev = (elt); \
38 		else \
39 			(list).tail = (elt); \
40 		(elt)->link.prev = NULL; \
41 		(elt)->link.next = (list).head; \
42 		(list).head = (elt); \
43 	} while (0)
44 
45 #define LWRES_LIST_APPEND(list, elt, link) \
46 	do { \
47 		if ((list).tail != NULL) \
48 			(list).tail->link.next = (elt); \
49 		else \
50 			(list).head = (elt); \
51 		(elt)->link.prev = (list).tail; \
52 		(elt)->link.next = NULL; \
53 		(list).tail = (elt); \
54 	} while (0)
55 
56 #define LWRES_LIST_UNLINK(list, elt, link) \
57 	do { \
58 		if ((elt)->link.next != NULL) \
59 			(elt)->link.next->link.prev = (elt)->link.prev; \
60 		else \
61 			(list).tail = (elt)->link.prev; \
62 		if ((elt)->link.prev != NULL) \
63 			(elt)->link.prev->link.next = (elt)->link.next; \
64 		else \
65 			(list).head = (elt)->link.next; \
66 		(elt)->link.prev = (void *)(-1); \
67 		(elt)->link.next = (void *)(-1); \
68 	} while (0)
69 
70 #define LWRES_LIST_PREV(elt, link) ((elt)->link.prev)
71 #define LWRES_LIST_NEXT(elt, link) ((elt)->link.next)
72 
73 #define LWRES_LIST_INSERTBEFORE(list, before, elt, link) \
74 	do { \
75 		if ((before)->link.prev == NULL) \
76 			LWRES_LIST_PREPEND(list, elt, link); \
77 		else { \
78 			(elt)->link.prev = (before)->link.prev; \
79 			(before)->link.prev = (elt); \
80 			(elt)->link.prev->link.next = (elt); \
81 			(elt)->link.next = (before); \
82 		} \
83 	} while (0)
84 
85 #define LWRES_LIST_INSERTAFTER(list, after, elt, link) \
86 	do { \
87 		if ((after)->link.next == NULL) \
88 			LWRES_LIST_APPEND(list, elt, link); \
89 		else { \
90 			(elt)->link.next = (after)->link.next; \
91 			(after)->link.next = (elt); \
92 			(elt)->link.next->link.prev = (elt); \
93 			(elt)->link.prev = (after); \
94 		} \
95 	} while (0)
96 
97 #define LWRES_LIST_APPENDLIST(list1, list2, link) \
98 	do { \
99 		if (LWRES_LIST_EMPTY(list1)) \
100 			(list1) = (list2); \
101 		else if (!LWRES_LIST_EMPTY(list2)) { \
102 			(list1).tail->link.next = (list2).head; \
103 			(list2).head->link.prev = (list1).tail; \
104 			(list1).tail = (list2).tail; \
105 		} \
106 		(list2).head = NULL; \
107 		(list2).tail = NULL; \
108 	} while (0)
109 
110 #define LWRES_LIST_ENQUEUE(list, elt, link) LWRES_LIST_APPEND(list, elt, link)
111 #define LWRES_LIST_DEQUEUE(list, elt, link) LWRES_LIST_UNLINK(list, elt, link)
112 
113 #endif /* LWRES_LIST_H */
114