/* -*- c -*- */
#include "config.h"


static longlong
MyPyLong_AsLongLong(PyObject *vv)
{
        longlong ret;

        if (!PyLong_Check(vv)) {
                PyObject *mylong;
                mylong = PyNumber_Long(vv);
                if (mylong == NULL) {
                    return (longlong) -1;
                }
                vv = mylong;
        }
        else {
            Py_INCREF(vv);
        }

        ret = PyLong_AsLongLong(vv);
        Py_DECREF(vv);
        return ret;
}


static ulong
MyPyLong_AsUnsignedLong(PyObject *vv)
{
        ulong ret;

        if (!PyLong_Check(vv)) {
                PyObject *mylong;
                mylong = PyNumber_Long(vv);
                if (mylong == NULL) {
                    return (ulong) -1;
                }
                vv = mylong;
        }
        else {
            Py_INCREF(vv);
        }

        ret = PyLong_AsUnsignedLong(vv);
        if (PyErr_Occurred()) {
                PyErr_Clear();
                ret = (ulong) PyLong_AsLong(vv);
        }
        Py_DECREF(vv);
        return ret;
}


static ulonglong
MyPyLong_AsUnsignedLongLong(PyObject *vv)
{
        ulonglong ret;

        if (!PyLong_Check(vv)) {
                PyObject *mylong;
                mylong = PyNumber_Long(vv);
                if (mylong == NULL) {
                    return (ulonglong) -1;
                }
                vv = mylong;
        }
        else {
            Py_INCREF(vv);
        }

        ret = PyLong_AsUnsignedLongLong(vv);
        if (PyErr_Occurred()) {
                PyErr_Clear();
                ret = (ulonglong) PyLong_AsLongLong(vv);
        }
        Py_DECREF(vv);
        return ret;
}


static double
_getNAN(void) {
#ifdef NAN
        return NAN;
#else
        static double nan=0;

        if (nan == 0) {
                double mul = 1e100;
                double tmp = 0.0;
                double pinf=0;
                pinf = mul;
                for (;;) {
                        pinf *= mul;
                        if (pinf == tmp) break;
                        tmp = pinf;
                }
                nan = pinf / pinf;
        }
        return nan;
#endif
}


static double
MyPyFloat_AsDouble(PyObject *obj)
{
        if (obj == Py_None) return _getNAN();
        return PyFloat_AsDouble(obj);
}


/****************** getitem and setitem **********************/

/**begin repeat

#TYP=BOOL,BYTE,UBYTE,SHORT,USHORT,INT,LONG,UINT,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE#
#func1=PyBool_FromLong, PyInt_FromLong*6, PyLong_FromUnsignedLong*2, PyLong_FromLongLong, PyLong_FromUnsignedLongLong, PyFloat_FromDouble*2#
#func2=PyObject_IsTrue, PyInt_AsLong*6, MyPyLong_AsUnsignedLong*2, MyPyLong_AsLongLong, MyPyLong_AsUnsignedLongLong, MyPyFloat_AsDouble*2#
#typ=Bool, byte, ubyte, short, ushort, int, long, uint, ulong, longlong, ulonglong, float, double#
#typ1=long*7, ulong*2, longlong, ulonglong, float, double#
#kind=Bool, Byte, UByte, Short, UShort, Int, Long, UInt, ULong, LongLong, ULongLong, Float, Double#
*/

static PyObject *
@TYP@_getitem(char *ip, PyArrayObject *ap) {
        @typ@ t1;

        if ((ap==NULL) || PyArray_ISBEHAVED_RO(ap)) {
                t1 = *((@typ@ *)ip);
                return @func1@((@typ1@)t1);
        }
        else {
                ap->descr->f->copyswap(&t1, ip, !PyArray_ISNOTSWAPPED(ap),
                                       ap);
                return @func1@((@typ1@)t1);
        }
}

static int
@TYP@_setitem(PyObject *op, char *ov, PyArrayObject *ap) {
        @typ@ temp;  /* ensures alignment */


        if (PyArray_IsScalar(op, @kind@)) {
                temp = ((Py@kind@ScalarObject *)op)->obval;
        }
        else {
                temp = (@typ@)@func2@(op);
        }
        if (PyErr_Occurred()) {
                if (PySequence_Check(op)) {
                        PyErr_Clear();
                        PyErr_SetString(PyExc_ValueError, "setting an array" \
                                        " element with a sequence.");
                }
                return -1;
        }
        if (ap == NULL || PyArray_ISBEHAVED(ap))
                *((@typ@ *)ov)=temp;
        else {
                ap->descr->f->copyswap(ov, &temp, !PyArray_ISNOTSWAPPED(ap),
                                       ap);
        }

        return 0;
}

/**end repeat**/


/**begin repeat

#TYP=CFLOAT,CDOUBLE#
#typ=float, double#
*/

static PyObject *
@TYP@_getitem(char *ip, PyArrayObject *ap) {
        @typ@ t1, t2;

        if ((ap==NULL) || PyArray_ISBEHAVED_RO(ap)) {
                return PyComplex_FromDoubles((double)((@typ@ *)ip)[0],
                                             (double)((@typ@ *)ip)[1]);
        }
        else {
                int size = sizeof(@typ@);
                Bool swap = !PyArray_ISNOTSWAPPED(ap);
                copy_and_swap(&t1, ip, size, 1, 0, swap);
                copy_and_swap(&t2, ip+size, size, 1, 0, swap);
                return PyComplex_FromDoubles((double)t1, (double)t2);
        }
}
/**end repeat**/

/**begin repeat

#TYP=CFLOAT, CDOUBLE, CLONGDOUBLE#
#typ=float, double, longdouble#
#kind=CFloat, CDouble, CLongDouble#
*/
static int
@TYP@_setitem(PyObject *op, char *ov, PyArrayObject *ap)
{
        Py_complex oop;
        PyObject *op2;
        c@typ@ temp;
        int rsize;

        if (!(PyArray_IsScalar(op, @kind@))) {
                if (PyArray_Check(op) && (PyArray_NDIM(op)==0)) {
                        op2 = ((PyArrayObject *)op)->descr->f->getitem     \
                                (((PyArrayObject *)op)->data,
                                 (PyArrayObject *)op);
                }
                else {
                        op2 = op; Py_INCREF(op);
                }
                if (op2 == Py_None) {
                        oop.real = oop.imag = _getNAN();
                }
                else {
                        oop = PyComplex_AsCComplex (op2);
                }
                Py_DECREF(op2);
                if (PyErr_Occurred()) return -1;
                temp.real = (@typ@) oop.real;
                temp.imag = (@typ@) oop.imag;
        }
        else {
                temp = ((Py@kind@ScalarObject *)op)->obval;
        }

        memcpy(ov, &temp, ap->descr->elsize);
        if (!PyArray_ISNOTSWAPPED(ap))
                byte_swap_vector(ov, 2, sizeof(@typ@));

        rsize = sizeof(@typ@);
        copy_and_swap(ov, &temp, rsize, 2, rsize, !PyArray_ISNOTSWAPPED(ap));
        return 0;
}
/**end repeat**/

static PyObject *
LONGDOUBLE_getitem(char *ip, PyArrayObject *ap)
{
        return PyArray_Scalar(ip, ap->descr, NULL);
}

static int
LONGDOUBLE_setitem(PyObject *op, char *ov, PyArrayObject *ap) {
        longdouble temp;  /* ensures alignment */

        if (PyArray_IsScalar(op, LongDouble)) {
                temp = ((PyLongDoubleScalarObject *)op)->obval;
        }
        else {
                temp = (longdouble) MyPyFloat_AsDouble(op);
        }
        if (PyErr_Occurred()) return -1;
        if (ap == NULL || PyArray_ISBEHAVED(ap))
                *((longdouble *)ov)=temp;
        else {
                copy_and_swap(ov, &temp, ap->descr->elsize, 1, 0,
                              !PyArray_ISNOTSWAPPED(ap));
        }
        return 0;
}

static PyObject *
CLONGDOUBLE_getitem(char *ip, PyArrayObject *ap)
{
        return PyArray_Scalar(ip, ap->descr, NULL);
}


/* UNICODE */
static PyObject *
UNICODE_getitem(char *ip, PyArrayObject *ap)
{
        PyObject *obj;
        int mysize;
        PyArray_UCS4 *dptr;
        char *buffer;
        int alloc=0;

        mysize = ap->descr->elsize >> 2;
        dptr = (PyArray_UCS4 *)ip + mysize-1;
        while(mysize > 0 && *dptr-- == 0) mysize--;
        if (!PyArray_ISBEHAVED(ap)) {
                buffer = _pya_malloc(mysize << 2);
                if (buffer == NULL)
                        return PyErr_NoMemory();
                alloc = 1;
                memcpy(buffer, ip, mysize << 2);
                if (!PyArray_ISNOTSWAPPED(ap)) {
                        byte_swap_vector(buffer, mysize, 4);
                }
        }
        else buffer = ip;
#ifdef Py_UNICODE_WIDE
        obj = PyUnicode_FromUnicode((const Py_UNICODE *)buffer, mysize);
#else
        /* create new empty unicode object of length mysize*2 */
        obj = MyPyUnicode_New(mysize*2);
        if (obj == NULL) {if (alloc) _pya_free(buffer); return obj;}
        mysize = PyUCS2Buffer_FromUCS4(((PyUnicodeObject *)obj)->str,
                                       (PyArray_UCS4 *)buffer, mysize);
        /* reset length of unicode object to ucs2size */
        if (MyPyUnicode_Resize((PyUnicodeObject *)obj, mysize) < 0) {
                if (alloc) _pya_free(buffer);
                Py_DECREF(obj);
                return NULL;
        }
#endif
        if (alloc) _pya_free(buffer);

        return obj;
}

