#ifndef NDARRAYTYPES_H
#define NDARRAYTYPES_H

/* This is auto-generated by the installer */
#include "numpyconfig.h"

#include "npy_common.h"
#include "npy_endian.h"
#include "npy_cpu.h"
#include "utils.h"

#ifdef NPY_ENABLE_SEPARATE_COMPILATION
        #define NPY_NO_EXPORT NPY_VISIBILITY_HIDDEN
#else
        #define NPY_NO_EXPORT static
#endif

/* Only use thread if configured in config and python supports it */
#if defined WITH_THREAD && !NPY_NO_SMP
        #define NPY_ALLOW_THREADS 1
#else
        #define NPY_ALLOW_THREADS 0
#endif



/*
 * There are several places in the code where an array of dimensions
 * is allocated statically.  This is the size of that static
 * allocation.
 *
 * The array creation itself could have arbitrary dimensions but all
 * the places where static allocation is used would need to be changed
 * to dynamic (including inside of several structures)
 */

#define NPY_MAXDIMS 32
#define NPY_MAXARGS 32

/* Used for Converter Functions "O&" code in ParseTuple */
#define NPY_FAIL 0
#define NPY_SUCCEED 1

/*
 * Binary compatibility version number.  This number is increased
 * whenever the C-API is changed such that binary compatibility is
 * broken, i.e. whenever a recompile of extension modules is needed.
 */
#define NPY_VERSION NPY_ABI_VERSION

/*
 * Minor API version.  This number is increased whenever a change is
 * made to the C-API -- whether it breaks binary compatibility or not.
 * Some changes, such as adding a function pointer to the end of the
 * function table, can be made without breaking binary compatibility.
 * In this case, only the NPY_FEATURE_VERSION (*not* NPY_VERSION)
 * would be increased.  Whenever binary compatibility is broken, both
 * NPY_VERSION and NPY_FEATURE_VERSION should be increased.
 */
#define NPY_FEATURE_VERSION NPY_API_VERSION

enum NPY_TYPES {    NPY_BOOL=0,
                    NPY_BYTE, NPY_UBYTE,
                    NPY_SHORT, NPY_USHORT,
                    NPY_INT, NPY_UINT,
                    NPY_LONG, NPY_ULONG,
                    NPY_LONGLONG, NPY_ULONGLONG,
                    NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE,
                    NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE,
                    NPY_OBJECT=17,
                    NPY_STRING, NPY_UNICODE,
                    NPY_VOID,
                    NPY_NTYPES,
                    NPY_NOTYPE,
                    NPY_CHAR,      /* special flag */
                    NPY_USERDEF=256  /* leave room for characters */
};

#define NPY_METADATA_DTSTR "__frequency__"

/* basetype array priority */
#define NPY_PRIORITY 0.0

/* default subtype priority */
#define NPY_SUBTYPE_PRIORITY 1.0

/* default scalar priority */
#define NPY_SCALAR_PRIORITY -1000000.0

/* How many floating point types are there */
#define NPY_NUM_FLOATTYPE 3

/*
 * We need to match npy_intp to a signed integer of the same size as a
 * pointer variable. npy_uintp to the equivalent unsigned integer
 */


/*
 * These characters correspond to the array type and the struct
 * module
 */

/*  except 'p' -- signed integer for pointer type */

enum NPY_TYPECHAR { NPY_BOOLLTR = '?',
                        NPY_BYTELTR = 'b',
                        NPY_UBYTELTR = 'B',
                        NPY_SHORTLTR = 'h',
                        NPY_USHORTLTR = 'H',
                        NPY_INTLTR = 'i',
                        NPY_UINTLTR = 'I',
                        NPY_LONGLTR = 'l',
                        NPY_ULONGLTR = 'L',
                        NPY_LONGLONGLTR = 'q',
                        NPY_ULONGLONGLTR = 'Q',
                        NPY_FLOATLTR = 'f',
                        NPY_DOUBLELTR = 'd',
                        NPY_LONGDOUBLELTR = 'g',
                        NPY_CFLOATLTR = 'F',
                        NPY_CDOUBLELTR = 'D',
                        NPY_CLONGDOUBLELTR = 'G',
                        NPY_OBJECTLTR = 'O',
                        NPY_STRINGLTR = 'S',
                        NPY_STRINGLTR2 = 'a',
                        NPY_UNICODELTR = 'U',
                        NPY_VOIDLTR = 'V',
                        NPY_DATETIMELTR = 'M',
                        NPY_TIMEDELTALTR = 'm',
                        NPY_CHARLTR = 'c',

                        /*
                         * No Descriptor, just a define -- this let's
                         * Python users specify an array of integers
                         * large enough to hold a pointer on the
                         * platform
                         */
                        NPY_INTPLTR = 'p',
                        NPY_UINTPLTR = 'P',

                        NPY_GENBOOLLTR ='b',
                        NPY_SIGNEDLTR = 'i',
                        NPY_UNSIGNEDLTR = 'u',
                        NPY_FLOATINGLTR = 'f',
                        NPY_COMPLEXLTR = 'c'
};

typedef enum {
        NPY_QUICKSORT=0,
        NPY_HEAPSORT=1,
        NPY_MERGESORT=2
} NPY_SORTKIND;
#define NPY_NSORTS (NPY_MERGESORT + 1)


typedef enum {
        NPY_SEARCHLEFT=0,
        NPY_SEARCHRIGHT=1
} NPY_SEARCHSIDE;
#define NPY_NSEARCHSIDES (NPY_SEARCHRIGHT + 1)


typedef enum {
        NPY_NOSCALAR=-1,
        NPY_BOOL_SCALAR,
        NPY_INTPOS_SCALAR,
        NPY_INTNEG_SCALAR,
        NPY_FLOAT_SCALAR,
        NPY_COMPLEX_SCALAR,
        NPY_OBJECT_SCALAR
} NPY_SCALARKIND;
#define NPY_NSCALARKINDS (NPY_OBJECT_SCALAR + 1)

typedef enum {
        NPY_ANYORDER=-1,
        NPY_CORDER=0,
        NPY_FORTRANORDER=1
} NPY_ORDER;


typedef enum {
        NPY_CLIP=0,
        NPY_WRAP=1,
        NPY_RAISE=2
} NPY_CLIPMODE;

typedef enum {
        NPY_FR_Y,
        NPY_FR_M,
        NPY_FR_W,
        NPY_FR_B,
        NPY_FR_D,
        NPY_FR_h,
        NPY_FR_m,
        NPY_FR_s,
        NPY_FR_ms,
        NPY_FR_us,
        NPY_FR_ns,
        NPY_FR_ps,
        NPY_FR_fs,
        NPY_FR_as
} NPY_DATETIMEUNIT;

