You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							333 lines
						
					
					
						
							15 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							333 lines
						
					
					
						
							15 KiB
						
					
					
				
								/* Copyright (C) 2001-2017 Peter Selinger.
							 | 
						|
								 *  This file is part of Potrace. It is free software and it is covered
							 | 
						|
								 *  by the GNU General Public License. See the file COPYING for details. */
							 | 
						|
								
							 | 
						|
								#ifndef _PS_LISTS_H
							 | 
						|
								#define _PS_LISTS_H
							 | 
						|
								
							 | 
						|
								/* here we define some general list macros. Because they are macros,
							 | 
						|
								 *  they should work on any datatype with a "->next" component. Some of
							 | 
						|
								 *  them use a "hook". If elt and list are of type t* then hook is of
							 | 
						|
								 *  type t**. A hook stands for an insertion point in the list, i.e.,
							 | 
						|
								 *  either before the first element, or between two elements, or after
							 | 
						|
								 *  the last element. If an operation "sets the hook" for an element,
							 | 
						|
								 *  then the hook is set to just before the element. One can insert
							 | 
						|
								 *  something at a hook. One can also unlink at a hook: this means,
							 | 
						|
								 *  unlink the element just after the hook. By "to unlink", we mean the
							 | 
						|
								 *  element is removed from the list, but not deleted. Thus, it and its
							 | 
						|
								 *  components still need to be freed. */
							 | 
						|
								
							 | 
						|
								/* Note: these macros are somewhat experimental. Only the ones that
							 | 
						|
								 *  are actually *used* have been tested. So be careful to test any
							 | 
						|
								 *  that you use. Looking at the output of the preprocessor, "gcc -E"
							 | 
						|
								 *  (possibly piped though "indent"), might help too. Also: these
							 | 
						|
								 *  macros define some internal (local) variables that start with
							 | 
						|
								 *  "_". */
							 | 
						|
								
							 | 
						|
								/* we enclose macro definitions whose body consists of more than one
							 | 
						|
								 *  statement in MACRO_BEGIN and MACRO_END, rather than '{' and '}'.  The
							 | 
						|
								 *  reason is that we want to be able to use the macro in a context
							 | 
						|
								 *  such as "if (...) macro(...); else ...". If we didn't use this obscure
							 | 
						|
								 *  trick, we'd have to omit the ";" in such cases. */
							 | 
						|
								
							 | 
						|
								#define MACRO_BEGIN \
							 | 
						|
								    do              \
							 | 
						|
								    {
							 | 
						|
								#define MACRO_END \
							 | 
						|
								    }             \
							 | 
						|
								    while( 0 )
							 | 
						|
								
							 | 
						|
								/* ---------------------------------------------------------------------- */
							 | 
						|
								/* macros for singly-linked lists */
							 | 
						|
								
							 | 
						|
								/* traverse list. At the end, elt is set to NULL. */
							 | 
						|
								#define list_forall( elt, list ) for( elt = list; elt != NULL; elt = elt->next )
							 | 
						|
								
							 | 
						|
								/* set elt to the first element of list satisfying boolean condition
							 | 
						|
								 *  c, or NULL if not found */
							 | 
						|
								#define list_find( elt, list, c )                       \
							 | 
						|
								    MACRO_BEGIN list_forall( elt, list ) if( c ) \
							 | 
						|
								        break; \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* like forall, except also set hook for elt. */
							 | 
						|
								#define list_forall2( elt, list, hook ) \
							 | 
						|
								    for( elt = list, hook = &list; elt != NULL; hook = &elt->next, elt = elt->next )
							 | 
						|
								
							 | 
						|
								/* same as list_find, except also set hook for elt. */
							 | 
						|
								#define list_find2( elt, list, c, hook )                       \
							 | 
						|
								    MACRO_BEGIN list_forall2( elt, list, hook ) if( c ) \
							 | 
						|
								        break; \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* same, except only use hook. */
							 | 
						|
								#define _list_forall_hook( list, hook ) for( hook = &list; *hook != NULL; hook = &( *hook )->next )
							 | 
						|
								
							 | 
						|
								/* same, except only use hook. Note: c may only refer to *hook, not elt. */
							 | 
						|
								#define _list_find_hook( list, c, hook )                       \
							 | 
						|
								    MACRO_BEGIN _list_forall_hook( list, hook ) if( c ) \
							 | 
						|
								        break; \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* insert element after hook */
							 | 
						|
								#define list_insert_athook( elt, hook ) \
							 | 
						|
								    MACRO_BEGIN elt->next = *hook;      \
							 | 
						|
								    *hook = elt;                        \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* insert element before hook */
							 | 
						|
								#define list_insert_beforehook( elt, hook ) \
							 | 
						|
								    MACRO_BEGIN elt->next = *hook;          \
							 | 
						|
								    *hook   = elt;                            \
							 | 
						|
								    hook    = &elt->next;                      \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* unlink element after hook, let elt be unlinked element, or NULL.
							 | 
						|
								 *  hook remains. */
							 | 
						|
								#define list_unlink_athook( list, elt, hook ) \
							 | 
						|
								    MACRO_BEGIN                               \
							 | 
						|
								    elt = hook ? *hook : NULL;                \
							 | 
						|
								    if( elt )                                 \
							 | 
						|
								    {                                         \
							 | 
						|
								        *hook = elt->next;                    \
							 | 
						|
								        elt->next = NULL;                     \
							 | 
						|
								    }                                         \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* unlink the specific element, if it is in the list. Otherwise, set
							 | 
						|
								 *  elt to NULL */
							 | 
						|
								#define list_unlink( listtype, list, elt )         \
							 | 
						|
								    MACRO_BEGIN                                    \
							 | 
						|
								    listtype * *_hook;                              \
							 | 
						|
								    _list_find_hook( list, *_hook == elt, _hook ); \
							 | 
						|
								    list_unlink_athook( list, elt, _hook );        \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* prepend elt to list */
							 | 
						|
								#define list_prepend( list, elt ) \
							 | 
						|
								    MACRO_BEGIN elt->next = list; \
							 | 
						|
								    list = elt;                   \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* append elt to list. */
							 | 
						|
								#define list_append( listtype, list, elt ) \
							 | 
						|
								    MACRO_BEGIN                            \
							 | 
						|
								    listtype * *_hook;                      \
							 | 
						|
								    _list_forall_hook( list, _hook )       \
							 | 
						|
								    {                                      \
							 | 
						|
								    }                                      \
							 | 
						|
								    list_insert_athook( elt, _hook );      \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* unlink the first element that satisfies the condition. */
							 | 
						|
								#define list_unlink_cond( listtype, list, elt, c ) \
							 | 
						|
								    MACRO_BEGIN                                    \
							 | 
						|
								    listtype * *_hook;                              \
							 | 
						|
								    list_find2( elt, list, c, _hook );             \
							 | 
						|
								    list_unlink_athook( list, elt, _hook );        \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* let elt be the nth element of the list, starting to count from 0.
							 | 
						|
								 *  Return NULL if out of bounds.   */
							 | 
						|
								#define list_nth( elt, list, n )                                    \
							 | 
						|
								    MACRO_BEGIN                                                     \
							 | 
						|
								    int _x;    /* only evaluate n once */                              \
							 | 
						|
								    for( _x = ( n ), elt = list; _x && elt; _x--, elt = elt->next ) \
							 | 
						|
								    {                                                               \
							 | 
						|
								    }                                                               \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* let elt be the nth element of the list, starting to count from 0.
							 | 
						|
								 *  Return NULL if out of bounds.   */
							 | 
						|
								#define list_nth_hook( elt, list, n, hook )               \
							 | 
						|
								    MACRO_BEGIN                                           \
							 | 
						|
								    int _x;    /* only evaluate n once */                    \
							 | 
						|
								    for( _x = ( n ), elt = list, hook = &list; _x && elt; \
							 | 
						|
								         _x--, hook = &elt->next, elt = elt->next )    \
							 | 
						|
								    {                                                     \
							 | 
						|
								    }                                                     \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* set n to the length of the list */
							 | 
						|
								#define list_length( listtype, list, n ) \
							 | 
						|
								    MACRO_BEGIN                          \
							 | 
						|
								    listtype * _elt;                      \
							 | 
						|
								    n = 0;                               \
							 | 
						|
								    list_forall( _elt, list ) n++;       \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* set n to the index of the first element satisfying cond, or -1 if
							 | 
						|
								 *  none found. Also set elt to the element, or NULL if none found. */
							 | 
						|
								#define list_index( list, n, elt, c ) \
							 | 
						|
								    MACRO_BEGIN                       \
							 | 
						|
								    n = 0;                            \
							 | 
						|
								    list_forall( elt, list )          \
							 | 
						|
								    {                                 \
							 | 
						|
								        if( c )                       \
							 | 
						|
								            break;                    \
							 | 
						|
								        n++;                          \
							 | 
						|
								    }                                 \
							 | 
						|
								    if( !elt )                        \
							 | 
						|
								        n = -1;                       \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* set n to the number of elements in the list that satisfy condition c */
							 | 
						|
								#define list_count( list, n, elt, c ) \
							 | 
						|
								    MACRO_BEGIN                       \
							 | 
						|
								    n = 0;                            \
							 | 
						|
								    list_forall( elt, list )          \
							 | 
						|
								    {                                 \
							 | 
						|
								        if( c )                       \
							 | 
						|
								            n++;                      \
							 | 
						|
								    }                                 \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* let elt be each element of the list, unlinked. At the end, set list=NULL. */
							 | 
						|
								#define list_forall_unlink( elt, list ) \
							 | 
						|
								    for( elt = list; elt ? ( list = elt->next, elt->next = NULL ), 1 : 0; elt = list )
							 | 
						|
								
							 | 
						|
								/* reverse a list (efficient) */
							 | 
						|
								#define list_reverse( listtype, list )                           \
							 | 
						|
								    MACRO_BEGIN                                                  \
							 | 
						|
								    listtype * _list1 = NULL, *elt;                               \
							 | 
						|
								    list_forall_unlink( elt, list ) list_prepend( _list1, elt ); \
							 | 
						|
								    list = _list1;                                               \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* insert the element ELT just before the first element TMP of the
							 | 
						|
								 *  list for which COND holds. Here COND must be a condition of ELT and
							 | 
						|
								 *  TMP.  Typical usage is to insert an element into an ordered list:
							 | 
						|
								 *  for instance, list_insert_ordered(listtype, list, elt, tmp,
							 | 
						|
								 *  elt->size <= tmp->size).  Note: if we give a "less than or equal"
							 | 
						|
								 *  condition, the new element will be inserted just before a sequence
							 | 
						|
								 *  of equal elements. If we give a "less than" condition, the new
							 | 
						|
								 *  element will be inserted just after a list of equal elements.
							 | 
						|
								 *  Note: it is much more efficient to construct a list with
							 | 
						|
								 *  list_prepend and then order it with list_merge_sort, than to
							 | 
						|
								 *  construct it with list_insert_ordered. */
							 | 
						|
								#define list_insert_ordered( listtype, list, elt, tmp, cond )   \
							 | 
						|
								    MACRO_BEGIN                                                 \
							 | 
						|
								    listtype * *_hook;                                           \
							 | 
						|
								    _list_find_hook( list, ( tmp = *_hook, ( cond ) ), _hook ); \
							 | 
						|
								    list_insert_athook( elt, _hook );                           \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* sort the given list, according to the comparison condition.
							 | 
						|
								 *  Typical usage is list_sort(listtype, list, a, b, a->size <
							 | 
						|
								 *  b->size).  Note: if we give "less than or equal" condition, each
							 | 
						|
								 *  segment of equal elements will be reversed in order. If we give a
							 | 
						|
								 *  "less than" condition, each segment of equal elements will retain
							 | 
						|
								 *  the original order. The latter is slower but sometimes
							 | 
						|
								 *  prettier. Average running time: n*n/2. */
							 | 
						|
								#define list_sort( listtype, list, a, b, cond )                                          \
							 | 
						|
								    MACRO_BEGIN                                                                          \
							 | 
						|
								    listtype * _newlist = NULL;                                                           \
							 | 
						|
								    list_forall_unlink( a, list ) list_insert_ordered( listtype, _newlist, a, b, cond ); \
							 | 
						|
								    list = _newlist;                                                                     \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* a much faster sort algorithm (merge sort, n log n worst case). It
							 | 
						|
								 *  is required that the list type has an additional, unused next1
							 | 
						|
								 *  component. Note there is no curious reversal of order of equal
							 | 
						|
								 *  elements as for list_sort. */
							 | 
						|
								
							 | 
						|
								#define list_mergesort( listtype, list, a, b, cond )                 \
							 | 
						|
								    MACRO_BEGIN                                                      \
							 | 
						|
								    listtype * _elt, **_hook1;                                        \
							 | 
						|
								                                                                     \
							 | 
						|
								    for( _elt = list; _elt; _elt = _elt->next1 )                     \
							 | 
						|
								    {                                                                \
							 | 
						|
								        _elt->next1 = _elt->next;                                    \
							 | 
						|
								        _elt->next  = NULL;                                           \
							 | 
						|
								    }                                                                \
							 | 
						|
								    do                                                               \
							 | 
						|
								    {                                                                \
							 | 
						|
								        _hook1 = &( list );                                          \
							 | 
						|
								        while( ( a = *_hook1 ) != NULL && ( b = a->next1 ) != NULL ) \
							 | 
						|
								        {                                                            \
							 | 
						|
								            _elt = b->next1;                                         \
							 | 
						|
								            _list_merge_cond( listtype, a, b, cond, *_hook1 );       \
							 | 
						|
								            _hook1  = &( ( *_hook1 )->next1 );                        \
							 | 
						|
								            *_hook1 = _elt;                                          \
							 | 
						|
								        }                                                            \
							 | 
						|
								    } \
							 | 
						|
								    while( _hook1 != &( list ) );                                  \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* merge two sorted lists. Store result at &result */
							 | 
						|
								#define _list_merge_cond( listtype, a, b, cond, result ) \
							 | 
						|
								    MACRO_BEGIN                                          \
							 | 
						|
								    listtype * *_hook;                                    \
							 | 
						|
								    _hook = &( result );                                 \
							 | 
						|
								    while( 1 )                                           \
							 | 
						|
								    {                                                    \
							 | 
						|
								        if( a == NULL )                                  \
							 | 
						|
								        {                                                \
							 | 
						|
								            *_hook = b;                                  \
							 | 
						|
								            break;                                       \
							 | 
						|
								        }                                                \
							 | 
						|
								        else if( b == NULL )                             \
							 | 
						|
								        {                                                \
							 | 
						|
								            *_hook = a;                                  \
							 | 
						|
								            break;                                       \
							 | 
						|
								        }                                                \
							 | 
						|
								        else if( cond )                                  \
							 | 
						|
								        {                                                \
							 | 
						|
								            *_hook  = a;                                  \
							 | 
						|
								            _hook   = &( a->next );                        \
							 | 
						|
								            a = a->next;                                 \
							 | 
						|
								        }                                                \
							 | 
						|
								        else                                             \
							 | 
						|
								        {                                                \
							 | 
						|
								            *_hook  = b;                                  \
							 | 
						|
								            _hook   = &( b->next );                        \
							 | 
						|
								            b = b->next;                                 \
							 | 
						|
								        }                                                \
							 | 
						|
								    }                                                    \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* ---------------------------------------------------------------------- */
							 | 
						|
								/* macros for doubly-linked lists */
							 | 
						|
								
							 | 
						|
								#define dlist_append( head, end, elt ) \
							 | 
						|
								    MACRO_BEGIN                        \
							 | 
						|
								    elt->prev   = end;                   \
							 | 
						|
								    elt->next   = NULL;                  \
							 | 
						|
								    if( end )                          \
							 | 
						|
								    {                                  \
							 | 
						|
								        end->next = elt;               \
							 | 
						|
								    }                                  \
							 | 
						|
								    else                               \
							 | 
						|
								    {                                  \
							 | 
						|
								        head = elt;                    \
							 | 
						|
								    }                                  \
							 | 
						|
								    end = elt;                         \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								/* let elt be each element of the list, unlinked. At the end, set list=NULL. */
							 | 
						|
								#define dlist_forall_unlink( elt, head, end )                                                      \
							 | 
						|
								    for( elt = head;                                                                               \
							 | 
						|
								         elt ? ( head = elt->next, elt->next = NULL, elt->prev = NULL ), 1 : ( end = NULL, 0 ); \
							 | 
						|
								         elt = head )
							 | 
						|
								
							 | 
						|
								/* unlink the first element of the list */
							 | 
						|
								#define dlist_unlink_first( head, end, elt ) \
							 | 
						|
								    MACRO_BEGIN                              \
							 | 
						|
								    elt = head;                              \
							 | 
						|
								    if( head )                               \
							 | 
						|
								    {                                        \
							 | 
						|
								        head = head->next;                   \
							 | 
						|
								        if( head )                           \
							 | 
						|
								        {                                    \
							 | 
						|
								            head->prev = NULL;               \
							 | 
						|
								        }                                    \
							 | 
						|
								        else                                 \
							 | 
						|
								        {                                    \
							 | 
						|
								            end = NULL;                      \
							 | 
						|
								        }                                    \
							 | 
						|
								        elt->prev   = NULL;                    \
							 | 
						|
								        elt->next   = NULL;                    \
							 | 
						|
								    }                                        \
							 | 
						|
								    MACRO_END
							 | 
						|
								
							 | 
						|
								#endif /* _PS_LISTS_H */
							 |