static int
UNICODE_setitem(PyObject *op, char *ov, PyArrayObject *ap)
{
        PyObject *temp;
        Py_UNICODE *ptr;
        int datalen;
#ifndef Py_UNICODE_WIDE
        char *buffer;
#endif

        if (!PyString_Check(op) && !PyUnicode_Check(op) &&
            PySequence_Check(op) && PySequence_Size(op) > 0) {
                PyErr_SetString(PyExc_ValueError,
                                "setting an array element with a sequence");
                return -1;
        }
        /* Sequence_Size might have returned an error */
        if (PyErr_Occurred()) PyErr_Clear();
        if ((temp=PyObject_Unicode(op)) == NULL) return -1;
        ptr = PyUnicode_AS_UNICODE(temp);
        if ((ptr == NULL) || (PyErr_Occurred())) {
                Py_DECREF(temp);
                return -1;
        }
        datalen = PyUnicode_GET_DATA_SIZE(temp);

#ifdef Py_UNICODE_WIDE
        memcpy(ov, ptr, MIN(ap->descr->elsize, datalen));
#else
        if (!PyArray_ISALIGNED(ap)) {
                buffer = _pya_malloc(ap->descr->elsize);
                if (buffer == NULL) {
                        Py_DECREF(temp);
                        PyErr_NoMemory();
                        return -1;
                }
        }
        else buffer = ov;
        datalen = PyUCS2Buffer_AsUCS4(ptr, (PyArray_UCS4 *)buffer,
                                      datalen >> 1,
                                      ap->descr->elsize >> 2);
        datalen <<= 2;
        if (!PyArray_ISALIGNED(ap)) {
                memcpy(ov, buffer, datalen);
                _pya_free(buffer);
        }
#endif
        /* Fill in the rest of the space with 0 */
        if (ap->descr->elsize > datalen) {
                memset(ov + datalen, 0, (ap->descr->elsize - datalen));
        }

        if (!PyArray_ISNOTSWAPPED(ap))
                byte_swap_vector(ov, ap->descr->elsize >> 2, 4);
        Py_DECREF(temp);
        return 0;
}

/* STRING -- can handle both NULL-terminated and not NULL-terminated cases
             will truncate all ending NULLs in returned string.
*/
static PyObject *
STRING_getitem(char *ip, PyArrayObject *ap)
{
        /* Will eliminate NULLs at the end */
        char *ptr;
        int size = ap->descr->elsize;

        ptr = ip + size-1;
        while (*ptr-- == '\0' && size > 0) size--;
        return PyString_FromStringAndSize(ip,size);
}

static int
STRING_setitem(PyObject *op, char *ov, PyArrayObject *ap)
{
        char *ptr;
        Py_ssize_t len;
        PyObject *temp=NULL;

        if (!PyString_Check(op) && !PyUnicode_Check(op) &&
            PySequence_Check(op) && PySequence_Size(op) > 0) {
                PyErr_SetString(PyExc_ValueError,
                                "setting an array element with a sequence");
                return -1;
        }
        /* Sequence_Size might have returned an error */
        if (PyErr_Occurred()) PyErr_Clear();
        if ((temp = PyObject_Str(op)) == NULL) return -1;

        if (PyString_AsStringAndSize(temp, &ptr, &len) == -1) {
                Py_DECREF(temp);
                return -1;
        }
        memcpy(ov, ptr, MIN(ap->descr->elsize,len));
	/* If string lenth is smaller than room in array
	   Then fill the rest of the element size
	   with NULL */
        if (ap->descr->elsize > len) {
                memset(ov + len, 0, (ap->descr->elsize - len));
        }
        Py_DECREF(temp);
        return 0;
}

/* OBJECT */

static PyObject *
OBJECT_getitem(char *ip, PyArrayObject *ap)
{
        if (*(PyObject **)ip == NULL) {
                Py_INCREF(Py_None);
                return Py_None;
        }
        if (!ap || PyArray_ISALIGNED(ap)) {
                Py_INCREF(*(PyObject **)ip);
                return *(PyObject **)ip;
        }
        else {
                PyObject **obj;
                obj = (PyObject **)ip;
                Py_INCREF(*obj);
                return *obj;
        }
}


static int
OBJECT_setitem(PyObject *op, char *ov, PyArrayObject *ap)
{
        Py_INCREF(op);
        if (!ap || PyArray_ISALIGNED(ap)) {
                Py_XDECREF(*(PyObject **)ov);
                *(PyObject **)ov = op;
        }
        else {
                PyObject **obj;
                obj = (PyObject **)ov;
                Py_XDECREF(*obj);
                memcpy(ov, &op, sizeof(PyObject *));
        }
        return PyErr_Occurred() ? -1:0;
}

/* VOID */

static PyObject *
VOID_getitem(char *ip, PyArrayObject *ap)
{
        PyObject *u=NULL;
        PyArray_Descr* descr;
        int itemsize;

        descr = ap->descr;
        if (descr->names) {
                PyObject *key;
                PyObject *names;
                int i, n;
                PyObject *ret;
                PyObject *tup, *title;
                PyArray_Descr *new;
                int offset;
                int savedflags;

                /* get the names from the fields dictionary*/
                names = descr->names;
                if (!names) goto finish;
                n = PyTuple_GET_SIZE(names);
                ret = PyTuple_New(n);
                savedflags = ap->flags;
                for (i=0; i<n; i++) {
                        key = PyTuple_GET_ITEM(names, i);
                        tup = PyDict_GetItem(descr->fields, key);
                        if (!PyArg_ParseTuple(tup, "Oi|O", &new, &offset,
                                              &title)) {
                                Py_DECREF(ret);
                                ap->descr = descr;
                                return NULL;
                        }
                        ap->descr = new;
                        /* update alignment based on offset */
                        if ((new->alignment > 1) &&                     \
                            ((((intp)(ip+offset)) % new->alignment) != 0))
                                ap->flags &= ~ALIGNED;
                        else
                                ap->flags |= ALIGNED;

                        PyTuple_SET_ITEM(ret, i,                        \
                                         new->f->getitem(ip+offset, ap));
                        ap->flags = savedflags;
                }
                ap->descr = descr;
                return ret;
        }

        if (descr->subarray) {
                /* return an array of the basic type */
                PyArray_Dims shape={NULL,-1};
                PyObject *ret;
                if (!(PyArray_IntpConverter(descr->subarray->shape,
                                            &shape))) {
                        PyDimMem_FREE(shape.ptr);
                        PyErr_SetString(PyExc_ValueError,
                                        "invalid shape in fixed-type tuple.");
                        return NULL;
                }
                Py_INCREF(descr->subarray->base);
                ret = PyArray_NewFromDescr(&PyArray_Type,
                                           descr->subarray->base,
                                           shape.len, shape.ptr,
                                           NULL, ip, ap->flags, NULL);
                PyDimMem_FREE(shape.ptr);
                if (!ret) return NULL;
                PyArray_BASE(ret) = (PyObject *)ap;
                Py_INCREF(ap);
                PyArray_UpdateFlags((PyArrayObject *)ret, UPDATE_ALL);
                return ret;
        }

 finish:
        if (PyDataType_FLAGCHK(descr, NPY_ITEM_HASOBJECT) ||
            PyDataType_FLAGCHK(descr, NPY_ITEM_IS_POINTER)) {
                PyErr_SetString(PyExc_ValueError,
                                "tried to get void-array with object"
                                " members as buffer.");
                return NULL;
        }

        itemsize=ap->descr->elsize;
        if (PyArray_ISWRITEABLE(ap))
                u = PyBuffer_FromReadWriteMemory(ip, itemsize);
        else
                u = PyBuffer_FromMemory(ip, itemsize);
        if (u==NULL) goto fail;

        /* default is to return buffer object pointing to current item */
        /*  a view of it */
        return u;

 fail:
        return NULL;
}



static int PyArray_CopyObject(PyArrayObject *, PyObject *);

static int
VOID_setitem(PyObject *op, char *ip, PyArrayObject *ap)
{
        PyArray_Descr* descr;
        int itemsize=ap->descr->elsize;
        int res;

        descr = ap->descr;
        if (descr->names && PyTuple_Check(op)) {
                PyObject *key;
                PyObject *names;
                int i, n;
                PyObject *tup, *title;
                PyArray_Descr *new;
                int offset;
                int savedflags;
                res = -1;
                /* get the names from the fields dictionary*/
                names = descr->names;
                n = PyTuple_GET_SIZE(names);
                if (PyTuple_GET_SIZE(op) != n) {
                        PyErr_SetString(PyExc_ValueError,
                                        "size of tuple must match "\
                                        "number of fields.");
                        return -1;
                }
                savedflags = ap->flags;
                for (i=0; i<n; i++) {
                        key = PyTuple_GET_ITEM(names, i);
                        tup = PyDict_GetItem(descr->fields, key);
                        if (!PyArg_ParseTuple(tup, "Oi|O", &new, &offset,
                                              &title)) {
                                ap->descr = descr;
                                return -1;
                        }
                        ap->descr = new;
                        /* remember to update alignment flags */
                        if ((new->alignment > 1) &&                     \
                            ((((intp)(ip+offset)) % new->alignment) != 0))
                                ap->flags &= ~ALIGNED;
                        else
                                ap->flags |= ALIGNED;

                        res = new->f->setitem(PyTuple_GET_ITEM(op, i),
                                              ip+offset, ap);
                        ap->flags = savedflags;
                        if (res < 0) break;
                }
                ap->descr = descr;
                return res;
        }

        if (descr->subarray) {
                /* copy into an array of the same basic type */
                PyArray_Dims shape={NULL,-1};
                PyObject *ret;
                if (!(PyArray_IntpConverter(descr->subarray->shape,
                                            &shape))) {
                        PyDimMem_FREE(shape.ptr);
                        PyErr_SetString(PyExc_ValueError,
                                        "invalid shape in fixed-type tuple.");
                        return -1;
                }
                Py_INCREF(descr->subarray->base);
                ret = PyArray_NewFromDescr(&PyArray_Type,
                                           descr->subarray->base,
                                           shape.len, shape.ptr,
                                           NULL, ip, ap->flags, NULL);
                PyDimMem_FREE(shape.ptr);
                if (!ret) return -1;
                PyArray_BASE(ret) = (PyObject *)ap;
                Py_INCREF(ap);
                PyArray_UpdateFlags((PyArrayObject *)ret, UPDATE_ALL);
                res = PyArray_CopyObject((PyArrayObject *)ret, op);
                Py_DECREF(ret);
                return res;
        }

        /* Default is to use buffer interface to set item */
        {
                const void *buffer;
                Py_ssize_t buflen;
                if (PyDataType_FLAGCHK(descr, NPY_ITEM_HASOBJECT) ||
                    PyDataType_FLAGCHK(descr, NPY_ITEM_IS_POINTER)) {
                        PyErr_SetString(PyExc_ValueError,
                                        "tried to set void-array with object"
                                        " members using buffer.");
                        return -1;
                }
                res = PyObject_AsReadBuffer(op, &buffer, &buflen);
                if (res == -1) goto fail;
                memcpy(ip, buffer, NPY_MIN(buflen, itemsize));
                if (itemsize > buflen) {
                        memset(ip+buflen, 0, (itemsize-buflen));
                }
        }
        return 0;

 fail:
        return -1;
}