#define NPY_DATETIME_NUMUNITS (NPY_FR_as + 1)
#define NPY_DATETIME_DEFAULTUNIT NPY_FR_us


#define NPY_STR_Y "Y"
#define NPY_STR_M "M"
#define NPY_STR_W "W"
#define NPY_STR_B "B"
#define NPY_STR_D "D"
#define NPY_STR_h "h"
#define NPY_STR_m "m"
#define NPY_STR_s "s"
#define NPY_STR_ms "ms"
#define NPY_STR_us "us"
#define NPY_STR_ns "ns"
#define NPY_STR_ps "ps"
#define NPY_STR_fs "fs"
#define NPY_STR_as "as"


/*
 * This is to typedef npy_intp to the appropriate pointer size for
 * this platform.  Py_intptr_t, Py_uintptr_t are defined in pyport.h.
 */
typedef Py_intptr_t npy_intp;
typedef Py_uintptr_t npy_uintp;
#define NPY_SIZEOF_INTP NPY_SIZEOF_PY_INTPTR_T
#define NPY_SIZEOF_UINTP NPY_SIZEOF_PY_INTPTR_T

#ifdef constchar
#undef constchar
#endif

#if (PY_VERSION_HEX < 0x02050000)
  #ifndef PY_SSIZE_T_MIN
    typedef int Py_ssize_t;
    #define PY_SSIZE_T_MAX INT_MAX
    #define PY_SSIZE_T_MIN INT_MIN
  #endif
#define NPY_SSIZE_T_PYFMT "i"
#undef PyIndex_Check
#define constchar const char
#define PyIndex_Check(op) 0
#else
#define NPY_SSIZE_T_PYFMT "n"
#define constchar char
#endif

#if NPY_SIZEOF_PY_INTPTR_T == NPY_SIZEOF_INT
        #define NPY_INTP NPY_INT
        #define NPY_UINTP NPY_UINT
        #define PyIntpArrType_Type PyIntArrType_Type
        #define PyUIntpArrType_Type PyUIntArrType_Type
        #define NPY_MAX_INTP NPY_MAX_INT
        #define NPY_MIN_INTP NPY_MIN_INT
        #define NPY_MAX_UINTP NPY_MAX_UINT
        #define NPY_INTP_FMT "d"
#elif NPY_SIZEOF_PY_INTPTR_T == NPY_SIZEOF_LONG
        #define NPY_INTP NPY_LONG
        #define NPY_UINTP NPY_ULONG
        #define PyIntpArrType_Type PyLongArrType_Type
        #define PyUIntpArrType_Type PyULongArrType_Type
        #define NPY_MAX_INTP NPY_MAX_LONG
        #define NPY_MIN_INTP MIN_LONG
        #define NPY_MAX_UINTP NPY_MAX_ULONG
        #define NPY_INTP_FMT "ld"
#elif defined(PY_LONG_LONG) && (NPY_SIZEOF_PY_INTPTR_T == NPY_SIZEOF_LONGLONG)
        #define NPY_INTP NPY_LONGLONG
        #define NPY_UINTP NPY_ULONGLONG
        #define PyIntpArrType_Type PyLongLongArrType_Type
        #define PyUIntpArrType_Type PyULongLongArrType_Type
        #define NPY_MAX_INTP NPY_MAX_LONGLONG
        #define NPY_MIN_INTP NPY_MIN_LONGLONG
        #define NPY_MAX_UINTP NPY_MAX_ULONGLONG
#ifdef _MSC_VER
        #define NPY_INTP_FMT "lld"
#else
        #define NPY_INTP_FMT "Ld"
#endif
#endif

/*
 * We can only use C99 formats for npy_int_p if it is the same as
 * intp_t, hence the condition on HAVE_UNITPTR_T
 */
#if (NPY_USE_C99_FORMATS) == 1 \
        && (defined HAVE_UINTPTR_T) \
        && (defined HAVE_INTTYPES_H)
        #include <inttypes.h>
        #undef NPY_INTP_FMT
        #define NPY_INTP_FMT PRIdPTR
#endif

#define NPY_ERR(str) fprintf(stderr, #str); fflush(stderr);
#define NPY_ERR2(str) fprintf(stderr, str); fflush(stderr);

#define NPY_STRINGIFY(x) #x
#define NPY_TOSTRING(x) NPY_STRINGIFY(x)

  /*
   * Macros to define how array, and dimension/strides data is
   * allocated.
   */

  /* Data buffer */
#define PyDataMem_NEW(size) ((char *)malloc(size))
#define PyDataMem_FREE(ptr)  free(ptr)
#define PyDataMem_RENEW(ptr,size) ((char *)realloc(ptr,size))

#define NPY_USE_PYMEM 1

#if NPY_USE_PYMEM == 1
#define PyArray_malloc PyMem_Malloc
#define PyArray_free PyMem_Free
#define PyArray_realloc PyMem_Realloc
#else
#define PyArray_malloc malloc
#define PyArray_free free
#define PyArray_realloc realloc
#endif

/* Dimensions and strides */
#define PyDimMem_NEW(size)                                         \
    ((npy_intp *)PyArray_malloc(size*sizeof(npy_intp)))

#define PyDimMem_FREE(ptr) PyArray_free(ptr)

#define PyDimMem_RENEW(ptr,size)                                   \
        ((npy_intp *)PyArray_realloc(ptr,size*sizeof(npy_intp)))

/* forward declaration */
struct _PyArray_Descr;

/* These must deal with unaligned and swapped data if necessary */
typedef PyObject * (PyArray_GetItemFunc) (void *, void *);
typedef int (PyArray_SetItemFunc)(PyObject *, void *, void *);

typedef void (PyArray_CopySwapNFunc)(void *, npy_intp, void *, npy_intp,
                                     npy_intp, int, void *);

typedef void (PyArray_CopySwapFunc)(void *, void *, int, void *);
typedef npy_bool (PyArray_NonzeroFunc)(void *, void *);


/*
 * These assume aligned and notswapped data -- a buffer will be used
 * before or contiguous data will be obtained
 */

typedef int (PyArray_CompareFunc)(const void *, const void *, void *);
typedef int (PyArray_ArgFunc)(void*, npy_intp, npy_intp*, void *);

typedef void (PyArray_DotFunc)(void *, npy_intp, void *, npy_intp, void *,
                               npy_intp, void *);

typedef void (PyArray_VectorUnaryFunc)(void *, void *, npy_intp, void *,
                                       void *);

/*
 * XXX the ignore argument should be removed next time the API version
 * is bumped. It used to be the separator.
 */
typedef int (PyArray_ScanFunc)(FILE *fp, void *dptr,
                               char *ignore, struct _PyArray_Descr *);
typedef int (PyArray_FromStrFunc)(char *s, void *dptr, char **endptr,
                                  struct _PyArray_Descr *);

typedef int (PyArray_FillFunc)(void *, npy_intp, void *);

