#line 1 "numpy/core/src/npysort/quicksort.c.src"

/*
 *****************************************************************************
 **       This file was autogenerated from a template  DO NOT EDIT!!!!      **
 **       Changes should be made to the original source (.src) file         **
 *****************************************************************************
 */

#line 1
/* -*- c -*- */

/*
 * The purpose of this module is to add faster sort functions
 * that are type-specific.  This is done by altering the
 * function table for the builtin descriptors.
 *
 * These sorting functions are copied almost directly from numarray
 * with a few modifications (complex comparisons compare the imaginary
 * part if the real parts are equal, for example), and the names
 * are changed.
 *
 * The original sorting code is due to Charles R. Harris who wrote
 * it for numarray.
 */

/*
 * Quick sort is usually the fastest, but the worst case scenario is O(N^2) so
 * the code switches to the O(NlogN) worst case heapsort if not enough progress
 * is made on the large side of the two quicksort partitions. This improves the
 * worst case while still retaining the speed of quicksort for the common case.
 * This is variant known as introsort.
 *
 *
 * def introsort(lower, higher, recursion_limit=log2(higher - lower + 1) * 2):
 *   # sort remainder with heapsort if we are not making enough progress
 *   # we arbitrarily choose 2 * log(n) as the cutoff point
 *   if recursion_limit < 0:
 *       heapsort(lower, higher)
 *       return
 *
 *   if lower < higher:
 *      pivot_pos = partition(lower, higher)
 *      # recurse into smaller first and leave larger on stack
 *      # this limits the required stack space
 *      if (pivot_pos - lower > higher - pivot_pos):
 *          quicksort(pivot_pos + 1, higher, recursion_limit - 1)
 *          quicksort(lower, pivot_pos, recursion_limit - 1)
 *      else:
 *          quicksort(lower, pivot_pos, recursion_limit - 1)
 *          quicksort(pivot_pos + 1, higher, recursion_limit - 1)
 *
 *
 * the below code implements this converted to an iteration and as an
 * additional minor optimization skips the recursion depth checking on the
 * smaller partition as it is always less than half of the remaining data and
 * will thus terminate fast enough
 */

#define NPY_NO_DEPRECATED_API NPY_API_VERSION

#include "npy_sort.h"
#include "npysort_common.h"
#include <stdlib.h>

#define NOT_USED NPY_UNUSED(unused)
/*
 * pushing largest partition has upper bound of log2(n) space
 * we store two pointers each time
 */
#define PYA_QS_STACK (NPY_BITSOF_INTP * 2)
#define SMALL_QUICKSORT 15
#define SMALL_MERGESORT 20
#define SMALL_STRING 16


/*
 *****************************************************************************
 **                            NUMERIC SORTS                                **
 *****************************************************************************
 */


#line 87