/****************** XXX_to_YYY *******************************/

/* Assumes contiguous, and aligned, from and to */


/**begin repeat
#to=(BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE)*16#
#from=BYTE*13,UBYTE*13,SHORT*13,USHORT*13,INT*13,UINT*13,LONG*13,ULONG*13,LONGLONG*13,ULONGLONG*13,FLOAT*13,DOUBLE*13,LONGDOUBLE*13,CFLOAT*13,CDOUBLE*13,CLONGDOUBLE*13#
#totyp=(byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble)*16#
#fromtyp=byte*13, ubyte*13, short*13, ushort*13, int*13, uint*13, long*13, ulong*13, longlong*13, ulonglong*13, float*13, double*13, longdouble*13, float*13, double*13, longdouble*13#
#incr= ip++*169,ip+=2*39#
*/
static void
@from@_to_@to@(register @fromtyp@ *ip, register @totyp@ *op, register intp n,
               PyArrayObject *aip, PyArrayObject *aop)
{
        while (n--) {
                *op++ = (@totyp@)*ip;
                @incr@;
        }
}
/**end repeat**/

/**begin repeat
#from=BOOL,BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE#
#fromtyp=Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble#
*/
static void
@from@_to_BOOL(register @fromtyp@ *ip, register Bool *op, register intp n,
               PyArrayObject *aip, PyArrayObject *aop)
{
        while (n--) {
                *op++ = (Bool)(*ip++ != FALSE);
        }
}
/**end repeat**/

/**begin repeat
#from=CFLOAT, CDOUBLE, CLONGDOUBLE#
#fromtyp=cfloat, cdouble, clongdouble#
*/
static void
@from@_to_BOOL(register @fromtyp@ *ip, register Bool *op, register intp n,
               PyArrayObject *aip, PyArrayObject *aop)
{
        while (n--) {
                *op = (Bool)(((*ip).real != FALSE) || ((*ip).imag != FALSE));
                op++; ip++;
        }
}
/**end repeat**/

/**begin repeat
#to=BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE#
#totyp=byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble#
*/
static void
BOOL_to_@to@(register Bool *ip, register @totyp@ *op, register intp n,
             PyArrayObject *aip, PyArrayObject *aop)
{
        while (n--) {
                *op++ = (@totyp@)(*ip++ != FALSE);
        }
}
/**end repeat**/

/**begin repeat

#to=(CFLOAT,CDOUBLE,CLONGDOUBLE)*14#
#from=BOOL*3,BYTE*3,UBYTE*3,SHORT*3,USHORT*3,INT*3,UINT*3,LONG*3,ULONG*3,LONGLONG*3,ULONGLONG*3,FLOAT*3,DOUBLE*3,LONGDOUBLE*3#
#fromtyp=Bool*3,byte*3, ubyte*3, short*3, ushort*3, int*3, uint*3, long*3, ulong*3, longlong*3, ulonglong*3, float*3, double*3, longdouble*3#
#totyp= (float, double, longdouble)*14#
*/
static void
@from@_to_@to@(register @fromtyp@ *ip, register @totyp@ *op, register intp n,
               PyArrayObject *aip, PyArrayObject *aop)
{
        while (n--) {
                *op++ = (@totyp@)*ip++;
                *op++ = 0.0;
        }

}
/**end repeat**/

/**begin repeat

#to=(CFLOAT,CDOUBLE,CLONGDOUBLE)*3#
#from=CFLOAT*3,CDOUBLE*3,CLONGDOUBLE*3#
#totyp=(float, double, longdouble)*3#
#fromtyp=float*3, double*3, longdouble*3#
*/
static void
@from@_to_@to@(register @fromtyp@ *ip, register @totyp@ *op, register intp n,
               PyArrayObject *aip, PyArrayObject *aop)
{
        n <<= 1;
        while (n--) {
                *op++ = (@totyp@)*ip++;
        }

}
/**end repeat**/

/**begin repeat

#from=BOOL,BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE,CFLOAT,CDOUBLE,CLONGDOUBLE, STRING, UNICODE, VOID, OBJECT#
#fromtyp=Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble, cfloat, cdouble, clongdouble, char, char, char, PyObject *#
#skip= 1*17, aip->descr->elsize*3, 1#
*/
static void
@from@_to_OBJECT(@fromtyp@ *ip, PyObject **op, intp n, PyArrayObject *aip,
                 PyArrayObject *aop)
{
        register intp i;
        int skip=@skip@;
        for(i=0;i<n;i++,ip+=skip,op++) {
                Py_XDECREF(*op);
                *op = @from@_getitem((char *)ip, aip);
        }
}
/**end repeat**/

/**begin repeat

#to=BOOL,BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE,CFLOAT,CDOUBLE,CLONGDOUBLE, STRING, UNICODE, VOID#
#totyp=Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble, cfloat, cdouble, clongdouble, char, char, char#
#skip= 1*17, aip->descr->elsize*3#
*/
static void
OBJECT_to_@to@(PyObject **ip, @totyp@ *op, intp n, PyArrayObject *aip,
                 PyArrayObject *aop)
{
        register intp i;
        int skip=@skip@;
        for(i=0;i<n;i++,ip++,op+=skip) {
                if (*ip == NULL) {
                        @to@_setitem(Py_False, (char *)op, aop);
                }
                else {
                        @to@_setitem(*ip, (char *)op, aop);
                }
        }
}
/**end repeat**/


/**begin repeat

#from=STRING*20, UNICODE*20, VOID*20#
#fromtyp=char*60#
#to=(BOOL,BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE,CFLOAT,CDOUBLE,CLONGDOUBLE,STRING,UNICODE,VOID)*3#
#totyp=(Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble, cfloat, cdouble, clongdouble, char, char, char)*3#
#oskip=(1*17,aop->descr->elsize*3)*3#
#convert=1*17,0*3,1*17,0*3,0*20#
#convstr=(Int*9,Long*2,Float*3,Complex*3,Tuple*3)*3#
*/
static void
@from@_to_@to@(@fromtyp@ *ip, @totyp@ *op, intp n, PyArrayObject *aip,
             PyArrayObject *aop)
{
        register intp i;
        PyObject *temp=NULL;
        int skip=aip->descr->elsize;
        int oskip=@oskip@;
        for(i=0; i<n; i++, ip+=skip, op+=oskip) {
                temp = @from@_getitem((char *)ip, aip);
                if (temp==NULL) return;
                /* convert from Python object to needed one */
                if (@convert@) {
                        PyObject *new, *args;
                        /* call out to the Python builtin given by convstr */
                        args = Py_BuildValue("(N)", temp);
                        new = Py@convstr@_Type.tp_new(&Py@convstr@_Type, args, NULL);
                        Py_DECREF(args);
                        temp = new;
                        if (temp==NULL) return;
                }

                @to@_setitem(temp,(char *)op, aop);
                Py_DECREF(temp);
        }
}

/**end repeat**/

/**begin repeat

#to=STRING*17, UNICODE*17, VOID*17#
#totyp=char*17, char*17, char*17#
#from=(BOOL,BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE,CFLOAT,CDOUBLE,CLONGDOUBLE)*3#
#fromtyp=(Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble, cfloat, cdouble, clongdouble)*3#
*/

static void
@from@_to_@to@(@fromtyp@ *ip, @totyp@ *op, intp n, PyArrayObject *aip,
             PyArrayObject *aop)
{
        register intp i;
        PyObject *temp=NULL;
        int skip=1;
        int oskip=aop->descr->elsize;
        for(i=0; i<n; i++, ip+=skip, op+=oskip) {
                temp = @from@_getitem((char *)ip, aip);
                if (temp==NULL) {
                        Py_INCREF(Py_False);
                        temp = Py_False;
                }
                @to@_setitem(temp,(char *)op, aop);
                Py_DECREF(temp);
        }
}

/**end repeat**/


/****************** scan *************************************/

/* The first ignore argument is for backwards compatibility.
   Should be removed when the API version is bumped up.
 */

/**begin repeat

#fname=SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE#
#type=short,ushort,int,uint,long,ulong,longlong,ulonglong,float,double,longdouble#
#format="hd","hu","d","u","ld","lu",LONGLONG_FMT,ULONGLONG_FMT,"f","lf","Lf"#
*/
static int
@fname@_scan (FILE *fp, @type@ *ip, void *ignore, PyArray_Descr *ignore2)
{
        return fscanf(fp, "%"@format@, ip);
}

/**end repeat**/

/**begin repeat
#fname=BYTE,UBYTE#
#type=byte,ubyte#
#btype=int,uint#
#format="d","u"#
*/
static int
@fname@_scan (FILE *fp, @type@ *ip, void *ignore, PyArray_Descr *ignore2)
{
        @btype@ temp;
        int num;
        num = fscanf(fp, "%"@format@, &temp);
        *ip = (@type@) temp;
	return num;
}
/**end repeat**/

