jpayne@69
|
1 /*
|
jpayne@69
|
2 * tkDList.h --
|
jpayne@69
|
3 *
|
jpayne@69
|
4 * A list is headed by pointers to first and last element. The elements
|
jpayne@69
|
5 * are doubly linked so that an arbitrary element can be removed without
|
jpayne@69
|
6 * a need to traverse the list. New elements can be added to the list
|
jpayne@69
|
7 * before or after an existing element or at the head/tail of the list.
|
jpayne@69
|
8 * A list may be traversed in the forward or backward direction.
|
jpayne@69
|
9 *
|
jpayne@69
|
10 * Copyright (c) 2018 by Gregor Cramer.
|
jpayne@69
|
11 *
|
jpayne@69
|
12 * See the file "license.terms" for information on usage and redistribution of
|
jpayne@69
|
13 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
jpayne@69
|
14 */
|
jpayne@69
|
15
|
jpayne@69
|
16 /*
|
jpayne@69
|
17 * Note that this file will not be included in header files, it is the purpose
|
jpayne@69
|
18 * of this file to be included in source files only. Thus we are not using the
|
jpayne@69
|
19 * prefix "Tk_" here for functions, because all the functions have private scope.
|
jpayne@69
|
20 */
|
jpayne@69
|
21
|
jpayne@69
|
22 /*
|
jpayne@69
|
23 * -------------------------------------------------------------------------------
|
jpayne@69
|
24 * Use the double linked list in the following way:
|
jpayne@69
|
25 * -------------------------------------------------------------------------------
|
jpayne@69
|
26 * typedef struct MyListEntry { TK_DLIST_LINKS(MyListEntry); int value; } MyListEntry;
|
jpayne@69
|
27 * TK_DLIST_DEFINE(MyList, MyListEntry);
|
jpayne@69
|
28 * MyList listHdr = TK_DLIST_LIST_INITIALIZER; // or MyList_Init(&listHdr)
|
jpayne@69
|
29 * MyListEntry *p;
|
jpayne@69
|
30 * int i = 0;
|
jpayne@69
|
31 * MyList_Append(&listHdr, ckalloc(sizeof(MyListEntry)));
|
jpayne@69
|
32 * MyList_Append(&listHdr, ckalloc(sizeof(MyListEntry)));
|
jpayne@69
|
33 * TK_DLIST_FOREACH(p, &listHdr) { p->value = i++; }
|
jpayne@69
|
34 * // ...
|
jpayne@69
|
35 * MyList_RemoveHead(&listHdr);
|
jpayne@69
|
36 * MyList_RemoveHead(&listHdr);
|
jpayne@69
|
37 * MyList_Clear(MyListEntry, &listHdr); // invokes ckfree() for each element
|
jpayne@69
|
38 * -------------------------------------------------------------------------------
|
jpayne@69
|
39 * IMPORTANT NOTE: TK_DLIST_LINKS must be used at start of struct!
|
jpayne@69
|
40 */
|
jpayne@69
|
41
|
jpayne@69
|
42 #ifndef TK_DLIST_DEFINED
|
jpayne@69
|
43 #define TK_DLIST_DEFINED
|
jpayne@69
|
44
|
jpayne@69
|
45 #include "tkInt.h"
|
jpayne@69
|
46
|
jpayne@69
|
47 /*
|
jpayne@69
|
48 * List definitions.
|
jpayne@69
|
49 */
|
jpayne@69
|
50
|
jpayne@69
|
51 #define TK_DLIST_LINKS(ElemType) \
|
jpayne@69
|
52 struct { \
|
jpayne@69
|
53 struct ElemType *prev; /* previous element */ \
|
jpayne@69
|
54 struct ElemType *next; /* next element */ \
|
jpayne@69
|
55 } _dl_
|
jpayne@69
|
56
|
jpayne@69
|
57 #define TK_DLIST_LIST_INITIALIZER { NULL, NULL }
|
jpayne@69
|
58 #define TK_DLIST_ELEM_INITIALIZER { NULL, NULL }
|
jpayne@69
|
59
|
jpayne@69
|
60 /*************************************************************************/
|
jpayne@69
|
61 /*
|
jpayne@69
|
62 * DList_Init: Initialize list header. This can also be used to clear the
|
jpayne@69
|
63 * list.
|
jpayne@69
|
64 *
|
jpayne@69
|
65 * See also: DList_Clear()
|
jpayne@69
|
66 */
|
jpayne@69
|
67 /*************************************************************************/
|
jpayne@69
|
68 /*
|
jpayne@69
|
69 * DList_ElemInit: Initialize a list element.
|
jpayne@69
|
70 */
|
jpayne@69
|
71 /*************************************************************************/
|
jpayne@69
|
72 /*
|
jpayne@69
|
73 * DList_InsertAfter: Insert 'elem' after 'listElem'. 'elem' must not
|
jpayne@69
|
74 * be linked, but 'listElem' must be linked.
|
jpayne@69
|
75 */
|
jpayne@69
|
76 /*************************************************************************/
|
jpayne@69
|
77 /*
|
jpayne@69
|
78 * DList_InsertBefore: Insert 'elem' before 'listElem'. 'elem' must not
|
jpayne@69
|
79 * be linked, but 'listElem' must be linked.
|
jpayne@69
|
80 */
|
jpayne@69
|
81 /*************************************************************************/
|
jpayne@69
|
82 /*
|
jpayne@69
|
83 * DList_Prepend: Insert 'elem' at start of list. This element must not
|
jpayne@69
|
84 * be linked.
|
jpayne@69
|
85 *
|
jpayne@69
|
86 * See also: DList_Append()
|
jpayne@69
|
87 */
|
jpayne@69
|
88 /*************************************************************************/
|
jpayne@69
|
89 /*
|
jpayne@69
|
90 * DList_Append: Append 'elem' to end of list. This element must not
|
jpayne@69
|
91 * be linked.
|
jpayne@69
|
92 *
|
jpayne@69
|
93 * See also: DList_Prepend()
|
jpayne@69
|
94 */
|
jpayne@69
|
95 /*************************************************************************/
|
jpayne@69
|
96 /*
|
jpayne@69
|
97 * DList_Move: Append all list items of 'src' to end of 'dst'.
|
jpayne@69
|
98 */
|
jpayne@69
|
99 /*************************************************************************/
|
jpayne@69
|
100 /*
|
jpayne@69
|
101 * DList_Remove: Remove 'elem' from list. This element must be linked.
|
jpayne@69
|
102 *
|
jpayne@69
|
103 * See also: DList_Free()
|
jpayne@69
|
104 */
|
jpayne@69
|
105 /*************************************************************************/
|
jpayne@69
|
106 /*
|
jpayne@69
|
107 * DList_Free: Remove 'elem' from list and free it. This element must
|
jpayne@69
|
108 * be linked.
|
jpayne@69
|
109 *
|
jpayne@69
|
110 * See also: DList_Remove()
|
jpayne@69
|
111 */
|
jpayne@69
|
112 /*************************************************************************/
|
jpayne@69
|
113 /*
|
jpayne@69
|
114 * DList_RemoveHead: Remove first element from list. The list must
|
jpayne@69
|
115 * not be empty.
|
jpayne@69
|
116 *
|
jpayne@69
|
117 * See also: DList_FreeHead()
|
jpayne@69
|
118 */
|
jpayne@69
|
119 /*************************************************************************/
|
jpayne@69
|
120 /*
|
jpayne@69
|
121 * DList_RemoveTail: Remove last element from list. The list must
|
jpayne@69
|
122 * not be empty.
|
jpayne@69
|
123 *
|
jpayne@69
|
124 * See also: DList_FreeTail()
|
jpayne@69
|
125 */
|
jpayne@69
|
126 /*************************************************************************/
|
jpayne@69
|
127 /*
|
jpayne@69
|
128 * DList_FreeHead: Remove first element from list and free it.
|
jpayne@69
|
129 * The list must not be empty.
|
jpayne@69
|
130 *
|
jpayne@69
|
131 * See also: DList_RemoveHead()
|
jpayne@69
|
132 */
|
jpayne@69
|
133 /*************************************************************************/
|
jpayne@69
|
134 /*
|
jpayne@69
|
135 * DList_FreeTail: Remove last element from list and free it.
|
jpayne@69
|
136 * The list must not be empty.
|
jpayne@69
|
137 *
|
jpayne@69
|
138 * See also: DList_RemoveTail()
|
jpayne@69
|
139 */
|
jpayne@69
|
140 /*************************************************************************/
|
jpayne@69
|
141 /*
|
jpayne@69
|
142 * DList_SwapElems: Swap positions of given elements 'lhs' and 'rhs'.
|
jpayne@69
|
143 * Both elements must be linked, and must belong to same list.
|
jpayne@69
|
144 */
|
jpayne@69
|
145 /*************************************************************************/
|
jpayne@69
|
146 /*
|
jpayne@69
|
147 * DList_Clear: Clear whole list and free all elements.
|
jpayne@69
|
148 *
|
jpayne@69
|
149 * See also: DList_Init
|
jpayne@69
|
150 */
|
jpayne@69
|
151 /*************************************************************************/
|
jpayne@69
|
152 /*
|
jpayne@69
|
153 * DList_Traverse: Iterate over all elements in list from first to last.
|
jpayne@69
|
154 * Call given function func(head, elem) for each element. The function has
|
jpayne@69
|
155 * to return the next element in list to traverse, normally this is
|
jpayne@69
|
156 * DList_Next(elem).
|
jpayne@69
|
157 *
|
jpayne@69
|
158 * See also: TK_DLIST_FOREACH, TK_DLIST_FOREACH_REVERSE
|
jpayne@69
|
159 */
|
jpayne@69
|
160 /*************************************************************************/
|
jpayne@69
|
161 /*
|
jpayne@69
|
162 * DList_First: Return pointer of first element in list, maybe it's NULL.
|
jpayne@69
|
163 */
|
jpayne@69
|
164 /*************************************************************************/
|
jpayne@69
|
165 /*
|
jpayne@69
|
166 * DList_Last: Return pointer of last element in list, maybe it's NULL.
|
jpayne@69
|
167 */
|
jpayne@69
|
168 /*************************************************************************/
|
jpayne@69
|
169 /*
|
jpayne@69
|
170 * DList_Next: Return pointer of next element after 'elem', maybe it's NULL.
|
jpayne@69
|
171 *
|
jpayne@69
|
172 * See also: DList_Prev()
|
jpayne@69
|
173 */
|
jpayne@69
|
174 /*************************************************************************/
|
jpayne@69
|
175 /*
|
jpayne@69
|
176 * DList_Prev: Return pointer of previous element before 'elem', maybe it's
|
jpayne@69
|
177 * NULL.
|
jpayne@69
|
178 *
|
jpayne@69
|
179 * See also: DList_Next()
|
jpayne@69
|
180 */
|
jpayne@69
|
181 /*************************************************************************/
|
jpayne@69
|
182 /*
|
jpayne@69
|
183 * DList_IsEmpty: Test whether given list is empty.
|
jpayne@69
|
184 */
|
jpayne@69
|
185 /*************************************************************************/
|
jpayne@69
|
186 /*
|
jpayne@69
|
187 * DList_IsLinked: Test whether given element is linked.
|
jpayne@69
|
188 */
|
jpayne@69
|
189 /*************************************************************************/
|
jpayne@69
|
190 /*
|
jpayne@69
|
191 * DList_IsFirst: Test whether given element is first element in list.
|
jpayne@69
|
192 * Note that 'elem' must be linked.
|
jpayne@69
|
193 *
|
jpayne@69
|
194 * See also: DList_IsLast(), DList_IsLinked()
|
jpayne@69
|
195 */
|
jpayne@69
|
196 /*************************************************************************/
|
jpayne@69
|
197 /*
|
jpayne@69
|
198 * DList_IsLast: Test whether given element is last element in list.
|
jpayne@69
|
199 * Note that 'elem' must be linked.
|
jpayne@69
|
200 *
|
jpayne@69
|
201 * See also: DList_IsFirst(), DList_IsLinked()
|
jpayne@69
|
202 */
|
jpayne@69
|
203 /*************************************************************************/
|
jpayne@69
|
204 /*
|
jpayne@69
|
205 * DList_Size: Count number of elements in given list.
|
jpayne@69
|
206 */
|
jpayne@69
|
207 /*************************************************************************/
|
jpayne@69
|
208 /*
|
jpayne@69
|
209 * TK_DLIST_FOREACH: Iterate over all elements in list from first to last.
|
jpayne@69
|
210 * 'var' is the name of the variable which points to current element.
|
jpayne@69
|
211 *
|
jpayne@69
|
212 * See also: TK_DLIST_FOREACH_REVERSE, DList_Traverse()
|
jpayne@69
|
213 */
|
jpayne@69
|
214 /*************************************************************************/
|
jpayne@69
|
215 /*
|
jpayne@69
|
216 * TK_DLIST_FOREACH_REVERSE: Iterate over all elements in list from last
|
jpayne@69
|
217 * to first (backwards). 'var' is the name of the variable which points to
|
jpayne@69
|
218 * current element.
|
jpayne@69
|
219 */
|
jpayne@69
|
220 /*************************************************************************/
|
jpayne@69
|
221
|
jpayne@69
|
222 #if defined(__GNUC__) || defined(__clang__)
|
jpayne@69
|
223 # define __TK_DLIST_UNUSED __attribute__((unused))
|
jpayne@69
|
224 #else
|
jpayne@69
|
225 # define __TK_DLIST_UNUSED
|
jpayne@69
|
226 #endif
|
jpayne@69
|
227
|
jpayne@69
|
228 #define TK_DLIST_DEFINE(LT, ElemType) /* LT = type of head/list */ \
|
jpayne@69
|
229 /* ------------------------------------------------------------------------- */ \
|
jpayne@69
|
230 typedef struct LT { \
|
jpayne@69
|
231 struct ElemType *first; /* first element */ \
|
jpayne@69
|
232 struct ElemType *last; /* last element */ \
|
jpayne@69
|
233 } LT; \
|
jpayne@69
|
234 \
|
jpayne@69
|
235 typedef struct ElemType *(LT##_Func)(LT *head, struct ElemType *elem); \
|
jpayne@69
|
236 \
|
jpayne@69
|
237 __TK_DLIST_UNUSED \
|
jpayne@69
|
238 static void \
|
jpayne@69
|
239 LT##_Init(LT *head) \
|
jpayne@69
|
240 { \
|
jpayne@69
|
241 assert(head); \
|
jpayne@69
|
242 head->first = NULL; \
|
jpayne@69
|
243 head->last = NULL; \
|
jpayne@69
|
244 } \
|
jpayne@69
|
245 \
|
jpayne@69
|
246 __TK_DLIST_UNUSED \
|
jpayne@69
|
247 static void \
|
jpayne@69
|
248 LT##_ElemInit(struct ElemType *elem) \
|
jpayne@69
|
249 { \
|
jpayne@69
|
250 assert(elem); \
|
jpayne@69
|
251 elem->_dl_.next = NULL; \
|
jpayne@69
|
252 elem->_dl_.prev = NULL; \
|
jpayne@69
|
253 } \
|
jpayne@69
|
254 \
|
jpayne@69
|
255 __TK_DLIST_UNUSED \
|
jpayne@69
|
256 static int \
|
jpayne@69
|
257 LT##_IsEmpty(LT *head) \
|
jpayne@69
|
258 { \
|
jpayne@69
|
259 assert(head); \
|
jpayne@69
|
260 return head->first == NULL; \
|
jpayne@69
|
261 } \
|
jpayne@69
|
262 \
|
jpayne@69
|
263 __TK_DLIST_UNUSED \
|
jpayne@69
|
264 static int \
|
jpayne@69
|
265 LT##_IsLinked(struct ElemType *elem) \
|
jpayne@69
|
266 { \
|
jpayne@69
|
267 assert(elem); \
|
jpayne@69
|
268 return elem->_dl_.next && elem->_dl_.prev; \
|
jpayne@69
|
269 } \
|
jpayne@69
|
270 \
|
jpayne@69
|
271 __TK_DLIST_UNUSED \
|
jpayne@69
|
272 static int \
|
jpayne@69
|
273 LT##_IsFirst(struct ElemType *elem) \
|
jpayne@69
|
274 { \
|
jpayne@69
|
275 assert(LT##_IsLinked(elem)); \
|
jpayne@69
|
276 return elem->_dl_.prev->_dl_.prev == elem; \
|
jpayne@69
|
277 } \
|
jpayne@69
|
278 \
|
jpayne@69
|
279 __TK_DLIST_UNUSED \
|
jpayne@69
|
280 static int \
|
jpayne@69
|
281 LT##_IsLast(struct ElemType *elem) \
|
jpayne@69
|
282 { \
|
jpayne@69
|
283 assert(LT##_IsLinked(elem)); \
|
jpayne@69
|
284 return elem->_dl_.next->_dl_.next == elem; \
|
jpayne@69
|
285 } \
|
jpayne@69
|
286 \
|
jpayne@69
|
287 __TK_DLIST_UNUSED \
|
jpayne@69
|
288 static struct ElemType * \
|
jpayne@69
|
289 LT##_First(LT *head) \
|
jpayne@69
|
290 { \
|
jpayne@69
|
291 assert(head); \
|
jpayne@69
|
292 return head->first; \
|
jpayne@69
|
293 } \
|
jpayne@69
|
294 \
|
jpayne@69
|
295 __TK_DLIST_UNUSED \
|
jpayne@69
|
296 static struct ElemType * \
|
jpayne@69
|
297 LT##_Last(LT *head) \
|
jpayne@69
|
298 { \
|
jpayne@69
|
299 assert(head); \
|
jpayne@69
|
300 return head->last; \
|
jpayne@69
|
301 } \
|
jpayne@69
|
302 \
|
jpayne@69
|
303 __TK_DLIST_UNUSED \
|
jpayne@69
|
304 static struct ElemType * \
|
jpayne@69
|
305 LT##_Next(struct ElemType *elem) \
|
jpayne@69
|
306 { \
|
jpayne@69
|
307 assert(elem); \
|
jpayne@69
|
308 return LT##_IsLast(elem) ? NULL : elem->_dl_.next; \
|
jpayne@69
|
309 } \
|
jpayne@69
|
310 \
|
jpayne@69
|
311 __TK_DLIST_UNUSED \
|
jpayne@69
|
312 static struct ElemType * \
|
jpayne@69
|
313 LT##_Prev(struct ElemType *elem) \
|
jpayne@69
|
314 { \
|
jpayne@69
|
315 assert(elem); \
|
jpayne@69
|
316 return LT##_IsFirst(elem) ? NULL : elem->_dl_.prev; \
|
jpayne@69
|
317 } \
|
jpayne@69
|
318 \
|
jpayne@69
|
319 __TK_DLIST_UNUSED \
|
jpayne@69
|
320 static unsigned \
|
jpayne@69
|
321 LT##_Size(const LT *head) \
|
jpayne@69
|
322 { \
|
jpayne@69
|
323 const struct ElemType *elem; \
|
jpayne@69
|
324 unsigned size = 0; \
|
jpayne@69
|
325 assert(head); \
|
jpayne@69
|
326 if ((elem = head->first)) { \
|
jpayne@69
|
327 for ( ; elem != (void *) head; elem = elem->_dl_.next) { \
|
jpayne@69
|
328 ++size; \
|
jpayne@69
|
329 } \
|
jpayne@69
|
330 } \
|
jpayne@69
|
331 return size; \
|
jpayne@69
|
332 } \
|
jpayne@69
|
333 \
|
jpayne@69
|
334 __TK_DLIST_UNUSED \
|
jpayne@69
|
335 static void \
|
jpayne@69
|
336 LT##_InsertAfter(struct ElemType *listElem, struct ElemType *elem) \
|
jpayne@69
|
337 { \
|
jpayne@69
|
338 assert(listElem); \
|
jpayne@69
|
339 assert(elem); \
|
jpayne@69
|
340 elem->_dl_.next = listElem->_dl_.next; \
|
jpayne@69
|
341 elem->_dl_.prev = listElem; \
|
jpayne@69
|
342 listElem->_dl_.next->_dl_.prev = elem; \
|
jpayne@69
|
343 listElem->_dl_.next = elem; \
|
jpayne@69
|
344 } \
|
jpayne@69
|
345 \
|
jpayne@69
|
346 __TK_DLIST_UNUSED \
|
jpayne@69
|
347 static void \
|
jpayne@69
|
348 LT##_InsertBefore(struct ElemType *listElem, struct ElemType *elem) \
|
jpayne@69
|
349 { \
|
jpayne@69
|
350 assert(listElem); \
|
jpayne@69
|
351 assert(elem); \
|
jpayne@69
|
352 elem->_dl_.next = listElem; \
|
jpayne@69
|
353 elem->_dl_.prev = listElem->_dl_.prev;; \
|
jpayne@69
|
354 listElem->_dl_.prev->_dl_.next = elem; \
|
jpayne@69
|
355 listElem->_dl_.prev = elem; \
|
jpayne@69
|
356 } \
|
jpayne@69
|
357 \
|
jpayne@69
|
358 __TK_DLIST_UNUSED \
|
jpayne@69
|
359 static void \
|
jpayne@69
|
360 LT##_Prepend(LT *head, struct ElemType *elem) \
|
jpayne@69
|
361 { \
|
jpayne@69
|
362 assert(head); \
|
jpayne@69
|
363 assert(elem); \
|
jpayne@69
|
364 elem->_dl_.prev = (void *) head; \
|
jpayne@69
|
365 if (!head->first) { \
|
jpayne@69
|
366 elem->_dl_.next = (void *) head; \
|
jpayne@69
|
367 head->last = elem; \
|
jpayne@69
|
368 } else { \
|
jpayne@69
|
369 elem->_dl_.next = head->first; \
|
jpayne@69
|
370 head->first->_dl_.prev = elem; \
|
jpayne@69
|
371 } \
|
jpayne@69
|
372 head->first = elem; \
|
jpayne@69
|
373 } \
|
jpayne@69
|
374 \
|
jpayne@69
|
375 __TK_DLIST_UNUSED \
|
jpayne@69
|
376 static void \
|
jpayne@69
|
377 LT##_Append(LT *head, struct ElemType *elem) \
|
jpayne@69
|
378 { \
|
jpayne@69
|
379 assert(head); \
|
jpayne@69
|
380 assert(elem); \
|
jpayne@69
|
381 elem->_dl_.next = (void *) head; \
|
jpayne@69
|
382 if (!head->first) { \
|
jpayne@69
|
383 elem->_dl_.prev = (void *) head; \
|
jpayne@69
|
384 head->first = elem; \
|
jpayne@69
|
385 } else { \
|
jpayne@69
|
386 elem->_dl_.prev = head->last; \
|
jpayne@69
|
387 head->last->_dl_.next = elem; \
|
jpayne@69
|
388 } \
|
jpayne@69
|
389 head->last = elem; \
|
jpayne@69
|
390 } \
|
jpayne@69
|
391 \
|
jpayne@69
|
392 __TK_DLIST_UNUSED \
|
jpayne@69
|
393 static void \
|
jpayne@69
|
394 LT##_Move(LT *dst, LT *src) \
|
jpayne@69
|
395 { \
|
jpayne@69
|
396 assert(dst); \
|
jpayne@69
|
397 assert(src); \
|
jpayne@69
|
398 if (src->first) { \
|
jpayne@69
|
399 if (dst->first) { \
|
jpayne@69
|
400 dst->last->_dl_.next = src->first; \
|
jpayne@69
|
401 src->first->_dl_.prev = dst->last; \
|
jpayne@69
|
402 dst->last = src->last; \
|
jpayne@69
|
403 } else { \
|
jpayne@69
|
404 *dst = *src; \
|
jpayne@69
|
405 dst->first->_dl_.prev = (void *) dst; \
|
jpayne@69
|
406 } \
|
jpayne@69
|
407 dst->last->_dl_.next = (void *) dst; \
|
jpayne@69
|
408 LT##_Init(src); \
|
jpayne@69
|
409 } \
|
jpayne@69
|
410 } \
|
jpayne@69
|
411 \
|
jpayne@69
|
412 __TK_DLIST_UNUSED \
|
jpayne@69
|
413 static void \
|
jpayne@69
|
414 LT##_Remove(struct ElemType *elem) \
|
jpayne@69
|
415 { \
|
jpayne@69
|
416 int isFirst, isLast; \
|
jpayne@69
|
417 assert(LT##_IsLinked(elem)); \
|
jpayne@69
|
418 isFirst = LT##_IsFirst(elem); \
|
jpayne@69
|
419 isLast = LT##_IsLast(elem); \
|
jpayne@69
|
420 if (isFirst && isLast) { \
|
jpayne@69
|
421 ((LT *) elem->_dl_.prev)->first = NULL; \
|
jpayne@69
|
422 ((LT *) elem->_dl_.next)->last = NULL; \
|
jpayne@69
|
423 } else { \
|
jpayne@69
|
424 if (isFirst) { \
|
jpayne@69
|
425 ((LT *) elem->_dl_.prev)->first = elem->_dl_.next; \
|
jpayne@69
|
426 } else { \
|
jpayne@69
|
427 elem->_dl_.prev->_dl_.next = elem->_dl_.next; \
|
jpayne@69
|
428 } \
|
jpayne@69
|
429 if (isLast) { \
|
jpayne@69
|
430 ((LT *) elem->_dl_.next)->last = elem->_dl_.prev; \
|
jpayne@69
|
431 } else { \
|
jpayne@69
|
432 elem->_dl_.next->_dl_.prev = elem->_dl_.prev; \
|
jpayne@69
|
433 } \
|
jpayne@69
|
434 } \
|
jpayne@69
|
435 LT##_ElemInit(elem); \
|
jpayne@69
|
436 } \
|
jpayne@69
|
437 \
|
jpayne@69
|
438 __TK_DLIST_UNUSED \
|
jpayne@69
|
439 static void \
|
jpayne@69
|
440 LT##_Free(struct ElemType *elem) \
|
jpayne@69
|
441 { \
|
jpayne@69
|
442 LT##_Remove(elem); \
|
jpayne@69
|
443 ckfree((void *) elem); \
|
jpayne@69
|
444 } \
|
jpayne@69
|
445 \
|
jpayne@69
|
446 __TK_DLIST_UNUSED \
|
jpayne@69
|
447 static void \
|
jpayne@69
|
448 LT##_RemoveHead(LT *head) \
|
jpayne@69
|
449 { \
|
jpayne@69
|
450 assert(!LT##_IsEmpty(head)); \
|
jpayne@69
|
451 LT##_Remove(head->first); \
|
jpayne@69
|
452 } \
|
jpayne@69
|
453 \
|
jpayne@69
|
454 __TK_DLIST_UNUSED \
|
jpayne@69
|
455 static void \
|
jpayne@69
|
456 LT##_RemoveTail(LT *head) \
|
jpayne@69
|
457 { \
|
jpayne@69
|
458 assert(!LT##_IsEmpty(head)); \
|
jpayne@69
|
459 LT##_Remove(head->last); \
|
jpayne@69
|
460 } \
|
jpayne@69
|
461 \
|
jpayne@69
|
462 __TK_DLIST_UNUSED \
|
jpayne@69
|
463 static void \
|
jpayne@69
|
464 LT##_FreeHead(LT *head) \
|
jpayne@69
|
465 { \
|
jpayne@69
|
466 assert(!LT##_IsEmpty(head)); \
|
jpayne@69
|
467 LT##_Free(head->first); \
|
jpayne@69
|
468 } \
|
jpayne@69
|
469 \
|
jpayne@69
|
470 __TK_DLIST_UNUSED \
|
jpayne@69
|
471 static void \
|
jpayne@69
|
472 LT##_FreeTail(LT *head) \
|
jpayne@69
|
473 { \
|
jpayne@69
|
474 assert(!LT##_IsEmpty(head)); \
|
jpayne@69
|
475 LT##_Free(head->last); \
|
jpayne@69
|
476 } \
|
jpayne@69
|
477 \
|
jpayne@69
|
478 __TK_DLIST_UNUSED \
|
jpayne@69
|
479 static void \
|
jpayne@69
|
480 LT##_SwapElems(struct ElemType *lhs, struct ElemType *rhs) \
|
jpayne@69
|
481 { \
|
jpayne@69
|
482 assert(lhs); \
|
jpayne@69
|
483 assert(rhs); \
|
jpayne@69
|
484 if (lhs != rhs) { \
|
jpayne@69
|
485 struct ElemType tmp; \
|
jpayne@69
|
486 if (LT##_IsFirst(lhs)) { \
|
jpayne@69
|
487 ((LT *) lhs->_dl_.prev)->first = rhs; \
|
jpayne@69
|
488 } else if (LT##_IsFirst(rhs)) { \
|
jpayne@69
|
489 ((LT *) rhs->_dl_.prev)->first = lhs; \
|
jpayne@69
|
490 } \
|
jpayne@69
|
491 if (LT##_IsLast(lhs)) { \
|
jpayne@69
|
492 ((LT *) lhs->_dl_.next)->last = rhs; \
|
jpayne@69
|
493 } else if (LT##_IsLast(rhs)) { \
|
jpayne@69
|
494 ((LT *) rhs->_dl_.next)->last = lhs; \
|
jpayne@69
|
495 } \
|
jpayne@69
|
496 tmp._dl_ = lhs->_dl_; \
|
jpayne@69
|
497 lhs->_dl_ = rhs->_dl_; \
|
jpayne@69
|
498 rhs->_dl_ = tmp._dl_; \
|
jpayne@69
|
499 } \
|
jpayne@69
|
500 } \
|
jpayne@69
|
501 \
|
jpayne@69
|
502 __TK_DLIST_UNUSED \
|
jpayne@69
|
503 static void \
|
jpayne@69
|
504 LT##_Clear(LT *head) \
|
jpayne@69
|
505 { \
|
jpayne@69
|
506 struct ElemType *p; \
|
jpayne@69
|
507 struct ElemType *next; \
|
jpayne@69
|
508 assert(head); \
|
jpayne@69
|
509 for (p = head->first; p; p = next) { \
|
jpayne@69
|
510 next = LT##_Next(p); \
|
jpayne@69
|
511 ckfree((void *) p); \
|
jpayne@69
|
512 } \
|
jpayne@69
|
513 LT##_Init(head); \
|
jpayne@69
|
514 } \
|
jpayne@69
|
515 \
|
jpayne@69
|
516 __TK_DLIST_UNUSED \
|
jpayne@69
|
517 static void \
|
jpayne@69
|
518 LT##_Traverse(LT *head, LT##_Func func) \
|
jpayne@69
|
519 { \
|
jpayne@69
|
520 struct ElemType *next; \
|
jpayne@69
|
521 struct ElemType *p; \
|
jpayne@69
|
522 assert(head); \
|
jpayne@69
|
523 for (p = head->first; p; p = next) { \
|
jpayne@69
|
524 next = func(head, p); \
|
jpayne@69
|
525 } \
|
jpayne@69
|
526 } \
|
jpayne@69
|
527 /* ------------------------------------------------------------------------- */
|
jpayne@69
|
528
|
jpayne@69
|
529 #define TK_DLIST_FOREACH(var, head) \
|
jpayne@69
|
530 assert(head); \
|
jpayne@69
|
531 for (var = head->first ? head->first : (void *) head; var != (void *) head; var = var->_dl_.next)
|
jpayne@69
|
532
|
jpayne@69
|
533 #define TK_DLIST_FOREACH_REVERSE(var, head) \
|
jpayne@69
|
534 assert(head); \
|
jpayne@69
|
535 for (var = head->last ? head->last : (void *) head; var != (void *) head; var = var->_dl_.prev)
|
jpayne@69
|
536
|
jpayne@69
|
537 #endif /* TK_DLIST_DEFINED */
|
jpayne@69
|
538
|
jpayne@69
|
539 /*
|
jpayne@69
|
540 * Local Variables:
|
jpayne@69
|
541 * mode: c
|
jpayne@69
|
542 * c-basic-offset: 4
|
jpayne@69
|
543 * fill-column: 105
|
jpayne@69
|
544 * End:
|
jpayne@69
|
545 * vi:set ts=8 sw=4:
|
jpayne@69
|
546 */
|