typedef int (PyArray_SortFunc)(void *, npy_intp, void *);
typedef int (PyArray_ArgSortFunc)(void *, npy_intp *, npy_intp, void *);

typedef int (PyArray_FillWithScalarFunc)(void *, npy_intp, void *, void *);

typedef int (PyArray_ScalarKindFunc)(void *);

typedef void (PyArray_FastClipFunc)(void *in, npy_intp n_in, void *min,
                                    void *max, void *out);
typedef void (PyArray_FastPutmaskFunc)(void *in, void *mask, npy_intp n_in,
                                       void *values, npy_intp nv);
typedef int  (PyArray_FastTakeFunc)(void *dest, void *src, npy_intp *indarray,
                                       npy_intp nindarray, npy_intp n_outer,
                                       npy_intp m_middle, npy_intp nelem,
                                       NPY_CLIPMODE clipmode);

typedef struct {
        npy_intp *ptr;
        int len;
} PyArray_Dims;

typedef struct {
        /* Functions to cast to all other standard types*/
        /* Can have some NULL entries */
        PyArray_VectorUnaryFunc *cast[NPY_NTYPES];

        /* The next four functions *cannot* be NULL */

        /*
         * Functions to get and set items with standard Python types
         * -- not array scalars
         */
        PyArray_GetItemFunc *getitem;
        PyArray_SetItemFunc *setitem;

        /*
         * Copy and/or swap data.  Memory areas may not overlap
         * Use memmove first if they might
         */
        PyArray_CopySwapNFunc *copyswapn;
        PyArray_CopySwapFunc *copyswap;

        /*
         * Function to compare items
         * Can be NULL
         */
        PyArray_CompareFunc *compare;

        /*
         * Function to select largest
         * Can be NULL
         */
        PyArray_ArgFunc *argmax;

        /*
         * Function to compute dot product
         * Can be NULL
         */
        PyArray_DotFunc *dotfunc;

        /*
         * Function to scan an ASCII file and
         * place a single value plus possible separator
         * Can be NULL
         */
        PyArray_ScanFunc *scanfunc;

        /*
         * Function to read a single value from a string
         * and adjust the pointer; Can be NULL
         */
        PyArray_FromStrFunc *fromstr;

        /*
         * Function to determine if data is zero or not
         * If NULL a default version is
         * used at Registration time.
         */
        PyArray_NonzeroFunc *nonzero;

        /*
         * Used for arange.
         * Can be NULL.
         */
        PyArray_FillFunc *fill;

        /*
         * Function to fill arrays with scalar values
         * Can be NULL
         */
        PyArray_FillWithScalarFunc *fillwithscalar;

        /*
         * Sorting functions
         * Can be NULL
         */
        PyArray_SortFunc *sort[NPY_NSORTS];
        PyArray_ArgSortFunc *argsort[NPY_NSORTS];

        /*
         * Dictionary of additional casting functions
         * PyArray_VectorUnaryFuncs
         * which can be populated to support casting
         * to other registered types. Can be NULL
         */
        PyObject *castdict;

        /*
         * Functions useful for generalizing
         * the casting rules.
         * Can be NULL;
         */
        PyArray_ScalarKindFunc *scalarkind;
        int **cancastscalarkindto;
        int *cancastto;

        PyArray_FastClipFunc *fastclip;
        PyArray_FastPutmaskFunc *fastputmask;
        PyArray_FastTakeFunc *fasttake;
} PyArray_ArrFuncs;


/* The item must be reference counted when it is inserted or extracted. */
#define NPY_ITEM_REFCOUNT   0x01
/* Same as needing REFCOUNT */
#define NPY_ITEM_HASOBJECT  0x01
/* Convert to list for pickling */
#define NPY_LIST_PICKLE     0x02
/* The item is a POINTER  */
#define NPY_ITEM_IS_POINTER 0x04
/* memory needs to be initialized for this data-type */
#define NPY_NEEDS_INIT      0x08
/* operations need Python C-API so don't give-up thread. */
#define NPY_NEEDS_PYAPI     0x10
/* Use f.getitem when extracting elements of this data-type */
#define NPY_USE_GETITEM     0x20
/* Use f.setitem when setting creating 0-d array from this data-type.*/
#define NPY_USE_SETITEM     0x40
/* define NPY_IS_COMPLEX */

/*
 *These are inherited for global data-type if any data-types in the
 * field have them
 */
#define NPY_FROM_FIELDS    (NPY_NEEDS_INIT | NPY_LIST_PICKLE |             \
                            NPY_ITEM_REFCOUNT | NPY_NEEDS_PYAPI)

#define NPY_OBJECT_DTYPE_FLAGS (NPY_LIST_PICKLE | NPY_USE_GETITEM |       \
                                NPY_ITEM_IS_POINTER | NPY_ITEM_REFCOUNT | \
                                NPY_NEEDS_INIT | NPY_NEEDS_PYAPI)

#define PyDataType_FLAGCHK(dtype, flag)                                   \
        (((dtype)->hasobject & (flag)) == (flag))

#define PyDataType_REFCHK(dtype)                                          \
        PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)

/* Change dtype hasobject to 32-bit in 1.1 and change its name */
typedef struct _PyArray_Descr {
        PyObject_HEAD
        PyTypeObject *typeobj;  /* the type object representing an
                                   instance of this type -- should not
                                   be two type_numbers with the same type
                                   object. */
        char kind;              /* kind for this type */
        char type;              /* unique-character representing this type */
        char byteorder;         /* '>' (big), '<' (little), '|'
                                   (not-applicable), or '=' (native). */
        char hasobject;         /* non-zero if it has object arrays
                                   in fields */
        int type_num;          /* number representing this type */
        int elsize;             /* element size for this type */
        int alignment;          /* alignment needed for this type */
        struct _arr_descr                                       \
        *subarray;              /* Non-NULL if this type is
                                   is an array (C-contiguous)
                                   of some other type
                                */
        PyObject *fields;       /* The fields dictionary for this type */
                                /* For statically defined descr this
                                   is always Py_None */

        PyObject *names;        /* An ordered tuple of field names or NULL
                                   if no fields are defined */

        PyArray_ArrFuncs *f;     /* a table of functions specific for each
                                    basic data descriptor */

        PyObject *metadata;     /* Metadata about this dtype */
} PyArray_Descr;

typedef struct _arr_descr {
        PyArray_Descr *base;
        PyObject *shape;       /* a tuple */
} PyArray_ArrayDescr;

/*
 * The main array object structure. It is recommended to use the macros
 * defined below (PyArray_DATA and friends) access fields here, instead
 * of the members themselves.
 */