static int
BOOL_scan (FILE *fp, Bool *ip, void *ignore, PyArray_Descr *ignore2)
{
        int temp;
        int num;
        num = fscanf(fp, "%d", &temp);
        *ip = (Bool) (temp != 0);
	return num;
}

/**begin repeat
#fname=CFLOAT,CDOUBLE,CLONGDOUBLE,OBJECT,STRING,UNICODE,VOID#
*/
#define @fname@_scan NULL
/**end repeat**/

/****************** fromstr *************************************/

/**begin repeat
#fname=BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG#
#type=byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong#
#func=(l,ul)*5#
#btype=(long,ulong)*5#
*/
static int
@fname@_fromstr(char *str, @type@ *ip, char **endptr, PyArray_Descr *ignore)
{
        @btype@ result;

        result = PyOS_strto@func@(str, endptr, 10);
        *ip = (@type@) result;
        return 0;
}
/**end repeat**/

/**begin repeat
#fname=FLOAT,DOUBLE,LONGDOUBLE#
#type=float,double,longdouble#
*/
#if (PY_VERSION_HEX >= 0x02040000) || defined(PyOS_ascii_strtod)
static int
@fname@_fromstr(char *str, @type@ *ip, char **endptr, PyArray_Descr *ignore)
{
        double result;

        result = PyOS_ascii_strtod(str, endptr);
        *ip = (@type@) result;
        return 0;
}
#else
#define @fname@_fromstr NULL
#endif
/**end repeat**/



/**begin repeat
#fname=BOOL,CFLOAT,CDOUBLE,CLONGDOUBLE,OBJECT,STRING,UNICODE,VOID#
*/
#define @fname@_fromstr NULL
/**end repeat**/


/****************** copyswapn *************************************/

/**begin repeat

#fname=SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE#
#fsize=SHORT,SHORT,INT,INT,LONG,LONG,LONGLONG,LONGLONG,FLOAT,DOUBLE,LONGDOUBLE#
#type=short,ushort,int,uint,long,ulong,longlong,ulonglong,float,double,longdouble#
*/
static void
@fname@_copyswapn (void *dst, intp dstride, void *src, intp sstride,
                   intp n, int swap, void *arr)
{
        if (src != NULL) {
                if (sstride == sizeof(@type@) && dstride == sizeof(@type@)) {
                        memcpy(dst, src, n*sizeof(@type@));
                }
                else {
                        _unaligned_strided_byte_copy(dst, dstride, src, sstride,
                                                     n, sizeof(@type@));
                }
        }
        if (swap) {
                _strided_byte_swap(dst, dstride, n, sizeof(@type@));
        }
}

static void
@fname@_copyswap (void *dst, void *src, int swap, void *arr)
{

        if (src != NULL) /* copy first if needed */
                memcpy(dst, src, sizeof(@type@));

        if (swap) {
                register char *a, *b, c;
                a = (char *)dst;
#if SIZEOF_@fsize@ == 2
                b = a + 1;
                c = *a; *a++ = *b; *b = c;
#elif SIZEOF_@fsize@ == 4
                b = a + 3;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
#elif SIZEOF_@fsize@ == 8
                b = a + 7;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
#elif SIZEOF_@fsize@ == 10
                b = a + 9;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
#elif SIZEOF_@fsize@ == 12
                b = a + 11;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
#elif SIZEOF_@fsize@ == 16
                b = a + 15;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
#else
                {
                        register int i, nn;
                        b = a + (SIZEOF_@fsize@-1);
                        nn = SIZEOF_@fsize@ / 2;
                        for (i=0; i<nn; i++) {
                                c=*a; *a++ = *b; *b-- = c;
                        }
                }
#endif
        }
}


/**end repeat**/

/**begin repeat

#fname=BOOL, BYTE, UBYTE#
#type=Bool, byte, ubyte#
*/
static void
@fname@_copyswapn (void *dst, intp dstride, void *src, intp sstride, intp n,
                   int swap, void *arr)
{
        if (src != NULL) {
                if (sstride == sizeof(@type@) && dstride == sizeof(@type@)) {
                        memcpy(dst, src, n*sizeof(@type@));
                }
                else {
                        _unaligned_strided_byte_copy(dst, dstride, src, sstride,
                                                     n, sizeof(@type@));
                }
        }
        /* ignore swap */
}

static void
@fname@_copyswap (void *dst, void *src, int swap, void *arr)
{
        if (src != NULL) /* copy first if needed */
                memcpy(dst, src, sizeof(@type@));
        /* ignore swap */
}

/**end repeat**/



/**begin repeat

#fname=CFLOAT,CDOUBLE,CLONGDOUBLE#
#type=cfloat, cdouble, clongdouble#
#fsize=FLOAT,DOUBLE,LONGDOUBLE#
*/
static void
@fname@_copyswapn (void *dst, intp dstride, void *src, intp sstride, intp n,
                   int swap, void *arr)
{

        if (src != NULL) { /* copy first if needed */
                if (sstride == sizeof(@type@) && dstride == sizeof(@type@)) {
                        memcpy(dst, src, n*sizeof(@type@));
                }
                else {
                        _unaligned_strided_byte_copy(dst, dstride, src,
                                                     sstride, n,
                                                     sizeof(@type@));
                }
        }

        if (swap) {
                _strided_byte_swap(dst, dstride, n, SIZEOF_@fsize@);
                _strided_byte_swap(((char *)dst + SIZEOF_@fsize@), dstride,
                                   n, SIZEOF_@fsize@);
        }
}

static void
@fname@_copyswap (void *dst, void *src, int swap, void *arr)
{
        if (src != NULL) /* copy first if needed */
                memcpy(dst, src, sizeof(@type@));

        if (swap) {
                register char *a, *b, c;
                a = (char *)dst;
#if SIZEOF_@fsize@ == 4
                b = a + 3;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
                a += 2;
                b = a + 3;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
#elif SIZEOF_@fsize@ == 8
                b = a + 7;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
                a += 4;
                b = a + 7;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
#elif SIZEOF_@fsize@ == 10
                b = a + 9;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
                a += 5;
                b = a + 9;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
#elif SIZEOF_@fsize@ == 12
                b = a + 11;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
                a += 6;
                b = a + 11;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
#elif SIZEOF_@fsize@ == 16
                b = a + 15;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
                a += 8;
                b = a + 15;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b-- = c;
                c = *a; *a++ = *b; *b   = c;
#else
                {
                        register int i, nn;
                        b = a + (SIZEOF_@fsize@-1);
                        nn = SIZEOF_@fsize@ / 2;
                        for (i=0; i<nn; i++) {
                                c=*a; *a++ = *b; *b-- = c;
                        }
                        a += nn / 2;
                        b = a + (SIZEOF_@fsize@-1);
                        nn = SIZEOF_@fsize@ / 2;
                        for (i=0; i<nn; i++) {
                                c=*a; *a++ = *b; *b-- = c;
                        }
                }
#endif
        }
}

/**end repeat**/

#define __ALIGNED(obj, sz) ((((size_t) obj) % (sz))==0)
static void
OBJECT_copyswapn (PyObject **dst, intp dstride, PyObject **src, intp sstride,
                  register intp n, int swap, void *arr)
{
        register intp i;
        if (src != NULL) {
                dstride /= sizeof(PyObject **);
                sstride /= sizeof(PyObject **);
                if (__ALIGNED(dst,sizeof(PyObject **)) && __ALIGNED(src, sizeof(PyObject **))) {
                        for (i=0; i<n; i++) {
                                Py_XINCREF(*src);
                                Py_XDECREF(*dst);
                                *dst = *src;
                                dst += dstride;
                                src += sstride;
                        }
                }
                else {
                        PyObject **dp, **sp;
                        for (i=0; i<n; i++) {
                                dp = dst;
                                sp = src;
                                Py_XINCREF(*sp);
                                Py_XDECREF(*dp);
                                memcpy(dst, src, sizeof(PyObject *));
                                dst += dstride;
                                src += sstride;
                        }
                }
        }
        /* ignore swap */
        return;
}

static void
OBJECT_copyswap(PyObject **dst, PyObject **src, int swap, void *arr)
{

        if (src != NULL) {
                if (__ALIGNED(dst,sizeof(PyObject **)) && __ALIGNED(src,sizeof(PyObject **))) {
                        Py_XINCREF(*src);
                        Py_XDECREF(*dst);
                        *dst = *src;
                }
                else {
                        PyObject **dp=dst, **sp=src;
                        Py_XINCREF(*sp);
                        Py_XDECREF(*dp);
                        memcpy(dst, src, sizeof(PyObject *));
                }
        }
}

/* ignore swap */
static void
STRING_copyswapn (char *dst, intp dstride, char *src, intp sstride,
                  intp n, int swap, PyArrayObject *arr)
{
        if (src != NULL && arr != NULL) {
                int itemsize = arr->descr->elsize;
                if (dstride == itemsize && sstride == itemsize) {
                        memcpy(dst, src, itemsize * n);
                }
                else {
                        _unaligned_strided_byte_copy(dst, dstride, src, sstride, n, itemsize);
                }
        }
        return;
}

/* */
static void
VOID_copyswapn (char *dst, intp dstride, char *src, intp sstride,
                intp n, int swap, PyArrayObject *arr)
{
        if (arr == NULL) return;
        if (PyArray_HASFIELDS(arr)) {
                PyObject *key, *value, *title=NULL;
                PyArray_Descr *new, *descr;
                int offset;
                Py_ssize_t pos=0;
                descr = arr->descr;
                while (PyDict_Next(descr->fields, &pos, &key, &value)) {
                        if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset,
                                              &title)) {
                                arr->descr=descr;return;
                        }
                        arr->descr = new;
                        new->f->copyswapn(dst+offset, dstride,
                                          (src != NULL ? src+offset : NULL),
                                          sstride, n, swap, arr);
                }
                arr->descr = descr;
                return;
        }
        if (swap && arr->descr->subarray != NULL) {
                PyArray_Descr *descr, *new;
                npy_intp num;
                npy_intp i;
                int subitemsize;
                char *dstptr, *srcptr;
                descr = arr->descr;
                new = descr->subarray->base;
                arr->descr = new;
                dstptr = dst;
                srcptr = src;
                subitemsize = new->elsize;
                num = descr->elsize / subitemsize;
                for (i=0; i<n; i++) {
                        new->f->copyswapn(dstptr, subitemsize, srcptr,
                                          subitemsize, num, swap, arr);
                        dstptr += dstride;
                        if (srcptr) srcptr += sstride;
                }
                arr->descr = descr;
                return;
        }
        if (src != NULL) {
                memcpy(dst, src, arr->descr->elsize * n);
        }
        return;
}

