ngspice/src/include/lsort.h

125 lines
2.8 KiB
C

/*
* 'Generic' linked-list sorting 'package'
*
* Use:
* #define TYPE the linked-list type (usually a struct)
* #define NEXT 'next' field name in the linked-list structure
* #define SORT sorting routine (see below)
*
* Optional:
* #define DECL_SORT 'static' or undefined
* #define DECL_SORT1 'static' or undefined
* #define SORT1 sorting routine (see below)
* #define FIELD select a subfield of the structure for the
* compare function (default is to pass
* a pointer to the structure)
* #include "lsort.h"
*
* This defines up to two routines:
* SORT1(TYPE *list, int (*compare)(TYPE *x, TYPE *y))
* sort the linked list 'list' according to the compare function
* 'compare'
*
* SORT(TYPE *list, int (*compare)(TYPE *x, TYPE *y), int length)
* sort the linked list 'list' according to the compare function
* 'compare'. length is the length of the linked list.
*
* Both routines gracefully handle length == 0 (in which case, list == 0
* is also allowed).
*
* By default, both routines are declared 'static'. This can be changed
* using '#define DECL_SORT' or '#define DECL_SORT1'.
*
* If field is used, then a pointer to the particular field is passed
* to the comparison function (rather than a TYPE *).
*/
/* This file was originally part of Cider 1b1 and has been moved to
* the ngspice misc directory since macros will probably be converted
* into real functions.
* (Paolo Nenzi 2001)
*/
#ifndef DECL_SORT1
#define DECL_SORT1 static
#endif
#ifndef DECL_SORT
#define DECL_SORT static
#endif
DECL_SORT TYPE *SORT();
#ifdef SORT1
DECL_SORT1 TYPE *SORT1(list_in, compare)
TYPE *list_in;
int (*compare)();
{
register long cnt;
register TYPE *p;
/* Find the length of the list */
for(p = list_in, cnt = 0; p != 0; p = p->NEXT, cnt++)
;
return SORT(list_in, compare, cnt);
}
#endif
DECL_SORT TYPE *SORT(list_in, compare, cnt)
TYPE *list_in;
int (*compare)();
long cnt;
{
register TYPE *p, **plast, *list1, *list2;
register long i;
if (cnt > 1) {
/* break the list in half */
for(p = list_in, i = cnt/2-1; i > 0; p = p->NEXT, i--)
;
list1 = list_in;
list2 = p->NEXT;
p->NEXT = 0;
/* Recursively sort the sub-lists (unless only 1 element) */
if ((i = cnt/2) > 1) {
list1 = SORT(list1, compare, i);
}
if ((i = cnt - i) > 1) {
list2 = SORT(list2, compare, i);
}
/* Merge the two sorted sub-lists */
plast = &list_in;
for(;;) {
#ifdef FIELD
if ((*compare)(&list1->FIELD, &list2->FIELD) <= 0) {
#else
if ((*compare)(list1, list2) <= 0) {
#endif
*plast = list1;
plast = &(list1->NEXT);
if ((list1 = list1->NEXT) == 0) {
*plast = list2;
break;
}
} else {
*plast = list2;
plast = &(list2->NEXT);
if ((list2 = list2->NEXT) == 0) {
*plast = list1;
break;
}
}
}
}
return list_in;
}