typedef struct PyArrayObject {
        PyObject_HEAD
        char *data;             /* pointer to raw data buffer */
        int nd;                 /* number of dimensions, also called ndim */
        npy_intp *dimensions;   /* size in each dimension */
        npy_intp *strides;      /*
                                 * bytes to jump to get to the
                                 * next element in each dimension
                                 */
        PyObject *base;         /*
                                 * This object should be decref'd upon
                                 * deletion of array
                                 *
                                 * For views it points to the original
                                 * array
                                 *
                                 * For creation from buffer object it
                                 * points to an object that shold be
                                 * decref'd on deletion
                                 *
                                 * For UPDATEIFCOPY flag this is an
                                 * array to-be-updated upon deletion
                                 * of this one
                                 */
        PyArray_Descr *descr;   /* Pointer to type structure */
        int flags;              /* Flags describing array -- see below */
        PyObject *weakreflist;  /* For weakreferences */
} PyArrayObject;

#define NPY_AO PyArrayObject

#define fortran fortran_        /* For some compilers */

/* Array Flags Object */
typedef struct PyArrayFlagsObject {
        PyObject_HEAD
        PyObject *arr;
        int flags;
} PyArrayFlagsObject;

/* Mirrors buffer object to ptr */

typedef struct {
        PyObject_HEAD
        PyObject *base;
        void *ptr;
        npy_intp len;
        int flags;
} PyArray_Chunk;


typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);

/*
 * Means c-style contiguous (last index varies the fastest). The data
 * elements right after each other.
 */
#define NPY_CONTIGUOUS    0x0001

/*
 * set if array is a contiguous Fortran array: the first index varies
 * the fastest in memory (strides array is reverse of C-contiguous
 * array)
 */
#define NPY_FORTRAN       0x0002

#define NPY_C_CONTIGUOUS NPY_CONTIGUOUS
#define NPY_F_CONTIGUOUS NPY_FORTRAN

/*
 * Note: all 0-d arrays are CONTIGUOUS and FORTRAN contiguous. If a
 * 1-d array is CONTIGUOUS it is also FORTRAN contiguous
 */

/*
 * If set, the array owns the data: it will be free'd when the array
 * is deleted.
 */
#define NPY_OWNDATA       0x0004

/*
 * An array never has the next four set; they're only used as parameter
 * flags to the the various FromAny functions
 */

/* Cause a cast to occur regardless of whether or not it is safe. */
#define NPY_FORCECAST     0x0010

/*
 * Always copy the array. Returned arrays are always CONTIGUOUS,
 * ALIGNED, and WRITEABLE.
 */
#define NPY_ENSURECOPY    0x0020

/* Make sure the returned array is a base-class ndarray */
#define NPY_ENSUREARRAY   0x0040

/*
 * Make sure that the strides are in units of the element size Needed
 * for some operations with record-arrays.
 */
#define NPY_ELEMENTSTRIDES 0x0080

/*
 * Array data is aligned on the appropiate memory address for the type
 * stored according to how the compiler would align things (e.g., an
 * array of integers (4 bytes each) starts on a memory address that's
 * a multiple of 4)
 */
#define NPY_ALIGNED       0x0100

/* Array data has the native endianness */
#define NPY_NOTSWAPPED    0x0200

/* Array data is writeable */
#define NPY_WRITEABLE     0x0400

/*
 * If this flag is set, then base contains a pointer to an array of
 * the same size that should be updated with the current contents of
 * this array when this array is deallocated
 */
#define NPY_UPDATEIFCOPY  0x1000

/* This flag is for the array interface */
#define NPY_ARR_HAS_DESCR  0x0800


#define NPY_BEHAVED (NPY_ALIGNED | NPY_WRITEABLE)
#define NPY_BEHAVED_NS (NPY_ALIGNED | NPY_WRITEABLE | NPY_NOTSWAPPED)
#define NPY_CARRAY (NPY_CONTIGUOUS | NPY_BEHAVED)
#define NPY_CARRAY_RO (NPY_CONTIGUOUS | NPY_ALIGNED)
#define NPY_FARRAY (NPY_FORTRAN | NPY_BEHAVED)
#define NPY_FARRAY_RO (NPY_FORTRAN | NPY_ALIGNED)
#define NPY_DEFAULT NPY_CARRAY
#define NPY_IN_ARRAY NPY_CARRAY_RO
#define NPY_OUT_ARRAY NPY_CARRAY
#define NPY_INOUT_ARRAY (NPY_CARRAY | NPY_UPDATEIFCOPY)
#define NPY_IN_FARRAY NPY_FARRAY_RO
#define NPY_OUT_FARRAY NPY_FARRAY
#define NPY_INOUT_FARRAY (NPY_FARRAY | NPY_UPDATEIFCOPY)

#define NPY_UPDATE_ALL (NPY_CONTIGUOUS | NPY_FORTRAN | NPY_ALIGNED)


/*
 * Size of internal buffers used for alignment Make BUFSIZE a multiple
 * of sizeof(cdouble) -- ususally 16 so that ufunc buffers are aligned
 */
#define NPY_MIN_BUFSIZE ((int)sizeof(cdouble))
#define NPY_MAX_BUFSIZE (((int)sizeof(cdouble))*1000000)
#define NPY_BUFSIZE 10000
/* #define NPY_BUFSIZE 80*/

#define PyArray_MAX(a,b) (((a)>(b))?(a):(b))
#define PyArray_MIN(a,b) (((a)<(b))?(a):(b))
#define PyArray_CLT(p,q) ((((p).real==(q).real) ? ((p).imag < (q).imag) : \
                               ((p).real < (q).real)))
#define PyArray_CGT(p,q) ((((p).real==(q).real) ? ((p).imag > (q).imag) : \
                               ((p).real > (q).real)))
#define PyArray_CLE(p,q) ((((p).real==(q).real) ? ((p).imag <= (q).imag) : \
                               ((p).real <= (q).real)))
#define PyArray_CGE(p,q) ((((p).real==(q).real) ? ((p).imag >= (q).imag) : \
                               ((p).real >= (q).real)))
#define PyArray_CEQ(p,q) (((p).real==(q).real) && ((p).imag == (q).imag))
#define PyArray_CNE(p,q) (((p).real!=(q).real) || ((p).imag != (q).imag))

/*
 * C API: consists of Macros and functions.  The MACROS are defined
 * here.
 */


#define PyArray_CHKFLAGS(m, FLAGS)                              \
        ((((PyArrayObject *)(m))->flags & (FLAGS)) == (FLAGS))

#define PyArray_ISCONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_CONTIGUOUS)
#define PyArray_ISWRITEABLE(m) PyArray_CHKFLAGS(m, NPY_WRITEABLE)
#define PyArray_ISALIGNED(m) PyArray_CHKFLAGS(m, NPY_ALIGNED)