static void
VOID_copyswap (char *dst, char *src, int swap, PyArrayObject *arr)
{
        if (arr==NULL) return;
        if (PyArray_HASFIELDS(arr)) {
                PyObject *key, *value, *title=NULL;
                PyArray_Descr *new, *descr;
                int offset;
                Py_ssize_t pos=0;
                descr = arr->descr;  /* Save it */
                while (PyDict_Next(descr->fields, &pos, &key, &value)) {
                        if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset,
                                              &title)) {
                                arr->descr=descr;return;
                        }
                        arr->descr = new;
                        new->f->copyswap(dst+offset,
                                         (src != NULL ? src+offset : NULL),
                                         swap, arr);
                }
                arr->descr = descr;
                return;
        }
        if (swap && arr->descr->subarray != NULL) {
                PyArray_Descr *descr, *new;
                npy_intp num;
                int itemsize;
                descr = arr->descr;
                new = descr->subarray->base;
                arr->descr = new;
                itemsize = new->elsize;
                num = descr->elsize / itemsize;
                new->f->copyswapn(dst, itemsize, src,
                                  itemsize, num, swap, arr);
                arr->descr = descr;
                return;
        }
        if (src != NULL) {
                memcpy(dst, src, arr->descr->elsize);
        }
        return;
}


static void
UNICODE_copyswapn (char *dst, intp dstride, char *src, intp sstride,
                   intp n, int swap, PyArrayObject *arr)
{
        int itemsize;
        if (arr==NULL) return;
        itemsize = arr->descr->elsize;
        if (src != NULL) {
                if (dstride == itemsize && sstride == itemsize)
                        memcpy(dst, src, n * itemsize);
                else
                        _unaligned_strided_byte_copy(dst, dstride, src,
                                                     sstride, n, itemsize);
        }

        n *= itemsize;
        if (swap) {
                register char *a, *b, c;
                n >>= 2; /* n is the number of unicode characters to swap */
                for (a = (char *)dst; n>0; n--) {
                        b = a + 3;
                        c=*a; *a++ = *b; *b-- = c;
                        c=*a; *a++ = *b; *b-- = c;
                        a += 2;
                }
        }
}


static void
STRING_copyswap (char *dst, char *src, int swap, PyArrayObject *arr)
{
        if (src != NULL && arr != NULL) {
                memcpy(dst, src, arr->descr->elsize);
        }
}

static void
UNICODE_copyswap (char *dst, char *src, int swap, PyArrayObject *arr)
{
        int itemsize;
        if (arr == NULL) return;
        itemsize = arr->descr->elsize;
        if (src != NULL) {
                memcpy(dst, src, itemsize);
        }

        if (swap) {
                register char *a, *b, c;
                itemsize >>= 2;
                for (a = (char *)dst; itemsize>0; itemsize--) {
                        b = a + 3;
                        c=*a; *a++ = *b; *b-- = c;
                        c=*a; *a++ = *b; *b-- = c;
                        a += 2;
                }
        }
}


/****************** nonzero **********************************/

/**begin repeat
#fname=BOOL,BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE#
#type=Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble#
*/
static Bool
@fname@_nonzero (@type@ *ip, PyArrayObject *ap)
{
        @type@ t1;
        if (ap==NULL || PyArray_ISBEHAVED_RO(ap))
                return (Bool) (*ip != 0);
        else {
                /* don't worry about swap, since we are just testing
                   whether or not equal to 0 */
                memcpy(&t1, ip, sizeof(@type@));
                return (Bool) (t1 != 0);
        }
}
/**end repeat**/

/**begin repeat
#fname=CFLOAT,CDOUBLE,CLONGDOUBLE#
#type=cfloat, cdouble, clongdouble#
*/
static Bool
@fname@_nonzero (@type@ *ip, PyArrayObject *ap)
{
        @type@ t1;
        if (ap==NULL || PyArray_ISBEHAVED_RO(ap))
                return (Bool) ((ip->real != 0) || (ip->imag != 0));
        else {
                /* don't worry about swap, since we are just testing
                   whether or not equal to 0 */
                memcpy(&t1, ip, sizeof(@type@));
                return (Bool) ((t1.real != 0) || (t1.imag != 0));
        }
}
/**end repeat**/


#define WHITESPACE " \t\n\r\v\f"
#define WHITELEN 6

static Bool
Py_STRING_ISSPACE(char ch)
{
        char white[] = WHITESPACE;
        int j;
        Bool space=FALSE;
        for (j=0; j<WHITELEN; j++) {
                if (ch == white[j]) {
                        space=TRUE;
                        break;
                }
        }
        return space;
}

static Bool
STRING_nonzero (char *ip, PyArrayObject *ap)
{
        int len = ap->descr->elsize;
        int i;
        Bool nonz = FALSE;

        for (i=0; i<len; i++) {
                if (!Py_STRING_ISSPACE(*ip)) {
                        nonz = TRUE;
                        break;
                }
                ip++;
        }
        return nonz;
}

#ifdef Py_UNICODE_WIDE
#define PyArray_UCS4_ISSPACE Py_UNICODE_ISSPACE
#else
#define PyArray_UCS4_ISSPACE(ch) Py_STRING_ISSPACE((char)ch)
#endif

static Bool
UNICODE_nonzero (PyArray_UCS4 *ip, PyArrayObject *ap)
{
        int len = ap->descr->elsize >> 2;
        int i;
        Bool nonz = FALSE;
        char *buffer=NULL;

        if ((!PyArray_ISNOTSWAPPED(ap)) || \
            (!PyArray_ISALIGNED(ap))) {
                buffer = _pya_malloc(ap->descr->elsize);
                if (buffer == NULL) {
                        return nonz;
                }
                memcpy(buffer, ip, ap->descr->elsize);
                if (!PyArray_ISNOTSWAPPED(ap)) {
                        byte_swap_vector(buffer, len, 4);
                }
                ip = (PyArray_UCS4 *)buffer;
        }

        for (i=0; i<len; i++) {
                if (!PyArray_UCS4_ISSPACE(*ip)) {
                        nonz = TRUE;
                        break;
                }
                ip++;
        }
        _pya_free(buffer);
        return nonz;
}

static Bool
OBJECT_nonzero (PyObject **ip, PyArrayObject *ap)
{

        if (*ip == NULL) return FALSE;
        if (PyArray_ISALIGNED(ap)) {
                return (Bool) PyObject_IsTrue(*ip);
        }
        else {
                PyObject **obj;
                obj = ip;
                return (Bool) PyObject_IsTrue(*obj);
        }
}

/* if we have fields, then nonzero only if all sub-fields are nonzero.
*/
static Bool
VOID_nonzero (char *ip, PyArrayObject *ap)
{
        int i;
        int len;
        Bool nonz = FALSE;

        if (PyArray_HASFIELDS(ap)) {
                PyArray_Descr *descr, *new;
                PyObject *key, *value, *title;
                int savedflags, offset;
                Py_ssize_t pos=0;
                descr = ap->descr;
                savedflags = ap->flags;
                while (PyDict_Next(descr->fields, &pos, &key, &value)) {
                        if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset,
                                              &title)) {PyErr_Clear(); continue;}
                        ap->descr = new;
                        ap->flags = savedflags;
                        if ((new->alignment > 1) && !__ALIGNED(ip+offset, new->alignment))
                                ap->flags &= ~ALIGNED;
                        else
                                ap->flags |= ALIGNED;
                        if (new->f->nonzero(ip+offset, ap)) {
                                nonz=TRUE;
                                break;
                        }
                }
                ap->descr = descr;
                ap->flags = savedflags;
                return nonz;
        }
        len = ap->descr->elsize;
        for (i=0; i<len; i++) {
                if (*ip != '\0') {
                        nonz = TRUE;
                        break;
                }
                ip++;
        }
        return nonz;
}

#undef __ALIGNED


/****************** compare **********************************/

static int
BOOL_compare(Bool *ip1, Bool *ip2, PyArrayObject *ap)
{
        return (*ip1 ? (*ip2 ? 0 : 1) : (*ip2 ? -1 : 0));
}

/**begin repeat
#fname=BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE#
#type=byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble#
*/

static int
@fname@_compare (@type@ *ip1, @type@ *ip2, PyArrayObject *ap)
{
        return *ip1 < *ip2 ? -1 : *ip1 == *ip2 ? 0 : 1;
}

/**end repeat**/

/* compare imaginary part first, then complex if equal imaginary  */
/**begin repeat
#fname=CFLOAT, CDOUBLE, CLONGDOUBLE#
#type= float, double, longdouble#
*/

static int
@fname@_compare (@type@ *ip1, @type@ *ip2, PyArrayObject *ap)
{
        if (*ip1 == *ip2) {
                return ip1[1]<ip2[1] ? -1 : (ip1[1] == ip2[1] ? 0 : 1);
        }
        else {
                return *ip1 < *ip2 ? -1 : 1;
        }
}
 /**end repeat**/

static int
OBJECT_compare(PyObject **ip1, PyObject **ip2, PyArrayObject *ap)
{
        if ((*ip1 == NULL) || (*ip2 == NULL)) {
                if (ip1 == ip2) return 1;
                if (ip1 == NULL) return -1;
                return 1;
        }
        return PyObject_Compare(*ip1, *ip2);
}

