comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/include/tkDList.h @ 69:33d812a61356

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