#if NPY_ALLOW_THREADS
#define NPY_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
#define NPY_END_ALLOW_THREADS Py_END_ALLOW_THREADS
#define NPY_BEGIN_THREADS_DEF PyThreadState *_save=NULL;
#define NPY_BEGIN_THREADS _save = PyEval_SaveThread();
#define NPY_END_THREADS   do {if (_save) PyEval_RestoreThread(_save);} while (0);

#define NPY_BEGIN_THREADS_DESCR(dtype)                          \
        do {if (!(PyDataType_FLAGCHK(dtype, NPY_NEEDS_PYAPI)))      \
                NPY_BEGIN_THREADS;} while (0);

#define NPY_END_THREADS_DESCR(dtype)                            \
        do {if (!(PyDataType_FLAGCHK(dtype, NPY_NEEDS_PYAPI)))      \
                NPY_END_THREADS; } while (0);

#define NPY_ALLOW_C_API_DEF  PyGILState_STATE __save__;
#define NPY_ALLOW_C_API      __save__ = PyGILState_Ensure();
#define NPY_DISABLE_C_API    PyGILState_Release(__save__);
#else
#define NPY_BEGIN_ALLOW_THREADS
#define NPY_END_ALLOW_THREADS
#define NPY_BEGIN_THREADS_DEF
#define NPY_BEGIN_THREADS
#define NPY_END_THREADS
#define NPY_BEGIN_THREADS_DESCR(dtype)
#define NPY_END_THREADS_DESCR(dtype)
#define NPY_ALLOW_C_API_DEF
#define NPY_ALLOW_C_API
#define NPY_DISABLE_C_API
#endif

/*****************************
 * Basic iterator object
 *****************************/

/* FWD declaration */
typedef struct PyArrayIterObject_tag PyArrayIterObject;

/*
 * type of the function which translates a set of coordinates to a
 * pointer to the data
 */
typedef char* (*npy_iter_get_dataptr_t)(PyArrayIterObject* iter, npy_intp*);

struct PyArrayIterObject_tag {
        PyObject_HEAD
        int               nd_m1;            /* number of dimensions - 1 */
        npy_intp          index, size;
        npy_intp          coordinates[NPY_MAXDIMS];/* N-dimensional loop */
        npy_intp          dims_m1[NPY_MAXDIMS];    /* ao->dimensions - 1 */
        npy_intp          strides[NPY_MAXDIMS];    /* ao->strides or fake */
        npy_intp          backstrides[NPY_MAXDIMS];/* how far to jump back */
        npy_intp          factors[NPY_MAXDIMS];     /* shape factors */
        PyArrayObject     *ao;
        char              *dataptr;        /* pointer to current item*/
        npy_bool          contiguous;

        npy_intp          bounds[NPY_MAXDIMS][2];
        npy_intp          limits[NPY_MAXDIMS][2];
        npy_intp          limits_sizes[NPY_MAXDIMS];
        npy_iter_get_dataptr_t translate;
} ;


/* Iterator API */
#define PyArrayIter_Check(op) PyObject_TypeCheck(op, &PyArrayIter_Type)

#define _PyAIT(it) ((PyArrayIterObject *)(it))
#define PyArray_ITER_RESET(it) {                                        \
        _PyAIT(it)->index = 0;                                          \
        _PyAIT(it)->dataptr = _PyAIT(it)->ao->data;                     \
        memset(_PyAIT(it)->coordinates, 0,                              \
               (_PyAIT(it)->nd_m1+1)*sizeof(npy_intp));                 \
}

#define _PyArray_ITER_NEXT1(it) {                                       \
        (it)->dataptr += _PyAIT(it)->strides[0];                        \
        (it)->coordinates[0]++;                                         \
}

#define _PyArray_ITER_NEXT2(it) {                                       \
        if ((it)->coordinates[1] < (it)->dims_m1[1]) {                  \
                (it)->coordinates[1]++;                                 \
                (it)->dataptr += (it)->strides[1];                      \
        }                                                               \
        else {                                                          \
                (it)->coordinates[1] = 0;                               \
                (it)->coordinates[0]++;                                 \
                (it)->dataptr += (it)->strides[0] -                     \
                        (it)->backstrides[1];                           \
        }                                                               \
}

#define _PyArray_ITER_NEXT3(it) {                                       \
        if ((it)->coordinates[2] < (it)->dims_m1[2]) {                  \
                (it)->coordinates[2]++;                                 \
                (it)->dataptr += (it)->strides[2];                      \
        }                                                               \
        else {                                                          \
                (it)->coordinates[2] = 0;                               \
                (it)->dataptr -= (it)->backstrides[2];                  \
                if ((it)->coordinates[1] < (it)->dims_m1[1]) {          \
                        (it)->coordinates[1]++;                         \
                        (it)->dataptr += (it)->strides[1];              \
                }                                                       \
                else {                                                  \
                        (it)->coordinates[1] = 0;                       \
                        (it)->coordinates[0]++;                         \
                        (it)->dataptr += (it)->strides[0] -             \
                                (it)->backstrides[1];                   \
                }                                                       \
        }                                                               \
}

#define PyArray_ITER_NEXT(it) {                                            \
        _PyAIT(it)->index++;                                               \
        if (_PyAIT(it)->nd_m1 == 0) {                                      \
                _PyArray_ITER_NEXT1(_PyAIT(it));                           \
        }                                                                  \
        else if (_PyAIT(it)->contiguous)                                   \
                _PyAIT(it)->dataptr += _PyAIT(it)->ao->descr->elsize;      \
        else if (_PyAIT(it)->nd_m1 == 1) {                                 \
                _PyArray_ITER_NEXT2(_PyAIT(it));                           \
        }                                                                  \
        else {                                                             \
                int __npy_i;                                               \
                for (__npy_i=_PyAIT(it)->nd_m1; __npy_i >= 0; __npy_i--) { \
                        if (_PyAIT(it)->coordinates[__npy_i] <             \
                            _PyAIT(it)->dims_m1[__npy_i]) {                \
                                _PyAIT(it)->coordinates[__npy_i]++;        \
                                _PyAIT(it)->dataptr +=                     \
                                        _PyAIT(it)->strides[__npy_i];      \
                                break;                                     \
                        }                                                  \
                        else {                                             \
                                _PyAIT(it)->coordinates[__npy_i] = 0;      \
                                _PyAIT(it)->dataptr -=                     \
                                        _PyAIT(it)->backstrides[__npy_i];  \
                        }                                                  \
                }                                                          \
        }                                                                  \
}