static int
STRING_compare(char *ip1, char *ip2, PyArrayObject *ap)
{
    const unsigned char *c1 = (unsigned char *)ip1;
    const unsigned char *c2 = (unsigned char *)ip2;
    const size_t len = ap->descr->elsize;
    size_t i;

    for(i = 0; i < len; ++i) {
        if (c1[i] != c2[i]) {
            return (c1[i] > c2[i]) ? 1 : -1;
        }
    }
    return 0;
}

/* taken from Python */
static int
UNICODE_compare(register PyArray_UCS4 *ip1, register PyArray_UCS4 *ip2,
                PyArrayObject *ap)
{
        register int itemsize=ap->descr->elsize;
        register PyArray_UCS4 c1, c2;

        if (itemsize < 0) return 0;

        while(itemsize-- > 0) {
                c1 = *ip1++;
                c2 = *ip2++;

                if (c1 != c2)
                        return (c1 < c2) ? -1 : 1;
        }
        return 0;
}

/* If fields are defined, then compare on first field and if equal
   compare on second field.  Continue until done or comparison results
   in not_equal.

   Must align data passed on to sub-comparisons.
*/

static int
VOID_compare(char *ip1, char *ip2, PyArrayObject *ap)
{
        PyArray_Descr *descr, *new;
        PyObject *names, *key;
        PyObject *tup, *title;
        char *nip1, *nip2;
        int i, offset, res=0;

        if (!PyArray_HASFIELDS(ap))
                return STRING_compare(ip1, ip2, ap);

        descr = ap->descr;
        /* Compare on the first-field.  If equal, then
           compare on the second-field, etc.
        */
        names = descr->names;
        for (i=0; i<PyTuple_GET_SIZE(names); i++) {
                key = PyTuple_GET_ITEM(names, i);
                tup = PyDict_GetItem(descr->fields, key);
                if (!PyArg_ParseTuple(tup, "Oi|O", &new, &offset,
                                      &title)) {
                        goto finish;
                }
                ap->descr = new;
                nip1 = ip1+offset;
                nip2 = ip2+offset;
                if (new->alignment > 1) {
                        if (((intp)(nip1) % new->alignment) != 0) {
                                /* create buffer and copy */
                                nip1 = _pya_malloc(new->elsize);
                                if (nip1 == NULL) goto finish;
                                memcpy(nip1, ip1+offset, new->elsize);
                        }
                        if (((intp)(nip2) % new->alignment) != 0) {
                            /* copy data to a buffer */
                                nip2 = _pya_malloc(new->elsize);
                                if (nip2 == NULL) {
                                        if (nip1 != ip1+offset)
                                                _pya_free(nip1);
                                        goto finish;
                                }
                                memcpy(nip2, ip2+offset, new->elsize);
                        }
                }
                res = new->f->compare(nip1, nip2, ap);
                if (new->alignment > 1) {
                        if (nip1 != ip1+offset) {
                                _pya_free(nip1);
                        }
                        if (nip2 != ip2+offset) {
                                _pya_free(nip2);
                        }
                }
                if (res != 0) break;
        }

 finish:
        ap->descr = descr;
        return res;
}

/****************** argfunc **********************************/

/**begin repeat

#fname= BOOL,BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE#
#type= Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble, float, double, longdouble#
#incr= ip++*14, ip+=2*3#
*/

static int
@fname@_argmax(@type@ *ip, intp n, intp *max_ind, PyArrayObject *aip)
{
        register intp i;
        @type@ mp=*ip;
        *max_ind=0;
        for (i=1; i<n; i++) {
                @incr@;
                if (*ip > mp) {
                        mp = *ip;
                        *max_ind = i;
                }
        }
        return 0;
}

/**end repeat**/

static int
OBJECT_argmax(PyObject **ip, intp n, intp *max_ind, PyArrayObject *aip)
{
        register intp i;
        PyObject *mp=ip[0]; *max_ind=0;
        i = 1;
        while(i<n && mp==NULL) {
                mp=ip[i];
                i++;
        }
        for(; i<n; i++) {
                ip++;
                if (*ip != NULL && PyObject_Compare(*ip,mp) > 0) {
                        mp = *ip;
                        *max_ind=i;
                }
        }
        return 0;
}

/**begin repeat

#fname= STRING, UNICODE#
#type= char, PyArray_UCS4#

*/
static int
@fname@_argmax(@type@ *ip, intp n, intp *max_ind, PyArrayObject *aip)
{
        register intp i;
        int elsize = aip->descr->elsize;
        @type@ *mp = (@type@ *)_pya_malloc(elsize);

        if (mp==NULL) return 0;
        memcpy(mp, ip, elsize);
        *max_ind = 0;
        for(i=1; i<n; i++) {
                ip += elsize;
                if (@fname@_compare(ip,mp,aip) > 0) {
                        memcpy(mp, ip, elsize);
                        *max_ind=i;
                }
        }
        _pya_free(mp);
        return 0;
}

/**end repeat**/

#define VOID_argmax NULL

static void
BOOL_dot(char *ip1, intp is1, char *ip2, intp is2, char *op, intp n,
         void *ignore)
{
        register Bool tmp=FALSE;
        register intp i;
        for(i=0;i<n;i++,ip1+=is1,ip2+=is2) {
                if ((*((Bool *)ip1) != 0) && (*((Bool *)ip2) != 0)) {
                        tmp = TRUE;
                        break;
                }
        }
        *((Bool *)op) = tmp;
}

/**begin repeat
#name=BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE#
#type= byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble#
#out= long, ulong, long, ulong, long, ulong, long, ulong, longlong, ulonglong, float, double, longdouble#
*/
static void
@name@_dot(char *ip1, intp is1, char *ip2, intp is2, char *op, intp n,
           void *ignore)
{
        register @out@ tmp=(@out@)0;
        register intp i;
        for(i=0;i<n;i++,ip1+=is1,ip2+=is2) {
                tmp += (@out@)(*((@type@ *)ip1)) * \
                        (@out@)(*((@type@ *)ip2));
        }
        *((@type@ *)op) = (@type@) tmp;
}
/**end repeat**/


/**begin repeat
#name=CFLOAT, CDOUBLE, CLONGDOUBLE#
#type= float, double, longdouble#
*/
static void @name@_dot(char *ip1, intp is1, char *ip2, intp is2,
                       char *op, intp n, void *ignore)
{
        @type@ tmpr=(@type@)0.0, tmpi=(@type@)0.0;
        intp i;
        for(i=0;i<n;i++,ip1+=is1,ip2+=is2) {
                tmpr += ((@type@ *)ip1)[0] * ((@type@ *)ip2)[0]
                        - ((@type@ *)ip1)[1] * ((@type@ *)ip2)[1];
                tmpi += ((@type@ *)ip1)[1] * ((@type@ *)ip2)[0]
                        + ((@type@ *)ip1)[0] * ((@type@ *)ip2)[1];
        }
        ((@type@ *)op)[0] = tmpr; ((@type@ *)op)[1] = tmpi;
}

/**end repeat**/

static void
OBJECT_dot(char *ip1, intp is1, char *ip2, intp is2, char *op, intp n,
           void *ignore)
{
        intp i;
        PyObject *tmp1, *tmp2, *tmp=NULL;
        PyObject **tmp3;
        for(i=0;i<n;i++,ip1+=is1,ip2+=is2) {
                if ((*((PyObject **)ip1) == NULL) || (*((PyObject **)ip2) == NULL)) {
                        tmp1 = Py_False;
                        Py_INCREF(Py_False);
                }
                else {
                        tmp1 = PyNumber_Multiply(*((PyObject **)ip1),
                                                 *((PyObject **)ip2));
                        if (!tmp1) { Py_XDECREF(tmp); return;}
                }
                if (i == 0) {
                        tmp = tmp1;
                } else {
                        tmp2 = PyNumber_Add(tmp, tmp1);
                        Py_XDECREF(tmp);
                        Py_XDECREF(tmp1);
                        if (!tmp2) return;
                        tmp = tmp2;
                }
        }
        tmp3 = (PyObject**) op;
        tmp2 = *tmp3;
        *((PyObject **)op) = tmp;
        Py_XDECREF(tmp2);
}

#define BOOL_fill NULL

/* this requires buffer to be filled with objects or NULL */
static void
OBJECT_fill(PyObject **buffer, intp length, void *ignored)
{
        intp i;
        PyObject *start = buffer[0];
        PyObject *delta = buffer[1];
        delta = PyNumber_Subtract(delta, start);
        if (!delta) return;
        start = PyNumber_Add(start, delta);
        if (!start) goto finish;
        buffer += 2;

        for (i=2; i<length; i++, buffer++) {
                start = PyNumber_Add(start, delta);
                if (!start) goto finish;
                Py_XDECREF(*buffer);
                *buffer = start;
        }

 finish:
        Py_DECREF(delta);
        return;
}

/**begin repeat
#NAME=BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE#
#typ=byte,ubyte,short,ushort,int,uint,long,ulong,longlong,ulonglong,float,double,longdouble#
*/
static void
@NAME@_fill(@typ@ *buffer, intp length, void *ignored)
{
        register intp i;
        @typ@ start = buffer[0];
        @typ@ delta = buffer[1];
        delta -= start;
        for (i=2; i<length; ++i) {
                buffer[i] = start + i*delta;
        }
}
/**end repeat**/

/**begin repeat
#NAME=CFLOAT,CDOUBLE,CLONGDOUBLE#
#typ=cfloat,cdouble,clongdouble#
*/
static void
@NAME@_fill(@typ@ *buffer, intp length, void *ignored)
{
        register intp i;
        @typ@ start;
        @typ@ delta;

        start.real = buffer->real;
        start.imag = buffer->imag;
        delta.real = buffer[1].real;
        delta.imag = buffer[1].imag;
        delta.real -= start.real;
        delta.imag -= start.imag;
        buffer += 2;
        for (i=2; i<length; i++, buffer++) {
                buffer->real = start.real + i*delta.real;
                buffer->imag = start.imag + i*delta.imag;
        }
}
/**end repeat**/