NPY_NO_EXPORT int
quicksort_bool(void *start, npy_intp num, void *NOT_USED)
{
    npy_bool vp;
    npy_bool *pl = start;
    npy_bool *pr = pl + num - 1;
    npy_bool *stack[PYA_QS_STACK];
    npy_bool **sptr = stack;
    npy_bool *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_bool(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (BOOL_LT(*pm, *pl)) BOOL_SWAP(*pm, *pl);
            if (BOOL_LT(*pr, *pm)) BOOL_SWAP(*pr, *pm);
            if (BOOL_LT(*pm, *pl)) BOOL_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            BOOL_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (BOOL_LT(*pi, vp));
                do --pj; while (BOOL_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                BOOL_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            BOOL_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && BOOL_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_bool(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_bool *v = vv;
    npy_bool vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_bool(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (BOOL_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (BOOL_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (BOOL_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (BOOL_LT(v[*pi], vp));
                do --pj; while (BOOL_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && BOOL_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_byte(void *start, npy_intp num, void *NOT_USED)
{
    npy_byte vp;
    npy_byte *pl = start;
    npy_byte *pr = pl + num - 1;
    npy_byte *stack[PYA_QS_STACK];
    npy_byte **sptr = stack;
    npy_byte *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_byte(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (BYTE_LT(*pm, *pl)) BYTE_SWAP(*pm, *pl);
            if (BYTE_LT(*pr, *pm)) BYTE_SWAP(*pr, *pm);
            if (BYTE_LT(*pm, *pl)) BYTE_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            BYTE_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (BYTE_LT(*pi, vp));
                do --pj; while (BYTE_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                BYTE_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            BYTE_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && BYTE_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_byte(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_byte *v = vv;
    npy_byte vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_byte(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (BYTE_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (BYTE_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (BYTE_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (BYTE_LT(v[*pi], vp));
                do --pj; while (BYTE_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && BYTE_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_ubyte(void *start, npy_intp num, void *NOT_USED)
{
    npy_ubyte vp;
    npy_ubyte *pl = start;
    npy_ubyte *pr = pl + num - 1;
    npy_ubyte *stack[PYA_QS_STACK];
    npy_ubyte **sptr = stack;
    npy_ubyte *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_ubyte(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (UBYTE_LT(*pm, *pl)) UBYTE_SWAP(*pm, *pl);
            if (UBYTE_LT(*pr, *pm)) UBYTE_SWAP(*pr, *pm);
            if (UBYTE_LT(*pm, *pl)) UBYTE_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            UBYTE_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (UBYTE_LT(*pi, vp));
                do --pj; while (UBYTE_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                UBYTE_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            UBYTE_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && UBYTE_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_ubyte(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_ubyte *v = vv;
    npy_ubyte vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_ubyte(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (UBYTE_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (UBYTE_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (UBYTE_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (UBYTE_LT(v[*pi], vp));
                do --pj; while (UBYTE_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && UBYTE_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_short(void *start, npy_intp num, void *NOT_USED)
{
    npy_short vp;
    npy_short *pl = start;
    npy_short *pr = pl + num - 1;
    npy_short *stack[PYA_QS_STACK];
    npy_short **sptr = stack;
    npy_short *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_short(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (SHORT_LT(*pm, *pl)) SHORT_SWAP(*pm, *pl);
            if (SHORT_LT(*pr, *pm)) SHORT_SWAP(*pr, *pm);
            if (SHORT_LT(*pm, *pl)) SHORT_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            SHORT_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (SHORT_LT(*pi, vp));
                do --pj; while (SHORT_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                SHORT_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            SHORT_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && SHORT_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_short(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_short *v = vv;
    npy_short vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_short(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (SHORT_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (SHORT_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (SHORT_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (SHORT_LT(v[*pi], vp));
                do --pj; while (SHORT_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && SHORT_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_ushort(void *start, npy_intp num, void *NOT_USED)
{
    npy_ushort vp;
    npy_ushort *pl = start;
    npy_ushort *pr = pl + num - 1;
    npy_ushort *stack[PYA_QS_STACK];
    npy_ushort **sptr = stack;
    npy_ushort *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_ushort(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (USHORT_LT(*pm, *pl)) USHORT_SWAP(*pm, *pl);
            if (USHORT_LT(*pr, *pm)) USHORT_SWAP(*pr, *pm);
            if (USHORT_LT(*pm, *pl)) USHORT_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            USHORT_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (USHORT_LT(*pi, vp));
                do --pj; while (USHORT_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                USHORT_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            USHORT_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && USHORT_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_ushort(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_ushort *v = vv;
    npy_ushort vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_ushort(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (USHORT_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (USHORT_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (USHORT_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (USHORT_LT(v[*pi], vp));
                do --pj; while (USHORT_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && USHORT_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_int(void *start, npy_intp num, void *NOT_USED)
{
    npy_int vp;
    npy_int *pl = start;
    npy_int *pr = pl + num - 1;
    npy_int *stack[PYA_QS_STACK];
    npy_int **sptr = stack;
    npy_int *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_int(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (INT_LT(*pm, *pl)) INT_SWAP(*pm, *pl);
            if (INT_LT(*pr, *pm)) INT_SWAP(*pr, *pm);
            if (INT_LT(*pm, *pl)) INT_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            INT_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (INT_LT(*pi, vp));
                do --pj; while (INT_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                INT_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            INT_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && INT_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_int(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_int *v = vv;
    npy_int vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_int(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (INT_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (INT_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (INT_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (INT_LT(v[*pi], vp));
                do --pj; while (INT_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && INT_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_uint(void *start, npy_intp num, void *NOT_USED)
{
    npy_uint vp;
    npy_uint *pl = start;
    npy_uint *pr = pl + num - 1;
    npy_uint *stack[PYA_QS_STACK];
    npy_uint **sptr = stack;
    npy_uint *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_uint(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (UINT_LT(*pm, *pl)) UINT_SWAP(*pm, *pl);
            if (UINT_LT(*pr, *pm)) UINT_SWAP(*pr, *pm);
            if (UINT_LT(*pm, *pl)) UINT_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            UINT_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (UINT_LT(*pi, vp));
                do --pj; while (UINT_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                UINT_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            UINT_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && UINT_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_uint(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_uint *v = vv;
    npy_uint vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_uint(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (UINT_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (UINT_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (UINT_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (UINT_LT(v[*pi], vp));
                do --pj; while (UINT_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && UINT_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_long(void *start, npy_intp num, void *NOT_USED)
{
    npy_long vp;
    npy_long *pl = start;
    npy_long *pr = pl + num - 1;
    npy_long *stack[PYA_QS_STACK];
    npy_long **sptr = stack;
    npy_long *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_long(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (LONG_LT(*pm, *pl)) LONG_SWAP(*pm, *pl);
            if (LONG_LT(*pr, *pm)) LONG_SWAP(*pr, *pm);
            if (LONG_LT(*pm, *pl)) LONG_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            LONG_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (LONG_LT(*pi, vp));
                do --pj; while (LONG_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                LONG_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            LONG_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && LONG_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_long(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_long *v = vv;
    npy_long vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_long(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (LONG_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (LONG_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (LONG_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (LONG_LT(v[*pi], vp));
                do --pj; while (LONG_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && LONG_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_ulong(void *start, npy_intp num, void *NOT_USED)
{
    npy_ulong vp;
    npy_ulong *pl = start;
    npy_ulong *pr = pl + num - 1;
    npy_ulong *stack[PYA_QS_STACK];
    npy_ulong **sptr = stack;
    npy_ulong *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_ulong(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (ULONG_LT(*pm, *pl)) ULONG_SWAP(*pm, *pl);
            if (ULONG_LT(*pr, *pm)) ULONG_SWAP(*pr, *pm);
            if (ULONG_LT(*pm, *pl)) ULONG_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            ULONG_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (ULONG_LT(*pi, vp));
                do --pj; while (ULONG_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                ULONG_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            ULONG_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && ULONG_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_ulong(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_ulong *v = vv;
    npy_ulong vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_ulong(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (ULONG_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (ULONG_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (ULONG_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (ULONG_LT(v[*pi], vp));
                do --pj; while (ULONG_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && ULONG_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_longlong(void *start, npy_intp num, void *NOT_USED)
{
    npy_longlong vp;
    npy_longlong *pl = start;
    npy_longlong *pr = pl + num - 1;
    npy_longlong *stack[PYA_QS_STACK];
    npy_longlong **sptr = stack;
    npy_longlong *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_longlong(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (LONGLONG_LT(*pm, *pl)) LONGLONG_SWAP(*pm, *pl);
            if (LONGLONG_LT(*pr, *pm)) LONGLONG_SWAP(*pr, *pm);
            if (LONGLONG_LT(*pm, *pl)) LONGLONG_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            LONGLONG_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (LONGLONG_LT(*pi, vp));
                do --pj; while (LONGLONG_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                LONGLONG_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            LONGLONG_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && LONGLONG_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_longlong(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_longlong *v = vv;
    npy_longlong vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_longlong(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (LONGLONG_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (LONGLONG_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (LONGLONG_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (LONGLONG_LT(v[*pi], vp));
                do --pj; while (LONGLONG_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && LONGLONG_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_ulonglong(void *start, npy_intp num, void *NOT_USED)
{
    npy_ulonglong vp;
    npy_ulonglong *pl = start;
    npy_ulonglong *pr = pl + num - 1;
    npy_ulonglong *stack[PYA_QS_STACK];
    npy_ulonglong **sptr = stack;
    npy_ulonglong *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_ulonglong(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (ULONGLONG_LT(*pm, *pl)) ULONGLONG_SWAP(*pm, *pl);
            if (ULONGLONG_LT(*pr, *pm)) ULONGLONG_SWAP(*pr, *pm);
            if (ULONGLONG_LT(*pm, *pl)) ULONGLONG_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            ULONGLONG_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (ULONGLONG_LT(*pi, vp));
                do --pj; while (ULONGLONG_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                ULONGLONG_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            ULONGLONG_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && ULONGLONG_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_ulonglong(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_ulonglong *v = vv;
    npy_ulonglong vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_ulonglong(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (ULONGLONG_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (ULONGLONG_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (ULONGLONG_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (ULONGLONG_LT(v[*pi], vp));
                do --pj; while (ULONGLONG_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && ULONGLONG_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_half(void *start, npy_intp num, void *NOT_USED)
{
    npy_ushort vp;
    npy_ushort *pl = start;
    npy_ushort *pr = pl + num - 1;
    npy_ushort *stack[PYA_QS_STACK];
    npy_ushort **sptr = stack;
    npy_ushort *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_half(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (HALF_LT(*pm, *pl)) HALF_SWAP(*pm, *pl);
            if (HALF_LT(*pr, *pm)) HALF_SWAP(*pr, *pm);
            if (HALF_LT(*pm, *pl)) HALF_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            HALF_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (HALF_LT(*pi, vp));
                do --pj; while (HALF_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                HALF_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            HALF_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && HALF_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_half(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_ushort *v = vv;
    npy_ushort vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_half(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (HALF_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (HALF_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (HALF_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (HALF_LT(v[*pi], vp));
                do --pj; while (HALF_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && HALF_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_float(void *start, npy_intp num, void *NOT_USED)
{
    npy_float vp;
    npy_float *pl = start;
    npy_float *pr = pl + num - 1;
    npy_float *stack[PYA_QS_STACK];
    npy_float **sptr = stack;
    npy_float *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_float(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (FLOAT_LT(*pm, *pl)) FLOAT_SWAP(*pm, *pl);
            if (FLOAT_LT(*pr, *pm)) FLOAT_SWAP(*pr, *pm);
            if (FLOAT_LT(*pm, *pl)) FLOAT_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            FLOAT_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (FLOAT_LT(*pi, vp));
                do --pj; while (FLOAT_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                FLOAT_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            FLOAT_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && FLOAT_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_float(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_float *v = vv;
    npy_float vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_float(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (FLOAT_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (FLOAT_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (FLOAT_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (FLOAT_LT(v[*pi], vp));
                do --pj; while (FLOAT_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && FLOAT_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_double(void *start, npy_intp num, void *NOT_USED)
{
    npy_double vp;
    npy_double *pl = start;
    npy_double *pr = pl + num - 1;
    npy_double *stack[PYA_QS_STACK];
    npy_double **sptr = stack;
    npy_double *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_double(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (DOUBLE_LT(*pm, *pl)) DOUBLE_SWAP(*pm, *pl);
            if (DOUBLE_LT(*pr, *pm)) DOUBLE_SWAP(*pr, *pm);
            if (DOUBLE_LT(*pm, *pl)) DOUBLE_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            DOUBLE_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (DOUBLE_LT(*pi, vp));
                do --pj; while (DOUBLE_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                DOUBLE_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            DOUBLE_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && DOUBLE_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_double(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_double *v = vv;
    npy_double vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_double(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (DOUBLE_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (DOUBLE_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (DOUBLE_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (DOUBLE_LT(v[*pi], vp));
                do --pj; while (DOUBLE_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && DOUBLE_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_longdouble(void *start, npy_intp num, void *NOT_USED)
{
    npy_longdouble vp;
    npy_longdouble *pl = start;
    npy_longdouble *pr = pl + num - 1;
    npy_longdouble *stack[PYA_QS_STACK];
    npy_longdouble **sptr = stack;
    npy_longdouble *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_longdouble(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (LONGDOUBLE_LT(*pm, *pl)) LONGDOUBLE_SWAP(*pm, *pl);
            if (LONGDOUBLE_LT(*pr, *pm)) LONGDOUBLE_SWAP(*pr, *pm);
            if (LONGDOUBLE_LT(*pm, *pl)) LONGDOUBLE_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            LONGDOUBLE_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (LONGDOUBLE_LT(*pi, vp));
                do --pj; while (LONGDOUBLE_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                LONGDOUBLE_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            LONGDOUBLE_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && LONGDOUBLE_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_longdouble(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_longdouble *v = vv;
    npy_longdouble vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_longdouble(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (LONGDOUBLE_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (LONGDOUBLE_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (LONGDOUBLE_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (LONGDOUBLE_LT(v[*pi], vp));
                do --pj; while (LONGDOUBLE_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && LONGDOUBLE_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_cfloat(void *start, npy_intp num, void *NOT_USED)
{
    npy_cfloat vp;
    npy_cfloat *pl = start;
    npy_cfloat *pr = pl + num - 1;
    npy_cfloat *stack[PYA_QS_STACK];
    npy_cfloat **sptr = stack;
    npy_cfloat *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_cfloat(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (CFLOAT_LT(*pm, *pl)) CFLOAT_SWAP(*pm, *pl);
            if (CFLOAT_LT(*pr, *pm)) CFLOAT_SWAP(*pr, *pm);
            if (CFLOAT_LT(*pm, *pl)) CFLOAT_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            CFLOAT_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (CFLOAT_LT(*pi, vp));
                do --pj; while (CFLOAT_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                CFLOAT_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            CFLOAT_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && CFLOAT_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_cfloat(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_cfloat *v = vv;
    npy_cfloat vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_cfloat(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (CFLOAT_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (CFLOAT_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (CFLOAT_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (CFLOAT_LT(v[*pi], vp));
                do --pj; while (CFLOAT_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && CFLOAT_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_cdouble(void *start, npy_intp num, void *NOT_USED)
{
    npy_cdouble vp;
    npy_cdouble *pl = start;
    npy_cdouble *pr = pl + num - 1;
    npy_cdouble *stack[PYA_QS_STACK];
    npy_cdouble **sptr = stack;
    npy_cdouble *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_cdouble(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (CDOUBLE_LT(*pm, *pl)) CDOUBLE_SWAP(*pm, *pl);
            if (CDOUBLE_LT(*pr, *pm)) CDOUBLE_SWAP(*pr, *pm);
            if (CDOUBLE_LT(*pm, *pl)) CDOUBLE_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            CDOUBLE_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (CDOUBLE_LT(*pi, vp));
                do --pj; while (CDOUBLE_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                CDOUBLE_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            CDOUBLE_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && CDOUBLE_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_cdouble(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_cdouble *v = vv;
    npy_cdouble vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_cdouble(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (CDOUBLE_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (CDOUBLE_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (CDOUBLE_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (CDOUBLE_LT(v[*pi], vp));
                do --pj; while (CDOUBLE_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && CDOUBLE_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_clongdouble(void *start, npy_intp num, void *NOT_USED)
{
    npy_clongdouble vp;
    npy_clongdouble *pl = start;
    npy_clongdouble *pr = pl + num - 1;
    npy_clongdouble *stack[PYA_QS_STACK];
    npy_clongdouble **sptr = stack;
    npy_clongdouble *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_clongdouble(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (CLONGDOUBLE_LT(*pm, *pl)) CLONGDOUBLE_SWAP(*pm, *pl);
            if (CLONGDOUBLE_LT(*pr, *pm)) CLONGDOUBLE_SWAP(*pr, *pm);
            if (CLONGDOUBLE_LT(*pm, *pl)) CLONGDOUBLE_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            CLONGDOUBLE_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (CLONGDOUBLE_LT(*pi, vp));
                do --pj; while (CLONGDOUBLE_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                CLONGDOUBLE_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            CLONGDOUBLE_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && CLONGDOUBLE_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_clongdouble(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_clongdouble *v = vv;
    npy_clongdouble vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_clongdouble(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (CLONGDOUBLE_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (CLONGDOUBLE_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (CLONGDOUBLE_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (CLONGDOUBLE_LT(v[*pi], vp));
                do --pj; while (CLONGDOUBLE_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && CLONGDOUBLE_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_datetime(void *start, npy_intp num, void *NOT_USED)
{
    npy_datetime vp;
    npy_datetime *pl = start;
    npy_datetime *pr = pl + num - 1;
    npy_datetime *stack[PYA_QS_STACK];
    npy_datetime **sptr = stack;
    npy_datetime *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_datetime(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (DATETIME_LT(*pm, *pl)) DATETIME_SWAP(*pm, *pl);
            if (DATETIME_LT(*pr, *pm)) DATETIME_SWAP(*pr, *pm);
            if (DATETIME_LT(*pm, *pl)) DATETIME_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            DATETIME_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (DATETIME_LT(*pi, vp));
                do --pj; while (DATETIME_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                DATETIME_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            DATETIME_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && DATETIME_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_datetime(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_datetime *v = vv;
    npy_datetime vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_datetime(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (DATETIME_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (DATETIME_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (DATETIME_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (DATETIME_LT(v[*pi], vp));
                do --pj; while (DATETIME_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && DATETIME_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 87

NPY_NO_EXPORT int
quicksort_timedelta(void *start, npy_intp num, void *NOT_USED)
{
    npy_timedelta vp;
    npy_timedelta *pl = start;
    npy_timedelta *pr = pl + num - 1;
    npy_timedelta *stack[PYA_QS_STACK];
    npy_timedelta **sptr = stack;
    npy_timedelta *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_timedelta(pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (TIMEDELTA_LT(*pm, *pl)) TIMEDELTA_SWAP(*pm, *pl);
            if (TIMEDELTA_LT(*pr, *pm)) TIMEDELTA_SWAP(*pr, *pm);
            if (TIMEDELTA_LT(*pm, *pl)) TIMEDELTA_SWAP(*pm, *pl);
            vp = *pm;
            pi = pl;
            pj = pr - 1;
            TIMEDELTA_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (TIMEDELTA_LT(*pi, vp));
                do --pj; while (TIMEDELTA_LT(vp, *pj));
                if (pi >= pj) {
                    break;
                }
                TIMEDELTA_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            TIMEDELTA_SWAP(*pi, *pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vp = *pi;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && TIMEDELTA_LT(vp, *pk)) {
                *pj-- = *pk--;
            }
            *pj = vp;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


NPY_NO_EXPORT int
aquicksort_timedelta(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
    npy_timedelta *v = vv;
    npy_timedelta vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_timedelta(vv, pl, pr - pl + 1, NULL);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (TIMEDELTA_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            if (TIMEDELTA_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
            if (TIMEDELTA_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
            vp = v[*pm];
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm, *pj);
            for (;;) {
                do ++pi; while (TIMEDELTA_LT(v[*pi], vp));
                do --pj; while (TIMEDELTA_LT(vp, v[*pj]));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi, *pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v[vi];
            pj = pi;
            pk = pi - 1;
            while (pj > pl && TIMEDELTA_LT(vp, v[*pk])) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}




/*
 *****************************************************************************
 **                             STRING SORTS                                **
 *****************************************************************************
 */


#line 255

NPY_NO_EXPORT int
quicksort_string(void *start, npy_intp num, void *varr)
{
    PyArrayObject *arr = varr;
    const size_t len = PyArray_ITEMSIZE(arr)/sizeof(npy_char);
    npy_char *vp;
    npy_char *pl = start;
    npy_char *pr = pl + (num - 1)*len;
    npy_char *stack[PYA_QS_STACK], **sptr = stack, *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    /* Items that have zero size don't make sense to sort */
    if (len == 0) {
        return 0;
    }

    vp = malloc(PyArray_ITEMSIZE(arr));
    if (vp == NULL) {
        return -NPY_ENOMEM;
    }

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_string(pl, (pr - pl) / len + 1, varr);
            goto stack_pop;
        }
        while ((size_t)(pr - pl) > SMALL_QUICKSORT*len) {
            /* quicksort partition */
            pm = pl + (((pr - pl)/len) >> 1)*len;
            if (STRING_LT(pm, pl, len)) STRING_SWAP(pm, pl, len);
            if (STRING_LT(pr, pm, len)) STRING_SWAP(pr, pm, len);
            if (STRING_LT(pm, pl, len)) STRING_SWAP(pm, pl, len);
            STRING_COPY(vp, pm, len);
            pi = pl;
            pj = pr - len;
            STRING_SWAP(pm, pj, len);
            for (;;) {
                do pi += len; while (STRING_LT(pi, vp, len));
                do pj -= len; while (STRING_LT(vp, pj, len));
                if (pi >= pj) {
                    break;
                }
                STRING_SWAP(pi, pj, len);
            }
            pk = pr - len;
            STRING_SWAP(pi, pk, len);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + len;
                *sptr++ = pr;
                pr = pi - len;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - len;
                pl = pi + len;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + len; pi <= pr; pi += len) {
            STRING_COPY(vp, pi, len);
            pj = pi;
            pk = pi - len;
            while (pj > pl && STRING_LT(vp, pk, len)) {
                STRING_COPY(pj, pk, len);
                pj -= len;
                pk -= len;
            }
            STRING_COPY(pj, vp, len);
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    free(vp);
    return 0;
}


NPY_NO_EXPORT int
aquicksort_string(void *vv, npy_intp* tosort, npy_intp num, void *varr)
{
    npy_char *v = vv;
    PyArrayObject *arr = varr;
    size_t len = PyArray_ITEMSIZE(arr)/sizeof(npy_char);
    npy_char *vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr=stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    /* Items that have zero size don't make sense to sort */
    if (len == 0) {
        return 0;
    }

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_string(vv, pl, pr - pl + 1, varr);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (STRING_LT(v + (*pm)*len, v + (*pl)*len, len)) INTP_SWAP(*pm, *pl);
            if (STRING_LT(v + (*pr)*len, v + (*pm)*len, len)) INTP_SWAP(*pr, *pm);
            if (STRING_LT(v + (*pm)*len, v + (*pl)*len, len)) INTP_SWAP(*pm, *pl);
            vp = v + (*pm)*len;
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm,*pj);
            for (;;) {
                do ++pi; while (STRING_LT(v + (*pi)*len, vp, len));
                do --pj; while (STRING_LT(vp, v + (*pj)*len, len));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v + vi*len;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && STRING_LT(vp, v + (*pk)*len, len)) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}


#line 255

NPY_NO_EXPORT int
quicksort_unicode(void *start, npy_intp num, void *varr)
{
    PyArrayObject *arr = varr;
    const size_t len = PyArray_ITEMSIZE(arr)/sizeof(npy_ucs4);
    npy_ucs4 *vp;
    npy_ucs4 *pl = start;
    npy_ucs4 *pr = pl + (num - 1)*len;
    npy_ucs4 *stack[PYA_QS_STACK], **sptr = stack, *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    /* Items that have zero size don't make sense to sort */
    if (len == 0) {
        return 0;
    }

    vp = malloc(PyArray_ITEMSIZE(arr));
    if (vp == NULL) {
        return -NPY_ENOMEM;
    }

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            heapsort_unicode(pl, (pr - pl) / len + 1, varr);
            goto stack_pop;
        }
        while ((size_t)(pr - pl) > SMALL_QUICKSORT*len) {
            /* quicksort partition */
            pm = pl + (((pr - pl)/len) >> 1)*len;
            if (UNICODE_LT(pm, pl, len)) UNICODE_SWAP(pm, pl, len);
            if (UNICODE_LT(pr, pm, len)) UNICODE_SWAP(pr, pm, len);
            if (UNICODE_LT(pm, pl, len)) UNICODE_SWAP(pm, pl, len);
            UNICODE_COPY(vp, pm, len);
            pi = pl;
            pj = pr - len;
            UNICODE_SWAP(pm, pj, len);
            for (;;) {
                do pi += len; while (UNICODE_LT(pi, vp, len));
                do pj -= len; while (UNICODE_LT(vp, pj, len));
                if (pi >= pj) {
                    break;
                }
                UNICODE_SWAP(pi, pj, len);
            }
            pk = pr - len;
            UNICODE_SWAP(pi, pk, len);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + len;
                *sptr++ = pr;
                pr = pi - len;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - len;
                pl = pi + len;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + len; pi <= pr; pi += len) {
            UNICODE_COPY(vp, pi, len);
            pj = pi;
            pk = pi - len;
            while (pj > pl && UNICODE_LT(vp, pk, len)) {
                UNICODE_COPY(pj, pk, len);
                pj -= len;
                pk -= len;
            }
            UNICODE_COPY(pj, vp, len);
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    free(vp);
    return 0;
}


NPY_NO_EXPORT int
aquicksort_unicode(void *vv, npy_intp* tosort, npy_intp num, void *varr)
{
    npy_ucs4 *v = vv;
    PyArrayObject *arr = varr;
    size_t len = PyArray_ITEMSIZE(arr)/sizeof(npy_ucs4);
    npy_ucs4 *vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr=stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    /* Items that have zero size don't make sense to sort */
    if (len == 0) {
        return 0;
    }

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            aheapsort_unicode(vv, pl, pr - pl + 1, varr);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (UNICODE_LT(v + (*pm)*len, v + (*pl)*len, len)) INTP_SWAP(*pm, *pl);
            if (UNICODE_LT(v + (*pr)*len, v + (*pm)*len, len)) INTP_SWAP(*pr, *pm);
            if (UNICODE_LT(v + (*pm)*len, v + (*pl)*len, len)) INTP_SWAP(*pm, *pl);
            vp = v + (*pm)*len;
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm,*pj);
            for (;;) {
                do ++pi; while (UNICODE_LT(v + (*pi)*len, vp, len));
                do --pj; while (UNICODE_LT(vp, v + (*pj)*len, len));
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v + vi*len;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && UNICODE_LT(vp, v + (*pk)*len, len)) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}




/*
 *****************************************************************************
 **                             GENERIC SORT                                **
 *****************************************************************************
 */


NPY_NO_EXPORT int
npy_quicksort(void *start, npy_intp num, void *varr)
{
    PyArrayObject *arr = varr;
    npy_intp elsize = PyArray_ITEMSIZE(arr);
    PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
    char *vp;
    char *pl = start;
    char *pr = pl + (num - 1)*elsize;
    char *stack[PYA_QS_STACK];
    char **sptr = stack;
    char *pm, *pi, *pj, *pk;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    /* Items that have zero size don't make sense to sort */
    if (elsize == 0) {
        return 0;
    }

    vp = malloc(elsize);
    if (vp == NULL) {
        return -NPY_ENOMEM;
    }

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            npy_heapsort(pl, (pr - pl) / elsize + 1, varr);
            goto stack_pop;
        }
        while(pr - pl > SMALL_QUICKSORT*elsize) {
            /* quicksort partition */
            pm = pl + (((pr - pl) / elsize) >> 1) * elsize;
            if (cmp(pm, pl, arr) < 0) {
                GENERIC_SWAP(pm, pl, elsize);
            }
            if (cmp(pr, pm, arr) < 0) {
                GENERIC_SWAP(pr, pm, elsize);
            }
            if (cmp(pm, pl, arr) < 0) {
                GENERIC_SWAP(pm, pl, elsize);
            }
            GENERIC_COPY(vp, pm, elsize);
            pi = pl;
            pj = pr - elsize;
            GENERIC_SWAP(pm, pj, elsize);
            /*
             * Generic comparisons may be buggy, so don't rely on the sentinels
             * to keep the pointers from going out of bounds.
             */
            for (;;) {
                do {
                    pi += elsize;
                } while (cmp(pi, vp, arr) < 0 && pi < pj);
                do {
                    pj -= elsize;
                } while (cmp(vp, pj, arr) < 0 && pi < pj);
                if (pi >= pj) {
                    break;
                }
                GENERIC_SWAP(pi, pj, elsize);
            }
            pk = pr - elsize;
            GENERIC_SWAP(pi, pk, elsize);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + elsize;
                *sptr++ = pr;
                pr = pi - elsize;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - elsize;
                pl = pi + elsize;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + elsize; pi <= pr; pi += elsize) {
            GENERIC_COPY(vp, pi, elsize);
            pj = pi;
            pk = pi - elsize;
            while (pj > pl && cmp(vp, pk, arr) < 0) {
                GENERIC_COPY(pj, pk, elsize);
                pj -= elsize;
                pk -= elsize;
            }
            GENERIC_COPY(pj, vp, elsize);
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    free(vp);
    return 0;
}


NPY_NO_EXPORT int
npy_aquicksort(void *vv, npy_intp* tosort, npy_intp num, void *varr)
{
    char *v = vv;
    PyArrayObject *arr = varr;
    npy_intp elsize = PyArray_ITEMSIZE(arr);
    PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
    char *vp;
    npy_intp *pl = tosort;
    npy_intp *pr = tosort + num - 1;
    npy_intp *stack[PYA_QS_STACK];
    npy_intp **sptr = stack;
    npy_intp *pm, *pi, *pj, *pk, vi;
    int depth[PYA_QS_STACK];
    int * psdepth = depth;
    int cdepth = npy_get_msb(num) * 2;

    /* Items that have zero size don't make sense to sort */
    if (elsize == 0) {
        return 0;
    }

    for (;;) {
        if (NPY_UNLIKELY(cdepth < 0)) {
            npy_aheapsort(vv, pl, pr - pl + 1, varr);
            goto stack_pop;
        }
        while ((pr - pl) > SMALL_QUICKSORT) {
            /* quicksort partition */
            pm = pl + ((pr - pl) >> 1);
            if (cmp(v + (*pm)*elsize, v + (*pl)*elsize, arr) < 0) {
                INTP_SWAP(*pm, *pl);
            }
            if (cmp(v + (*pr)*elsize, v + (*pm)*elsize, arr) < 0) {
                INTP_SWAP(*pr, *pm);
            }
            if (cmp(v + (*pm)*elsize, v + (*pl)*elsize, arr) < 0) {
                INTP_SWAP(*pm, *pl);
            }
            vp = v + (*pm)*elsize;
            pi = pl;
            pj = pr - 1;
            INTP_SWAP(*pm,*pj);
            for (;;) {
                do {
                    ++pi;
                } while (cmp(v + (*pi)*elsize, vp, arr) < 0 && pi < pj);
                do {
                    --pj;
                } while (cmp(vp, v + (*pj)*elsize, arr) < 0 && pi < pj);
                if (pi >= pj) {
                    break;
                }
                INTP_SWAP(*pi,*pj);
            }
            pk = pr - 1;
            INTP_SWAP(*pi,*pk);
            /* push largest partition on stack */
            if (pi - pl < pr - pi) {
                *sptr++ = pi + 1;
                *sptr++ = pr;
                pr = pi - 1;
            }
            else {
                *sptr++ = pl;
                *sptr++ = pi - 1;
                pl = pi + 1;
            }
            *psdepth++ = --cdepth;
        }

        /* insertion sort */
        for (pi = pl + 1; pi <= pr; ++pi) {
            vi = *pi;
            vp = v + vi*elsize;
            pj = pi;
            pk = pi - 1;
            while (pj > pl && cmp(vp, v + (*pk)*elsize, arr) < 0) {
                *pj-- = *pk--;
            }
            *pj = vi;
        }
stack_pop:
        if (sptr == stack) {
            break;
        }
        pr = *(--sptr);
        pl = *(--sptr);
        cdepth = *(--psdepth);
    }

    return 0;
}