#define PyArray_ITER_GOTO(it, destination) {                            \
        int __npy_i;                                                    \
        _PyAIT(it)->index = 0;                                          \
        _PyAIT(it)->dataptr = _PyAIT(it)->ao->data;                     \
        for (__npy_i = _PyAIT(it)->nd_m1; __npy_i>=0; __npy_i--) {      \
                if (destination[__npy_i] < 0) {                         \
                        destination[__npy_i] +=                         \
                                _PyAIT(it)->dims_m1[__npy_i]+1;         \
                }                                                       \
                _PyAIT(it)->dataptr += destination[__npy_i] *           \
                        _PyAIT(it)->strides[__npy_i];                   \
                _PyAIT(it)->coordinates[__npy_i] =                      \
                        destination[__npy_i];                           \
                _PyAIT(it)->index += destination[__npy_i] *             \
                        ( __npy_i==_PyAIT(it)->nd_m1 ? 1 :              \
                          _PyAIT(it)->dims_m1[__npy_i+1]+1) ;           \
        }                                                               \
}

#define PyArray_ITER_GOTO1D(it, ind) {                                     \
        int __npy_i;                                                       \
        npy_intp __npy_ind = (npy_intp) (ind);                             \
        if (__npy_ind < 0) __npy_ind += _PyAIT(it)->size;                  \
        _PyAIT(it)->index = __npy_ind;                                     \
        if (_PyAIT(it)->nd_m1 == 0) {                                      \
                _PyAIT(it)->dataptr = _PyAIT(it)->ao->data +               \
                        __npy_ind * _PyAIT(it)->strides[0];                \
        }                                                                  \
        else if (_PyAIT(it)->contiguous)                                   \
                _PyAIT(it)->dataptr = _PyAIT(it)->ao->data +               \
                        __npy_ind * _PyAIT(it)->ao->descr->elsize;         \
        else {                                                             \
                _PyAIT(it)->dataptr = _PyAIT(it)->ao->data;                \
                for (__npy_i = 0; __npy_i<=_PyAIT(it)->nd_m1;              \
                     __npy_i++) {                                          \
                        _PyAIT(it)->dataptr +=                             \
                                (__npy_ind / _PyAIT(it)->factors[__npy_i]) \
                                * _PyAIT(it)->strides[__npy_i];            \
                        __npy_ind %= _PyAIT(it)->factors[__npy_i];         \
                }                                                          \
        }                                                                  \
}

#define PyArray_ITER_DATA(it) ((void *)(_PyAIT(it)->dataptr))

#define PyArray_ITER_NOTDONE(it) (_PyAIT(it)->index < _PyAIT(it)->size)


/*
 * Any object passed to PyArray_Broadcast must be binary compatible
 * with this structure.
 */

typedef struct {
        PyObject_HEAD
        int                  numiter;                 /* number of iters */
        npy_intp             size;                    /* broadcasted size */
        npy_intp             index;                   /* current index */
        int                  nd;                      /* number of dims */
        npy_intp             dimensions[NPY_MAXDIMS]; /* dimensions */
        PyArrayIterObject    *iters[NPY_MAXARGS];     /* iterators */
} PyArrayMultiIterObject;

#define _PyMIT(m) ((PyArrayMultiIterObject *)(m))
#define PyArray_MultiIter_RESET(multi) {                                      \
        int __npy_mi;                                                         \
        _PyMIT(multi)->index = 0;                                             \
        for (__npy_mi=0; __npy_mi < _PyMIT(multi)->numiter;  __npy_mi++) {    \
                PyArray_ITER_RESET(_PyMIT(multi)->iters[__npy_mi]);           \
        }                                                                     \
}

#define PyArray_MultiIter_NEXT(multi) {                                       \
        int __npy_mi;                                                         \
        _PyMIT(multi)->index++;                                               \
        for (__npy_mi=0; __npy_mi < _PyMIT(multi)->numiter;   __npy_mi++) {   \
                PyArray_ITER_NEXT(_PyMIT(multi)->iters[__npy_mi]);            \
        }                                                                     \
}

#define PyArray_MultiIter_GOTO(multi, dest) {                               \
        int __npy_mi;                                                       \
        for (__npy_mi=0; __npy_mi < _PyMIT(multi)->numiter; __npy_mi++) {   \
                PyArray_ITER_GOTO(_PyMIT(multi)->iters[__npy_mi], dest);    \
        }                                                                   \
        _PyMIT(multi)->index = _PyMIT(multi)->iters[0]->index;              \
}

#define PyArray_MultiIter_GOTO1D(multi, ind) {                             \
        int __npy_mi;                                                      \
        for (__npy_mi=0; __npy_mi < _PyMIT(multi)->numiter; __npy_mi++) {  \
                PyArray_ITER_GOTO1D(_PyMIT(multi)->iters[__npy_mi], ind);  \
        }                                                                  \
        _PyMIT(multi)->index = _PyMIT(multi)->iters[0]->index;             \
}

#define PyArray_MultiIter_DATA(multi, i)                \
        ((void *)(_PyMIT(multi)->iters[i]->dataptr))

#define PyArray_MultiIter_NEXTi(multi, i)               \
        PyArray_ITER_NEXT(_PyMIT(multi)->iters[i])

#define PyArray_MultiIter_NOTDONE(multi)                \
        (_PyMIT(multi)->index < _PyMIT(multi)->size)

/* Store the information needed for fancy-indexing over an array */

typedef struct {
        PyObject_HEAD
        /*
         * Multi-iterator portion --- needs to be present in this
         * order to work with PyArray_Broadcast
         */

        int                   numiter;                 /* number of index-array
                                                          iterators */
        npy_intp              size;                    /* size of broadcasted
                                                          result */
        npy_intp              index;                   /* current index */
        int                   nd;                      /* number of dims */
        npy_intp              dimensions[NPY_MAXDIMS]; /* dimensions */
        PyArrayIterObject     *iters[NPY_MAXDIMS];     /* index object
                                                          iterators */
        PyArrayIterObject     *ait;                    /* flat Iterator for
                                                          underlying array */

        /* flat iterator for subspace (when numiter < nd) */
        PyArrayIterObject     *subspace;

        /*
         * if subspace iteration, then this is the array of axes in
         * the underlying array represented by the index objects
         */
        int                   iteraxes[NPY_MAXDIMS];
        /*
         * if subspace iteration, the these are the coordinates to the
         * start of the subspace.
         */
        npy_intp              bscoord[NPY_MAXDIMS];

        PyObject              *indexobj;               /* creating obj */
        int                   consec;
        char                  *dataptr;

} PyArrayMapIterObject;

enum {
    NPY_NEIGHBORHOOD_ITER_ZERO_PADDING,
    NPY_NEIGHBORHOOD_ITER_ONE_PADDING,
    NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING,
    NPY_NEIGHBORHOOD_ITER_CIRCULAR_PADDING,
    NPY_NEIGHBORHOOD_ITER_MIRROR_PADDING
};