/* this requires buffer to be filled with objects or NULL */
static void
OBJECT_fillwithscalar(PyObject **buffer, intp length, PyObject **value, void *ignored)
{
        intp i;
        PyObject *val = *value;
        for (i=0; i<length; i++) {
                Py_XDECREF(buffer[i]);
                Py_XINCREF(val);
                buffer[i] = val;
        }
}
/**begin repeat
#NAME=BOOL,BYTE,UBYTE#
#typ=Bool,byte,ubyte#
*/
static void
@NAME@_fillwithscalar(@typ@ *buffer, intp length, @typ@ *value, void *ignored)
{
        memset(buffer, *value, length);
}
/**end repeat**/

/**begin repeat
#NAME=SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE,CFLOAT,CDOUBLE,CLONGDOUBLE#
#typ=short,ushort,int,uint,long,ulong,longlong,ulonglong,float,double,longdouble,cfloat,cdouble,clongdouble#
*/
static void
@NAME@_fillwithscalar(@typ@ *buffer, intp length, @typ@ *value, void *ignored)
{
        register intp i;
        @typ@ val = *value;
        for (i=0; i<length; ++i) {
                buffer[i] = val;
        }
}

/**end repeat**/



/************************
 * Fast clip functions
 *************************/

/**begin repeat
#name=BOOL,BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE#
#type= Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble#
*/
static void
@name@_fastclip(@type@ *in, intp ni, @type@ *min, @type@ *max, @type@ *out)
{
        register npy_intp i;
        @type@ max_val=0, min_val=0;

	if (max != NULL)
		max_val = *max;
	if (min != NULL)
		min_val = *min;

	if (max == NULL) {
		for (i = 0; i < ni; i++) {
			if (in[i] < min_val) {
				out[i] = min_val;
			}
		}
		return;
	}

	if (min == NULL) {
		for (i = 0; i < ni; i++) {
			if (in[i] > max_val) {
				out[i] = max_val;
			}
		}
		return;
	}

        for (i = 0; i < ni; i++) {
                if (in[i] < min_val) {
                        out[i]   = min_val;
                } else if (in[i] > max_val) {
                        out[i]   = max_val;
                }
        }

        return;
}
/**end repeat**/

/**begin repeat
#name=CFLOAT, CDOUBLE, CLONGDOUBLE#
#type= cfloat, cdouble, clongdouble#
*/
static void
@name@_fastclip(@type@ *in, intp ni, @type@ *min, @type@ *max, @type@ *out)
{
        register npy_intp i;
        @type@ max_val, min_val;
	
        min_val = *min;
        max_val = *max;

	if (max != NULL)
		max_val = *max;
	if (min != NULL)
		min_val = *min;

	if (max == NULL) {
		for (i = 0; i < ni; i++) {
			if (PyArray_CLT(in[i],min_val)) {
				out[i] = min_val;
			}
		}
		return;
	}

	if (min == NULL) {
		for (i = 0; i < ni; i++) {
			if (PyArray_CGT(in[i], max_val)) {
				out[i] = max_val;
			}
		}
		return;
	}

        for (i = 0; i < ni; i++) {
                if (PyArray_CLT(in[i], min_val)) {
                        out[i] = min_val;
                } else if (PyArray_CGT(in[i], max_val)) {
                        out[i] = max_val;
                }
        }
        return;
}

/**end repeat**/

#define OBJECT_fastclip NULL

/************************
 * Fast putmask functions
 *************************/

/**begin repeat
#name=BOOL,BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE,CFLOAT, CDOUBLE, CLONGDOUBLE#
#type= Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble,cfloat, cdouble, clongdouble#
*/
static void
@name@_fastputmask(@type@ *in, Bool *mask, intp ni, @type@ *vals, intp nv)
{
        register npy_intp i;
        @type@ s_val;

        if (nv == 1) {
                s_val = *vals;
                for (i = 0; i < ni; i++) {
                        if (mask[i]) {
                                in[i] = s_val;
                        }
                }
        }
        else {
                for (i = 0; i < ni; i++) {
                        if (mask[i]) {
                                in[i] = vals[i%nv];
                        }
                }
        }
        return;
}
/**end repeat**/

#define OBJECT_fastputmask NULL


#define _ALIGN(type) offsetof(struct {char c; type v;},v)

/* Disable harmless compiler warning "4116: unnamed type definition in
   parentheses" which is caused by the _ALIGN macro.  */

#if defined(_MSC_VER)
#pragma warning(disable:4116)
#endif


/**begin repeat

#from= VOID, STRING, UNICODE#
#align= char, char, PyArray_UCS4#
#NAME= Void, String, Unicode#
#endian= |, |, =#
*/

static PyArray_ArrFuncs _Py@NAME@_ArrFuncs = {
        {
                (PyArray_VectorUnaryFunc*)@from@_to_BOOL,
                (PyArray_VectorUnaryFunc*)@from@_to_BYTE,
                (PyArray_VectorUnaryFunc*)@from@_to_UBYTE,
                (PyArray_VectorUnaryFunc*)@from@_to_SHORT,
                (PyArray_VectorUnaryFunc*)@from@_to_USHORT,
                (PyArray_VectorUnaryFunc*)@from@_to_INT,
                (PyArray_VectorUnaryFunc*)@from@_to_UINT,
                (PyArray_VectorUnaryFunc*)@from@_to_LONG,
                (PyArray_VectorUnaryFunc*)@from@_to_ULONG,
                (PyArray_VectorUnaryFunc*)@from@_to_LONGLONG,
                (PyArray_VectorUnaryFunc*)@from@_to_ULONGLONG,
                (PyArray_VectorUnaryFunc*)@from@_to_FLOAT,
                (PyArray_VectorUnaryFunc*)@from@_to_DOUBLE,
                (PyArray_VectorUnaryFunc*)@from@_to_LONGDOUBLE,
                (PyArray_VectorUnaryFunc*)@from@_to_CFLOAT,
                (PyArray_VectorUnaryFunc*)@from@_to_CDOUBLE,
                (PyArray_VectorUnaryFunc*)@from@_to_CLONGDOUBLE,
                (PyArray_VectorUnaryFunc*)@from@_to_OBJECT,
                (PyArray_VectorUnaryFunc*)@from@_to_STRING,
                (PyArray_VectorUnaryFunc*)@from@_to_UNICODE,
                (PyArray_VectorUnaryFunc*)@from@_to_VOID
        },
        (PyArray_GetItemFunc*)@from@_getitem,
        (PyArray_SetItemFunc*)@from@_setitem,
        (PyArray_CopySwapNFunc*)@from@_copyswapn,
        (PyArray_CopySwapFunc*)@from@_copyswap,
        (PyArray_CompareFunc*)@from@_compare,
        (PyArray_ArgFunc*)@from@_argmax,
        (PyArray_DotFunc*)NULL,
        (PyArray_ScanFunc*)@from@_scan,
        (PyArray_FromStrFunc*)@from@_fromstr,
        (PyArray_NonzeroFunc*)@from@_nonzero,
        (PyArray_FillFunc*)NULL,
        (PyArray_FillWithScalarFunc*)NULL,
        {
                NULL, NULL, NULL
        },
        {
                NULL, NULL, NULL
        },
        NULL,
        (PyArray_ScalarKindFunc*)NULL,
        NULL,
        NULL,
        (PyArray_FastClipFunc *)NULL,
        (PyArray_FastPutmaskFunc *)NULL
};

static PyArray_Descr @from@_Descr = {
        PyObject_HEAD_INIT(&PyArrayDescr_Type)
        &Py@NAME@ArrType_Type,
        PyArray_@from@LTR,
        PyArray_@from@LTR,
        '@endian@', 0,
        PyArray_@from@, 0,
        _ALIGN(@align@),
        NULL,
        NULL,
        NULL,
        &_Py@NAME@_ArrFuncs,
};

/**end repeat**/


/**begin repeat

#from= BOOL,BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE,CFLOAT,CDOUBLE,CLONGDOUBLE,OBJECT#
#num= 1*14,2*3,1#
#fromtyp= Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble, float, double, longdouble, PyObject *#
#NAME= Bool, Byte, UByte, Short, UShort, Int, UInt, Long, ULong, LongLong, ULongLong, Float, Double, LongDouble, CFloat, CDouble, CLongDouble, Object#
#kind= GENBOOL, SIGNED, UNSIGNED, SIGNED, UNSIGNED, SIGNED, UNSIGNED, SIGNED, UNSIGNED, SIGNED, UNSIGNED, FLOATING, FLOATING, FLOATING, COMPLEX, COMPLEX, COMPLEX, OBJECT#
#endian= |*3, =*14, |#
#isobject= 0*17,NPY_OBJECT_DTYPE_FLAGS#
*/

static PyArray_ArrFuncs _Py@NAME@_ArrFuncs = {
        {
                (PyArray_VectorUnaryFunc*)@from@_to_BOOL,
                (PyArray_VectorUnaryFunc*)@from@_to_BYTE,
                (PyArray_VectorUnaryFunc*)@from@_to_UBYTE,
                (PyArray_VectorUnaryFunc*)@from@_to_SHORT,
                (PyArray_VectorUnaryFunc*)@from@_to_USHORT,
                (PyArray_VectorUnaryFunc*)@from@_to_INT,
                (PyArray_VectorUnaryFunc*)@from@_to_UINT,
                (PyArray_VectorUnaryFunc*)@from@_to_LONG,
                (PyArray_VectorUnaryFunc*)@from@_to_ULONG,
                (PyArray_VectorUnaryFunc*)@from@_to_LONGLONG,
                (PyArray_VectorUnaryFunc*)@from@_to_ULONGLONG,
                (PyArray_VectorUnaryFunc*)@from@_to_FLOAT,
                (PyArray_VectorUnaryFunc*)@from@_to_DOUBLE,
                (PyArray_VectorUnaryFunc*)@from@_to_LONGDOUBLE,
                (PyArray_VectorUnaryFunc*)@from@_to_CFLOAT,
                (PyArray_VectorUnaryFunc*)@from@_to_CDOUBLE,
                (PyArray_VectorUnaryFunc*)@from@_to_CLONGDOUBLE,
                (PyArray_VectorUnaryFunc*)@from@_to_OBJECT,
                (PyArray_VectorUnaryFunc*)@from@_to_STRING,
                (PyArray_VectorUnaryFunc*)@from@_to_UNICODE,
                (PyArray_VectorUnaryFunc*)@from@_to_VOID
        },
        (PyArray_GetItemFunc*)@from@_getitem,
        (PyArray_SetItemFunc*)@from@_setitem,
        (PyArray_CopySwapNFunc*)@from@_copyswapn,
        (PyArray_CopySwapFunc*)@from@_copyswap,
        (PyArray_CompareFunc*)@from@_compare,
        (PyArray_ArgFunc*)@from@_argmax,
        (PyArray_DotFunc*)@from@_dot,
        (PyArray_ScanFunc*)@from@_scan,
        (PyArray_FromStrFunc*)@from@_fromstr,
        (PyArray_NonzeroFunc*)@from@_nonzero,
        (PyArray_FillFunc*)@from@_fill,
        (PyArray_FillWithScalarFunc*)@from@_fillwithscalar,
        {
                NULL, NULL, NULL
        },
        {
                NULL, NULL, NULL
        },
        NULL,
        (PyArray_ScalarKindFunc*)NULL,
        NULL,
        NULL,
        (PyArray_FastClipFunc*)@from@_fastclip,
        (PyArray_FastPutmaskFunc*)@from@_fastputmask
};

