// template qsort adapted from  msdev\crt\src\qsort.c
// created 7/96  bobp

// template<class T>
// void QSort (T *base, unsigned nEl, BOOL fSortUp)
// 
// quicksort array of T
//
// Uses class T member functions:
//    operator =
//  operator <=

#ifndef __TQSORT_INCL
#define __TQSORT_INCL

template<class T>
inline void Swap(T &a, T &b)
{
    T x = a; a = b; b = x;
}

template<class T>
static void __cdecl ShortSort (T *lo, T *hi, BOOL fUp)
{
    T *p, *max;

    while (hi > lo) {
        max = lo;
        if (fUp) {
            for (p = lo+1; p <= hi; p++) {
                if ( !(*p <= *max) )
                    max = p;
            }
        } else {
            for (p = lo+1; p <= hi; p++) {
                if ( !(*max <= *p) )
                    max = p;
            }
        }

        Swap (*max, *hi);

        hi --;
    }
}

#define CUTOFF 8            /* testing shows that this is good value */

template<class T>
void QSort (T *base, unsigned nEl, BOOL fUp)
{
    T *lo, *hi;              /* ends of sub-array currently sorting */
    T *mid;                  /* points to middle of subarray */
    T *loguy, *higuy;        /* traveling pointers for partition step */
    unsigned size;           /* size of the sub-array */
    T *lostk[30], *histk[30];
    int stkptr;              /* stack for saving sub-array to be processed */

    /* Note: the number of stack entries required is no more than
       1 + log2(size), so 30 is sufficient for any array */

    if (nEl < 2)
        return;                 /* nothing to do */

    stkptr = 0;                 /* initialize stack */

    lo = base;
    hi = base + (nEl-1);        /* initialize limits */

recurse:

    size = (int)(hi - lo) + 1;   /* number of el's to sort */

    if (size <= CUTOFF) {
         ShortSort(lo, hi, fUp);
    }
    else {
        mid = lo + (size / 2);   /* find middle element */
        Swap(*mid, *lo);         /* swap it to beginning of array */
        loguy = lo;
        higuy = hi + 1;

        for (;;) {
            if (fUp) {
                do  {
                    loguy ++;
                } while (loguy <= hi && *loguy <= *lo);

                do  {
                    higuy --;
                } while (higuy > lo && *lo <= *higuy);
            } else {
                do  {
                    loguy ++;
                } while (loguy <= hi && *lo <= *loguy);

                do  {
                    higuy --;
                } while (higuy > lo && *higuy <= *lo);
            }

            if (higuy < loguy)
                break;

            Swap(*loguy, *higuy);
        }

        Swap(*lo, *higuy);     /* put partition element in place */

        if ( higuy - 1 - lo >= hi - loguy ) {
            if (lo + 1 < higuy) {
                lostk[stkptr] = lo;
                histk[stkptr] = higuy - 1;
                ++stkptr;
            }                           /* save big recursion for later */

            if (loguy < hi) {
                lo = loguy;
                goto recurse;           /* do small recursion */
            }
        }
        else {
            if (loguy < hi) {
                lostk[stkptr] = loguy;
                histk[stkptr] = hi;
                ++stkptr;               /* save big recursion for later */
            }

            if (lo + 1 < higuy) {
                hi = higuy - 1;
                goto recurse;           /* do small recursion */
            }
        }
    }

    --stkptr;
    if (stkptr >= 0) {
        lo = lostk[stkptr];
        hi = histk[stkptr];
        goto recurse;           /* pop subarray from stack */
    }
}

#endif