typedef struct {
    PyObject_HEAD

    /*
     * PyArrayIterObject part: keep this in this exact order
     */
    int               nd_m1;            /* number of dimensions - 1 */
    npy_intp          index, size;
    npy_intp          coordinates[NPY_MAXDIMS];/* N-dimensional loop */
    npy_intp          dims_m1[NPY_MAXDIMS];    /* ao->dimensions - 1 */
    npy_intp          strides[NPY_MAXDIMS];    /* ao->strides or fake */
    npy_intp          backstrides[NPY_MAXDIMS];/* how far to jump back */
    npy_intp          factors[NPY_MAXDIMS];     /* shape factors */
    PyArrayObject     *ao;
    char              *dataptr;        /* pointer to current item*/
    npy_bool          contiguous;

    npy_intp          bounds[NPY_MAXDIMS][2];
    npy_intp          limits[NPY_MAXDIMS][2];
    npy_intp          limits_sizes[NPY_MAXDIMS];
    npy_iter_get_dataptr_t translate;

    /*
     * New members
     */
    npy_intp nd;

    /* Dimensions is the dimension of the array */
    npy_intp dimensions[NPY_MAXDIMS];

    /*
     * Neighborhood points coordinates are computed relatively to the
     * point pointed by _internal_iter
     */
    PyArrayIterObject* _internal_iter;
    /*
     * To keep a reference to the representation of the constant value
     * for constant padding
     */
    char* constant;

    int mode;
} PyArrayNeighborhoodIterObject;

/*
 * Neighborhood iterator API
 */

/* General: those work for any mode */
static NPY_INLINE int
PyArrayNeighborhoodIter_Reset(PyArrayNeighborhoodIterObject* iter);
static NPY_INLINE int
PyArrayNeighborhoodIter_Next(PyArrayNeighborhoodIterObject* iter);
#if 0
static NPY_INLINE int
PyArrayNeighborhoodIter_Next2D(PyArrayNeighborhoodIterObject* iter);
#endif

/*
 * Include inline implementations - functions defined there are not
 * considered public API
 */
#define _NPY_INCLUDE_NEIGHBORHOOD_IMP
#include "_neighborhood_iterator_imp.h"
#undef _NPY_INCLUDE_NEIGHBORHOOD_IMP

/* The default array type */
#define NPY_DEFAULT_TYPE NPY_DOUBLE
#define PyArray_DEFAULT NPY_DEFAULT_TYPE

/*
 * All sorts of useful ways to look into a PyArrayObject.  These are
 * the recommended over casting to PyArrayObject and accessing the
 * members directly.
 */

#define PyArray_NDIM(obj) (((PyArrayObject *)(obj))->nd)
#define PyArray_ISONESEGMENT(m) (PyArray_NDIM(m) == 0 ||                      \
                                 PyArray_CHKFLAGS(m, NPY_CONTIGUOUS) ||       \
                                 PyArray_CHKFLAGS(m, NPY_FORTRAN))

#define PyArray_ISFORTRAN(m) (PyArray_CHKFLAGS(m, NPY_FORTRAN) &&             \
                             (PyArray_NDIM(m) > 1))

#define PyArray_FORTRAN_IF(m) ((PyArray_CHKFLAGS(m, NPY_FORTRAN) ?            \
                              NPY_FORTRAN : 0))

#define FORTRAN_IF PyArray_FORTRAN_IF
#define PyArray_DATA(obj) ((void *)(((PyArrayObject *)(obj))->data))
#define PyArray_BYTES(obj) (((PyArrayObject *)(obj))->data)
#define PyArray_DIMS(obj) (((PyArrayObject *)(obj))->dimensions)
#define PyArray_STRIDES(obj) (((PyArrayObject *)(obj))->strides)
#define PyArray_DIM(obj,n) (PyArray_DIMS(obj)[n])
#define PyArray_STRIDE(obj,n) (PyArray_STRIDES(obj)[n])
#define PyArray_BASE(obj) (((PyArrayObject *)(obj))->base)
#define PyArray_DESCR(obj) (((PyArrayObject *)(obj))->descr)
#define PyArray_FLAGS(obj) (((PyArrayObject *)(obj))->flags)
#define PyArray_ITEMSIZE(obj) (((PyArrayObject *)(obj))->descr->elsize)
#define PyArray_TYPE(obj) (((PyArrayObject *)(obj))->descr->type_num)

#define PyArray_GETITEM(obj,itemptr)                                          \
        ((PyArrayObject *)(obj))->descr->f->getitem((char *)(itemptr),        \
                                                 (PyArrayObject *)(obj))

#define PyArray_SETITEM(obj,itemptr,v)                                        \
        ((PyArrayObject *)(obj))->descr->f->setitem((PyObject *)(v),          \
                                                    (char *)(itemptr),        \
                                                    (PyArrayObject *)(obj))


#define PyTypeNum_ISBOOL(type) ((type) == NPY_BOOL)

#define PyTypeNum_ISUNSIGNED(type) (((type) == NPY_UBYTE) ||   \
                                 ((type) == NPY_USHORT) ||     \
                                 ((type) == NPY_UINT) ||       \
                                 ((type) == NPY_ULONG) ||      \
                                 ((type) == NPY_ULONGLONG))

#define PyTypeNum_ISSIGNED(type) (((type) == NPY_BYTE) ||      \
                               ((type) == NPY_SHORT) ||        \
                               ((type) == NPY_INT) ||          \
                               ((type) == NPY_LONG) ||         \
                               ((type) == NPY_LONGLONG))

#define PyTypeNum_ISINTEGER(type) (((type) >= NPY_BYTE) &&     \
                                ((type) <= NPY_ULONGLONG))

#define PyTypeNum_ISFLOAT(type) (((type) >= NPY_FLOAT) &&      \
                              ((type) <= NPY_LONGDOUBLE))

#define PyTypeNum_ISNUMBER(type) ((type) <= NPY_CLONGDOUBLE)

#define PyTypeNum_ISSTRING(type) (((type) == NPY_STRING) ||    \
                                  ((type) == NPY_UNICODE))

#define PyTypeNum_ISCOMPLEX(type) (((type) >= NPY_CFLOAT) &&   \
                                ((type) <= NPY_CLONGDOUBLE))

#define PyTypeNum_ISPYTHON(type) (((type) == NPY_LONG) ||      \
                                  ((type) == NPY_DOUBLE) ||    \
                                  ((type) == NPY_CDOUBLE) ||   \
                                  ((type) == NPY_BOOL) ||      \
                                  ((type) == NPY_OBJECT ))

#define PyTypeNum_ISFLEXIBLE(type) (((type) >=NPY_STRING) &&  \
                                    ((type) <=NPY_VOID))

#define PyTypeNum_ISUSERDEF(type) (((type) >= NPY_USERDEF) && \
                                   ((type) < NPY_USERDEF+     \
                                    NPY_NUMUSERTYPES))

#define PyTypeNum_ISEXTENDED(type) (PyTypeNum_ISFLEXIBLE(type) ||  \
                                    PyTypeNum_ISUSERDEF(type))

