Mercurial > repos > rliterman > csp2
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/include/tkDList.h Tue Mar 18 17:55:14 2025 -0400 @@ -0,0 +1,546 @@ +/* + * tkDList.h -- + * + * A list is headed by pointers to first and last element. The elements + * are doubly linked so that an arbitrary element can be removed without + * a need to traverse the list. New elements can be added to the list + * before or after an existing element or at the head/tail of the list. + * A list may be traversed in the forward or backward direction. + * + * Copyright (c) 2018 by Gregor Cramer. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + */ + +/* + * Note that this file will not be included in header files, it is the purpose + * of this file to be included in source files only. Thus we are not using the + * prefix "Tk_" here for functions, because all the functions have private scope. + */ + +/* + * ------------------------------------------------------------------------------- + * Use the double linked list in the following way: + * ------------------------------------------------------------------------------- + * typedef struct MyListEntry { TK_DLIST_LINKS(MyListEntry); int value; } MyListEntry; + * TK_DLIST_DEFINE(MyList, MyListEntry); + * MyList listHdr = TK_DLIST_LIST_INITIALIZER; // or MyList_Init(&listHdr) + * MyListEntry *p; + * int i = 0; + * MyList_Append(&listHdr, ckalloc(sizeof(MyListEntry))); + * MyList_Append(&listHdr, ckalloc(sizeof(MyListEntry))); + * TK_DLIST_FOREACH(p, &listHdr) { p->value = i++; } + * // ... + * MyList_RemoveHead(&listHdr); + * MyList_RemoveHead(&listHdr); + * MyList_Clear(MyListEntry, &listHdr); // invokes ckfree() for each element + * ------------------------------------------------------------------------------- + * IMPORTANT NOTE: TK_DLIST_LINKS must be used at start of struct! + */ + +#ifndef TK_DLIST_DEFINED +#define TK_DLIST_DEFINED + +#include "tkInt.h" + +/* + * List definitions. + */ + +#define TK_DLIST_LINKS(ElemType) \ +struct { \ + struct ElemType *prev; /* previous element */ \ + struct ElemType *next; /* next element */ \ +} _dl_ + +#define TK_DLIST_LIST_INITIALIZER { NULL, NULL } +#define TK_DLIST_ELEM_INITIALIZER { NULL, NULL } + +/*************************************************************************/ +/* + * DList_Init: Initialize list header. This can also be used to clear the + * list. + * + * See also: DList_Clear() + */ +/*************************************************************************/ +/* + * DList_ElemInit: Initialize a list element. + */ +/*************************************************************************/ +/* + * DList_InsertAfter: Insert 'elem' after 'listElem'. 'elem' must not + * be linked, but 'listElem' must be linked. + */ +/*************************************************************************/ +/* + * DList_InsertBefore: Insert 'elem' before 'listElem'. 'elem' must not + * be linked, but 'listElem' must be linked. + */ +/*************************************************************************/ +/* + * DList_Prepend: Insert 'elem' at start of list. This element must not + * be linked. + * + * See also: DList_Append() + */ +/*************************************************************************/ +/* + * DList_Append: Append 'elem' to end of list. This element must not + * be linked. + * + * See also: DList_Prepend() + */ +/*************************************************************************/ +/* + * DList_Move: Append all list items of 'src' to end of 'dst'. + */ +/*************************************************************************/ +/* + * DList_Remove: Remove 'elem' from list. This element must be linked. + * + * See also: DList_Free() + */ +/*************************************************************************/ +/* + * DList_Free: Remove 'elem' from list and free it. This element must + * be linked. + * + * See also: DList_Remove() + */ +/*************************************************************************/ +/* + * DList_RemoveHead: Remove first element from list. The list must + * not be empty. + * + * See also: DList_FreeHead() + */ +/*************************************************************************/ +/* + * DList_RemoveTail: Remove last element from list. The list must + * not be empty. + * + * See also: DList_FreeTail() + */ +/*************************************************************************/ +/* + * DList_FreeHead: Remove first element from list and free it. + * The list must not be empty. + * + * See also: DList_RemoveHead() + */ +/*************************************************************************/ +/* + * DList_FreeTail: Remove last element from list and free it. + * The list must not be empty. + * + * See also: DList_RemoveTail() + */ +/*************************************************************************/ +/* + * DList_SwapElems: Swap positions of given elements 'lhs' and 'rhs'. + * Both elements must be linked, and must belong to same list. + */ +/*************************************************************************/ +/* + * DList_Clear: Clear whole list and free all elements. + * + * See also: DList_Init + */ +/*************************************************************************/ +/* + * DList_Traverse: Iterate over all elements in list from first to last. + * Call given function func(head, elem) for each element. The function has + * to return the next element in list to traverse, normally this is + * DList_Next(elem). + * + * See also: TK_DLIST_FOREACH, TK_DLIST_FOREACH_REVERSE + */ +/*************************************************************************/ +/* + * DList_First: Return pointer of first element in list, maybe it's NULL. + */ +/*************************************************************************/ +/* + * DList_Last: Return pointer of last element in list, maybe it's NULL. + */ +/*************************************************************************/ +/* + * DList_Next: Return pointer of next element after 'elem', maybe it's NULL. + * + * See also: DList_Prev() + */ +/*************************************************************************/ +/* + * DList_Prev: Return pointer of previous element before 'elem', maybe it's + * NULL. + * + * See also: DList_Next() + */ +/*************************************************************************/ +/* + * DList_IsEmpty: Test whether given list is empty. + */ +/*************************************************************************/ +/* + * DList_IsLinked: Test whether given element is linked. + */ +/*************************************************************************/ +/* + * DList_IsFirst: Test whether given element is first element in list. + * Note that 'elem' must be linked. + * + * See also: DList_IsLast(), DList_IsLinked() + */ +/*************************************************************************/ +/* + * DList_IsLast: Test whether given element is last element in list. + * Note that 'elem' must be linked. + * + * See also: DList_IsFirst(), DList_IsLinked() + */ +/*************************************************************************/ +/* + * DList_Size: Count number of elements in given list. + */ +/*************************************************************************/ +/* + * TK_DLIST_FOREACH: Iterate over all elements in list from first to last. + * 'var' is the name of the variable which points to current element. + * + * See also: TK_DLIST_FOREACH_REVERSE, DList_Traverse() + */ +/*************************************************************************/ +/* + * TK_DLIST_FOREACH_REVERSE: Iterate over all elements in list from last + * to first (backwards). 'var' is the name of the variable which points to + * current element. + */ +/*************************************************************************/ + +#if defined(__GNUC__) || defined(__clang__) +# define __TK_DLIST_UNUSED __attribute__((unused)) +#else +# define __TK_DLIST_UNUSED +#endif + +#define TK_DLIST_DEFINE(LT, ElemType) /* LT = type of head/list */ \ +/* ------------------------------------------------------------------------- */ \ +typedef struct LT { \ + struct ElemType *first; /* first element */ \ + struct ElemType *last; /* last element */ \ +} LT; \ + \ +typedef struct ElemType *(LT##_Func)(LT *head, struct ElemType *elem); \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_Init(LT *head) \ +{ \ + assert(head); \ + head->first = NULL; \ + head->last = NULL; \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_ElemInit(struct ElemType *elem) \ +{ \ + assert(elem); \ + elem->_dl_.next = NULL; \ + elem->_dl_.prev = NULL; \ +} \ + \ +__TK_DLIST_UNUSED \ +static int \ +LT##_IsEmpty(LT *head) \ +{ \ + assert(head); \ + return head->first == NULL; \ +} \ + \ +__TK_DLIST_UNUSED \ +static int \ +LT##_IsLinked(struct ElemType *elem) \ +{ \ + assert(elem); \ + return elem->_dl_.next && elem->_dl_.prev; \ +} \ + \ +__TK_DLIST_UNUSED \ +static int \ +LT##_IsFirst(struct ElemType *elem) \ +{ \ + assert(LT##_IsLinked(elem)); \ + return elem->_dl_.prev->_dl_.prev == elem; \ +} \ + \ +__TK_DLIST_UNUSED \ +static int \ +LT##_IsLast(struct ElemType *elem) \ +{ \ + assert(LT##_IsLinked(elem)); \ + return elem->_dl_.next->_dl_.next == elem; \ +} \ + \ +__TK_DLIST_UNUSED \ +static struct ElemType * \ +LT##_First(LT *head) \ +{ \ + assert(head); \ + return head->first; \ +} \ + \ +__TK_DLIST_UNUSED \ +static struct ElemType * \ +LT##_Last(LT *head) \ +{ \ + assert(head); \ + return head->last; \ +} \ + \ +__TK_DLIST_UNUSED \ +static struct ElemType * \ +LT##_Next(struct ElemType *elem) \ +{ \ + assert(elem); \ + return LT##_IsLast(elem) ? NULL : elem->_dl_.next; \ +} \ + \ +__TK_DLIST_UNUSED \ +static struct ElemType * \ +LT##_Prev(struct ElemType *elem) \ +{ \ + assert(elem); \ + return LT##_IsFirst(elem) ? NULL : elem->_dl_.prev; \ +} \ + \ +__TK_DLIST_UNUSED \ +static unsigned \ +LT##_Size(const LT *head) \ +{ \ + const struct ElemType *elem; \ + unsigned size = 0; \ + assert(head); \ + if ((elem = head->first)) { \ + for ( ; elem != (void *) head; elem = elem->_dl_.next) { \ + ++size; \ + } \ + } \ + return size; \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_InsertAfter(struct ElemType *listElem, struct ElemType *elem) \ +{ \ + assert(listElem); \ + assert(elem); \ + elem->_dl_.next = listElem->_dl_.next; \ + elem->_dl_.prev = listElem; \ + listElem->_dl_.next->_dl_.prev = elem; \ + listElem->_dl_.next = elem; \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_InsertBefore(struct ElemType *listElem, struct ElemType *elem) \ +{ \ + assert(listElem); \ + assert(elem); \ + elem->_dl_.next = listElem; \ + elem->_dl_.prev = listElem->_dl_.prev;; \ + listElem->_dl_.prev->_dl_.next = elem; \ + listElem->_dl_.prev = elem; \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_Prepend(LT *head, struct ElemType *elem) \ +{ \ + assert(head); \ + assert(elem); \ + elem->_dl_.prev = (void *) head; \ + if (!head->first) { \ + elem->_dl_.next = (void *) head; \ + head->last = elem; \ + } else { \ + elem->_dl_.next = head->first; \ + head->first->_dl_.prev = elem; \ + } \ + head->first = elem; \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_Append(LT *head, struct ElemType *elem) \ +{ \ + assert(head); \ + assert(elem); \ + elem->_dl_.next = (void *) head; \ + if (!head->first) { \ + elem->_dl_.prev = (void *) head; \ + head->first = elem; \ + } else { \ + elem->_dl_.prev = head->last; \ + head->last->_dl_.next = elem; \ + } \ + head->last = elem; \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_Move(LT *dst, LT *src) \ +{ \ + assert(dst); \ + assert(src); \ + if (src->first) { \ + if (dst->first) { \ + dst->last->_dl_.next = src->first; \ + src->first->_dl_.prev = dst->last; \ + dst->last = src->last; \ + } else { \ + *dst = *src; \ + dst->first->_dl_.prev = (void *) dst; \ + } \ + dst->last->_dl_.next = (void *) dst; \ + LT##_Init(src); \ + } \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_Remove(struct ElemType *elem) \ +{ \ + int isFirst, isLast; \ + assert(LT##_IsLinked(elem)); \ + isFirst = LT##_IsFirst(elem); \ + isLast = LT##_IsLast(elem); \ + if (isFirst && isLast) { \ + ((LT *) elem->_dl_.prev)->first = NULL; \ + ((LT *) elem->_dl_.next)->last = NULL; \ + } else { \ + if (isFirst) { \ + ((LT *) elem->_dl_.prev)->first = elem->_dl_.next; \ + } else { \ + elem->_dl_.prev->_dl_.next = elem->_dl_.next; \ + } \ + if (isLast) { \ + ((LT *) elem->_dl_.next)->last = elem->_dl_.prev; \ + } else { \ + elem->_dl_.next->_dl_.prev = elem->_dl_.prev; \ + } \ + } \ + LT##_ElemInit(elem); \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_Free(struct ElemType *elem) \ +{ \ + LT##_Remove(elem); \ + ckfree((void *) elem); \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_RemoveHead(LT *head) \ +{ \ + assert(!LT##_IsEmpty(head)); \ + LT##_Remove(head->first); \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_RemoveTail(LT *head) \ +{ \ + assert(!LT##_IsEmpty(head)); \ + LT##_Remove(head->last); \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_FreeHead(LT *head) \ +{ \ + assert(!LT##_IsEmpty(head)); \ + LT##_Free(head->first); \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_FreeTail(LT *head) \ +{ \ + assert(!LT##_IsEmpty(head)); \ + LT##_Free(head->last); \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_SwapElems(struct ElemType *lhs, struct ElemType *rhs) \ +{ \ + assert(lhs); \ + assert(rhs); \ + if (lhs != rhs) { \ + struct ElemType tmp; \ + if (LT##_IsFirst(lhs)) { \ + ((LT *) lhs->_dl_.prev)->first = rhs; \ + } else if (LT##_IsFirst(rhs)) { \ + ((LT *) rhs->_dl_.prev)->first = lhs; \ + } \ + if (LT##_IsLast(lhs)) { \ + ((LT *) lhs->_dl_.next)->last = rhs; \ + } else if (LT##_IsLast(rhs)) { \ + ((LT *) rhs->_dl_.next)->last = lhs; \ + } \ + tmp._dl_ = lhs->_dl_; \ + lhs->_dl_ = rhs->_dl_; \ + rhs->_dl_ = tmp._dl_; \ + } \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_Clear(LT *head) \ +{ \ + struct ElemType *p; \ + struct ElemType *next; \ + assert(head); \ + for (p = head->first; p; p = next) { \ + next = LT##_Next(p); \ + ckfree((void *) p); \ + } \ + LT##_Init(head); \ +} \ + \ +__TK_DLIST_UNUSED \ +static void \ +LT##_Traverse(LT *head, LT##_Func func) \ +{ \ + struct ElemType *next; \ + struct ElemType *p; \ + assert(head); \ + for (p = head->first; p; p = next) { \ + next = func(head, p); \ + } \ +} \ +/* ------------------------------------------------------------------------- */ + +#define TK_DLIST_FOREACH(var, head) \ + assert(head); \ + for (var = head->first ? head->first : (void *) head; var != (void *) head; var = var->_dl_.next) + +#define TK_DLIST_FOREACH_REVERSE(var, head) \ + assert(head); \ + for (var = head->last ? head->last : (void *) head; var != (void *) head; var = var->_dl_.prev) + +#endif /* TK_DLIST_DEFINED */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 105 + * End: + * vi:set ts=8 sw=4: + */