File indexing completed on 2024-12-22 04:04:12

0001 /* Copyright (C) 2001-2019 Peter Selinger.
0002    This file is part of Potrace. It is free software and it is covered
0003    by the GNU General Public License. See the file COPYING for details. */
0004 
0005 
0006 #ifndef _PS_LISTS_H
0007 #define _PS_LISTS_H
0008 
0009 /* here we define some general list macros. Because they are macros,
0010    they should work on any datatype with a "->next" component. Some of
0011    them use a "hook". If elt and list are of type t* then hook is of
0012    type t**. A hook stands for an insertion point in the list, i.e.,
0013    either before the first element, or between two elements, or after
0014    the last element. If an operation "sets the hook" for an element,
0015    then the hook is set to just before the element. One can insert
0016    something at a hook. One can also unlink at a hook: this means,
0017    unlink the element just after the hook. By "to unlink", we mean the
0018    element is removed from the list, but not deleted. Thus, it and its
0019    components still need to be freed. */
0020 
0021 /* Note: these macros are somewhat experimental. Only the ones that
0022    are actually *used* have been tested. So be careful to test any
0023    that you use. Looking at the output of the preprocessor, "gcc -E"
0024    (possibly piped though "indent"), might help too. Also: these
0025    macros define some internal (local) variables that start with
0026    "_". */
0027 
0028 /* we enclose macro definitions whose body consists of more than one
0029    statement in MACRO_BEGIN and MACRO_END, rather than '{' and '}'.  The
0030    reason is that we want to be able to use the macro in a context
0031    such as "if (...) macro(...); else ...". If we didn't use this obscure
0032    trick, we'd have to omit the ";" in such cases. */
0033 
0034 #define MACRO_BEGIN do {
0035 #define MACRO_END   } while (0)
0036 
0037 /* ---------------------------------------------------------------------- */
0038 /* macros for singly-linked lists */
0039 
0040 /* traverse list. At the end, elt is set to NULL. */
0041 #define list_forall(elt, list)   for (elt=list; elt!=NULL; elt=elt->next)
0042 
0043 /* set elt to the first element of list satisfying boolean condition
0044    c, or NULL if not found */
0045 #define list_find(elt, list, c) \
0046   MACRO_BEGIN list_forall(elt, list) if (c) break; MACRO_END
0047 
0048 /* like forall, except also set hook for elt. */
0049 #define list_forall2(elt, list, hook) \
0050   for (elt=list, hook=&list; elt!=NULL; hook=&elt->next, elt=elt->next)
0051 
0052 /* same as list_find, except also set hook for elt. */
0053 #define list_find2(elt, list, c, hook) \
0054   MACRO_BEGIN list_forall2(elt, list, hook) if (c) break; MACRO_END
0055 
0056 /* same, except only use hook. */
0057 #define _list_forall_hook(list, hook) \
0058   for (hook=&list; *hook!=NULL; hook=&(*hook)->next)
0059 
0060 /* same, except only use hook. Note: c may only refer to *hook, not elt. */
0061 #define _list_find_hook(list, c, hook) \
0062   MACRO_BEGIN _list_forall_hook(list, hook) if (c) break; MACRO_END
0063 
0064 /* insert element after hook */
0065 #define list_insert_athook(elt, hook) \
0066   MACRO_BEGIN elt->next = *hook; *hook = elt; MACRO_END
0067 
0068 /* insert element before hook */
0069 #define list_insert_beforehook(elt, hook) \
0070   MACRO_BEGIN elt->next = *hook; *hook = elt; hook=&elt->next; MACRO_END
0071 
0072 /* unlink element after hook, let elt be unlinked element, or NULL.
0073    hook remains. */
0074 #define list_unlink_athook(list, elt, hook) \
0075   MACRO_BEGIN \
0076   elt = hook ? *hook : NULL; if (elt) { *hook = elt->next; elt->next = NULL; }\
0077   MACRO_END
0078 
0079 /* unlink the specific element, if it is in the list. Otherwise, set
0080    elt to NULL */
0081 #define list_unlink(listtype, list, elt)      \
0082   MACRO_BEGIN                                 \
0083   listtype **_hook;               \
0084   _list_find_hook(list, *_hook==elt, _hook);  \
0085   list_unlink_athook(list, elt, _hook);       \
0086   MACRO_END
0087 
0088 /* prepend elt to list */
0089 #define list_prepend(list, elt) \
0090   MACRO_BEGIN elt->next = list; list = elt; MACRO_END
0091 
0092 /* append elt to list. */
0093 #define list_append(listtype, list, elt)     \
0094   MACRO_BEGIN                                \
0095   listtype **_hook;                          \
0096   _list_forall_hook(list, _hook) {}          \
0097   list_insert_athook(elt, _hook);            \
0098   MACRO_END
0099 
0100 /* unlink the first element that satisfies the condition. */
0101 #define list_unlink_cond(listtype, list, elt, c)     \
0102   MACRO_BEGIN                                        \
0103   listtype **_hook;                  \
0104   list_find2(elt, list, c, _hook);                   \
0105   list_unlink_athook(list, elt, _hook);              \
0106   MACRO_END
0107 
0108 /* let elt be the nth element of the list, starting to count from 0.
0109    Return NULL if out of bounds.   */
0110 #define list_nth(elt, list, n)                                \
0111   MACRO_BEGIN                                                 \
0112   int _x;  /* only evaluate n once */                         \
0113   for (_x=(n), elt=list; _x && elt; _x--, elt=elt->next) {}   \
0114   MACRO_END
0115 
0116 /* let elt be the nth element of the list, starting to count from 0.
0117    Return NULL if out of bounds.   */
0118 #define list_nth_hook(elt, list, n, hook)                     \
0119   MACRO_BEGIN                                                 \
0120   int _x;  /* only evaluate n once */                         \
0121   for (_x=(n), elt=list, hook=&list; _x && elt; _x--, hook=&elt->next, elt=elt->next) {}   \
0122   MACRO_END
0123 
0124 /* set n to the length of the list */
0125 #define list_length(listtype, list, n)                   \
0126   MACRO_BEGIN                                            \
0127   listtype *_elt;                        \
0128   n=0;                           \
0129   list_forall(_elt, list)                \
0130     n++;                         \
0131   MACRO_END
0132 
0133 /* set n to the index of the first element satisfying cond, or -1 if
0134    none found. Also set elt to the element, or NULL if none found. */
0135 #define list_index(list, n, elt, c)                      \
0136   MACRO_BEGIN                        \
0137   n=0;                           \
0138   list_forall(elt, list) {               \
0139     if (c) break;                    \
0140     n++;                         \
0141   }                          \
0142   if (!elt)                      \
0143     n=-1;                        \
0144   MACRO_END
0145 
0146 /* set n to the number of elements in the list that satisfy condition c */
0147 #define list_count(list, n, elt, c)                      \
0148   MACRO_BEGIN                        \
0149   n=0;                           \
0150   list_forall(elt, list) {               \
0151     if (c) n++;                      \
0152   }                                                      \
0153   MACRO_END
0154 
0155 /* let elt be each element of the list, unlinked. At the end, set list=NULL. */
0156 #define list_forall_unlink(elt, list) \
0157   for (elt=list; elt ? (list=elt->next, elt->next=NULL), 1 : 0; elt=list)
0158 
0159 /* reverse a list (efficient) */
0160 #define list_reverse(listtype, list)            \
0161   MACRO_BEGIN                   \
0162   listtype *_list1=NULL, *elt;          \
0163   list_forall_unlink(elt, list)         \
0164     list_prepend(_list1, elt);          \
0165   list = _list1;                \
0166   MACRO_END
0167 
0168 /* insert the element ELT just before the first element TMP of the
0169    list for which COND holds. Here COND must be a condition of ELT and
0170    TMP.  Typical usage is to insert an element into an ordered list:
0171    for instance, list_insert_ordered(listtype, list, elt, tmp,
0172    elt->size <= tmp->size).  Note: if we give a "less than or equal"
0173    condition, the new element will be inserted just before a sequence
0174    of equal elements. If we give a "less than" condition, the new
0175    element will be inserted just after a list of equal elements.
0176    Note: it is much more efficient to construct a list with
0177    list_prepend and then order it with list_merge_sort, than to
0178    construct it with list_insert_ordered. */
0179 #define list_insert_ordered(listtype, list, elt, tmp, cond) \
0180   MACRO_BEGIN                                               \
0181   listtype **_hook;                                         \
0182   _list_find_hook(list, (tmp=*_hook, (cond)), _hook);       \
0183   list_insert_athook(elt, _hook);                           \
0184   MACRO_END
0185 
0186 /* sort the given list, according to the comparison condition.
0187    Typical usage is list_sort(listtype, list, a, b, a->size <
0188    b->size).  Note: if we give "less than or equal" condition, each
0189    segment of equal elements will be reversed in order. If we give a
0190    "less than" condition, each segment of equal elements will retain
0191    the original order. The latter is slower but sometimes
0192    prettier. Average running time: n*n/2. */
0193 #define list_sort(listtype, list, a, b, cond)            \
0194   MACRO_BEGIN                                            \
0195   listtype *_newlist=NULL;                               \
0196   list_forall_unlink(a, list)                            \
0197     list_insert_ordered(listtype, _newlist, a, b, cond); \
0198   list = _newlist;                                       \
0199   MACRO_END
0200 
0201 /* a much faster sort algorithm (merge sort, n log n worst case). It
0202    is required that the list type has an additional, unused next1
0203    component. Note there is no curious reversal of order of equal
0204    elements as for list_sort. */
0205 
0206 #define list_mergesort(listtype, list, a, b, cond)              \
0207   MACRO_BEGIN                               \
0208   listtype *_elt, **_hook1;                     \
0209                                     \
0210   for (_elt=list; _elt; _elt=_elt->next1) {         \
0211     _elt->next1 = _elt->next;                       \
0212     _elt->next = NULL;                          \
0213   }                                 \
0214   do {                                                  \
0215     _hook1 = &(list);                               \
0216     while ((a = *_hook1) != NULL && (b = a->next1) != NULL ) {  \
0217       _elt = b->next1;                          \
0218       _list_merge_cond(listtype, a, b, cond, *_hook1);          \
0219       _hook1 = &((*_hook1)->next1);                 \
0220       *_hook1 = _elt;                               \
0221     }                                   \
0222   } while (_hook1 != &(list));                                  \
0223   MACRO_END
0224 
0225 /* merge two sorted lists. Store result at &result */
0226 #define _list_merge_cond(listtype, a, b, cond, result)   \
0227   MACRO_BEGIN                                            \
0228   listtype **_hook;                  \
0229   _hook = &(result);                     \
0230   while (1) {                                            \
0231      if (a==NULL) {                  \
0232        *_hook = b;                   \
0233        break;                        \
0234      } else if (b==NULL) {               \
0235        *_hook = a;                   \
0236        break;                        \
0237      } else if (cond) {                  \
0238        *_hook = a;                   \
0239        _hook = &(a->next);               \
0240        a = a->next;                  \
0241      } else {                        \
0242        *_hook = b;                   \
0243        _hook = &(b->next);               \
0244        b = b->next;                  \
0245      }                           \
0246   }                          \
0247   MACRO_END
0248 
0249 /* ---------------------------------------------------------------------- */
0250 /* macros for doubly-linked lists */
0251 
0252 #define dlist_append(head, end, elt)                    \
0253   MACRO_BEGIN                                            \
0254   elt->prev = end;                   \
0255   elt->next = NULL;                  \
0256   if (end) {                         \
0257     end->next = elt;                     \
0258   } else {                           \
0259     head = elt;                      \
0260   }                              \
0261   end = elt;                         \
0262   MACRO_END
0263 
0264 /* let elt be each element of the list, unlinked. At the end, set list=NULL. */
0265 #define dlist_forall_unlink(elt, head, end) \
0266   for (elt=head; elt ? (head=elt->next, elt->next=NULL, elt->prev=NULL), 1 : (end=NULL, 0); elt=head)
0267 
0268 /* unlink the first element of the list */
0269 #define dlist_unlink_first(head, end, elt)               \
0270   MACRO_BEGIN                                \
0271   elt = head;                        \
0272   if (head) {                        \
0273     head = head->next;                   \
0274     if (head) {                      \
0275       head->prev = NULL;                 \
0276     } else {                         \
0277       end = NULL;                    \
0278     }                            \
0279     elt->prev = NULL;                    \
0280     elt->next = NULL;                    \
0281   }                          \
0282   MACRO_END
0283 
0284 #endif /* _PS_LISTS_H */
0285