#define PyTypeNum_ISOBJECT(type) ((type) == NPY_OBJECT)


#define PyDataType_ISBOOL(obj) PyTypeNum_ISBOOL(_PyADt(obj))
#define PyDataType_ISUNSIGNED(obj) PyTypeNum_ISUNSIGNED(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISSIGNED(obj) PyTypeNum_ISSIGNED(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISINTEGER(obj) PyTypeNum_ISINTEGER(((PyArray_Descr*)(obj))->type_num )
#define PyDataType_ISFLOAT(obj) PyTypeNum_ISFLOAT(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISNUMBER(obj) PyTypeNum_ISNUMBER(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISSTRING(obj) PyTypeNum_ISSTRING(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISCOMPLEX(obj) PyTypeNum_ISCOMPLEX(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISPYTHON(obj) PyTypeNum_ISPYTHON(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISFLEXIBLE(obj) PyTypeNum_ISFLEXIBLE(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISUSERDEF(obj) PyTypeNum_ISUSERDEF(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISEXTENDED(obj) PyTypeNum_ISEXTENDED(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_ISOBJECT(obj) PyTypeNum_ISOBJECT(((PyArray_Descr*)(obj))->type_num)
#define PyDataType_HASFIELDS(obj) (((PyArray_Descr *)(obj))->names != NULL)

#define PyArray_ISBOOL(obj) PyTypeNum_ISBOOL(PyArray_TYPE(obj))
#define PyArray_ISUNSIGNED(obj) PyTypeNum_ISUNSIGNED(PyArray_TYPE(obj))
#define PyArray_ISSIGNED(obj) PyTypeNum_ISSIGNED(PyArray_TYPE(obj))
#define PyArray_ISINTEGER(obj) PyTypeNum_ISINTEGER(PyArray_TYPE(obj))
#define PyArray_ISFLOAT(obj) PyTypeNum_ISFLOAT(PyArray_TYPE(obj))
#define PyArray_ISNUMBER(obj) PyTypeNum_ISNUMBER(PyArray_TYPE(obj))
#define PyArray_ISSTRING(obj) PyTypeNum_ISSTRING(PyArray_TYPE(obj))
#define PyArray_ISCOMPLEX(obj) PyTypeNum_ISCOMPLEX(PyArray_TYPE(obj))
#define PyArray_ISPYTHON(obj) PyTypeNum_ISPYTHON(PyArray_TYPE(obj))
#define PyArray_ISFLEXIBLE(obj) PyTypeNum_ISFLEXIBLE(PyArray_TYPE(obj))
#define PyArray_ISUSERDEF(obj) PyTypeNum_ISUSERDEF(PyArray_TYPE(obj))
#define PyArray_ISEXTENDED(obj) PyTypeNum_ISEXTENDED(PyArray_TYPE(obj))
#define PyArray_ISOBJECT(obj) PyTypeNum_ISOBJECT(PyArray_TYPE(obj))
#define PyArray_HASFIELDS(obj) PyDataType_HASFIELDS(PyArray_DESCR(obj))

    /*
     * FIXME: This should check for a flag on the data-type that
     * states whether or not it is variable length.  Because the
     * ISFLEXIBLE check is hard-coded to the built-in data-types.
     */
#define PyArray_ISVARIABLE(obj) PyTypeNum_ISFLEXIBLE(PyArray_TYPE(obj))

#define PyArray_SAFEALIGNEDCOPY(obj) (PyArray_ISALIGNED(obj) && !PyArray_ISVARIABLE(obj))


#define NPY_LITTLE '<'
#define NPY_BIG '>'
#define NPY_NATIVE '='
#define NPY_SWAP 's'
#define NPY_IGNORE '|'

#if NPY_BYTE_ORDER == NPY_BIG_ENDIAN
#define NPY_NATBYTE NPY_BIG
#define NPY_OPPBYTE NPY_LITTLE
#else
#define NPY_NATBYTE NPY_LITTLE
#define NPY_OPPBYTE NPY_BIG
#endif

#define PyArray_ISNBO(arg) ((arg) != NPY_OPPBYTE)
#define PyArray_IsNativeByteOrder PyArray_ISNBO
#define PyArray_ISNOTSWAPPED(m) PyArray_ISNBO(PyArray_DESCR(m)->byteorder)
#define PyArray_ISBYTESWAPPED(m) (!PyArray_ISNOTSWAPPED(m))

#define PyArray_FLAGSWAP(m, flags) (PyArray_CHKFLAGS(m, flags) &&       \
                                    PyArray_ISNOTSWAPPED(m))

#define PyArray_ISCARRAY(m) PyArray_FLAGSWAP(m, NPY_CARRAY)
#define PyArray_ISCARRAY_RO(m) PyArray_FLAGSWAP(m, NPY_CARRAY_RO)
#define PyArray_ISFARRAY(m) PyArray_FLAGSWAP(m, NPY_FARRAY)
#define PyArray_ISFARRAY_RO(m) PyArray_FLAGSWAP(m, NPY_FARRAY_RO)
#define PyArray_ISBEHAVED(m) PyArray_FLAGSWAP(m, NPY_BEHAVED)
#define PyArray_ISBEHAVED_RO(m) PyArray_FLAGSWAP(m, NPY_ALIGNED)


#define PyDataType_ISNOTSWAPPED(d) PyArray_ISNBO(((PyArray_Descr *)(d))->byteorder)
#define PyDataType_ISBYTESWAPPED(d) (!PyDataType_ISNOTSWAPPED(d))


/*
 * This is the form of the struct that's returned pointed by the
 * PyCObject attribute of an array __array_struct__. See
 * http://numpy.scipy.org/array_interface.shtml for the full
 * documentation.
 */
typedef struct {
    int two;              /*
                           * contains the integer 2 as a sanity
                           * check
                           */

    int nd;               /* number of dimensions */

    char typekind;        /*
                           * kind in array --- character code of
                           * typestr
                           */

    int itemsize;         /* size of each element */

    int flags;            /*
                           * how should be data interpreted. Valid
                           * flags are CONTIGUOUS (1), FORTRAN (2),
                           * ALIGNED (0x100), NOTSWAPPED (0x200), and
                           * WRITEABLE (0x400).  ARR_HAS_DESCR (0x800)
                           * states that arrdescr field is present in
                           * structure
                           */

    npy_intp *shape;       /*
                            * A length-nd array of shape
                            * information
                            */

    npy_intp *strides;    /* A length-nd array of stride information */

    void *data;           /* A pointer to the first element of the array */

    PyObject *descr;      /*
                           * A list of fields or NULL (ignored if flags
                           * does not have ARR_HAS_DESCR flag set)
                           */
} PyArrayInterface;

#endif /* NPY_ARRAYTYPES_H */
