diff --git a/src/libCom/ellLib/ellLib.h b/src/libCom/ellLib/ellLib.h index f99859f3d..300a2df3f 100644 --- a/src/libCom/ellLib/ellLib.h +++ b/src/libCom/ellLib/ellLib.h @@ -56,6 +56,8 @@ epicsShareFunc void ellInsert (ELLLIST *plist, ELLNODE *pPrev, ELLNODE *pNode); epicsShareFunc ELLNODE * ellNth (ELLLIST *pList, int nodeNum); epicsShareFunc ELLNODE * ellNStep (ELLNODE *pNode, int nStep); epicsShareFunc int ellFind (ELLLIST *pList, ELLNODE *pNode); +typedef int (*pListCmp)(ELLNODE* A, ELLNODE* B); +epicsShareFunc void ellSortStable(ELLLIST *pList, pListCmp); epicsShareFunc void ellFree2 (ELLLIST *pList, FREEFUNC freeFunc); epicsShareFunc void ellVerify (ELLLIST *pList); diff --git a/src/libCom/ellLib/ellSort.c b/src/libCom/ellLib/ellSort.c new file mode 100644 index 000000000..89f3f3819 --- /dev/null +++ b/src/libCom/ellLib/ellSort.c @@ -0,0 +1,80 @@ +/* + * Use of mergesort algorithm based on analysis by + * http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html + */ +#include + +#define epicsExportSharedSymbols +#include "epicsAssert.h" +#include "ellLib.h" + +static void ellMoveN(ELLLIST* pTo, ELLLIST* pFrom, int count ) +{ + for(;count && ellCount(pFrom); count--) { + ELLNODE *node = ellGet(pFrom); + ellAdd(pTo, node); + } +} + +/* Stable (MergeSort) to given list. + * The comparison function cmp(A,B) is expected + * to return -1 for AB. + */ +void ellSortStable(ELLLIST *pList, pListCmp cmp) +{ + ELLLIST INP, P, Q; + size_t insize = 1; /* initial sub-list size */ + if(ellCount(pList)<=1) + return; + + ellInit(&INP); + ellInit(&P); + ellInit(&Q); + + /* Process is to iteratively sort + * a sequence of sub-lists of size 'insize' + */ + + while(insize < ellCount(pList)) { + + assert(ellCount(&INP)==0); + + /* shift previous results to inputs */ + ellConcat(&INP, pList); + + assert(ellCount(pList)==0); + + while(ellCount(&INP)) + { + ELLNODE *p, *q; + + assert(ellCount(&P)==0); + assert(ellCount(&Q)==0); + + /* Pull out the next pair of sub-lists */ + ellMoveN(&Q, &INP, insize); + ellMoveN(&P, &INP, insize); + + /* merge these sub-lists */ + while((p=ellFirst(&P)) && (q=ellFirst(&Q))) + { + if((*cmp)(p,q) < 0) { + ellAdd(pList, ellGet(&P)); + } else { + ellAdd(pList, ellGet(&Q)); + } + } + + /* concatinate any remaining to result */ + if(ellFirst(&P)) + ellConcat(pList, &P); + else if(ellFirst(&Q)) + ellConcat(pList, &Q); + + assert(!ellFirst(&P) && !ellFirst(&Q)); + } + + insize *= 2; + } + +}