/*
 *****************************************************************************
 **               IMPORTANT NOTE for npy_partition.h.src -> npy_partition.h **
 *****************************************************************************
 *  The template file loops.h.src is not automatically converted into
 *  loops.h by the build system.  If you edit this file, you must manually
 *  do the conversion using numpy/distutils/conv_template.py from the
 *  command line as follows:
 *
 *  $ cd <NumPy source root directory>
 *  $ python  numpy/distutils/conv_template.py numpy/core/src/private/npy_partition.h.src
 *  $
 */


#ifndef __NPY_PARTITION_H__
#define __NPY_PARTITION_H__


#include "npy_sort.h"

/* Python include is for future object sorts */
#include <Python.h>
#include <numpy/npy_common.h>
#include <numpy/ndarraytypes.h>

#define NPY_MAX_PIVOT_STACK 50


/**begin repeat
 *
 * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
 *         LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE,
 *         CFLOAT, CDOUBLE, CLONGDOUBLE#
 * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong,
 *         longlong, ulonglong, half, float, double, longdouble,
 *         cfloat, cdouble, clongdouble#
 * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int,
 *         npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong,
 *         npy_ushort, npy_float, npy_double, npy_longdouble, npy_cfloat,
 *         npy_cdouble, npy_clongdouble#
 */

int introselect_@suff@(@type@ *v, npy_intp num,
                       npy_intp kth,
                       npy_intp * pivots,
                       npy_intp * npiv,
                       void *NOT_USED);
int aintroselect_@suff@(@type@ *v, npy_intp* tosort, npy_intp num,
                        npy_intp kth,
                        npy_intp * pivots,
                        npy_intp * npiv,
                        void *NOT_USED);


/**end repeat**/

int introselect_string(npy_char *vec, npy_intp cnt, npy_intp kth, PyArrayObject *arr);
int aintroselect_string(npy_char *vec, npy_intp *ind, npy_intp cnt, npy_intp kth, void *null);


int introselect_unicode(npy_ucs4 *vec, npy_intp cnt, npy_intp kth, PyArrayObject *arr);
int aintroselect_unicode(npy_ucs4 *vec, npy_intp *ind, npy_intp cnt, npy_intp kth, void *null);

int npy_introselect(void *base, size_t num, size_t size, size_t kth, npy_comparator cmp);

typedef struct {
    enum NPY_TYPES typenum;
    PyArray_PartitionFunc * part[NPY_NSELECTS];
    PyArray_ArgPartitionFunc * argpart[NPY_NSELECTS];
} part_map;

static part_map _part_map[] = {
/**begin repeat
 *
 * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
 *         LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE,
 *         CFLOAT, CDOUBLE, CLONGDOUBLE#
 * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong,
 *         longlong, ulonglong, half, float, double, longdouble,
 *         cfloat, cdouble, clongdouble#
 * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int,
 *         npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong,
 *         npy_ushort, npy_float, npy_double, npy_longdouble, npy_cfloat,
 *         npy_cdouble, npy_clongdouble#
 */
    {
        NPY_@TYPE@,
        {
            (PyArray_PartitionFunc *)&introselect_@suff@,
        },
        {
            (PyArray_ArgPartitionFunc *)&aintroselect_@suff@,
        }
    },
/**end repeat**/
};


static NPY_INLINE PyArray_PartitionFunc *
get_partition_func(int type, NPY_SELECTKIND which)
{
    npy_intp i;
    if (which >= NPY_NSELECTS) {
        return NULL;
    }
    for (i = 0; i < sizeof(_part_map)/sizeof(_part_map[0]); i++) {
        if (type == _part_map[i].typenum) {
            return _part_map[i].part[which];
        }
    }
    return NULL;
}


static NPY_INLINE PyArray_ArgPartitionFunc *
get_argpartition_func(int type, NPY_SELECTKIND which)
{
    npy_intp i;
    if (which >= NPY_NSELECTS) {
        return NULL;
    }
    for (i = 0; i < sizeof(_part_map)/sizeof(_part_map[0]); i++) {
        if (type == _part_map[i].typenum) {
            return _part_map[i].argpart[which];
        }
    }
    return NULL;
}

#endif