static PyArray_Descr @from@_Descr = {
        PyObject_HEAD_INIT(&PyArrayDescr_Type)
        &Py@NAME@ArrType_Type,
        PyArray_@kind@LTR,
        PyArray_@from@LTR,
        '@endian@', @isobject@,
        PyArray_@from@,
        @num@*sizeof(@fromtyp@),
        _ALIGN(@fromtyp@),
        NULL,
        NULL,
        NULL,
        &_Py@NAME@_ArrFuncs,
};

/**end repeat**/

#define _MAX_LETTER 128
static char _letter_to_num[_MAX_LETTER];

static PyArray_Descr *_builtin_descrs[] = {
        &BOOL_Descr,
        &BYTE_Descr,
        &UBYTE_Descr,
        &SHORT_Descr,
        &USHORT_Descr,
        &INT_Descr,
        &UINT_Descr,
        &LONG_Descr,
        &ULONG_Descr,
        &LONGLONG_Descr,
        &ULONGLONG_Descr,
        &FLOAT_Descr,
        &DOUBLE_Descr,
        &LONGDOUBLE_Descr,
        &CFLOAT_Descr,
        &CDOUBLE_Descr,
        &CLONGDOUBLE_Descr,
        &OBJECT_Descr,
        &STRING_Descr,
        &UNICODE_Descr,
        &VOID_Descr,
};

/*OBJECT_API
 Get the PyArray_Descr structure for a type.
*/
static PyArray_Descr *
PyArray_DescrFromType(int type)
{
        PyArray_Descr *ret=NULL;

        if (type < PyArray_NTYPES) {
                ret = _builtin_descrs[type];
        }
        else if (type == PyArray_NOTYPE) {
                /* This needs to not raise an error so
                   that PyArray_DescrFromType(PyArray_NOTYPE)
                   works for backwards-compatible C-API
                */
                return NULL;
        }
        else if ((type == PyArray_CHAR) || \
                 (type == PyArray_CHARLTR)) {
                ret = PyArray_DescrNew(_builtin_descrs[PyArray_STRING]);
                ret->elsize = 1;
                ret->type = PyArray_CHARLTR;
                return ret;
        }
        else if PyTypeNum_ISUSERDEF(type) {
                ret = userdescrs[type-PyArray_USERDEF];
        }
        else {
                int num=PyArray_NTYPES;
                if (type < _MAX_LETTER)
                        num = (int) _letter_to_num[type];
                if (num >= PyArray_NTYPES)
                        ret = NULL;
                else
                        ret = _builtin_descrs[num];
        }
        if (ret==NULL) {
                PyErr_SetString(PyExc_ValueError,
                                "Invalid data-type for array");
        }
        else Py_INCREF(ret);
        return ret;
}


static int
set_typeinfo(PyObject *dict)
{
        PyObject *infodict, *s;
        int i;

        for (i=0; i<_MAX_LETTER; i++) {
                _letter_to_num[i] = PyArray_NTYPES;
        }

/**begin repeat
#name=BOOL,BYTE,UBYTE,SHORT,USHORT,INT,UINT,INTP,UINTP,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE,CFLOAT,CDOUBLE,CLONGDOUBLE,OBJECT,STRING,UNICODE,VOID#
*/
        _letter_to_num[PyArray_@name@LTR] = PyArray_@name@;
/**end repeat**/
        _letter_to_num[PyArray_STRINGLTR2] = PyArray_STRING;

/**begin repeat
#name=BOOL,BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE,CFLOAT,CDOUBLE,CLONGDOUBLE,OBJECT,STRING,UNICODE,VOID#
*/
        @name@_Descr.fields = Py_None;
/**end repeat**/

        /* Set a dictionary with type information */
        infodict = PyDict_New();
        if (infodict == NULL) return -1;

#define BITSOF_INTP CHAR_BIT*SIZEOF_PY_INTPTR_T
#define BITSOF_BYTE CHAR_BIT

/**begin repeat

#name=BOOL,BYTE,UBYTE,SHORT,USHORT,INT,UINT,INTP,UINTP,LONG,ULONG,LONGLONG,ULONGLONG#
#uname=BOOL,BYTE*2,SHORT*2,INT*2,INTP*2,LONG*2,LONGLONG*2#
#Name=Bool,Byte,UByte,Short,UShort,Int,UInt,Intp,UIntp,Long,ULong,LongLong,ULongLong#
#type=Bool,byte,ubyte,short,ushort,int,uint,intp,uintp,long,ulong,longlong,ulonglong#
#max=1,MAX_BYTE,MAX_UBYTE,MAX_SHORT,MAX_USHORT,MAX_INT,PyLong_FromUnsignedLong(MAX_UINT),PyLong_FromLongLong((longlong) MAX_INTP),PyLong_FromUnsignedLongLong((ulonglong) MAX_UINTP),MAX_LONG,PyLong_FromUnsignedLong((unsigned long) MAX_ULONG),PyLong_FromLongLong((longlong) MAX_LONGLONG), PyLong_FromUnsignedLongLong((ulonglong) MAX_ULONGLONG)#
#min=0,MIN_BYTE,0,MIN_SHORT,0,MIN_INT,0,PyLong_FromLongLong((longlong) MIN_INTP),0,MIN_LONG,0,PyLong_FromLongLong((longlong) MIN_LONGLONG),0#
#cx=i*6,N,N,N,l,N,N,N#
#cn=i*7,N,i,l,i,N,i#
*/
        PyDict_SetItemString(infodict, "@name@",
                             s=Py_BuildValue("ciii@cx@@cn@O",
                                             PyArray_@name@LTR,
                                             PyArray_@name@,
                                             BITSOF_@uname@,
                                             _ALIGN(@type@),
                                             @max@, @min@,
                                     (PyObject *)&Py@Name@ArrType_Type));
        Py_DECREF(s);
/**end repeat**/

#define BITSOF_CFLOAT 2*BITSOF_FLOAT
#define BITSOF_CDOUBLE 2*BITSOF_DOUBLE
#define BITSOF_CLONGDOUBLE 2*BITSOF_LONGDOUBLE

/**begin repeat

#type=float,double,longdouble,cfloat,cdouble,clongdouble#
#name=FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE#
#Name=Float,Double,LongDouble,CFloat,CDouble,CLongDouble#
*/
        PyDict_SetItemString(infodict, "@name@",
                             s=Py_BuildValue("ciiiO", PyArray_@name@LTR,
                                             PyArray_@name@, BITSOF_@name@,
                                             _ALIGN(@type@),
                                             (PyObject *)\
                                             &Py@Name@ArrType_Type));
        Py_DECREF(s);
/**end repeat**/

        PyDict_SetItemString(infodict, "OBJECT",
                             s=Py_BuildValue("ciiiO", PyArray_OBJECTLTR,
                                             PyArray_OBJECT,
                                             sizeof(PyObject *)*CHAR_BIT,
                                             _ALIGN(PyObject *),
                                             (PyObject *)\
                                             &PyObjectArrType_Type));
        Py_DECREF(s);
        PyDict_SetItemString(infodict, "STRING",
                             s=Py_BuildValue("ciiiO", PyArray_STRINGLTR,
                                             PyArray_STRING, 0,
                                             _ALIGN(char),
                                             (PyObject *)\
                                             &PyStringArrType_Type));
        Py_DECREF(s);
        PyDict_SetItemString(infodict, "UNICODE",
                             s=Py_BuildValue("ciiiO", PyArray_UNICODELTR,
                                             PyArray_UNICODE, 0,
                                             _ALIGN(PyArray_UCS4),
                                             (PyObject *)\
                                             &PyUnicodeArrType_Type));
        Py_DECREF(s);
        PyDict_SetItemString(infodict, "VOID",
                             s=Py_BuildValue("ciiiO", PyArray_VOIDLTR,
                                             PyArray_VOID, 0,
                                             _ALIGN(char),
                                             (PyObject *)\
                                             &PyVoidArrType_Type));
        Py_DECREF(s);

#define SETTYPE(name)                           \
        Py_INCREF(&Py##name##ArrType_Type);     \
        PyDict_SetItemString(infodict, #name,   \
                             (PyObject *)&Py##name##ArrType_Type);

        SETTYPE(Generic)
        SETTYPE(Number)
        SETTYPE(Integer)
        SETTYPE(Inexact)
        SETTYPE(SignedInteger)
        SETTYPE(UnsignedInteger)
        SETTYPE(Floating)
        SETTYPE(ComplexFloating)
        SETTYPE(Flexible)
        SETTYPE(Character)

#undef SETTYPE

        PyDict_SetItemString(dict, "typeinfo", infodict);
        Py_DECREF(infodict);
        return 0;
}

#undef _MAX_LETTER
