summaryrefslogtreecommitdiff
path: root/numpy/core/src/arrayobject.c
diff options
context:
space:
mode:
authorTravis Oliphant <oliphant@enthought.com>2006-01-04 17:33:12 +0000
committerTravis Oliphant <oliphant@enthought.com>2006-01-04 17:33:12 +0000
commit8057b2d910a5a6726a666a2c18ac495dbb9e6000 (patch)
treee8ab5a397e9d2d1fd3885f3524821587ee2d407c /numpy/core/src/arrayobject.c
parentda9c6da4a304d240492b653f526b9607b032921c (diff)
downloadnumpy-8057b2d910a5a6726a666a2c18ac495dbb9e6000.tar.gz
rename sub-packages
Diffstat (limited to 'numpy/core/src/arrayobject.c')
-rw-r--r--numpy/core/src/arrayobject.c8472
1 files changed, 8472 insertions, 0 deletions
diff --git a/numpy/core/src/arrayobject.c b/numpy/core/src/arrayobject.c
new file mode 100644
index 000000000..72db76373
--- /dev/null
+++ b/numpy/core/src/arrayobject.c
@@ -0,0 +1,8472 @@
+/*
+ Provide multidimensional arrays as a basic object type in python.
+
+Based on Original Numeric implementation
+Copyright (c) 1995, 1996, 1997 Jim Hugunin, hugunin@mit.edu
+
+with contributions from many Numeric Python developers 1995-2004
+
+Heavily modified in 2005 with inspiration from Numarray
+
+by
+
+Travis Oliphant
+Assistant Professor at
+Brigham Young University
+
+maintainer email: oliphant.travis@ieee.org
+
+Numarray design (which provided guidance) by
+Space Science Telescope Institute
+ (J. Todd Miller, Perry Greenfield, Rick White)
+
+*/
+
+/* Helper functions */
+
+#define error_converting(x) (((x) == -1) && PyErr_Occurred())
+
+/*OBJECT_API*/
+static intp
+PyArray_PyIntAsIntp(PyObject *o)
+{
+ longlong long_value = -1;
+ PyObject *obj;
+ static char *msg = "an integer is required";
+ PyObject *arr=NULL;
+ PyArray_Descr *descr;
+ intp ret;
+
+ if (!o) {
+ PyErr_SetString(PyExc_TypeError, msg);
+ return -1;
+ }
+ descr = PyArray_DescrFromType(PyArray_INTP);
+ if (PyArray_Check(o)) {
+ if (PyArray_SIZE(o)!=1 || !PyArray_ISINTEGER(o)) {
+ PyErr_SetString(PyExc_TypeError, msg);
+ Py_DECREF(descr);
+ return -1;
+ }
+ arr = PyArray_CastToType((PyArrayObject *)o, descr, 0);
+ }
+ else if (PyArray_IsScalar(o, Integer)) {
+ arr = PyArray_FromScalar(o, descr);
+ }
+ if (arr != NULL) {
+ ret = *((intp *)PyArray_DATA(arr));
+ Py_DECREF(arr);
+ return ret;
+ }
+ if (PyInt_Check(o)) {
+ long_value = (longlong) PyInt_AS_LONG(o);
+ } else if (PyLong_Check(o)) {
+ long_value = (longlong) PyLong_AsLongLong(o);
+ } else if (o->ob_type->tp_as_number != NULL && \
+ o->ob_type->tp_as_number->nb_long != NULL) {
+ obj = o->ob_type->tp_as_number->nb_long(o);
+ if (obj != NULL) {
+ long_value = (longlong) PyLong_AsLongLong(obj);
+ Py_DECREF(obj);
+ }
+ } else if (o->ob_type->tp_as_number != NULL && \
+ o->ob_type->tp_as_number->nb_int != NULL) {
+ obj = o->ob_type->tp_as_number->nb_int(o);
+ if (obj != NULL) {
+ long_value = (longlong) PyLong_AsLongLong(obj);
+ Py_DECREF(obj);
+ }
+ } else {
+ PyErr_SetString(PyExc_NotImplementedError,"");
+ }
+
+ if error_converting(long_value) {
+ PyErr_SetString(PyExc_TypeError, msg);
+ return -1;
+ }
+
+#if (SIZEOF_LONGLONG != SIZEOF_PY_INTPTR_T)
+ if ((long_value < MIN_INTP) || (long_value > MAX_INTP)) {
+ PyErr_SetString(PyExc_ValueError,
+ "integer won't fit into a C intp");
+ return -1;
+ }
+#endif
+ return (intp) long_value;
+}
+
+
+static PyObject *array_int(PyArrayObject *v);
+
+/*OBJECT_API*/
+static int
+PyArray_PyIntAsInt(PyObject *o)
+{
+ long long_value = -1;
+ PyObject *obj;
+ static char *msg = "an integer is required";
+ PyObject *arr=NULL;
+ PyArray_Descr *descr;
+ int ret;
+
+
+ if (!o) {
+ PyErr_SetString(PyExc_TypeError, msg);
+ return -1;
+ }
+ descr = PyArray_DescrFromType(PyArray_INT);
+ if (PyArray_Check(o)) {
+ if (PyArray_SIZE(o)!=1 || !PyArray_ISINTEGER(o)) {
+ PyErr_SetString(PyExc_TypeError, msg);
+ Py_DECREF(descr);
+ return -1;
+ }
+ arr = PyArray_CastToType((PyArrayObject *)o, descr, 0);
+ }
+ if (PyArray_IsScalar(o, Integer)) {
+ arr = PyArray_FromScalar(o, descr);
+ }
+ if (arr != NULL) {
+ ret = *((int *)PyArray_DATA(arr));
+ Py_DECREF(arr);
+ return ret;
+ }
+ if (PyInt_Check(o)) {
+ long_value = (long) PyInt_AS_LONG(o);
+ } else if (PyLong_Check(o)) {
+ long_value = (long) PyLong_AsLong(o);
+ } else if (o->ob_type->tp_as_number != NULL && \
+ o->ob_type->tp_as_number->nb_long != NULL) {
+ obj = o->ob_type->tp_as_number->nb_long(o);
+ if (obj == NULL) return -1;
+ long_value = (long) PyLong_AsLong(obj);
+ Py_DECREF(obj);
+ } else if (o->ob_type->tp_as_number != NULL && \
+ o->ob_type->tp_as_number->nb_int != NULL) {
+ obj = o->ob_type->tp_as_number->nb_int(o);
+ if (obj == NULL) return -1;
+ long_value = (long) PyLong_AsLong(obj);
+ Py_DECREF(obj);
+ } else {
+ PyErr_SetString(PyExc_NotImplementedError,"");
+ }
+ if error_converting(long_value) {
+ PyErr_SetString(PyExc_TypeError, msg);
+ return -1;
+ }
+
+#if (SIZEOF_LONG != SIZEOF_INT)
+ if ((long_value < INT_MIN) || (long_value > INT_MAX)) {
+ PyErr_SetString(PyExc_ValueError,
+ "integer won't fit into a C int");
+ return -1;
+ }
+#endif
+ return (int) long_value;
+}
+
+
+/*OBJECT_API
+ Get Priority from object
+*/
+static double
+PyArray_GetPriority(PyObject *obj, double default_)
+{
+ PyObject *ret;
+ double priority=PyArray_PRIORITY;
+
+ if (PyArray_CheckExact(obj))
+ return priority;
+ if (PyBigArray_CheckExact(obj))
+ return PyArray_BIG_PRIORITY;
+
+ ret = PyObject_GetAttrString(obj, "__array_priority__");
+ if (ret != NULL) priority = PyFloat_AsDouble(ret);
+ if (PyErr_Occurred()) {
+ PyErr_Clear();
+ priority = default_;
+ }
+ Py_XDECREF(ret);
+ return priority;
+}
+
+/* Backward compatibility only */
+/* In both Zero and One
+
+ ***You must free the memory once you are done with it
+ using PyDataMem_FREE(ptr) or you create a memory leak***
+
+ If arr is an Object array you are getting a
+ BORROWED reference to Zero or One.
+ Do not DECREF.
+ Please INCREF if you will be hanging on to it.
+
+ The memory for the ptr still must be freed in any case;
+*/
+
+
+/*OBJECT_API
+ Get pointer to zero of correct type for array.
+*/
+static char *
+PyArray_Zero(PyArrayObject *arr)
+{
+ char *zeroval;
+ int ret, storeflags;
+ PyObject *obj;
+
+ zeroval = PyDataMem_NEW(arr->descr->elsize);
+ if (zeroval == NULL) {
+ PyErr_SetNone(PyExc_MemoryError);
+ return NULL;
+ }
+
+ obj=PyInt_FromLong((long) 0);
+ if (PyArray_ISOBJECT(arr)) {
+ memcpy(zeroval, &obj, sizeof(PyObject *));
+ Py_DECREF(obj);
+ return zeroval;
+ }
+ storeflags = arr->flags;
+ arr->flags |= BEHAVED_FLAGS;
+ ret = arr->descr->f->setitem(obj, zeroval, arr);
+ arr->flags = storeflags;
+ Py_DECREF(obj);
+ if (ret < 0) {
+ PyDataMem_FREE(zeroval);
+ return NULL;
+ }
+ return zeroval;
+}
+
+/*OBJECT_API
+ Get pointer to one of correct type for array
+*/
+static char *
+PyArray_One(PyArrayObject *arr)
+{
+ char *oneval;
+ int ret, storeflags;
+ PyObject *obj;
+
+ oneval = PyDataMem_NEW(arr->descr->elsize);
+ if (oneval == NULL) {
+ PyErr_SetNone(PyExc_MemoryError);
+ return NULL;
+ }
+
+ obj = PyInt_FromLong((long) 1);
+ if (PyArray_ISOBJECT(arr)) {
+ memcpy(oneval, &obj, sizeof(PyObject *));
+ Py_DECREF(obj);
+ return oneval;
+ }
+
+ storeflags = arr->flags;
+ arr->flags |= BEHAVED_FLAGS;
+ ret = arr->descr->f->setitem(obj, oneval, arr);
+ arr->flags = storeflags;
+ Py_DECREF(obj);
+ if (ret < 0) {
+ PyDataMem_FREE(oneval);
+ return NULL;
+ }
+ return oneval;
+}
+
+/* End deprecated */
+
+
+static int
+do_sliced_copy(char *dest, intp *dest_strides, intp *dest_dimensions,
+ int dest_nd, char *src, intp *src_strides,
+ intp *src_dimensions, int src_nd, int elsize,
+ int copies) {
+ intp i, j;
+
+ if (src_nd == 0 && dest_nd == 0) {
+ for(j=0; j<copies; j++) {
+ memmove(dest, src, elsize);
+ dest += elsize;
+ }
+ return 0;
+ }
+
+ if (dest_nd > src_nd) {
+ for(i=0; i<*dest_dimensions; i++, dest += *dest_strides) {
+ if (do_sliced_copy(dest, dest_strides+1,
+ dest_dimensions+1, dest_nd-1,
+ src, src_strides,
+ src_dimensions, src_nd,
+ elsize, copies) == -1)
+ return -1;
+ }
+ return 0;
+ }
+
+ if (dest_nd == 1) {
+ if (*dest_dimensions != *src_dimensions) {
+ PyErr_SetString(PyExc_ValueError,
+ "matrices are not aligned for copy");
+ return -1;
+ }
+ for(i=0; i<*dest_dimensions; i++, src += *src_strides) {
+ for(j=0; j<copies; j++) {
+ memmove(dest, src, elsize);
+ dest += *dest_strides;
+ }
+ }
+ } else {
+ for(i=0; i<*dest_dimensions; i++, dest += *dest_strides,
+ src += *src_strides) {
+ if (do_sliced_copy(dest, dest_strides+1,
+ dest_dimensions+1, dest_nd-1,
+ src, src_strides+1,
+ src_dimensions+1, src_nd-1,
+ elsize, copies) == -1)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* This function reduces a source and destination array until a
+ discontiguous segment is found in either the source or
+ destination. Thus, an N dimensional array where the last dimension
+ is contiguous and has size n while the items are of size elsize,
+ will be reduced to an N-1 dimensional array with items of size n *
+ elsize.
+
+ This process is repeated until a discontiguous section is found.
+ Thus, a contiguous array will be reduced to a 0-dimensional array
+ with items of size elsize * sizeof(N-dimensional array).
+
+ Finally, if a source array has been reduced to a 0-dimensional
+ array with large element sizes, the contiguous destination array is
+ reduced as well.
+
+ The only thing this function changes is the element size, the
+ number of copies, and the source and destination number of
+ dimensions. The strides and dimensions are not changed.
+*/
+
+static int
+optimize_slices(intp **dest_strides, intp **dest_dimensions,
+ int *dest_nd, intp **src_strides,
+ intp **src_dimensions, int *src_nd,
+ int *elsize, int *copies)
+{
+ while (*src_nd > 0) {
+ if (((*dest_strides)[*dest_nd-1] == *elsize) &&
+ ((*src_strides)[*src_nd-1] == *elsize)) {
+ if ((*dest_dimensions)[*dest_nd-1] !=
+ (*src_dimensions)[*src_nd-1]) {
+ PyErr_SetString(PyExc_ValueError,
+ "matrices are not aligned");
+ return -1;
+ }
+ *elsize *= (*dest_dimensions)[*dest_nd-1];
+ *dest_nd-=1; *src_nd-=1;
+ } else {
+ break;
+ }
+ }
+ if (*src_nd == 0) {
+ while (*dest_nd > 0) {
+ if (((*dest_strides)[*dest_nd-1] == *elsize)) {
+ *copies *= (*dest_dimensions)[*dest_nd-1];
+ *dest_nd-=1;
+ } else {
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static char *
+contiguous_data(PyArrayObject *src)
+{
+ intp dest_strides[MAX_DIMS], *dest_strides_ptr;
+ intp *dest_dimensions=src->dimensions;
+ int dest_nd=src->nd;
+ intp *src_strides = src->strides;
+ intp *src_dimensions=src->dimensions;
+ int src_nd=src->nd;
+ int elsize=src->descr->elsize;
+ int copies=1;
+ int ret, i;
+ intp stride=elsize;
+ char *new_data;
+
+ for(i=dest_nd-1; i>=0; i--) {
+ dest_strides[i] = stride;
+ stride *= dest_dimensions[i];
+ }
+
+ dest_strides_ptr = dest_strides;
+
+ if (optimize_slices(&dest_strides_ptr, &dest_dimensions, &dest_nd,
+ &src_strides, &src_dimensions, &src_nd,
+ &elsize, &copies) == -1)
+ return NULL;
+
+ new_data = (char *)_pya_malloc(stride);
+
+ ret = do_sliced_copy(new_data, dest_strides_ptr, dest_dimensions,
+ dest_nd, src->data, src_strides,
+ src_dimensions, src_nd, elsize, copies);
+
+ if (ret != -1) { return new_data; }
+ else { _pya_free(new_data); return NULL; }
+}
+
+/* end Helper functions */
+
+
+static PyObject *PyArray_New(PyTypeObject *, int nd, intp *,
+ int, intp *, void *, int, int, PyObject *);
+
+/* C-API functions */
+
+/* Used for arrays of python objects to increment the reference count of */
+/* every python object in the array. */
+/*OBJECT_API
+ For object arrays, increment all internal references.
+*/
+static int
+PyArray_INCREF(PyArrayObject *mp)
+{
+ intp i, n;
+
+ PyObject **data, **data2;
+
+ if (mp->descr->type_num != PyArray_OBJECT) return 0;
+
+ if (PyArray_ISONESEGMENT(mp)) {
+ data = (PyObject **)mp->data;
+ } else {
+ if ((data = (PyObject **)contiguous_data(mp)) == NULL)
+ return -1;
+ }
+
+ n = PyArray_SIZE(mp);
+ data2 = data;
+ for(i=0; i<n; i++, data++) Py_XINCREF(*data);
+
+ if (!PyArray_ISONESEGMENT(mp)) _pya_free(data2);
+
+ return 0;
+}
+
+/*OBJECT_API
+ Decrement all internal references for object arrays.
+*/
+static int
+PyArray_XDECREF(PyArrayObject *mp)
+{
+ intp i, n;
+ PyObject **data, **data2;
+
+ if (mp->descr->type_num != PyArray_OBJECT) return 0;
+
+ if (PyArray_ISONESEGMENT(mp)) {
+ data = (PyObject **)mp->data;
+ } else {
+ if ((data = (PyObject **)contiguous_data(mp)) == NULL)
+ return -1;
+ }
+
+ n = PyArray_SIZE(mp);
+ data2 = data;
+ for(i=0; i<n; i++, data++) Py_XDECREF(*data);
+
+ if (!PyArray_ISONESEGMENT(mp)) _pya_free(data2);
+
+ return 0;
+}
+
+/* byte-swap inplace (unrolled loops for special cases) */
+static void
+byte_swap_vector(void *p, int n, int size) {
+ char *a, *b, c=0;
+ int j,m;
+
+ switch(size) {
+ case 1: /* no byteswap necessary */
+ break;
+ case 2:
+ for (a = (char*)p ; n > 0; n--, a += 1) {
+ b = a + 1;
+ c = *a; *a++ = *b; *b = c;
+ }
+ break;
+ case 4:
+ for (a = (char*)p ; n > 0; n--, a += 2) {
+ b = a + 3;
+ c = *a; *a++ = *b; *b-- = c;
+ c = *a; *a++ = *b; *b = c;
+ }
+ break;
+ case 8:
+ for (a = (char*)p ; n > 0; n--, 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;
+ }
+ break;
+ default:
+ m = size / 2;
+ for (a = (char *)p ; n > 0; n--, a += m) {
+ b = a + (size-1);
+ for (j=0; j<m; j++)
+ c=*a; *a++ = *b; *b-- = c;
+ }
+ break;
+ }
+}
+
+
+/* If numitems > 1, then dst must be contiguous */
+static void
+copy_and_swap(void *dst, void *src, int itemsize, intp numitems,
+ intp srcstrides, int swap)
+{
+ int i;
+ char *s1 = (char *)src;
+ char *d1 = (char *)dst;
+
+
+ if ((numitems == 1) || (itemsize == srcstrides))
+ memcpy(d1, s1, itemsize*numitems);
+ else {
+ for (i = 0; i < numitems; i++) {
+ memcpy(d1, s1, itemsize);
+ d1 += itemsize;
+ s1 += srcstrides;
+ }
+ }
+
+ if (swap)
+ byte_swap_vector(d1, numitems, itemsize);
+}
+
+static PyArray_Descr **userdescrs=NULL;
+/* Computer-generated arraytype and scalartype code */
+#include "scalartypes.inc"
+#include "arraytypes.inc"
+
+static char *
+index2ptr(PyArrayObject *mp, intp i)
+{
+ if(mp->nd == 0) {
+ PyErr_SetString(PyExc_IndexError,
+ "0-d arrays can't be indexed");
+ return NULL;
+ }
+ if (i==0 && mp->dimensions[0] > 0)
+ return mp->data;
+
+ if (mp->nd>0 && i>0 && i < mp->dimensions[0]) {
+ return mp->data+i*mp->strides[0];
+ }
+ PyErr_SetString(PyExc_IndexError,"index out of bounds");
+ return NULL;
+}
+
+/*OBJECT_API
+ Compute the size of an array (in number of items)
+*/
+static intp
+PyArray_Size(PyObject *op)
+{
+ if (PyArray_Check(op)) {
+ return PyArray_SIZE((PyArrayObject *)op);
+ }
+ else {
+ return 0;
+ }
+}
+
+/* If destination is not the right type, then src
+ will be cast to destination.
+*/
+
+/* Does a flat iterator-based copy.
+
+ The arrays are assumed to have the same number of elements
+ They can be different sizes and have different types however.
+*/
+
+/*OBJECT_API
+ Copy an Array into another array.
+*/
+static int
+PyArray_CopyInto(PyArrayObject *dest, PyArrayObject *src)
+{
+ intp dsize, ssize, sbytes, ncopies;
+ int elsize, index;
+ PyArrayIterObject *dit=NULL;
+ PyArrayIterObject *sit=NULL;
+ char *dptr;
+ int swap;
+ PyArray_CopySwapFunc *copyswap;
+ PyArray_CopySwapNFunc *copyswapn;
+
+ if (!PyArray_ISWRITEABLE(dest)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "cannot write to array");
+ return -1;
+ }
+
+ if (!PyArray_EquivArrTypes(dest, src)) {
+ return PyArray_CastTo(dest, src);
+ }
+
+ dsize = PyArray_SIZE(dest);
+ ssize = PyArray_SIZE(src);
+ if (ssize == 0) return 0;
+ if (dsize % ssize != 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "number of elements in destination must be "\
+ "integer multiple of number of "\
+ "elements in source");
+ return -1;
+ }
+ ncopies = (dsize / ssize);
+
+ swap = PyArray_ISNOTSWAPPED(dest) != PyArray_ISNOTSWAPPED(src);
+ copyswap = dest->descr->f->copyswap;
+ copyswapn = dest->descr->f->copyswapn;
+
+ elsize = dest->descr->elsize;
+
+ if ((PyArray_ISCONTIGUOUS(dest) && PyArray_ISCONTIGUOUS(src)) \
+ || (PyArray_ISFORTRAN(dest) && PyArray_ISFORTRAN(src))) {
+
+ PyArray_XDECREF(dest);
+ dptr = dest->data;
+ sbytes = ssize * src->descr->elsize;
+ while(ncopies--) {
+ memmove(dptr, src->data, sbytes);
+ dptr += sbytes;
+ }
+ if (swap)
+ copyswapn(dest->data, NULL, dsize, 1, elsize);
+ PyArray_INCREF(dest);
+ return 0;
+ }
+
+ dit = (PyArrayIterObject *)PyArray_IterNew((PyObject *)dest);
+ sit = (PyArrayIterObject *)PyArray_IterNew((PyObject *)src);
+
+ if ((dit == NULL) || (sit == NULL)) {
+ Py_XDECREF(dit);
+ Py_XDECREF(sit);
+ return -1;
+ }
+
+ PyArray_XDECREF(dest);
+ while(ncopies--) {
+ index = ssize;
+ while(index--) {
+ memmove(dit->dataptr, sit->dataptr, elsize);
+ if (swap)
+ copyswap(dit->dataptr, NULL, 1, elsize);
+ PyArray_ITER_NEXT(dit);
+ PyArray_ITER_NEXT(sit);
+ }
+ PyArray_ITER_RESET(sit);
+ }
+ PyArray_INCREF(dest);
+ Py_DECREF(dit);
+ Py_DECREF(sit);
+ return 0;
+}
+
+
+static int
+PyArray_CopyObject(PyArrayObject *dest, PyObject *src_object)
+{
+ PyArrayObject *src;
+ int ret;
+
+ Py_INCREF(dest->descr);
+ src = (PyArrayObject *)PyArray_FromAny(src_object,
+ dest->descr, 0,
+ dest->nd, FORTRAN_IF(dest));
+ if (src == NULL) return -1;
+
+ ret = PyArray_CopyInto(dest, src);
+ Py_DECREF(src);
+ return ret;
+}
+
+
+/* These are also old calls (should use PyArray_New) */
+
+/* They all zero-out the memory as previously done */
+
+/* steals reference to descr -- and enforces native byteorder on it.*/
+/*OBJECT_API
+ Like FromDimsAndData but uses the Descr structure instead of typecode
+ as input.
+*/
+static PyObject *
+PyArray_FromDimsAndDataAndDescr(int nd, int *d,
+ PyArray_Descr *descr,
+ char *data)
+{
+ PyObject *ret;
+#if SIZEOF_INTP != SIZEOF_INT
+ int i;
+ intp newd[MAX_DIMS];
+#endif
+
+ if (!PyArray_ISNBO(descr->byteorder))
+ descr->byteorder = '=';
+
+#if SIZEOF_INTP != SIZEOF_INT
+ for (i=0; i<nd; i++) newd[i] = (intp) d[i];
+ ret = PyArray_NewFromDescr(&PyArray_Type, descr,
+ nd, newd,
+ NULL, data,
+ (data ? CARRAY_FLAGS : 0), NULL);
+#else
+ ret = PyArray_NewFromDescr(&PyArray_Type, descr,
+ nd, (intp *)d,
+ NULL, data,
+ (data ? CARRAY_FLAGS : 0), NULL);
+#endif
+ return ret;
+}
+
+/*OBJECT_API
+ Construct an empty array from dimensions and typenum
+*/
+static PyObject *
+PyArray_FromDims(int nd, int *d, int type)
+{
+ PyObject *ret;
+ ret = PyArray_FromDimsAndDataAndDescr(nd, d,
+ PyArray_DescrFromType(type),
+ NULL);
+ /* Old FromDims set memory to zero --- some algorithms
+ relied on that. Better keep it the same. If
+ Object type, then it's already been set to zero, though.
+ */
+ if (ret && (PyArray_DESCR(ret)->type_num != PyArray_OBJECT)) {
+ memset(PyArray_DATA(ret), 0, PyArray_NBYTES(ret));
+ }
+ return ret;
+}
+
+/* end old calls */
+
+/*OBJECT_API
+ Copy an array.
+*/
+static PyObject *
+PyArray_NewCopy(PyArrayObject *m1, int fortran)
+{
+ PyArrayObject *ret;
+ if (fortran < 0) fortran = PyArray_ISFORTRAN(m1);
+
+ Py_INCREF(m1->descr);
+ ret = (PyArrayObject *)PyArray_NewFromDescr(m1->ob_type,
+ m1->descr,
+ m1->nd,
+ m1->dimensions,
+ NULL, NULL,
+ fortran,
+ (PyObject *)m1);
+ if (ret == NULL) return NULL;
+ if (PyArray_CopyInto(ret, m1) == -1) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ return (PyObject *)ret;
+}
+
+static PyObject *array_big_item(PyArrayObject *, intp);
+
+/* Does nothing with descr (cannot be NULL) */
+/*OBJECT_API
+ Get scalar-equivalent to a region of memory described by a descriptor.
+*/
+static PyObject *
+PyArray_Scalar(void *data, PyArray_Descr *descr, PyObject *base)
+{
+ PyTypeObject *type;
+ PyObject *obj;
+ void *destptr;
+ PyArray_CopySwapFunc *copyswap;
+ int type_num;
+ int itemsize;
+ int swap;
+
+ type_num = descr->type_num;
+ itemsize = descr->elsize;
+ type = descr->typeobj;
+ copyswap = descr->f->copyswap;
+ swap = !PyArray_ISNBO(descr->byteorder);
+ if (type->tp_itemsize != 0) /* String type */
+ obj = type->tp_alloc(type, itemsize);
+ else
+ obj = type->tp_alloc(type, 0);
+ if (obj == NULL) return NULL;
+ if PyTypeNum_ISEXTENDED(type_num) {
+ if (type_num == PyArray_STRING) {
+ destptr = PyString_AS_STRING(obj);
+ ((PyStringObject *)obj)->ob_shash = -1;
+ ((PyStringObject *)obj)->ob_sstate = \
+ SSTATE_NOT_INTERNED;
+ }
+ else if (type_num == PyArray_UNICODE) {
+ PyUnicodeObject *uni = (PyUnicodeObject*)obj;
+ int length = itemsize / sizeof(Py_UNICODE);
+ /* Need an extra slot and need to use
+ Python memory manager */
+ uni->str = NULL;
+ destptr = PyMem_NEW(Py_UNICODE, length+1);
+ if (destptr == NULL) {
+ Py_DECREF(obj);
+ return PyErr_NoMemory();
+ }
+ uni->str = (Py_UNICODE *)destptr;
+ uni->str[0] = 0;
+ uni->str[length] = 0;
+ uni->length = length;
+ uni->hash = -1;
+ uni->defenc = NULL;
+ }
+ else {
+ PyVoidScalarObject *vobj = (PyVoidScalarObject *)obj;
+ vobj->base = NULL;
+ vobj->descr = descr;
+ Py_INCREF(descr);
+ vobj->obval = NULL;
+ vobj->ob_size = itemsize;
+ vobj->flags = BEHAVED_FLAGS | OWNDATA;
+ swap = 0;
+ if (descr->fields) {
+ if (base) {
+ Py_INCREF(base);
+ vobj->base = base;
+ vobj->flags = PyArray_FLAGS(base);
+ vobj->flags &= ~OWNDATA;
+ vobj->obval = data;
+ return obj;
+ }
+ }
+ destptr = PyDataMem_NEW(itemsize);
+ if (destptr == NULL) {
+ Py_DECREF(obj);
+ return PyErr_NoMemory();
+ }
+ vobj->obval = destptr;
+ }
+ }
+ else {
+ destptr = _SOFFSET_(obj, type_num);
+ }
+ /* copyswap for OBJECT increments the reference count */
+ copyswap(destptr, data, swap, itemsize);
+ return obj;
+}
+
+/* returns an Array-Scalar Object of the type of arr
+ from the given pointer to memory -- main Scalar creation function
+ default new method calls this.
+*/
+
+/* Ideally, here the descriptor would contain all the information needed.
+ So, that we simply need the data and the descriptor, and perhaps
+ a flag
+*/
+
+/*OBJECT_API
+ Get scalar-equivalent to 0-d array
+*/
+static PyObject *
+PyArray_ToScalar(void *data, PyArrayObject *arr)
+{
+ return PyArray_Scalar(data, arr->descr, (PyObject *)arr);
+}
+
+
+/* Return Python scalar if 0-d array object is encountered */
+
+/*OBJECT_API
+ Return either an array or the appropriate Python object if the array
+ is 0d and matches a Python type.
+*/
+static PyObject *
+PyArray_Return(PyArrayObject *mp)
+{
+
+
+ if (mp == NULL) return NULL;
+
+ if (PyErr_Occurred()) {
+ Py_XDECREF(mp);
+ return NULL;
+ }
+
+ if (mp->nd == 0) {
+ PyObject *ret;
+ ret = PyArray_ToScalar(mp->data, mp);
+ Py_DECREF(mp);
+ return ret;
+ }
+ else {
+ return (PyObject *)mp;
+ }
+}
+
+/*
+ returns typenum to associate with this type >=PyArray_USERDEF.
+ Also creates a copy of the VOID_DESCR table inserting it's typeobject in
+ and it's typenum in the appropriate place.
+
+ needs the userdecrs table and PyArray_NUMUSER variables
+ defined in arratypes.inc
+*/
+/*OBJECT_API
+ Register Data type
+*/
+static int
+PyArray_RegisterDataType(PyTypeObject *type)
+{
+ PyArray_Descr *descr;
+ PyObject *obj;
+ int typenum;
+ int i;
+
+ if ((type == &PyVoidArrType_Type) || \
+ !PyType_IsSubtype(type, &PyVoidArrType_Type)) {
+ PyErr_SetString(PyExc_ValueError,
+ "can only register void subtypes");
+ return -1;
+ }
+ /* See if this type is already registered */
+ for (i=0; i<PyArray_NUMUSERTYPES; i++) {
+ descr = userdescrs[i];
+ if (descr->typeobj == type)
+ return descr->type_num;
+ }
+ descr = PyArray_DescrNewFromType(PyArray_VOID);
+ typenum = PyArray_USERDEF + PyArray_NUMUSERTYPES;
+ descr->type_num = typenum;
+ descr->typeobj = type;
+ obj = PyObject_GetAttrString((PyObject *)type,"itemsize");
+ if (obj) {
+ i = PyInt_AsLong(obj);
+ if ((i < 0) && (PyErr_Occurred())) PyErr_Clear();
+ else descr->elsize = i;
+ Py_DECREF(obj);
+ }
+ Py_INCREF(type);
+ userdescrs = realloc(userdescrs,
+ (PyArray_NUMUSERTYPES+1)*sizeof(void *));
+ if (userdescrs == NULL) {
+ PyErr_SetString(PyExc_MemoryError, "RegisterDataType");
+ Py_DECREF(descr);
+ return -1;
+ }
+ userdescrs[PyArray_NUMUSERTYPES++] = descr;
+ return typenum;
+}
+
+
+/*
+ copyies over from the old descr table for anything
+ NULL or zero in what is given.
+ DECREF's the Descr already there.
+ places a pointer to the new one into the slot.
+*/
+
+/* steals a reference to descr */
+/*OBJECT_API
+ Insert Descr Table
+*/
+static int
+PyArray_RegisterDescrForType(int typenum, PyArray_Descr *descr)
+{
+ PyArray_Descr *old;
+
+ if (!PyTypeNum_ISUSERDEF(typenum)) {
+ PyErr_SetString(PyExc_TypeError,
+ "data type not registered");
+ Py_DECREF(descr);
+ return -1;
+ }
+ old = userdescrs[typenum-PyArray_USERDEF];
+ descr->typeobj = old->typeobj;
+ descr->type_num = typenum;
+
+ if (descr->f == NULL) descr->f = old->f;
+ if (descr->fields == NULL) {
+ descr->fields = old->fields;
+ Py_XINCREF(descr->fields);
+ }
+ if (descr->subarray == NULL && old->subarray) {
+ descr->subarray = _pya_malloc(sizeof(PyArray_ArrayDescr));
+ memcpy(descr->subarray, old->subarray,
+ sizeof(PyArray_ArrayDescr));
+ Py_INCREF(descr->subarray->shape);
+ Py_INCREF(descr->subarray->base);
+ }
+ Py_XINCREF(descr->typeobj);
+
+#define _ZERO_CHECK(member) \
+ if (descr->member == 0) descr->member = old->member
+
+ _ZERO_CHECK(kind);
+ _ZERO_CHECK(type);
+ _ZERO_CHECK(byteorder);
+ _ZERO_CHECK(elsize);
+ _ZERO_CHECK(alignment);
+#undef _ZERO_CHECK
+
+ Py_DECREF(old);
+ userdescrs[typenum-PyArray_USERDEF] = descr;
+ return 0;
+}
+
+
+/*OBJECT_API
+ To File
+*/
+static int
+PyArray_ToFile(PyArrayObject *self, FILE *fp, char *sep, char *format)
+{
+ intp size;
+ intp n, n2;
+ int n3, n4;
+ PyArrayIterObject *it;
+ PyObject *obj, *strobj, *tupobj;
+
+ n3 = (sep ? strlen((const char *)sep) : 0);
+ if (n3 == 0) { /* binary data */
+ if (PyArray_ISOBJECT(self)) {
+ PyErr_SetString(PyExc_ValueError, "cannot write "\
+ "object arrays to a file in " \
+ "binary mode");
+ return -1;
+ }
+
+ if (PyArray_ISCONTIGUOUS(self)) {
+ size = PyArray_SIZE(self);
+ if ((n=fwrite((const void *)self->data,
+ (size_t) self->descr->elsize,
+ (size_t) size, fp)) < size) {
+ PyErr_Format(PyExc_ValueError,
+ "%ld requested and %ld written",
+ (long) size, (long) n);
+ return -1;
+ }
+ }
+ else {
+ it=(PyArrayIterObject *) \
+ PyArray_IterNew((PyObject *)self);
+ while(it->index < it->size) {
+ if (fwrite((const void *)it->dataptr,
+ (size_t) self->descr->elsize,
+ 1, fp) < 1) {
+ PyErr_Format(PyExc_IOError,
+ "problem writing element"\
+ " %d to file",
+ (int)it->index);
+ Py_DECREF(it);
+ return -1;
+ }
+ PyArray_ITER_NEXT(it);
+ }
+ Py_DECREF(it);
+ }
+ }
+ else { /* text data */
+ it=(PyArrayIterObject *) \
+ PyArray_IterNew((PyObject *)self);
+ n4 = (format ? strlen((const char *)format) : 0);
+ while(it->index < it->size) {
+ obj = self->descr->f->getitem(it->dataptr, self);
+ if (obj == NULL) {Py_DECREF(it); return -1;}
+ if (n4 == 0) { /* standard writing */
+ strobj = PyObject_Str(obj);
+ Py_DECREF(obj);
+ if (strobj == NULL) {Py_DECREF(it); return -1;}
+ }
+ else { /* use format string */
+ tupobj = PyTuple_New(1);
+ if (tupobj == NULL) {Py_DECREF(it); return -1;}
+ PyTuple_SET_ITEM(tupobj,0,obj);
+ obj = PyString_FromString((const char *)format);
+ if (obj == NULL) {Py_DECREF(tupobj);
+ Py_DECREF(it); return -1;}
+ strobj = PyString_Format(obj, tupobj);
+ Py_DECREF(obj);
+ Py_DECREF(tupobj);
+ if (strobj == NULL) {Py_DECREF(it); return -1;}
+ }
+ if ((n=fwrite(PyString_AS_STRING(strobj),
+ 1, n2=PyString_GET_SIZE(strobj),
+ fp)) < n2) {
+ PyErr_Format(PyExc_IOError,
+ "problem writing element %d"\
+ " to file",
+ (int) it->index);
+ Py_DECREF(strobj);
+ Py_DECREF(it);
+ return -1;
+ }
+ /* write separator for all but last one */
+ if (it->index != it->size-1)
+ fwrite(sep, 1, n3, fp);
+ Py_DECREF(strobj);
+ PyArray_ITER_NEXT(it);
+ }
+ Py_DECREF(it);
+ }
+ return 0;
+}
+
+/*OBJECT_API
+ To List
+*/
+static PyObject *
+PyArray_ToList(PyArrayObject *self)
+{
+ PyObject *lp;
+ PyArrayObject *v;
+ intp sz, i;
+
+ if (!PyArray_Check(self)) return (PyObject *)self;
+
+ if (self->nd == 0)
+ return self->descr->f->getitem(self->data,self);
+
+ sz = self->dimensions[0];
+ lp = PyList_New(sz);
+
+ for (i=0; i<sz; i++) {
+ v=(PyArrayObject *)array_big_item(self, i);
+ if (v->nd >= self->nd) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "array_item not returning smaller-" \
+ "dimensional array");
+ Py_DECREF(v);
+ Py_DECREF(lp);
+ return NULL;
+ }
+ PyList_SetItem(lp, i, PyArray_ToList(v));
+ Py_DECREF(v);
+ }
+
+ return lp;
+}
+
+static PyObject *
+PyArray_ToString(PyArrayObject *self)
+{
+ intp numbytes;
+ intp index;
+ char *dptr;
+ int elsize;
+ PyObject *ret;
+ PyArrayIterObject *it;
+
+ /* if (PyArray_TYPE(self) == PyArray_OBJECT) {
+ PyErr_SetString(PyExc_ValueError, "a string for the data" \
+ "in an object array is not appropriate");
+ return NULL;
+ }
+ */
+
+ numbytes = PyArray_NBYTES(self);
+ if (PyArray_ISONESEGMENT(self)) {
+ ret = PyString_FromStringAndSize(self->data, (int) numbytes);
+ }
+ else {
+ it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self);
+ if (it==NULL) return NULL;
+ ret = PyString_FromStringAndSize(NULL, (int) numbytes);
+ if (ret == NULL) {Py_DECREF(it); return NULL;}
+ dptr = PyString_AS_STRING(ret);
+ index = it->size;
+ elsize = self->descr->elsize;
+ while(index--) {
+ memcpy(dptr, it->dataptr, elsize);
+ dptr += elsize;
+ PyArray_ITER_NEXT(it);
+ }
+ Py_DECREF(it);
+ }
+ return ret;
+}
+
+
+/*********************** end C-API functions **********************/
+
+
+/* array object functions */
+
+static void
+array_dealloc(PyArrayObject *self) {
+
+ if (self->weakreflist != NULL)
+ PyObject_ClearWeakRefs((PyObject *)self);
+
+ if(self->base) {
+ /* UPDATEIFCOPY means that base points to an
+ array that should be updated with the contents
+ of this array upon destruction.
+ self->base->flags must have been WRITEABLE
+ (checked previously) and it was locked here
+ thus, unlock it.
+ */
+ if (self->flags & UPDATEIFCOPY) {
+ ((PyArrayObject *)self->base)->flags |= WRITEABLE;
+ Py_INCREF(self); /* hold on to self in next call */
+ PyArray_CopyInto((PyArrayObject *)self->base, self);
+ /* Don't need to DECREF -- because we are deleting
+ self already... */
+ }
+ /* In any case base is pointing to something that we need
+ to DECREF -- either a view or a buffer object */
+ Py_DECREF(self->base);
+ }
+
+ if ((self->flags & OWN_DATA) && self->data) {
+ /* Free internal references if an Object array */
+ if (PyArray_ISOBJECT(self))
+ PyArray_XDECREF(self);
+ PyDataMem_FREE(self->data);
+ }
+
+ PyDimMem_FREE(self->dimensions);
+
+ Py_DECREF(self->descr);
+
+ self->ob_type->tp_free((PyObject *)self);
+}
+
+/*************************************************************************
+ **************** Implement Mapping Protocol ***************************
+ *************************************************************************/
+
+static int
+array_length(PyArrayObject *self)
+{
+ if (self->nd != 0) {
+ return self->dimensions[0];
+ } else {
+ PyErr_SetString(PyExc_TypeError, "len() of unsized object");
+ return -1;
+ }
+}
+
+static PyObject *
+array_big_item(PyArrayObject *self, intp i)
+{
+ char *item;
+ PyArrayObject *r;
+
+ if(self->nd == 0) {
+ PyErr_SetString(PyExc_IndexError,
+ "0-d arrays can't be indexed");
+ return NULL;
+ }
+ if ((item = index2ptr(self, i)) == NULL) return NULL;
+
+ Py_INCREF(self->descr);
+ r = (PyArrayObject *)PyArray_NewFromDescr(self->ob_type,
+ self->descr,
+ self->nd-1,
+ self->dimensions+1,
+ self->strides+1, item,
+ self->flags,
+ (PyObject *)self);
+ if (r == NULL) return NULL;
+ Py_INCREF(self);
+ r->base = (PyObject *)self;
+ PyArray_UpdateFlags(r, CONTIGUOUS | FORTRAN);
+ return (PyObject *)r;
+}
+
+static PyObject *
+array_item_nice(PyArrayObject *self, int i)
+{
+ return PyArray_Return((PyArrayObject *)array_big_item(self, (intp) i));
+}
+
+
+static int
+array_ass_big_item(PyArrayObject *self, intp i, PyObject *v)
+{
+ PyArrayObject *tmp;
+ char *item;
+ int ret;
+
+ if (v == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "can't delete array elements");
+ return -1;
+ }
+ if (!PyArray_ISWRITEABLE(self)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "array is not writeable");
+ return -1;
+ }
+ if (self->nd == 0) {
+ PyErr_SetString(PyExc_IndexError,
+ "0-d arrays can't be indexed.");
+ return -1;
+ }
+
+ if (i < 0) i = i+self->dimensions[0];
+
+ if (self->nd > 1) {
+ if((tmp = (PyArrayObject *)array_big_item(self, i)) == NULL)
+ return -1;
+ ret = PyArray_CopyObject(tmp, v);
+ Py_DECREF(tmp);
+ return ret;
+ }
+
+ if ((item = index2ptr(self, i)) == NULL) return -1;
+ if (self->descr->f->setitem(v, item, self) == -1) return -1;
+ return 0;
+}
+
+#if SIZEOF_INT == SIZEOF_INTP
+#define array_ass_item array_ass_big_item
+#else
+static int
+array_ass_item(PyArrayObject *self, int i, PyObject *v)
+{
+ return array_ass_big_item(self, (intp) i, v);
+}
+#endif
+
+
+/* -------------------------------------------------------------- */
+static int
+slice_coerce_index(PyObject *o, intp *v)
+{
+ *v = PyArray_PyIntAsIntp(o);
+ if (error_converting(*v)) {
+ PyErr_Clear();
+ return 0;
+ }
+ return 1;
+}
+
+
+/* This is basically PySlice_GetIndicesEx, but with our coercion
+ * of indices to integers (plus, that function is new in Python 2.3) */
+static int
+slice_GetIndices(PySliceObject *r, intp length,
+ intp *start, intp *stop, intp *step,
+ intp *slicelength)
+{
+ intp defstart, defstop;
+
+ if (r->step == Py_None) {
+ *step = 1;
+ } else {
+ if (!slice_coerce_index(r->step, step)) return -1;
+ if (*step == 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "slice step cannot be zero");
+ return -1;
+ }
+ }
+
+ defstart = *step < 0 ? length - 1 : 0;
+ defstop = *step < 0 ? -1 : length;
+
+ if (r->start == Py_None) {
+ *start = *step < 0 ? length-1 : 0;
+ } else {
+ if (!slice_coerce_index(r->start, start)) return -1;
+ if (*start < 0) *start += length;
+ if (*start < 0) *start = (*step < 0) ? -1 : 0;
+ if (*start >= length) {
+ *start = (*step < 0) ? length - 1 : length;
+ }
+ }
+
+ if (r->stop == Py_None) {
+ *stop = defstop;
+ } else {
+ if (!slice_coerce_index(r->stop, stop)) return -1;
+ if (*stop < 0) *stop += length;
+ if (*stop < 0) *stop = -1;
+ if (*stop > length) *stop = length;
+ }
+
+ if ((*step < 0 && *stop >= *start) || \
+ (*step > 0 && *start >= *stop)) {
+ *slicelength = 0;
+ } else if (*step < 0) {
+ *slicelength = (*stop - *start + 1) / (*step) + 1;
+ } else {
+ *slicelength = (*stop - *start - 1) / (*step) + 1;
+ }
+
+ return 0;
+}
+
+#define PseudoIndex -1
+#define RubberIndex -2
+#define SingleIndex -3
+
+static intp
+parse_subindex(PyObject *op, intp *step_size, intp *n_steps, intp max)
+{
+ intp index;
+
+ if (op == Py_None) {
+ *n_steps = PseudoIndex;
+ index = 0;
+ } else if (op == Py_Ellipsis) {
+ *n_steps = RubberIndex;
+ index = 0;
+ } else if (PySlice_Check(op)) {
+ intp stop;
+ if (slice_GetIndices((PySliceObject *)op, max,
+ &index, &stop, step_size, n_steps) < 0) {
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_IndexError,
+ "invalid slice");
+ }
+ goto fail;
+ }
+ if (*n_steps <= 0) {
+ *n_steps = 0;
+ *step_size = 1;
+ index = 0;
+ }
+ } else {
+ index = PyArray_PyIntAsIntp(op);
+ if (error_converting(index)) {
+ PyErr_SetString(PyExc_IndexError,
+ "each subindex must be either a "\
+ "slice, an integer, Ellipsis, or "\
+ "newaxis");
+ goto fail;
+ }
+ *n_steps = SingleIndex;
+ *step_size = 0;
+ if (index < 0) index += max;
+ if (index >= max || index < 0) {
+ PyErr_SetString(PyExc_IndexError, "invalid index");
+ goto fail;
+ }
+ }
+ return index;
+ fail:
+ return -1;
+}
+
+
+static int
+parse_index(PyArrayObject *self, PyObject *op,
+ intp *dimensions, intp *strides, intp *offset_ptr)
+{
+ int i, j, n;
+ int nd_old, nd_new, n_add, n_pseudo;
+ intp n_steps, start, offset, step_size;
+ PyObject *op1=NULL;
+ int is_slice;
+
+
+ if (PySlice_Check(op) || op == Py_Ellipsis || op == Py_None) {
+ n = 1;
+ op1 = op;
+ Py_INCREF(op);
+ /* this relies on the fact that n==1 for loop below */
+ is_slice = 1;
+ }
+ else {
+ if (!PySequence_Check(op)) {
+ PyErr_SetString(PyExc_IndexError,
+ "index must be either an int "\
+ "or a sequence");
+ return -1;
+ }
+ n = PySequence_Length(op);
+ is_slice = 0;
+ }
+
+ nd_old = nd_new = 0;
+
+ offset = 0;
+ for(i=0; i<n; i++) {
+ if (!is_slice) {
+ if (!(op1=PySequence_GetItem(op, i))) {
+ PyErr_SetString(PyExc_IndexError,
+ "invalid index");
+ return -1;
+ }
+ }
+
+ start = parse_subindex(op1, &step_size, &n_steps,
+ nd_old < self->nd ? \
+ self->dimensions[nd_old] : 0);
+ Py_DECREF(op1);
+ if (start == -1) break;
+
+ if (n_steps == PseudoIndex) {
+ dimensions[nd_new] = 1; strides[nd_new] = 0; nd_new++;
+ } else {
+ if (n_steps == RubberIndex) {
+ for(j=i+1, n_pseudo=0; j<n; j++) {
+ op1 = PySequence_GetItem(op, j);
+ if (op1 == Py_None) n_pseudo++;
+ Py_DECREF(op1);
+ }
+ n_add = self->nd-(n-i-n_pseudo-1+nd_old);
+ if (n_add < 0) {
+ PyErr_SetString(PyExc_IndexError,
+ "too many indices");
+ return -1;
+ }
+ for(j=0; j<n_add; j++) {
+ dimensions[nd_new] = \
+ self->dimensions[nd_old];
+ strides[nd_new] = \
+ self->strides[nd_old];
+ nd_new++; nd_old++;
+ }
+ } else {
+ if (nd_old >= self->nd) {
+ PyErr_SetString(PyExc_IndexError,
+ "too many indices");
+ return -1;
+ }
+ offset += self->strides[nd_old]*start;
+ nd_old++;
+ if (n_steps != SingleIndex) {
+ dimensions[nd_new] = n_steps;
+ strides[nd_new] = step_size * \
+ self->strides[nd_old-1];
+ nd_new++;
+ }
+ }
+ }
+ }
+ if (i < n) return -1;
+ n_add = self->nd-nd_old;
+ for(j=0; j<n_add; j++) {
+ dimensions[nd_new] = self->dimensions[nd_old];
+ strides[nd_new] = self->strides[nd_old];
+ nd_new++; nd_old++;
+ }
+ *offset_ptr = offset;
+ return nd_new;
+}
+
+static void
+_swap_axes(PyArrayMapIterObject *mit, PyArrayObject **ret)
+{
+ PyObject *new;
+ int n1, n2, n3, val;
+ int i;
+ PyArray_Dims permute;
+ intp d[MAX_DIMS];
+
+ permute.ptr = d;
+ permute.len = mit->nd;
+
+ /* tuple for transpose is
+ (n1,..,n1+n2-1,0,..,n1-1,n1+n2,...,n3-1)
+ n1 is the number of dimensions of
+ the broadcasted index array
+ n2 is the number of dimensions skipped at the
+ start
+ n3 is the number of dimensions of the
+ result
+ */
+ n1 = mit->iters[0]->nd_m1 + 1;
+ n2 = mit->iteraxes[0];
+ n3 = mit->nd;
+ val = n1;
+ i = 0;
+ while(val < n1+n2)
+ permute.ptr[i++] = val++;
+ val = 0;
+ while(val < n1)
+ permute.ptr[i++] = val++;
+ val = n1+n2;
+ while(val < n3)
+ permute.ptr[i++] = val++;
+
+ new = PyArray_Transpose(*ret, &permute);
+ Py_DECREF(*ret);
+ *ret = (PyArrayObject *)new;
+}
+
+/* Prototypes for Mapping calls --- not part of the C-API
+ because only useful as part of a getitem call.
+*/
+
+static void PyArray_MapIterReset(PyArrayMapIterObject *);
+static void PyArray_MapIterNext(PyArrayMapIterObject *);
+static void PyArray_MapIterBind(PyArrayMapIterObject *, PyArrayObject *);
+static PyObject* PyArray_MapIterNew(PyObject *, int);
+
+static PyObject *
+PyArray_GetMap(PyArrayMapIterObject *mit)
+{
+
+ PyArrayObject *ret, *temp;
+ PyArrayIterObject *it;
+ int index;
+ int swap;
+ PyArray_CopySwapFunc *copyswap;
+
+ /* Unbound map iterator --- Bind should have been called */
+ if (mit->ait == NULL) return NULL;
+
+ /* This relies on the map iterator object telling us the shape
+ of the new array in nd and dimensions.
+ */
+ temp = mit->ait->ao;
+ Py_INCREF(temp->descr);
+ ret = (PyArrayObject *)\
+ PyArray_NewFromDescr(temp->ob_type,
+ temp->descr,
+ mit->nd, mit->dimensions,
+ NULL, NULL,
+ PyArray_ISFORTRAN(temp),
+ (PyObject *)temp);
+ if (ret == NULL) return NULL;
+
+ /* Now just iterate through the new array filling it in
+ with the next object from the original array as
+ defined by the mapping iterator */
+
+ if ((it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)ret))
+ == NULL) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+ index = it->size;
+ swap = (PyArray_ISNOTSWAPPED(temp) != PyArray_ISNOTSWAPPED(ret));
+ copyswap = ret->descr->f->copyswap;
+ PyArray_MapIterReset(mit);
+ while (index--) {
+ copyswap(it->dataptr, mit->dataptr, swap, ret->descr->elsize);
+ PyArray_MapIterNext(mit);
+ PyArray_ITER_NEXT(it);
+ }
+ Py_DECREF(it);
+
+ /* check for consecutive axes */
+ if ((mit->subspace != NULL) && (mit->consec)) {
+ if (mit->iteraxes[0] > 0) { /* then we need to swap */
+ _swap_axes(mit, &ret);
+ }
+ }
+ return (PyObject *)ret;
+}
+
+static int
+PyArray_SetMap(PyArrayMapIterObject *mit, PyObject *op)
+{
+ PyObject *arr=NULL;
+ PyArrayIterObject *it;
+ int index;
+ int swap;
+ PyArray_CopySwapFunc *copyswap;
+ PyArray_Descr *descr;
+
+ /* Unbound Map Iterator */
+ if (mit->ait == NULL) return -1;
+
+ descr = mit->ait->ao->descr;
+ Py_INCREF(descr);
+ arr = PyArray_FromAny(op, descr, 0, 0, FORCECAST);
+ if (arr == NULL) return -1;
+
+ if ((mit->subspace != NULL) && (mit->consec)) {
+ if (mit->iteraxes[0] > 0) { /* then we need to swap */
+ _swap_axes(mit, (PyArrayObject **)&arr);
+ }
+ }
+
+ if ((it = (PyArrayIterObject *)PyArray_IterNew(arr))==NULL) {
+ Py_DECREF(arr);
+ return -1;
+ }
+
+ index = mit->size;
+ swap = (PyArray_ISNOTSWAPPED(mit->ait->ao) != \
+ (PyArray_ISNOTSWAPPED(arr)));
+
+ copyswap = PyArray_DESCR(arr)->f->copyswap;
+ PyArray_MapIterReset(mit);
+ /* Need to decref OBJECT arrays */
+ if (PyTypeNum_ISOBJECT(descr->type_num)) {
+ while (index--) {
+ Py_XDECREF(*((PyObject **)mit->dataptr));
+ Py_INCREF(*((PyObject **)it->dataptr));
+ memmove(mit->dataptr, it->dataptr, sizeof(PyObject *));
+ PyArray_MapIterNext(mit);
+ PyArray_ITER_NEXT(it);
+ if (it->index == it->size)
+ PyArray_ITER_RESET(it);
+ }
+ Py_DECREF(arr);
+ Py_DECREF(it);
+ return 0;
+ }
+ while(index--) {
+ memmove(mit->dataptr, it->dataptr, PyArray_ITEMSIZE(arr));
+ copyswap(mit->dataptr, NULL, swap, PyArray_ITEMSIZE(arr));
+ PyArray_MapIterNext(mit);
+ PyArray_ITER_NEXT(it);
+ if (it->index == it->size)
+ PyArray_ITER_RESET(it);
+ }
+ Py_DECREF(arr);
+ Py_DECREF(it);
+ return 0;
+}
+
+/* Called when treating array object like a mapping -- called first from
+ Python when using a[object] unless object is a standard slice object
+ (not an extended one).
+
+*/
+
+/* There are two situations:
+
+ 1 - the subscript is a standard view and a reference to the
+ array can be returned
+
+ 2 - the subscript uses Boolean masks or integer indexing and
+ therefore a new array is created and returned.
+
+*/
+
+/* Always returns arrays */
+
+static PyObject *iter_subscript(PyArrayIterObject *, PyObject *);
+
+static PyObject *
+array_subscript(PyArrayObject *self, PyObject *op)
+{
+ intp dimensions[MAX_DIMS], strides[MAX_DIMS];
+ intp offset;
+ int nd, oned;
+ intp i;
+ PyArrayObject *other;
+ PyArrayMapIterObject *mit;
+
+ if (PyString_Check(op) || PyUnicode_Check(op)) {
+ if (self->descr->fields) {
+ PyObject *obj;
+ obj = PyDict_GetItem(self->descr->fields, op);
+ if (obj != NULL) {
+ PyArray_Descr *descr;
+ int offset;
+ PyObject *title;
+
+ if (PyArg_ParseTuple(obj, "Oi|O",
+ &descr, &offset, &title)) {
+ Py_INCREF(descr);
+ return PyArray_GetField(self, descr,
+ offset);
+ }
+ }
+ }
+
+ PyErr_Format(PyExc_ValueError,
+ "field named %s not found.",
+ PyString_AsString(op));
+ return NULL;
+ }
+ if (self->nd == 0) {
+ PyErr_SetString(PyExc_IndexError,
+ "0-d arrays can't be indexed.");
+ return NULL;
+ }
+ if (PyArray_IsScalar(op, Integer) || PyInt_Check(op) || \
+ PyLong_Check(op)) {
+ intp value;
+ value = PyArray_PyIntAsIntp(op);
+ if (PyErr_Occurred())
+ PyErr_Clear();
+ else if (value >= 0) {
+ return array_big_item(self, value);
+ }
+ else /* (value < 0) */ {
+ value += self->dimensions[0];
+ return array_big_item(self, value);
+ }
+ }
+
+ oned = ((self->nd == 1) && !(PyTuple_Check(op) && PyTuple_GET_SIZE(op) > 1));
+
+ /* wrap arguments into a mapiter object */
+ mit = (PyArrayMapIterObject *)PyArray_MapIterNew(op, oned);
+ if (mit == NULL) return NULL;
+ if (!mit->view) { /* fancy indexing */
+ if (oned) {
+ PyArrayIterObject *it;
+ PyObject *rval;
+ it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self);
+ if (it == NULL) {Py_DECREF(mit); return NULL;}
+ rval = iter_subscript(it, mit->indexobj);
+ Py_DECREF(it);
+ Py_DECREF(mit);
+ return rval;
+ }
+ PyArray_MapIterBind(mit, self);
+ other = (PyArrayObject *)PyArray_GetMap(mit);
+ Py_DECREF(mit);
+ return (PyObject *)other;
+ }
+ Py_DECREF(mit);
+
+ i = PyArray_PyIntAsIntp(op);
+ if (!error_converting(i)) {
+ if (i < 0 && self->nd > 0) i = i+self->dimensions[0];
+ return array_big_item(self, i);
+ }
+ PyErr_Clear();
+
+ /* Standard (view-based) Indexing */
+ if ((nd = parse_index(self, op, dimensions, strides, &offset))
+ == -1)
+ return NULL;
+
+ /* This will only work if new array will be a view */
+ Py_INCREF(self->descr);
+ if ((other = (PyArrayObject *) \
+ PyArray_NewFromDescr(self->ob_type, self->descr,
+ nd, dimensions,
+ strides, self->data+offset,
+ self->flags,
+ (PyObject *)self)) == NULL)
+ return NULL;
+
+
+ other->base = (PyObject *)self;
+ Py_INCREF(self);
+
+ PyArray_UpdateFlags(other, UPDATE_ALL_FLAGS);
+
+ return (PyObject *)other;
+}
+
+
+/* Another assignment hacked by using CopyObject. */
+
+/* This only works if subscript returns a standard view. */
+
+/* Again there are two cases. In the first case, PyArray_CopyObject
+ can be used. In the second case, a new indexing function has to be
+ used.
+*/
+
+static int iter_ass_subscript(PyArrayIterObject *, PyObject *, PyObject *);
+
+static int
+array_ass_sub(PyArrayObject *self, PyObject *index, PyObject *op)
+{
+ int ret, oned;
+ intp i;
+ PyArrayObject *tmp;
+ PyArrayMapIterObject *mit;
+
+ if (op == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "cannot delete array elements");
+ return -1;
+ }
+ if (!PyArray_ISWRITEABLE(self)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "array is not writeable");
+ return -1;
+ }
+
+ if (PyArray_IsScalar(index, Integer) || PyInt_Check(index) || \
+ PyLong_Check(index)) {
+ intp value;
+ value = PyArray_PyIntAsIntp(index);
+ if (PyErr_Occurred())
+ PyErr_Clear();
+ else
+ return array_ass_big_item(self, value, op);
+ }
+
+ if (PyString_Check(index) || PyUnicode_Check(index)) {
+ if (self->descr->fields) {
+ PyObject *obj;
+ obj = PyDict_GetItem(self->descr->fields, index);
+ if (obj != NULL) {
+ PyArray_Descr *descr;
+ int offset;
+ PyObject *title;
+
+ if (PyArg_ParseTuple(obj, "Oi|O",
+ &descr, &offset, &title)) {
+ Py_INCREF(descr);
+ return PyArray_SetField(self, descr,
+ offset, op);
+ }
+ }
+ }
+
+ PyErr_Format(PyExc_ValueError,
+ "field named %s not found.",
+ PyString_AsString(index));
+ return -1;
+ }
+
+ if (self->nd == 0) {
+ PyErr_SetString(PyExc_IndexError,
+ "0-d arrays can't be indexed.");
+ return -1;
+ }
+
+ oned = ((self->nd == 1) && !(PyTuple_Check(op) && PyTuple_GET_SIZE(op) > 1));
+
+ mit = (PyArrayMapIterObject *)PyArray_MapIterNew(index, oned);
+ if (mit == NULL) return -1;
+ if (!mit->view) {
+ if (oned) {
+ PyArrayIterObject *it;
+ int rval;
+ it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self);
+ if (it == NULL) {Py_DECREF(mit); return -1;}
+ rval = iter_ass_subscript(it, mit->indexobj, op);
+ Py_DECREF(it);
+ Py_DECREF(mit);
+ return rval;
+ }
+ PyArray_MapIterBind(mit, self);
+ ret = PyArray_SetMap(mit, op);
+ Py_DECREF(mit);
+ return ret;
+ }
+ Py_DECREF(mit);
+
+ i = PyArray_PyIntAsIntp(index);
+ if (!error_converting(i)) {
+ return array_ass_big_item(self, i, op);
+ }
+ PyErr_Clear();
+
+ /* Rest of standard (view-based) indexing */
+
+ if ((tmp = (PyArrayObject *)array_subscript(self, index)) == NULL)
+ return -1;
+ if (PyArray_ISOBJECT(self) && (tmp->nd == 0)) {
+ ret = tmp->descr->f->setitem(op, tmp->data, tmp);
+ }
+ else {
+ ret = PyArray_CopyObject(tmp, op);
+ }
+ Py_DECREF(tmp);
+ return ret;
+}
+
+/* There are places that require that array_subscript return a PyArrayObject
+ and not possibly a scalar. Thus, this is the function exposed to
+ Python so that 0-dim arrays are passed as scalars
+*/
+
+static PyObject *
+array_subscript_nice(PyArrayObject *self, PyObject *op)
+{
+ return PyArray_Return((PyArrayObject *)array_subscript(self, op));
+}
+
+
+static PyMappingMethods array_as_mapping = {
+ (inquiry)array_length, /*mp_length*/
+ (binaryfunc)array_subscript_nice, /*mp_subscript*/
+ (objobjargproc)array_ass_sub, /*mp_ass_subscript*/
+};
+
+/****************** End of Mapping Protocol ******************************/
+
+
+/*************************************************************************
+ **************** Implement Buffer Protocol ****************************
+ *************************************************************************/
+
+/* removed multiple segment interface */
+
+static int
+array_getsegcount(PyArrayObject *self, int *lenp)
+{
+ if (lenp)
+ *lenp = PyArray_NBYTES(self);
+
+ if (PyArray_ISONESEGMENT(self)) {
+ return 1;
+ }
+
+ if (lenp)
+ *lenp = 0;
+ return 0;
+}
+
+static int
+array_getreadbuf(PyArrayObject *self, int segment, void **ptrptr)
+{
+ if (segment != 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "accessing non-existing array segment");
+ return -1;
+ }
+
+ if (PyArray_ISONESEGMENT(self)) {
+ *ptrptr = self->data;
+ return PyArray_NBYTES(self);
+ }
+ PyErr_SetString(PyExc_ValueError, "array is not a single segment");
+ *ptrptr = NULL;
+ return -1;
+}
+
+
+static int
+array_getwritebuf(PyArrayObject *self, int segment, void **ptrptr)
+{
+ if (PyArray_CHKFLAGS(self, WRITEABLE))
+ return array_getreadbuf(self, segment, (void **) ptrptr);
+ else {
+ PyErr_SetString(PyExc_ValueError, "array cannot be "\
+ "accessed as a writeable buffer");
+ return -1;
+ }
+}
+
+static int
+array_getcharbuf(PyArrayObject *self, int segment, const char **ptrptr)
+{
+ if (self->descr->type_num == PyArray_STRING || \
+ self->descr->type_num == PyArray_UNICODE)
+ return array_getreadbuf(self, segment, (void **) ptrptr);
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "non-character array cannot be interpreted "\
+ "as character buffer");
+ return -1;
+ }
+}
+
+static PyBufferProcs array_as_buffer = {
+ (getreadbufferproc)array_getreadbuf, /*bf_getreadbuffer*/
+ (getwritebufferproc)array_getwritebuf, /*bf_getwritebuffer*/
+ (getsegcountproc)array_getsegcount, /*bf_getsegcount*/
+ (getcharbufferproc)array_getcharbuf, /*bf_getcharbuffer*/
+};
+
+/****************** End of Buffer Protocol *******************************/
+
+
+/*************************************************************************
+ **************** Implement Number Protocol ****************************
+ *************************************************************************/
+
+
+typedef struct {
+ PyObject *add,
+ *subtract,
+ *multiply,
+ *divide,
+ *remainder,
+ *power,
+ *sqrt,
+ *negative,
+ *absolute,
+ *invert,
+ *left_shift,
+ *right_shift,
+ *bitwise_and,
+ *bitwise_xor,
+ *bitwise_or,
+ *less,
+ *less_equal,
+ *equal,
+ *not_equal,
+ *greater,
+ *greater_equal,
+ *floor_divide,
+ *true_divide,
+ *logical_or,
+ *logical_and,
+ *floor,
+ *ceil,
+ *maximum,
+ *minimum;
+
+} NumericOps;
+
+static NumericOps n_ops = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL};
+
+/* Dictionary can contain any of the numeric operations, by name.
+ Those not present will not be changed
+ */
+
+#define SET(op) temp=PyDict_GetItemString(dict, #op); \
+ if (temp != NULL) { \
+ if (!(PyCallable_Check(temp))) return -1; \
+ Py_XDECREF(n_ops.op); \
+ n_ops.op = temp; \
+ }
+
+
+/*OBJECT_API
+ Set internal structure with number functions that all arrays will use
+*/
+int
+PyArray_SetNumericOps(PyObject *dict)
+{
+ PyObject *temp = NULL;
+ SET(add);
+ SET(subtract);
+ SET(multiply);
+ SET(divide);
+ SET(remainder);
+ SET(power);
+ SET(sqrt);
+ SET(negative);
+ SET(absolute);
+ SET(invert);
+ SET(left_shift);
+ SET(right_shift);
+ SET(bitwise_and);
+ SET(bitwise_or);
+ SET(bitwise_xor);
+ SET(less);
+ SET(less_equal);
+ SET(equal);
+ SET(not_equal);
+ SET(greater);
+ SET(greater_equal);
+ SET(floor_divide);
+ SET(true_divide);
+ SET(logical_or);
+ SET(logical_and);
+ SET(floor);
+ SET(ceil);
+ SET(maximum);
+ SET(minimum);
+ return 0;
+}
+
+#define GET(op) if (n_ops.op && \
+ (PyDict_SetItemString(dict, #op, n_ops.op)==-1)) \
+ goto fail;
+
+/*OBJECT_API
+ Get dictionary showing number functions that all arrays will use
+*/
+static PyObject *
+PyArray_GetNumericOps(void)
+{
+ PyObject *dict;
+ if ((dict = PyDict_New())==NULL)
+ return NULL;
+ GET(add);
+ GET(subtract);
+ GET(multiply);
+ GET(divide);
+ GET(remainder);
+ GET(power);
+ GET(sqrt);
+ GET(negative);
+ GET(absolute);
+ GET(invert);
+ GET(left_shift);
+ GET(right_shift);
+ GET(bitwise_and);
+ GET(bitwise_or);
+ GET(bitwise_xor);
+ GET(less);
+ GET(less_equal);
+ GET(equal);
+ GET(not_equal);
+ GET(greater);
+ GET(greater_equal);
+ GET(floor_divide);
+ GET(true_divide);
+ GET(logical_or);
+ GET(logical_and);
+ GET(floor);
+ GET(ceil);
+ GET(maximum);
+ GET(minimum);
+ return dict;
+
+ fail:
+ Py_DECREF(dict);
+ return NULL;
+}
+
+static PyObject *
+PyArray_GenericReduceFunction(PyArrayObject *m1, PyObject *op, int axis,
+ int rtype)
+{
+ PyObject *args, *ret=NULL, *meth;
+ if (op == NULL) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ if (rtype == PyArray_NOTYPE)
+ args = Py_BuildValue("(Oi)", m1, axis);
+ else {
+ PyArray_Descr *descr;
+ descr = PyArray_DescrFromType(rtype);
+ args = Py_BuildValue("(Oic)", m1, axis, descr->type);
+ Py_DECREF(descr);
+ }
+ meth = PyObject_GetAttrString(op, "reduce");
+ if (meth && PyCallable_Check(meth)) {
+ ret = PyObject_Call(meth, args, NULL);
+ }
+ Py_DECREF(args);
+ Py_DECREF(meth);
+ return ret;
+}
+
+
+static PyObject *
+PyArray_GenericAccumulateFunction(PyArrayObject *m1, PyObject *op, int axis,
+ int rtype)
+{
+ PyObject *args, *ret=NULL, *meth;
+ if (op == NULL) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ if (rtype == PyArray_NOTYPE)
+ args = Py_BuildValue("(Oi)", m1, axis);
+ else {
+ PyArray_Descr *descr;
+ descr = PyArray_DescrFromType(rtype);
+ args = Py_BuildValue("(Oic)", m1, axis, descr->type);
+ Py_DECREF(descr);
+ }
+ meth = PyObject_GetAttrString(op, "accumulate");
+ if (meth && PyCallable_Check(meth)) {
+ ret = PyObject_Call(meth, args, NULL);
+ }
+ Py_DECREF(args);
+ Py_DECREF(meth);
+ return ret;
+}
+
+
+static PyObject *
+PyArray_GenericBinaryFunction(PyArrayObject *m1, PyObject *m2, PyObject *op)
+{
+ if (op == NULL) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ return PyObject_CallFunction(op, "OO", m1, m2);
+}
+
+static PyObject *
+PyArray_GenericUnaryFunction(PyArrayObject *m1, PyObject *op)
+{
+ if (op == NULL) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ return PyObject_CallFunction(op, "(O)", m1);
+}
+
+static PyObject *
+PyArray_GenericInplaceBinaryFunction(PyArrayObject *m1,
+ PyObject *m2, PyObject *op)
+{
+ if (op == NULL) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ return PyObject_CallFunction(op, "OOO", m1, m2, m1);
+}
+
+static PyObject *
+array_add(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericBinaryFunction(m1, m2, n_ops.add);
+}
+
+static PyObject *
+array_subtract(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericBinaryFunction(m1, m2, n_ops.subtract);
+}
+
+static PyObject *
+array_multiply(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericBinaryFunction(m1, m2, n_ops.multiply);
+}
+
+static PyObject *
+array_divide(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericBinaryFunction(m1, m2, n_ops.divide);
+}
+
+static PyObject *
+array_remainder(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericBinaryFunction(m1, m2, n_ops.remainder);
+}
+
+static PyObject *
+array_power(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericBinaryFunction(m1, m2, n_ops.power);
+}
+
+static PyObject *
+array_negative(PyArrayObject *m1)
+{
+ return PyArray_GenericUnaryFunction(m1, n_ops.negative);
+}
+
+static PyObject *
+array_absolute(PyArrayObject *m1)
+{
+ return PyArray_GenericUnaryFunction(m1, n_ops.absolute);
+}
+
+static PyObject *
+array_invert(PyArrayObject *m1)
+{
+ return PyArray_GenericUnaryFunction(m1, n_ops.invert);
+}
+
+static PyObject *
+array_left_shift(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericBinaryFunction(m1, m2, n_ops.left_shift);
+}
+
+static PyObject *
+array_right_shift(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericBinaryFunction(m1, m2, n_ops.right_shift);
+}
+
+static PyObject *
+array_bitwise_and(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_and);
+}
+
+static PyObject *
+array_bitwise_or(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_or);
+}
+
+static PyObject *
+array_bitwise_xor(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_xor);
+}
+
+static PyObject *
+array_inplace_add(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.add);
+}
+
+static PyObject *
+array_inplace_subtract(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.subtract);
+}
+
+static PyObject *
+array_inplace_multiply(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.multiply);
+}
+
+static PyObject *
+array_inplace_divide(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.divide);
+}
+
+static PyObject *
+array_inplace_remainder(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.remainder);
+}
+
+static PyObject *
+array_inplace_power(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.power);
+}
+
+static PyObject *
+array_inplace_left_shift(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.left_shift);
+}
+
+static PyObject *
+array_inplace_right_shift(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.right_shift);
+}
+
+static PyObject *
+array_inplace_bitwise_and(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_and);
+}
+
+static PyObject *
+array_inplace_bitwise_or(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_or);
+}
+
+static PyObject *
+array_inplace_bitwise_xor(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_xor);
+}
+
+static PyObject *
+array_floor_divide(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericBinaryFunction(m1, m2, n_ops.floor_divide);
+}
+
+static PyObject *
+array_true_divide(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericBinaryFunction(m1, m2, n_ops.true_divide);
+}
+
+static PyObject *
+array_inplace_floor_divide(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericInplaceBinaryFunction(m1, m2,
+ n_ops.floor_divide);
+}
+
+static PyObject *
+array_inplace_true_divide(PyArrayObject *m1, PyObject *m2)
+{
+ return PyArray_GenericInplaceBinaryFunction(m1, m2,
+ n_ops.true_divide);
+}
+
+/* Array evaluates as "TRUE" if any of the elements are non-zero*/
+static int
+array_any_nonzero(PyArrayObject *mp)
+{
+ intp index;
+ PyArrayIterObject *it;
+ Bool anyTRUE = FALSE;
+
+ it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp);
+ if (it==NULL) return anyTRUE;
+ index = it->size;
+ while(index--) {
+ if (mp->descr->f->nonzero(it->dataptr, mp)) {
+ anyTRUE = TRUE;
+ break;
+ }
+ PyArray_ITER_NEXT(it);
+ }
+ Py_DECREF(it);
+ return anyTRUE;
+}
+
+static int
+_array_nonzero(PyArrayObject *mp)
+{
+ intp n;
+ n = PyArray_SIZE(mp);
+ if (n == 1) {
+ return mp->descr->f->nonzero(mp->data, mp);
+ }
+ else if (n == 0) {
+ return 0;
+ }
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "The truth value of an array " \
+ "with more than one element is ambiguous. " \
+ "Use a.any() or a.all()");
+ return -1;
+ }
+}
+
+
+
+static PyObject *
+array_divmod(PyArrayObject *op1, PyObject *op2)
+{
+ PyObject *divp, *modp, *result;
+
+ divp = array_floor_divide(op1, op2);
+ if (divp == NULL) return NULL;
+ modp = array_remainder(op1, op2);
+ if (modp == NULL) {
+ Py_DECREF(divp);
+ return NULL;
+ }
+ result = Py_BuildValue("OO", divp, modp);
+ Py_DECREF(divp);
+ Py_DECREF(modp);
+ return result;
+}
+
+
+static PyObject *
+array_int(PyArrayObject *v)
+{
+ PyObject *pv, *pv2;
+ if (PyArray_SIZE(v) != 1) {
+ PyErr_SetString(PyExc_TypeError, "only length-1 arrays can be"\
+ " converted to Python scalars");
+ return NULL;
+ }
+ pv = v->descr->f->getitem(v->data, v);
+ if (pv == NULL) return NULL;
+ if (pv->ob_type->tp_as_number == 0) {
+ PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\
+ "scalar object is not a number");
+ Py_DECREF(pv);
+ return NULL;
+ }
+ if (pv->ob_type->tp_as_number->nb_int == 0) {
+ PyErr_SetString(PyExc_TypeError, "don't know how to convert "\
+ "scalar number to int");
+ Py_DECREF(pv);
+ return NULL;
+ }
+
+ pv2 = pv->ob_type->tp_as_number->nb_int(pv);
+ Py_DECREF(pv);
+ return pv2;
+}
+
+static PyObject *
+array_float(PyArrayObject *v)
+{
+ PyObject *pv, *pv2;
+ if (PyArray_SIZE(v) != 1) {
+ PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\
+ "be converted to Python scalars");
+ return NULL;
+ }
+ pv = v->descr->f->getitem(v->data, v);
+ if (pv == NULL) return NULL;
+ if (pv->ob_type->tp_as_number == 0) {
+ PyErr_SetString(PyExc_TypeError, "cannot convert to an "\
+ "int; scalar object is not a number");
+ Py_DECREF(pv);
+ return NULL;
+ }
+ if (pv->ob_type->tp_as_number->nb_float == 0) {
+ PyErr_SetString(PyExc_TypeError, "don't know how to convert "\
+ "scalar number to float");
+ Py_DECREF(pv);
+ return NULL;
+ }
+ pv2 = pv->ob_type->tp_as_number->nb_float(pv);
+ Py_DECREF(pv);
+ return pv2;
+}
+
+static PyObject *
+array_long(PyArrayObject *v)
+{
+ PyObject *pv, *pv2;
+ if (PyArray_SIZE(v) != 1) {
+ PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\
+ "be converted to Python scalars");
+ return NULL;
+ }
+ pv = v->descr->f->getitem(v->data, v);
+ if (pv->ob_type->tp_as_number == 0) {
+ PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\
+ "scalar object is not a number");
+ return NULL;
+ }
+ if (pv->ob_type->tp_as_number->nb_long == 0) {
+ PyErr_SetString(PyExc_TypeError, "don't know how to convert "\
+ "scalar number to long");
+ return NULL;
+ }
+ pv2 = pv->ob_type->tp_as_number->nb_long(pv);
+ Py_DECREF(pv);
+ return pv2;
+}
+
+static PyObject *
+array_oct(PyArrayObject *v)
+{
+ PyObject *pv, *pv2;
+ if (PyArray_SIZE(v) != 1) {
+ PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\
+ "be converted to Python scalars");
+ return NULL;
+ }
+ pv = v->descr->f->getitem(v->data, v);
+ if (pv->ob_type->tp_as_number == 0) {
+ PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\
+ "scalar object is not a number");
+ return NULL;
+ }
+ if (pv->ob_type->tp_as_number->nb_oct == 0) {
+ PyErr_SetString(PyExc_TypeError, "don't know how to convert "\
+ "scalar number to oct");
+ return NULL;
+ }
+ pv2 = pv->ob_type->tp_as_number->nb_oct(pv);
+ Py_DECREF(pv);
+ return pv2;
+}
+
+static PyObject *
+array_hex(PyArrayObject *v)
+{
+ PyObject *pv, *pv2;
+ if (PyArray_SIZE(v) != 1) {
+ PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\
+ "be converted to Python scalars");
+ return NULL;
+ }
+ pv = v->descr->f->getitem(v->data, v);
+ if (pv->ob_type->tp_as_number == 0) {
+ PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\
+ "scalar object is not a number");
+ return NULL;
+ }
+ if (pv->ob_type->tp_as_number->nb_hex == 0) {
+ PyErr_SetString(PyExc_TypeError, "don't know how to convert "\
+ "scalar number to hex");
+ return NULL;
+ }
+ pv2 = pv->ob_type->tp_as_number->nb_hex(pv);
+ Py_DECREF(pv);
+ return pv2;
+}
+
+static PyObject *
+_array_copy_nice(PyArrayObject *self)
+{
+ return PyArray_Return((PyArrayObject *) \
+ PyArray_Copy(self));
+}
+
+static PyNumberMethods array_as_number = {
+ (binaryfunc)array_add, /*nb_add*/
+ (binaryfunc)array_subtract, /*nb_subtract*/
+ (binaryfunc)array_multiply, /*nb_multiply*/
+ (binaryfunc)array_divide, /*nb_divide*/
+ (binaryfunc)array_remainder, /*nb_remainder*/
+ (binaryfunc)array_divmod, /*nb_divmod*/
+ (ternaryfunc)array_power, /*nb_power*/
+ (unaryfunc)array_negative, /*nb_neg*/
+ (unaryfunc)_array_copy_nice, /*nb_pos*/
+ (unaryfunc)array_absolute, /*(unaryfunc)array_abs,*/
+ (inquiry)_array_nonzero, /*nb_nonzero*/
+ (unaryfunc)array_invert, /*nb_invert*/
+ (binaryfunc)array_left_shift, /*nb_lshift*/
+ (binaryfunc)array_right_shift, /*nb_rshift*/
+ (binaryfunc)array_bitwise_and, /*nb_and*/
+ (binaryfunc)array_bitwise_xor, /*nb_xor*/
+ (binaryfunc)array_bitwise_or, /*nb_or*/
+ 0, /*nb_coerce*/
+ (unaryfunc)array_int, /*nb_int*/
+ (unaryfunc)array_long, /*nb_long*/
+ (unaryfunc)array_float, /*nb_float*/
+ (unaryfunc)array_oct, /*nb_oct*/
+ (unaryfunc)array_hex, /*nb_hex*/
+
+ /*This code adds augmented assignment functionality*/
+ /*that was made available in Python 2.0*/
+ (binaryfunc)array_inplace_add, /*inplace_add*/
+ (binaryfunc)array_inplace_subtract, /*inplace_subtract*/
+ (binaryfunc)array_inplace_multiply, /*inplace_multiply*/
+ (binaryfunc)array_inplace_divide, /*inplace_divide*/
+ (binaryfunc)array_inplace_remainder, /*inplace_remainder*/
+ (ternaryfunc)array_inplace_power, /*inplace_power*/
+ (binaryfunc)array_inplace_left_shift, /*inplace_lshift*/
+ (binaryfunc)array_inplace_right_shift, /*inplace_rshift*/
+ (binaryfunc)array_inplace_bitwise_and, /*inplace_and*/
+ (binaryfunc)array_inplace_bitwise_xor, /*inplace_xor*/
+ (binaryfunc)array_inplace_bitwise_or, /*inplace_or*/
+
+ (binaryfunc)array_floor_divide, /*nb_floor_divide*/
+ (binaryfunc)array_true_divide, /*nb_true_divide*/
+ (binaryfunc)array_inplace_floor_divide, /*nb_inplace_floor_divide*/
+ (binaryfunc)array_inplace_true_divide, /*nb_inplace_true_divide*/
+
+};
+
+/****************** End of Buffer Protocol *******************************/
+
+
+/*************************************************************************
+ **************** Implement Sequence Protocol **************************
+ *************************************************************************/
+
+/* Some of this is repeated in the array_as_mapping protocol. But
+ we fill it in here so that PySequence_XXXX calls work as expected
+*/
+
+
+static PyObject *
+array_slice(PyArrayObject *self, int ilow, int ihigh)
+{
+ PyArrayObject *r;
+ int l;
+ char *data;
+
+ if (self->nd == 0) {
+ PyErr_SetString(PyExc_ValueError, "cannot slice a scalar");
+ return NULL;
+ }
+
+ l=self->dimensions[0];
+ if (ihigh < 0) ihigh += l;
+ if (ilow < 0) ilow += l;
+ if (ilow < 0) ilow = 0;
+ else if (ilow > l) ilow = l;
+ if (ihigh < 0) ihigh = 0;
+ else if (ihigh > l) ihigh = l;
+ if (ihigh < ilow) ihigh = ilow;
+
+ if (ihigh != ilow) {
+ data = index2ptr(self, ilow);
+ if (data == NULL) return NULL;
+ } else {
+ data = self->data;
+ }
+
+ self->dimensions[0] = ihigh-ilow;
+ Py_INCREF(self->descr);
+ r = (PyArrayObject *) \
+ PyArray_NewFromDescr(self->ob_type, self->descr,
+ self->nd, self->dimensions,
+ self->strides, data,
+ self->flags, (PyObject *)self);
+
+ self->dimensions[0] = l;
+ r->base = (PyObject *)self;
+ Py_INCREF(self);
+ PyArray_UpdateFlags(r, UPDATE_ALL_FLAGS);
+ return (PyObject *)r;
+}
+
+
+static int
+array_ass_slice(PyArrayObject *self, int ilow, int ihigh, PyObject *v) {
+ int ret;
+ PyArrayObject *tmp;
+
+ if (v == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "cannot delete array elements");
+ return -1;
+ }
+ if (!PyArray_ISWRITEABLE(self)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "array is not writeable");
+ return -1;
+ }
+ if ((tmp = (PyArrayObject *)array_slice(self, ilow, ihigh)) \
+ == NULL)
+ return -1;
+ ret = PyArray_CopyObject(tmp, v);
+ Py_DECREF(tmp);
+
+ return ret;
+}
+
+static int
+array_contains(PyArrayObject *self, PyObject *el)
+{
+ /* equivalent to (self == el).any() */
+
+ PyObject *res;
+ int ret;
+
+ res = PyArray_EnsureArray(PyObject_RichCompare((PyObject *)self, el, Py_EQ));
+ if (res == NULL) return -1;
+ ret = array_any_nonzero((PyArrayObject *)res);
+ Py_DECREF(res);
+ return ret;
+}
+
+
+static PySequenceMethods array_as_sequence = {
+ (inquiry)array_length, /*sq_length*/
+ (binaryfunc)NULL, /* sq_concat is handled by nb_add*/
+ (intargfunc)NULL, /* sq_repeat is handled nb_multiply*/
+ (intargfunc)array_item_nice, /*sq_item*/
+ (intintargfunc)array_slice, /*sq_slice*/
+ (intobjargproc)array_ass_item, /*sq_ass_item*/
+ (intintobjargproc)array_ass_slice, /*sq_ass_slice*/
+ (objobjproc) array_contains, /* sq_contains */
+ (binaryfunc) NULL, /* sg_inplace_concat */
+ (intargfunc) NULL /* sg_inplace_repeat */
+};
+
+
+/****************** End of Sequence Protocol ****************************/
+
+
+static int
+dump_data(char **string, int *n, int *max_n, char *data, int nd,
+ intp *dimensions, intp *strides, PyArrayObject* self)
+{
+ PyArray_Descr *descr=self->descr;
+ PyObject *op, *sp;
+ char *ostring;
+ int i, N;
+
+#define CHECK_MEMORY if (*n >= *max_n-16) { *max_n *= 2; \
+ *string = (char *)_pya_realloc(*string, *max_n); }
+
+ if (nd == 0) {
+
+ if ((op = descr->f->getitem(data, self)) == NULL) return -1;
+ sp = PyObject_Repr(op);
+ if (sp == NULL) {Py_DECREF(op); return -1;}
+ ostring = PyString_AsString(sp);
+ N = PyString_Size(sp)*sizeof(char);
+ *n += N;
+ CHECK_MEMORY
+ memmove(*string+(*n-N), ostring, N);
+ Py_DECREF(sp);
+ Py_DECREF(op);
+ return 0;
+ } else {
+ CHECK_MEMORY
+ (*string)[*n] = '[';
+ *n += 1;
+ for(i=0; i<dimensions[0]; i++) {
+ if (dump_data(string, n, max_n,
+ data+(*strides)*i,
+ nd-1, dimensions+1,
+ strides+1, self) < 0)
+ return -1;
+ CHECK_MEMORY
+ if (i<dimensions[0]-1) {
+ (*string)[*n] = ',';
+ (*string)[*n+1] = ' ';
+ *n += 2;
+ }
+ }
+ CHECK_MEMORY
+ (*string)[*n] = ']'; *n += 1;
+ return 0;
+ }
+
+#undef CHECK_MEMORY
+}
+
+static PyObject *
+array_repr_builtin(PyArrayObject *self)
+{
+ PyObject *ret;
+ char *string;
+ int n, max_n;
+
+ max_n = PyArray_NBYTES(self)*4*sizeof(char) + 7;
+
+ if ((string = (char *)_pya_malloc(max_n)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError, "out of memory");
+ return NULL;
+ }
+
+ n = 6;
+ sprintf(string, "array(");
+
+ if (dump_data(&string, &n, &max_n, self->data,
+ self->nd, self->dimensions,
+ self->strides, self) < 0) {
+ _pya_free(string); return NULL;
+ }
+
+ if (PyArray_ISEXTENDED(self)) {
+ char buf[100];
+ snprintf(buf, sizeof(buf), "%d", self->descr->elsize);
+ sprintf(string+n, ", '%c%s')", self->descr->type, buf);
+ ret = PyString_FromStringAndSize(string, n+6+strlen(buf));
+ }
+ else {
+ sprintf(string+n, ", '%c')", self->descr->type);
+ ret = PyString_FromStringAndSize(string, n+6);
+ }
+
+
+ _pya_free(string);
+ return ret;
+}
+
+static PyObject *PyArray_StrFunction=NULL;
+static PyObject *PyArray_ReprFunction=NULL;
+
+/*OBJECT_API
+ Set the array print function to be a Python function.
+*/
+static void
+PyArray_SetStringFunction(PyObject *op, int repr)
+{
+ if (repr) {
+ /* Dispose of previous callback */
+ Py_XDECREF(PyArray_ReprFunction);
+ /* Add a reference to new callback */
+ Py_XINCREF(op);
+ /* Remember new callback */
+ PyArray_ReprFunction = op;
+ } else {
+ /* Dispose of previous callback */
+ Py_XDECREF(PyArray_StrFunction);
+ /* Add a reference to new callback */
+ Py_XINCREF(op);
+ /* Remember new callback */
+ PyArray_StrFunction = op;
+ }
+}
+
+static PyObject *
+array_repr(PyArrayObject *self)
+{
+ PyObject *s, *arglist;
+
+ if (PyArray_ReprFunction == NULL) {
+ s = array_repr_builtin(self);
+ } else {
+ arglist = Py_BuildValue("(O)", self);
+ s = PyEval_CallObject(PyArray_ReprFunction, arglist);
+ Py_DECREF(arglist);
+ }
+ return s;
+}
+
+static PyObject *
+array_str(PyArrayObject *self)
+{
+ PyObject *s, *arglist;
+
+ if (PyArray_StrFunction == NULL) {
+ s = array_repr(self);
+ } else {
+ arglist = Py_BuildValue("(O)", self);
+ s = PyEval_CallObject(PyArray_StrFunction, arglist);
+ Py_DECREF(arglist);
+ }
+ return s;
+}
+
+static PyObject *
+array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op)
+{
+ PyObject *array_other, *result;
+
+ switch (cmp_op)
+ {
+ case Py_LT:
+ return PyArray_GenericBinaryFunction(self, other,
+ n_ops.less);
+ case Py_LE:
+ return PyArray_GenericBinaryFunction(self, other,
+ n_ops.less_equal);
+ case Py_EQ:
+ /* Try to convert other to an array */
+ array_other = PyArray_FromObject(other,
+ PyArray_NOTYPE, 0, 0);
+ /* If not successful, then return the integer
+ object 0. This fixes code that used to
+ allow equality comparisons between arrays
+ and other objects which would give a result
+ of 0
+ */
+ if ((array_other == NULL) || \
+ (array_other == Py_None)) {
+ Py_XDECREF(array_other);
+ PyErr_Clear();
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+ result = PyArray_GenericBinaryFunction(self,
+ array_other,
+ n_ops.equal);
+ /* If the comparison results in NULL, then the
+ two array objects can not be compared together so
+ return zero
+ */
+ Py_DECREF(array_other);
+ if (result == NULL) {
+ PyErr_Clear();
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+ return result;
+ case Py_NE:
+ /* Try to convert other to an array */
+ array_other = PyArray_FromObject(other,
+ PyArray_NOTYPE, 0, 0);
+ /* If not successful, then objects cannot be
+ compared and cannot be equal, therefore,
+ return True;
+ */
+ if ((array_other == NULL) || \
+ (array_other == Py_None)) {
+ Py_XDECREF(array_other);
+ PyErr_Clear();
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ result = PyArray_GenericBinaryFunction(self,
+ array_other,
+ n_ops.not_equal);
+ Py_DECREF(array_other);
+ if (result == NULL) {
+ PyErr_Clear();
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ return result;
+ case Py_GT:
+ return PyArray_GenericBinaryFunction(self, other,
+ n_ops.greater);
+ case Py_GE:
+ return PyArray_GenericBinaryFunction(self,
+ other,
+ n_ops.greater_equal);
+ }
+ return NULL;
+}
+
+static PyObject *
+_check_axis(PyArrayObject *arr, int *axis, int flags)
+{
+ PyObject *temp;
+ int n = arr->nd;
+
+ if ((*axis >= MAX_DIMS) || (n==0)) {
+ temp = PyArray_Ravel(arr,0);
+ *axis = 0;
+ return temp;
+ }
+ else {
+ if (flags) {
+ temp = PyArray_FromAny((PyObject *)arr, NULL,
+ 0, 0, flags);
+ if (temp == NULL) return NULL;
+ }
+ else {
+ Py_INCREF(arr);
+ temp = (PyObject *)arr;
+ }
+ }
+ if (*axis < 0) *axis += n;
+ if ((*axis < 0) || (*axis >= n)) {
+ PyErr_Format(PyExc_ValueError,
+ "axis(=%d) out of bounds", *axis);
+ Py_DECREF(temp);
+ return NULL;
+ }
+ return temp;
+}
+
+#include "arraymethods.c"
+
+/* Lifted from numarray */
+static PyObject *
+PyArray_IntTupleFromIntp(int len, intp *vals)
+{
+ int i;
+ PyObject *intTuple = PyTuple_New(len);
+ if (!intTuple) goto fail;
+ for(i=0; i<len; i++) {
+#if SIZEOF_INTP <= SIZEOF_LONG
+ PyObject *o = PyInt_FromLong((long) vals[i]);
+#else
+ PyObject *o = PyLong_FromLongLong((longlong) vals[i]);
+#endif
+ if (!o) {
+ Py_DECREF(intTuple);
+ intTuple = NULL;
+ goto fail;
+ }
+ PyTuple_SET_ITEM(intTuple, i, o);
+ }
+ fail:
+ return intTuple;
+}
+
+/* Returns the number of dimensions or -1 if an error occurred */
+/* vals must be large enough to hold maxvals */
+/*MULTIARRAY_API
+ PyArray_IntpFromSequence
+*/
+static int
+PyArray_IntpFromSequence(PyObject *seq, intp *vals, int maxvals)
+{
+ int nd, i;
+ PyObject *op;
+
+ /* Check to see if sequence is a single integer first.
+ or, can be made into one */
+ if ((nd=PySequence_Length(seq)) == -1) {
+ if (PyErr_Occurred()) PyErr_Clear();
+ if (!(op = PyNumber_Int(seq))) return -1;
+ nd = 1;
+ vals[0] = (intp ) PyInt_AsLong(op);
+ Py_DECREF(op);
+ } else {
+ for(i=0; i < MIN(nd,maxvals); i++) {
+ op = PySequence_GetItem(seq, i);
+ if (op == NULL) return -1;
+ vals[i]=(intp )PyInt_AsLong(op);
+ Py_DECREF(op);
+ if(PyErr_Occurred()) return -1;
+ }
+ }
+ return nd;
+}
+
+
+/* Check whether the given array is stored contiguously (row-wise) in
+ memory. */
+static int
+_IsContiguous(PyArrayObject *ap)
+{
+ intp sd;
+ int i;
+
+ if (ap->nd == 0) return 1;
+ sd = ap->descr->elsize;
+ if (ap->nd == 1) return sd == ap->strides[0];
+ for (i = ap->nd-1; i >= 0; --i) {
+ /* contiguous by definition */
+ if (ap->dimensions[i] == 0) return 1;
+
+ if (ap->strides[i] != sd) return 0;
+ sd *= ap->dimensions[i];
+ }
+ return 1;
+}
+
+
+static int
+_IsFortranContiguous(PyArrayObject *ap)
+{
+ intp sd;
+ int i;
+
+ if (ap->nd == 0) return 1;
+ sd = ap->descr->elsize;
+ if (ap->nd == 1) return sd == ap->strides[0];
+ for (i=0; i< ap->nd; ++i) {
+ /* contiguous by definition */
+ if (ap->dimensions[i] == 0) return 1;
+
+ if (ap->strides[i] != sd) return 0;
+ sd *= ap->dimensions[i];
+ }
+ return 1;
+}
+
+static int
+_IsAligned(PyArrayObject *ap)
+{
+ int i, alignment, aligned=1;
+ intp ptr;
+ int type = ap->descr->type_num;
+
+ if ((type == PyArray_STRING) || (type == PyArray_VOID))
+ return 1;
+
+ alignment = ap->descr->alignment;
+ if (alignment == 1) return 1;
+
+ ptr = (intp) ap->data;
+ aligned = (ptr % alignment) == 0;
+ for (i=0; i <ap->nd; i++)
+ aligned &= ((ap->strides[i] % alignment) == 0);
+ return aligned != 0;
+}
+
+static Bool
+_IsWriteable(PyArrayObject *ap)
+{
+ PyObject *base=ap->base;
+ void *dummy;
+ int n;
+
+ /* If we own our own data, then no-problem */
+ if ((base == NULL) || (ap->flags & OWN_DATA)) return TRUE;
+
+ /* Get to the final base object
+ If it is a writeable array, then return TRUE
+ If we can find an array object
+ or a writeable buffer object as the final base object
+ or a string object (for pickling support memory savings).
+ - this last could be removed if a proper pickleable
+ buffer was added to Python.
+ */
+
+ while(PyArray_Check(base)) {
+ if (PyArray_CHKFLAGS(base, OWN_DATA))
+ return (Bool) (PyArray_ISWRITEABLE(base));
+ base = PyArray_BASE(base);
+ }
+
+ /* here so pickle support works seamlessly
+ and unpickled array can be set and reset writeable
+ -- could be abused -- */
+ if PyString_Check(base) return TRUE;
+
+ if (PyObject_AsWriteBuffer(base, &dummy, &n) < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/*OBJECT_API
+ Update Several Flags at once.
+*/
+static void
+PyArray_UpdateFlags(PyArrayObject *ret, int flagmask)
+{
+
+ if (flagmask & FORTRAN) {
+ if (_IsFortranContiguous(ret)) {
+ ret->flags |= FORTRAN;
+ if (ret->nd > 1) ret->flags &= ~CONTIGUOUS;
+ }
+ else ret->flags &= ~FORTRAN;
+ }
+ if (flagmask & CONTIGUOUS) {
+ if (_IsContiguous(ret)) {
+ ret->flags |= CONTIGUOUS;
+ if (ret->nd > 1) ret->flags &= ~FORTRAN;
+ }
+ else ret->flags &= ~CONTIGUOUS;
+ }
+ if (flagmask & ALIGNED) {
+ if (_IsAligned(ret)) ret->flags |= ALIGNED;
+ else ret->flags &= ~ALIGNED;
+ }
+ /* This is not checked by default WRITEABLE is not part of UPDATE_ALL_FLAGS */
+ if (flagmask & WRITEABLE) {
+ if (_IsWriteable(ret)) ret->flags |= WRITEABLE;
+ else ret->flags &= ~WRITEABLE;
+ }
+ return;
+}
+
+/* This routine checks to see if newstrides (of length nd) will not
+ walk outside of the memory implied by a single segment array of the provided
+ dimensions and element size. If numbytes is 0 it will be calculated from
+ the provided shape and element size.
+*/
+/*OBJECT_API*/
+static Bool
+PyArray_CheckStrides(int elsize, int nd, intp numbytes,
+ intp *dims, intp *newstrides)
+{
+ int i;
+
+ if (numbytes == 0)
+ numbytes = PyArray_MultiplyList(dims, nd) * elsize;
+
+ for (i=0; i<nd; i++) {
+ if (newstrides[i]*(dims[i]-1)+elsize > numbytes) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+
+}
+
+
+/* This is the main array creation routine. */
+
+/* Flags argument has multiple related meanings
+ depending on data and strides:
+
+ If data is given, then flags is flags associated with data.
+ If strides is not given, then a contiguous strides array will be created
+ and the CONTIGUOUS bit will be set. If the flags argument
+ has the FORTRAN bit set, then a FORTRAN-style strides array will be
+ created (and of course the FORTRAN flag bit will be set).
+
+ If data is not given but created here, then flags will be DEFAULT_FLAGS
+ and a non-zero flags argument can be used to indicate a FORTRAN style
+ array is desired.
+*/
+
+static intp
+_array_fill_strides(intp *strides, intp *dims, int nd, intp itemsize,
+ int inflag, int *objflags)
+{
+ int i;
+ /* Only make Fortran strides if not contiguous as well */
+ if ((inflag & FORTRAN) && !(inflag & CONTIGUOUS)) {
+ for (i=0; i<nd; i++) {
+ strides[i] = itemsize;
+ itemsize *= dims[i] ? dims[i] : 1;
+ }
+ *objflags |= FORTRAN;
+ if (nd > 1) *objflags &= ~CONTIGUOUS;
+ else *objflags |= CONTIGUOUS;
+ }
+ else {
+ for (i=nd-1;i>=0;i--) {
+ strides[i] = itemsize;
+ itemsize *= dims[i] ? dims[i] : 1;
+ }
+ *objflags |= CONTIGUOUS;
+ if (nd > 1) *objflags &= ~FORTRAN;
+ else *objflags |= FORTRAN;
+ }
+ return itemsize;
+}
+
+/*OBJECT_API
+ Generic new array creation routine.
+*/
+static PyObject *
+PyArray_New(PyTypeObject *subtype, int nd, intp *dims, int type_num,
+ intp *strides, void *data, int itemsize, int flags,
+ PyObject *obj)
+{
+ PyArray_Descr *descr;
+ PyObject *new;
+
+ descr = PyArray_DescrFromType(type_num);
+ if (descr == NULL) return NULL;
+ if (descr->elsize == 0) {
+ if (itemsize < 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "data type must provide an itemsize");
+ Py_DECREF(descr);
+ return NULL;
+ }
+ PyArray_DESCR_REPLACE(descr);
+ descr->elsize = itemsize;
+ }
+ new = PyArray_NewFromDescr(subtype, descr, nd, dims, strides,
+ data, flags, obj);
+ return new;
+}
+
+/* Change a sub-array field to the base descriptor */
+static int
+_update_descr_and_dimensions(PyArray_Descr **des, intp *newdims,
+ intp *newstrides, int oldnd)
+{
+ PyArray_Descr *old;
+ int newnd;
+ int numnew;
+ intp *mydim;
+ int i;
+
+ old = *des;
+ *des = old->subarray->base;
+
+ mydim = newdims + oldnd;
+ if (PyTuple_Check(old->subarray->shape)) {
+ numnew = PyTuple_GET_SIZE(old->subarray->shape);
+
+ for (i=0; i<numnew; i++) {
+ mydim[i] = (intp) PyInt_AsLong \
+ (PyTuple_GET_ITEM(old->subarray->shape, i));
+ }
+ }
+ else {
+ numnew = 1;
+ mydim[0] = (intp) PyInt_AsLong(old->subarray->shape);
+ }
+
+ newnd = oldnd + numnew;
+
+ if (newstrides) {
+ intp tempsize;
+ intp *mystrides;
+ mystrides = newstrides + oldnd;
+ /* Make new strides */
+ tempsize = (*des)->elsize;
+ for (i=numnew-1; i>=0; i--) {
+ mystrides[i] = tempsize;
+ tempsize *= mydim[i] ? mydim[i] : 1;
+ }
+ }
+ Py_INCREF(*des);
+ Py_DECREF(old);
+ return newnd;
+}
+
+
+/* steals a reference to descr (even on failure) */
+/*OBJECT_API
+ Generic new array creation routine.
+*/
+static PyObject *
+PyArray_NewFromDescr(PyTypeObject *subtype, PyArray_Descr *descr, int nd,
+ intp *dims, intp *strides, void *data,
+ int flags, PyObject *obj)
+{
+ PyArrayObject *self;
+ register int i;
+ intp sd;
+
+ if (descr->subarray) {
+ PyObject *ret;
+ intp newdims[2*MAX_DIMS];
+ intp *newstrides=NULL;
+ memcpy(newdims, dims, nd*sizeof(intp));
+ if (strides) {
+ newstrides = newdims + MAX_DIMS;
+ memcpy(newstrides, strides, nd*sizeof(intp));
+ }
+ nd =_update_descr_and_dimensions(&descr, newdims,
+ newstrides, nd);
+ ret = PyArray_NewFromDescr(subtype, descr, nd, newdims,
+ newstrides,
+ data, flags, obj);
+ return ret;
+ }
+
+ if (nd < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "number of dimensions must be >=0");
+ Py_DECREF(descr);
+ return NULL;
+ }
+ if (nd > MAX_DIMS) {
+ PyErr_Format(PyExc_ValueError,
+ "maximum number of dimensions is %d", MAX_DIMS);
+ Py_DECREF(descr);
+ return NULL;
+ }
+
+ /* Check dimensions */
+ for (i=nd-1;i>=0;i--) {
+ if (dims[i] < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "negative dimensions " \
+ "are not allowed");
+ Py_DECREF(descr);
+ return NULL;
+ }
+ }
+
+ self = (PyArrayObject *) subtype->tp_alloc(subtype, 0);
+ if (self == NULL) {
+ Py_DECREF(descr);
+ return NULL;
+ }
+ self->dimensions = NULL;
+ if (data == NULL) { /* strides is NULL too */
+ self->flags = DEFAULT_FLAGS;
+ if (flags) {
+ self->flags |= FORTRAN;
+ if (nd > 1) self->flags &= ~CONTIGUOUS;
+ flags = FORTRAN;
+ }
+ }
+ else self->flags = (flags & ~UPDATEIFCOPY);
+
+ sd = descr->elsize;
+
+ if (nd > 0) {
+ self->dimensions = PyDimMem_NEW(2*nd);
+ if (self->dimensions == NULL) {
+ PyErr_NoMemory();
+ goto fail;
+ }
+ self->strides = self->dimensions + nd;
+ memcpy(self->dimensions, dims, sizeof(intp)*nd);
+ if (strides == NULL) { /* fill it in */
+ sd = _array_fill_strides(self->strides, dims, nd, sd,
+ flags, &(self->flags));
+ }
+ else {
+ if (data == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "if 'strides' is given in " \
+ "array creation, data must " \
+ "be given too");
+ PyDimMem_FREE(self->dimensions);
+ self->ob_type->tp_free((PyObject *)self);
+ return NULL;
+ }
+ memcpy(self->strides, strides, sizeof(intp)*nd);
+ }
+ }
+
+ self->descr = descr;
+
+
+ if (data == NULL) {
+
+ /* Allocate something even for zero-space arrays
+ e.g. shape=(0,) -- otherwise buffer exposure
+ (a.data) doesn't work as it should. */
+
+ if (sd==0) sd = sizeof(intp);
+
+ if ((data = PyDataMem_NEW(sd))==NULL) {
+ PyErr_NoMemory();
+ goto fail;
+ }
+ self->flags |= OWN_DATA;
+
+ /* It is bad to have unitialized OBJECT pointers */
+ if (descr == &OBJECT_Descr) {
+ memset(data, 0, sd);
+ }
+ }
+ else {
+ self->flags &= ~OWN_DATA; /* If data is passed in,
+ this object won't own it
+ by default.
+ Caller must arrange for
+ this to be reset if truly
+ desired */
+ }
+ self->data = data;
+ self->nd = nd;
+ self->base = (PyObject *)NULL;
+ self->weakreflist = (PyObject *)NULL;
+
+ /* call the __array_finalize__
+ method if a subtype and some object passed in */
+ if ((obj != NULL) && (subtype != &PyArray_Type) &&
+ (subtype != &PyBigArray_Type)) {
+ PyObject *res;
+ if (!(self->flags & OWNDATA)) { /* did not allocate own data */
+ /* update flags before calling back into
+ Python */
+ PyArray_UpdateFlags(self, UPDATE_ALL_FLAGS);
+ }
+ res = PyObject_CallMethod((PyObject *)self,
+ "__array_finalize__",
+ "O", obj);
+ if (res == NULL) {
+ if (self->flags & OWNDATA) PyDataMem_FREE(self);
+ PyDimMem_FREE(self->dimensions);
+ /* theoretically should free self
+ but this causes segmentation faults...
+ Not sure why */
+ return NULL;
+ }
+ else Py_DECREF(res);
+ }
+
+ return (PyObject *)self;
+
+ fail:
+ Py_DECREF(descr);
+ PyDimMem_FREE(self->dimensions);
+ subtype->tp_free((PyObject *)self);
+ return NULL;
+
+}
+
+
+
+/*OBJECT_API
+ Resize (reallocate data). Only works if nothing else is referencing
+ this array and it is contiguous.
+*/
+static PyObject *
+PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape)
+{
+ intp oldsize, newsize;
+ int new_nd=newshape->len, k, n, elsize;
+ int refcnt;
+ intp* new_dimensions=newshape->ptr;
+ intp new_strides[MAX_DIMS];
+ intp sd;
+ intp *dimptr;
+ char *new_data;
+
+ if (!PyArray_ISCONTIGUOUS(self)) {
+ PyErr_SetString(PyExc_ValueError,
+ "resize only works on contiguous arrays");
+ return NULL;
+ }
+
+
+ newsize = PyArray_MultiplyList(new_dimensions, new_nd);
+
+ if (newsize == 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "newsize is zero; cannot delete an array "\
+ "in this way");
+ return NULL;
+ }
+ oldsize = PyArray_SIZE(self);
+
+ if (oldsize != newsize) {
+ if (!(self->flags & OWN_DATA)) {
+ PyErr_SetString(PyExc_ValueError,
+ "cannot resize this array: " \
+ "it does not own its data");
+ return NULL;
+ }
+
+ refcnt = REFCOUNT(self);
+ if ((refcnt > 2) || (self->base != NULL) || \
+ (self->weakreflist != NULL)) {
+ PyErr_SetString(PyExc_ValueError,
+ "cannot resize an array that has "\
+ "been referenced or is referencing\n"\
+ "another array in this way. Use the "\
+ "resize function");
+ return NULL;
+ }
+
+ /* Reallocate space if needed */
+ new_data = PyDataMem_RENEW(self->data,
+ newsize*(self->descr->elsize));
+ if (new_data == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "cannot allocate memory for array");
+ return NULL;
+ }
+ self->data = new_data;
+ }
+
+ if ((newsize > oldsize) && PyArray_ISWRITEABLE(self)) {
+ /* Fill new memory with zeros */
+ elsize = self->descr->elsize;
+ if ((PyArray_TYPE(self) == PyArray_OBJECT)) {
+ PyObject *zero = PyInt_FromLong(0);
+ PyObject **optr;
+ optr = ((PyObject **)self->data) + oldsize;
+ n = newsize - oldsize;
+ for (k=0; k<n; k++) {
+ Py_INCREF(zero);
+ *optr++ = zero;
+ }
+ Py_DECREF(zero);
+ }
+ else{
+ memset(self->data+oldsize*elsize, 0,
+ (newsize-oldsize)*elsize);
+ }
+ }
+
+ if (self->nd != new_nd) { /* Different number of dimensions. */
+ self->nd = new_nd;
+
+ /* Need new dimensions and strides arrays */
+ dimptr = PyDimMem_RENEW(self->dimensions, 2*new_nd);
+ if (dimptr == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "cannot allocate memory for array " \
+ "(array may be corrupted)");
+ return NULL;
+ }
+ self->dimensions = dimptr;
+ self->strides = dimptr + new_nd;
+ }
+
+ /* make new_strides variable */
+ sd = (intp) self->descr->elsize;
+ sd = _array_fill_strides(new_strides, new_dimensions, new_nd, sd,
+ 0, &(self->flags));
+
+
+ memmove(self->dimensions, new_dimensions, new_nd*sizeof(intp));
+ memmove(self->strides, new_strides, new_nd*sizeof(intp));
+
+ Py_INCREF(Py_None);
+ return Py_None;
+
+}
+
+
+/* Assumes contiguous */
+/*OBJECT_API*/
+static void
+PyArray_FillObjectArray(PyArrayObject *arr, PyObject *obj)
+{
+ PyObject **optr;
+ intp i,n;
+ optr = (PyObject **)(arr->data);
+ n = PyArray_SIZE(arr);
+ if (obj == NULL) {
+ for (i=0; i<n; i++) {
+ *optr++ = NULL;
+ }
+ }
+ else {
+ for (i=0; i<n; i++) {
+ Py_INCREF(obj);
+ *optr++ = obj;
+ }
+ }
+}
+
+/*OBJECT_API*/
+static int
+PyArray_FillWithScalar(PyArrayObject *arr, PyObject *obj)
+{
+ PyObject *newarr;
+ int itemsize, swap;
+ void *fromptr;
+ PyArray_Descr *descr;
+ intp size;
+ PyArray_CopySwapFunc *copyswap;
+
+ descr = PyArray_DESCR(arr);
+ itemsize = descr->elsize;
+ Py_INCREF(descr);
+ newarr = PyArray_FromAny(obj, descr, 0,0, ALIGNED);
+ if (newarr == NULL) return -1;
+ fromptr = PyArray_DATA(newarr);
+ size=PyArray_SIZE(arr);
+ swap=!PyArray_ISNOTSWAPPED(arr);
+ copyswap = arr->descr->f->copyswap;
+ if (PyArray_ISONESEGMENT(arr)) {
+ char *toptr=PyArray_DATA(arr);
+ while (size--) {
+ copyswap(toptr, fromptr, swap, itemsize);
+ toptr += itemsize;
+ }
+ }
+ else {
+ PyArrayIterObject *iter;
+
+ iter = (PyArrayIterObject *)\
+ PyArray_IterNew((PyObject *)arr);
+ if (iter == NULL) {
+ Py_DECREF(newarr);
+ return -1;
+ }
+ while(size--) {
+ copyswap(iter->dataptr, fromptr, swap, itemsize);
+ PyArray_ITER_NEXT(iter);
+ }
+ Py_DECREF(iter);
+ }
+ Py_DECREF(newarr);
+ return 0;
+}
+
+static PyObject *
+array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"shape", "dtype", "buffer",
+ "offset", "strides",
+ "fortran", NULL};
+ PyArray_Descr *descr=NULL;
+ int type_num;
+ int itemsize;
+ PyArray_Dims dims = {NULL, 0};
+ PyArray_Dims strides = {NULL, 0};
+ PyArray_Chunk buffer;
+ longlong offset=0;
+ int fortran = 0;
+ PyArrayObject *ret;
+
+ buffer.ptr = NULL;
+ /* Usually called with shape and type
+ but can also be called with buffer, strides, and swapped info
+ */
+
+ /* For now, let's just use this to create an empty, contiguous
+ array of a specific type and shape.
+ */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&LO&i",
+ kwlist, PyArray_IntpConverter,
+ &dims,
+ PyArray_DescrConverter,
+ &descr,
+ PyArray_BufferConverter,
+ &buffer,
+ &offset,
+ &PyArray_IntpConverter,
+ &strides,
+ &fortran))
+ goto fail;
+
+ type_num = descr->type_num;
+ itemsize = descr->elsize;
+
+ if (dims.ptr == NULL) {
+ PyErr_SetString(PyExc_ValueError, "need to give a "\
+ "valid shape as the first argument");
+ goto fail;
+ }
+ if (buffer.ptr == NULL) {
+ ret = (PyArrayObject *)\
+ PyArray_NewFromDescr(subtype, descr,
+ (int)dims.len,
+ dims.ptr,
+ NULL, NULL, fortran, NULL);
+ if (ret == NULL) {descr=NULL;goto fail;}
+ if (type_num == PyArray_OBJECT) { /* place Py_None */
+ PyArray_FillObjectArray(ret, Py_None);
+ }
+ }
+ else { /* buffer given -- use it */
+ buffer.len -= offset;
+ buffer.ptr += offset;
+ if (dims.len == 1 && dims.ptr[0] == -1) {
+ dims.ptr[0] = buffer.len / itemsize;
+ }
+ else if (buffer.len < itemsize* \
+ PyArray_MultiplyList(dims.ptr, dims.len)) {
+ PyErr_SetString(PyExc_TypeError,
+ "buffer is too small for " \
+ "requested array");
+ goto fail;
+ }
+ if (strides.ptr != NULL) {
+ if (strides.len != dims.len) {
+ PyErr_SetString(PyExc_ValueError,
+ "strides, if given, must be "\
+ "the same length as shape");
+ goto fail;
+ }
+ if (!PyArray_CheckStrides(itemsize, strides.len,
+ buffer.len,
+ dims.ptr, strides.ptr)) {
+ PyErr_SetString(PyExc_ValueError,
+ "strides is incompatible "\
+ "with shape of requested"\
+ "array and size of buffer");
+ goto fail;
+ }
+ }
+ if (type_num == PyArray_OBJECT) {
+ PyErr_SetString(PyExc_TypeError, "cannot construct "\
+ "an object array from buffer data");
+ goto fail;
+ }
+ /* get writeable and aligned */
+ if (fortran) buffer.flags |= FORTRAN;
+ ret = (PyArrayObject *)\
+ PyArray_NewFromDescr(subtype, descr,
+ dims.len, dims.ptr,
+ strides.ptr,
+ (char *)buffer.ptr,
+ buffer.flags, NULL);
+ if (ret == NULL) {descr=NULL; goto fail;}
+ PyArray_UpdateFlags(ret, UPDATE_ALL_FLAGS);
+ ret->base = buffer.base;
+ Py_INCREF(buffer.base);
+ }
+
+ PyDimMem_FREE(dims.ptr);
+ if (strides.ptr) PyDimMem_FREE(strides.ptr);
+ return (PyObject *)ret;
+
+ fail:
+ Py_XDECREF(descr);
+ if (dims.ptr) PyDimMem_FREE(dims.ptr);
+ if (strides.ptr) PyDimMem_FREE(strides.ptr);
+ return NULL;
+}
+
+
+static PyObject *
+array_iter(PyArrayObject *arr)
+{
+ if (arr->nd == 0) {
+ PyErr_SetString(PyExc_TypeError,
+ "iteration over a scalar (0-dim array)");
+ return NULL;
+ }
+ return PySeqIter_New((PyObject *)arr);
+}
+
+
+/******************* array attribute get and set routines ******************/
+
+static PyObject *
+array_ndim_get(PyArrayObject *self)
+{
+ return PyInt_FromLong(self->nd);
+}
+
+static PyObject *
+array_flags_get(PyArrayObject *self)
+{
+ return PyObject_CallMethod(_scipy_internal, "flagsobj", "Oii",
+ self, self->flags, 0);
+}
+
+static PyObject *
+array_shape_get(PyArrayObject *self)
+{
+ return PyArray_IntTupleFromIntp(self->nd, self->dimensions);
+}
+
+
+static int
+array_shape_set(PyArrayObject *self, PyObject *val)
+{
+ int nd;
+ PyObject *ret;
+
+ ret = PyArray_Reshape(self, val);
+ if (ret == NULL) return -1;
+
+ /* Free old dimensions and strides */
+ PyDimMem_FREE(self->dimensions);
+ nd = PyArray_NDIM(ret);
+ self->nd = nd;
+ if (nd > 0) { /* create new dimensions and strides */
+ self->dimensions = PyDimMem_NEW(2*nd);
+ if (self->dimensions == NULL) {
+ Py_DECREF(ret);
+ PyErr_SetString(PyExc_MemoryError,"");
+ return -1;
+ }
+ self->strides = self->dimensions + nd;
+ memcpy(self->dimensions, PyArray_DIMS(ret),
+ nd*sizeof(intp));
+ memcpy(self->strides, PyArray_STRIDES(ret),
+ nd*sizeof(intp));
+ }
+ else {self->dimensions=NULL; self->strides=NULL;}
+ Py_DECREF(ret);
+ PyArray_UpdateFlags(self, CONTIGUOUS | FORTRAN);
+ return 0;
+}
+
+
+static PyObject *
+array_strides_get(PyArrayObject *self)
+{
+ return PyArray_IntTupleFromIntp(self->nd, self->strides);
+}
+
+static int
+array_strides_set(PyArrayObject *self, PyObject *obj)
+{
+ PyArray_Dims newstrides = {NULL, 0};
+ PyArrayObject *new;
+ intp numbytes;
+
+ if (!PyArray_IntpConverter(obj, &newstrides) || \
+ newstrides.ptr == NULL) {
+ PyErr_SetString(PyExc_TypeError, "invalid strides");
+ return -1;
+ }
+ if (newstrides.len != self->nd) {
+ PyErr_Format(PyExc_ValueError, "strides must be " \
+ " same length as shape (%d)", self->nd);
+ goto fail;
+ }
+ new = self;
+ while(new->base != NULL) {
+ if (PyArray_Check(new->base))
+ new = (PyArrayObject *)new->base;
+ }
+ numbytes = PyArray_MultiplyList(new->dimensions,
+ new->nd)*new->descr->elsize;
+
+ if (!PyArray_CheckStrides(self->descr->elsize, self->nd, numbytes,
+ self->dimensions, newstrides.ptr)) {
+ PyErr_SetString(PyExc_ValueError, "strides is not "\
+ "compatible with available memory");
+ goto fail;
+ }
+ memcpy(self->strides, newstrides.ptr, sizeof(intp)*newstrides.len);
+ PyArray_UpdateFlags(self, CONTIGUOUS | FORTRAN);
+ PyDimMem_FREE(newstrides.ptr);
+ return 0;
+
+ fail:
+ PyDimMem_FREE(newstrides.ptr);
+ return -1;
+}
+
+
+static PyObject *
+array_protocol_strides_get(PyArrayObject *self)
+{
+ if PyArray_ISCONTIGUOUS(self) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return PyArray_IntTupleFromIntp(self->nd, self->strides);
+}
+
+static PyObject *
+array_priority_get(PyArrayObject *self)
+{
+ if (PyArray_CheckExact(self))
+ return PyFloat_FromDouble(PyArray_PRIORITY);
+ else if (PyBigArray_CheckExact(self))
+ return PyFloat_FromDouble(PyArray_BIG_PRIORITY);
+ else
+ return PyFloat_FromDouble(PyArray_SUBTYPE_PRIORITY);
+}
+
+
+static PyObject *
+array_dataptr_get(PyArrayObject *self)
+{
+ return Py_BuildValue("NO",
+ PyString_FromFormat("%p", self->data),
+ (self->flags & WRITEABLE ? Py_False :
+ Py_True));
+}
+
+static PyObject *
+array_data_get(PyArrayObject *self)
+{
+ intp nbytes;
+ if (!(PyArray_ISONESEGMENT(self))) {
+ PyErr_SetString(PyExc_AttributeError, "cannot get single-"\
+ "segment buffer for discontiguous array");
+ return NULL;
+ }
+ nbytes = PyArray_NBYTES(self);
+ if PyArray_ISWRITEABLE(self)
+ return PyBuffer_FromReadWriteObject((PyObject *)self, 0,
+ (int) nbytes);
+ else
+ return PyBuffer_FromObject((PyObject *)self, 0, (int) nbytes);
+}
+
+static int
+array_data_set(PyArrayObject *self, PyObject *op)
+{
+ void *buf;
+ int buf_len;
+ int writeable=1;
+
+ if (PyObject_AsWriteBuffer(op, &buf, &buf_len) < 0) {
+ writeable = 0;
+ if (PyObject_AsReadBuffer(op, (const void **)&buf,
+ &buf_len) < 0) {
+ PyErr_SetString(PyExc_AttributeError,
+ "object does not have single-segment " \
+ "buffer interface");
+ return -1;
+ }
+ }
+ if (!PyArray_ISONESEGMENT(self)) {
+ PyErr_SetString(PyExc_AttributeError, "cannot set single-" \
+ "segment buffer for discontiguous array");
+ return -1;
+ }
+ if (PyArray_NBYTES(self) > buf_len) {
+ PyErr_SetString(PyExc_AttributeError,
+ "not enough data for array");
+ return -1;
+ }
+ if (self->flags & OWN_DATA) {
+ PyArray_XDECREF(self);
+ PyDataMem_FREE(self->data);
+ }
+ if (self->base) {
+ if (self->flags & UPDATEIFCOPY) {
+ ((PyArrayObject *)self->base)->flags |= WRITEABLE;
+ self->flags &= ~UPDATEIFCOPY;
+ }
+ Py_DECREF(self->base);
+ }
+ Py_INCREF(op);
+ self->base = op;
+ self->data = buf;
+ self->flags = CARRAY_FLAGS;
+ if (!writeable)
+ self->flags &= ~WRITEABLE;
+ return 0;
+}
+
+
+static PyObject *
+array_itemsize_get(PyArrayObject *self)
+{
+ return PyInt_FromLong((long) self->descr->elsize);
+}
+
+static PyObject *
+array_size_get(PyArrayObject *self)
+{
+ intp size=PyArray_SIZE(self);
+#if SIZEOF_INTP <= SIZEOF_LONG
+ return PyInt_FromLong((long) size);
+#else
+ if (size > MAX_LONG || size < MIN_LONG)
+ return PyLong_FromLongLong(size);
+ else
+ return PyInt_FromLong((long) size);
+#endif
+}
+
+static PyObject *
+array_nbytes_get(PyArrayObject *self)
+{
+ intp nbytes = PyArray_NBYTES(self);
+#if SIZEOF_INTP <= SIZEOF_LONG
+ return PyInt_FromLong((long) nbytes);
+#else
+ if (nbytes > MAX_LONG || nbytes < MIN_LONG)
+ return PyLong_FromLongLong(nbytes);
+ else
+ return PyInt_FromLong((long) nbytes);
+#endif
+}
+
+
+static PyObject *
+array_typechar_get(PyArrayObject *self)
+{
+ if PyArray_ISEXTENDED(self)
+ return PyString_FromFormat("%c%d", (self->descr->type),
+ self->descr->elsize);
+ else
+ return PyString_FromStringAndSize(&(self->descr->type), 1);
+}
+
+static PyObject *arraydescr_protocol_typestr_get(PyArray_Descr *);
+
+static PyObject *
+array_typestr_get(PyArrayObject *self)
+{
+ return arraydescr_protocol_typestr_get(self->descr);
+}
+
+static PyObject *
+array_descr_get(PyArrayObject *self)
+{
+ Py_INCREF(self->descr);
+ return (PyObject *)self->descr;
+}
+
+
+/* If the type is changed.
+ Also needing change: strides, itemsize
+
+ Either itemsize is exactly the same
+ or the array is single-segment (contiguous or fortran) with
+ compatibile dimensions
+
+ The shape and strides will be adjusted in that case as well.
+*/
+
+static int
+array_descr_set(PyArrayObject *self, PyObject *arg)
+{
+ PyArray_Descr *newtype=NULL;
+ intp newdim;
+ int index;
+ char *msg = "new type not compatible with array.";
+
+ if (!(PyArray_DescrConverter(arg, &newtype)) ||
+ newtype == NULL) {
+ PyErr_SetString(PyExc_TypeError, "invalid type for array");
+ return -1;
+ }
+ if (newtype->type_num == PyArray_OBJECT || \
+ self->descr->type_num == PyArray_OBJECT) {
+ PyErr_SetString(PyExc_TypeError, \
+ "Cannot change descriptor for object"\
+ "array.");
+ Py_DECREF(newtype);
+ return -1;
+ }
+
+ if ((newtype->elsize != self->descr->elsize) && \
+ (self->nd == 0 || !PyArray_ISONESEGMENT(self) || \
+ newtype->subarray)) goto fail;
+
+ if (PyArray_ISCONTIGUOUS(self)) index = self->nd - 1;
+ else index = 0;
+
+ if (newtype->elsize < self->descr->elsize) {
+ /* if it is compatible increase the size of the
+ dimension at end (or at the front for FORTRAN)
+ */
+ if (self->descr->elsize % newtype->elsize != 0)
+ goto fail;
+ newdim = self->descr->elsize / newtype->elsize;
+ self->dimensions[index] *= newdim;
+ self->strides[index] = newtype->elsize;
+ }
+
+ else if (newtype->elsize > self->descr->elsize) {
+
+ /* Determine if last (or first if FORTRAN) dimension
+ is compatible */
+
+ newdim = self->dimensions[index] * self->descr->elsize;
+ if ((newdim % newtype->elsize) != 0) goto fail;
+
+ self->dimensions[index] = newdim / newtype->elsize;
+ self->strides[index] = newtype->elsize;
+ }
+
+ /* fall through -- adjust type*/
+
+ Py_DECREF(self->descr);
+ if (newtype->subarray) {
+ /* create new array object from data and update
+ dimensions, strides and descr from it */
+ PyArrayObject *temp;
+
+ temp = (PyArrayObject *)\
+ PyArray_NewFromDescr(&PyArray_Type, newtype, self->nd,
+ self->dimensions, self->strides,
+ self->data, self->flags, NULL);
+ PyDimMem_FREE(self->dimensions);
+ self->dimensions = temp->dimensions;
+ self->nd = temp->nd;
+ self->strides = temp->strides;
+ Py_DECREF(newtype);
+ newtype = temp->descr;
+ /* Fool deallocator */
+ temp->nd = 0;
+ temp->dimensions = NULL;
+ temp->descr = NULL;
+ Py_DECREF(temp);
+ }
+
+ self->descr = newtype;
+ PyArray_UpdateFlags(self, UPDATE_ALL_FLAGS);
+
+ return 0;
+
+ fail:
+ PyErr_SetString(PyExc_ValueError, msg);
+ Py_DECREF(newtype);
+ return -1;
+}
+
+static PyObject *
+array_protocol_descr_get(PyArrayObject *self)
+{
+ PyObject *res;
+ PyObject *dobj;
+
+ res = PyObject_GetAttrString((PyObject *)self->descr, "arrdescr");
+ if (res) return res;
+ PyErr_Clear();
+
+ /* get default */
+ dobj = PyTuple_New(2);
+ if (dobj == NULL) return NULL;
+ PyTuple_SET_ITEM(dobj, 0, PyString_FromString(""));
+ PyTuple_SET_ITEM(dobj, 1, array_typestr_get(self));
+ res = PyList_New(1);
+ if (res == NULL) {Py_DECREF(dobj); return NULL;}
+ PyList_SET_ITEM(res, 0, dobj);
+ return res;
+}
+
+static PyObject *
+array_struct_get(PyArrayObject *self)
+{
+ PyArrayInterface *inter;
+
+ inter = (PyArrayInterface *)_pya_malloc(sizeof(PyArrayInterface));
+ inter->version = 2;
+ inter->nd = self->nd;
+ inter->typekind = self->descr->kind;
+ inter->itemsize = self->descr->elsize;
+ inter->flags = self->flags;
+ /* reset unused flags */
+ inter->flags &= ~(UPDATEIFCOPY | OWNDATA);
+ if (PyArray_ISNOTSWAPPED(self)) inter->flags |= NOTSWAPPED;
+ inter->strides = self->strides;
+ inter->shape = self->dimensions;
+ inter->data = self->data;
+ Py_INCREF(self);
+ return PyCObject_FromVoidPtrAndDesc(inter, self, gentype_struct_free);
+}
+
+static PyObject *
+array_type_get(PyArrayObject *self)
+{
+ Py_INCREF(self->descr->typeobj);
+ return (PyObject *)self->descr->typeobj;
+}
+
+
+
+static PyObject *
+array_base_get(PyArrayObject *self)
+{
+ if (self->base == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ else {
+ Py_INCREF(self->base);
+ return self->base;
+ }
+}
+
+
+static PyObject *
+array_real_get(PyArrayObject *self)
+{
+ PyArrayObject *ret;
+
+ if (PyArray_ISCOMPLEX(self)) {
+ ret = (PyArrayObject *)PyArray_New(self->ob_type,
+ self->nd,
+ self->dimensions,
+ self->descr->type_num - \
+ PyArray_NUM_FLOATTYPE,
+ self->strides,
+ self->data,
+ 0,
+ self->flags, (PyObject *)self);
+ if (ret == NULL) return NULL;
+ ret->flags &= ~CONTIGUOUS;
+ ret->flags &= ~FORTRAN;
+ Py_INCREF(self);
+ ret->base = (PyObject *)self;
+ return (PyObject *)ret;
+ }
+ else {
+ Py_INCREF(self);
+ return (PyObject *)self;
+ }
+}
+
+
+static int
+array_real_set(PyArrayObject *self, PyObject *val)
+{
+ PyArrayObject *ret;
+ PyArrayObject *new;
+ int rint;
+
+ new = (PyArrayObject *)PyArray_FromAny(val, NULL, 0, 0, 0);
+ if (new == NULL) return -1;
+
+ if (PyArray_ISCOMPLEX(self)) {
+ ret = (PyArrayObject *)PyArray_New(self->ob_type,
+ self->nd,
+ self->dimensions,
+ self->descr->type_num - \
+ PyArray_NUM_FLOATTYPE,
+ self->strides,
+ self->data,
+ 0,
+ self->flags, (PyObject *)self);
+ if (ret == NULL) {Py_DECREF(new); return -1;}
+ ret->flags &= ~CONTIGUOUS;
+ ret->flags &= ~FORTRAN;
+ Py_INCREF(self);
+ ret->base = (PyObject *)self;
+ }
+ else {
+ Py_INCREF(self);
+ ret = self;
+ }
+ rint = PyArray_CopyInto(ret, new);
+ Py_DECREF(ret);
+ Py_DECREF(new);
+ return rint;
+}
+
+static PyObject *
+array_imag_get(PyArrayObject *self)
+{
+ PyArrayObject *ret;
+ PyArray_Descr *type;
+
+ if (PyArray_ISCOMPLEX(self)) {
+ type = PyArray_DescrFromType(self->descr->type_num -
+ PyArray_NUM_FLOATTYPE);
+ ret = (PyArrayObject *) \
+ PyArray_NewFromDescr(self->ob_type,
+ type,
+ self->nd,
+ self->dimensions,
+ self->strides,
+ self->data + type->elsize,
+ self->flags, (PyObject *)self);
+ if (ret == NULL) return NULL;
+ ret->flags &= ~CONTIGUOUS;
+ ret->flags &= ~FORTRAN;
+ Py_INCREF(self);
+ ret->base = (PyObject *)self;
+ return (PyObject *) ret;
+ }
+ else {
+ type = self->descr;
+ Py_INCREF(type);
+ ret = (PyArrayObject *)PyArray_Zeros(self->nd,
+ self->dimensions,
+ type,
+ PyArray_ISFORTRAN(self));
+ ret->flags &= ~WRITEABLE;
+ return (PyObject *)ret;
+ }
+}
+
+static int
+array_imag_set(PyArrayObject *self, PyObject *val)
+{
+ if (PyArray_ISCOMPLEX(self)) {
+ PyArrayObject *ret;
+ PyArrayObject *new;
+ int rint;
+
+ new = (PyArrayObject *)PyArray_FromAny(val, NULL, 0, 0, 0);
+ if (new == NULL) return -1;
+ ret = (PyArrayObject *)PyArray_New(self->ob_type,
+ self->nd,
+ self->dimensions,
+ self->descr->type_num - \
+ PyArray_NUM_FLOATTYPE,
+ self->strides,
+ self->data + \
+ (self->descr->elsize >> 1),
+ 0,
+ self->flags, (PyObject *)self);
+ if (ret == NULL) {
+ Py_DECREF(new);
+ return -1;
+ }
+ ret->flags &= ~CONTIGUOUS;
+ ret->flags &= ~FORTRAN;
+ Py_INCREF(self);
+ ret->base = (PyObject *)self;
+ rint = PyArray_CopyInto(ret, new);
+ Py_DECREF(ret);
+ Py_DECREF(new);
+ return rint;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "does not have imaginary " \
+ "part to set");
+ return -1;
+ }
+}
+
+static PyObject *
+array_flat_get(PyArrayObject *self)
+{
+ return PyArray_IterNew((PyObject *)self);
+}
+
+static int
+array_flat_set(PyArrayObject *self, PyObject *val)
+{
+ PyObject *arr=NULL;
+ int retval = -1;
+ PyArrayIterObject *selfit=NULL, *arrit=NULL;
+ PyArray_Descr *typecode;
+ int swap;
+ PyArray_CopySwapFunc *copyswap;
+
+ typecode = self->descr;
+ Py_INCREF(typecode);
+ arr = PyArray_FromAny(val, typecode,
+ 0, 0, FORCECAST | FORTRAN_IF(self));
+ if (arr == NULL) return -1;
+ arrit = (PyArrayIterObject *)PyArray_IterNew(arr);
+ if (arrit == NULL) goto exit;
+ selfit = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self);
+ if (selfit == NULL) goto exit;
+
+ swap = PyArray_ISNOTSWAPPED(self) != PyArray_ISNOTSWAPPED(arr);
+ copyswap = self->descr->f->copyswap;
+ if (PyArray_ISOBJECT(self)) {
+ while(selfit->index < selfit->size) {
+ Py_XDECREF(*((PyObject **)selfit->dataptr));
+ Py_INCREF(*((PyObject **)arrit->dataptr));
+ memmove(selfit->dataptr, arrit->dataptr,
+ sizeof(PyObject *));
+ PyArray_ITER_NEXT(selfit);
+ PyArray_ITER_NEXT(arrit);
+ if (arrit->index == arrit->size)
+ PyArray_ITER_RESET(arrit);
+ }
+ retval = 0;
+ goto exit;
+ }
+
+ while(selfit->index < selfit->size) {
+ memmove(selfit->dataptr, arrit->dataptr, self->descr->elsize);
+ copyswap(selfit->dataptr, NULL, swap, self->descr->elsize);
+ PyArray_ITER_NEXT(selfit);
+ PyArray_ITER_NEXT(arrit);
+ if (arrit->index == arrit->size)
+ PyArray_ITER_RESET(arrit);
+ }
+ retval = 0;
+ exit:
+ Py_XDECREF(selfit);
+ Py_XDECREF(arrit);
+ Py_XDECREF(arr);
+ return retval;
+}
+
+static PyGetSetDef array_getsetlist[] = {
+ {"ndim",
+ (getter)array_ndim_get,
+ NULL,
+ "number of array dimensions"},
+ {"flags",
+ (getter)array_flags_get,
+ NULL,
+ "special dictionary of flags"},
+ {"shape",
+ (getter)array_shape_get,
+ (setter)array_shape_set,
+ "tuple of array dimensions"},
+ {"strides",
+ (getter)array_strides_get,
+ (setter)array_strides_set,
+ "tuple of bytes steps in each dimension"},
+ {"data",
+ (getter)array_data_get,
+ (setter)array_data_set,
+ "pointer to start of data"},
+ {"itemsize",
+ (getter)array_itemsize_get,
+ NULL,
+ "length of one element in bytes"},
+ {"size",
+ (getter)array_size_get,
+ NULL,
+ "number of elements in the array"},
+ {"nbytes",
+ (getter)array_nbytes_get,
+ NULL,
+ "number of bytes in the array"},
+ {"base",
+ (getter)array_base_get,
+ NULL,
+ "base object"},
+ {"dtype",
+ (getter)array_type_get,
+ NULL,
+ "get array type class"},
+ {"dtypechar",
+ (getter)array_typechar_get,
+ NULL,
+ "get array type character code"},
+ {"dtypestr",
+ (getter)array_typestr_get,
+ NULL,
+ "get array type string"},
+ {"dtypedescr",
+ (getter)array_descr_get,
+ (setter)array_descr_set,
+ "get(set) data-type-descriptor for array"},
+ {"real",
+ (getter)array_real_get,
+ (setter)array_real_set,
+ "real part of array"},
+ {"imag",
+ (getter)array_imag_get,
+ (setter)array_imag_set,
+ "imaginary part of array"},
+ {"flat",
+ (getter)array_flat_get,
+ (setter)array_flat_set,
+ "a 1-d view of a contiguous array"},
+ {"__array_data__",
+ (getter)array_dataptr_get,
+ NULL,
+ "Array protocol: data"},
+ {"__array_typestr__",
+ (getter)array_typestr_get,
+ NULL,
+ "Array protocol: typestr"},
+ {"__array_descr__",
+ (getter)array_protocol_descr_get,
+ NULL,
+ "Array protocol: descr"},
+ {"__array_shape__",
+ (getter)array_shape_get,
+ NULL,
+ "Array protocol: shape"},
+ {"__array_strides__",
+ (getter)array_protocol_strides_get,
+ NULL,
+ "Array protocol: strides"},
+ {"__array_struct__",
+ (getter)array_struct_get,
+ NULL,
+ "Array protocol: struct"},
+ {"__array_priority__",
+ (getter)array_priority_get,
+ NULL,
+ "Array priority"},
+ {NULL, NULL, NULL, NULL}, /* Sentinel */
+};
+
+/****************** end of attribute get and set routines *******************/
+
+
+static PyObject *
+array_alloc(PyTypeObject *type, int nitems)
+{
+ PyObject *obj;
+ /* nitems will always be 0 */
+ obj = (PyObject *)_pya_malloc(sizeof(PyArrayObject));
+ PyObject_Init(obj, type);
+ return obj;
+}
+
+
+static char Arraytype__doc__[] =
+ "A array object represents a multidimensional, homogeneous array\n"
+ " of fixed-size items. An associated data-type-descriptor object\n"
+ " details the data-type in an array (including byteorder and any\n"
+ " fields). An array can be constructed using the scipy.array\n"
+ " command. Arrays are sequence, mapping and numeric objects.\n"
+ " More information is available in the scipy module and by looking\n"
+ " at the methods and attributes of an array.\n\n"
+ " ndarray.__new__(subtype, shape=, dtype=int_, buffer=None, \n"
+ " offset=0, strides=None, fortran=False)\n\n"
+ " There are two modes of creating an array using __new__:\n"
+ " 1) If buffer is None, then only shape, dtype, and fortran \n"
+ " are used\n"
+ " 2) If buffer is an object exporting the buffer interface, then\n"
+ " all keywords are interpreted.\n"
+ " The dtype parameter can be any object that can be interpreted \n"
+ " as a scipy.dtypedescr object.\n\n"
+ " No __init__ method is needed because the array is fully \n"
+ " initialized after the __new__ method.";
+
+static PyTypeObject PyBigArray_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "scipy.bigndarray", /*tp_name*/
+ sizeof(PyArrayObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)array_dealloc, /*tp_dealloc */
+ (printfunc)NULL, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ (cmpfunc)0, /*tp_compare*/
+ (reprfunc)array_repr, /*tp_repr*/
+ &array_as_number, /*tp_as_number*/
+ NULL, /*tp_as_sequence*/
+ &array_as_mapping, /*tp_as_mapping*/
+ (hashfunc)0, /*tp_hash*/
+ (ternaryfunc)0, /*tp_call*/
+ (reprfunc)array_str, /*tp_str*/
+
+ (getattrofunc)0, /*tp_getattro*/
+ (setattrofunc)0, /*tp_setattro*/
+ NULL, /*tp_as_buffer*/
+ (Py_TPFLAGS_DEFAULT
+ | Py_TPFLAGS_BASETYPE
+ | Py_TPFLAGS_CHECKTYPES), /*tp_flags*/
+ /*Documentation string */
+ Arraytype__doc__, /*tp_doc*/
+
+ (traverseproc)0, /*tp_traverse */
+ (inquiry)0, /*tp_clear */
+ (richcmpfunc)array_richcompare,
+ offsetof(PyArrayObject, weakreflist), /*tp_weaklistoffset */
+
+ /* Iterator support (use standard) */
+
+ (getiterfunc)array_iter, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+
+ /* Sub-classing (new-style object) support */
+
+ array_methods, /* tp_methods */
+ 0, /* tp_members */
+ array_getsetlist, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ array_alloc, /* tp_alloc */
+ (newfunc)array_new, /* tp_new */
+ _pya_free, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0 /* tp_weaklist */
+};
+
+/* A standard array will subclass from the Big Array and
+ add the array_as_sequence table
+ and the array_as_buffer table
+ */
+
+static PyTypeObject PyArray_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "scipy.ndarray", /*tp_name*/
+ sizeof(PyArrayObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+};
+
+
+/* The rest of this code is to build the right kind of array from a python */
+/* object. */
+
+static int
+discover_depth(PyObject *s, int max, int stop_at_string, int stop_at_tuple)
+{
+ int d=0;
+ PyObject *e;
+
+ if(max < 1) return -1;
+
+ if(! PySequence_Check(s) || PyInstance_Check(s) || \
+ PySequence_Length(s) < 0) {
+ PyErr_Clear(); return 0;
+ }
+ if (PyArray_Check(s))
+ return PyArray_NDIM(s);
+ if(PyString_Check(s) || PyBuffer_Check(s) || PyUnicode_Check(s))
+ return stop_at_string ? 0:1;
+ if (stop_at_tuple && PyTuple_Check(s)) return 0;
+ if ((e=PyObject_GetAttrString(s, "__array_shape__")) != NULL) {
+ if (PyTuple_Check(e)) d=PyTuple_GET_SIZE(e);
+ else d=-1;
+ Py_DECREF(e);
+ if (d>-1) return d;
+ }
+ else PyErr_Clear();
+
+ if (PySequence_Length(s) == 0)
+ return 1;
+ if ((e=PySequence_GetItem(s,0)) == NULL) return -1;
+ if(e!=s) {
+ d=discover_depth(e, max-1, stop_at_string, stop_at_tuple);
+ if(d >= 0) d++;
+ }
+ Py_DECREF(e);
+ return d;
+}
+
+static int
+discover_itemsize(PyObject *s, int nd, int *itemsize)
+{
+ int n, r, i;
+ PyObject *e;
+
+ n = PyObject_Length(s);
+
+ if ((nd == 0) || PyString_Check(s) || \
+ PyUnicode_Check(s) || PyBuffer_Check(s)) {
+ if PyUnicode_Check(s)
+ *itemsize = MAX(*itemsize, sizeof(Py_UNICODE)*n);
+ else
+ *itemsize = MAX(*itemsize, n);
+ return 0;
+ }
+ for (i=0; i<n; i++) {
+ if ((e=PySequence_GetItem(s,i))==NULL) return -1;
+ r=discover_itemsize(e,nd-1,itemsize);
+ Py_DECREF(e);
+ if (r == -1) return -1;
+ }
+ return 0;
+}
+
+/* Take an arbitrary object known to represent
+ an array of ndim nd, and determine the size in each dimension
+*/
+
+static int
+discover_dimensions(PyObject *s, int nd, intp *d, int check_it)
+{
+ PyObject *e;
+ int r, n, i, n_lower;
+
+ n=PyObject_Length(s);
+ *d = n;
+ if(*d < 0) return -1;
+ if(nd <= 1) return 0;
+ n_lower = 0;
+ for(i=0; i<n; i++) {
+ if ((e=PySequence_GetItem(s,i)) == NULL) return -1;
+ r=discover_dimensions(e,nd-1,d+1,check_it);
+ Py_DECREF(e);
+
+ if (r == -1) return -1;
+ if (check_it && n_lower != 0 && n_lower != d[1]) {
+ PyErr_SetString(PyExc_ValueError,
+ "inconsistent shape in sequence");
+ return -1;
+ }
+ if (d[1] > n_lower) n_lower = d[1];
+ }
+ d[1] = n_lower;
+
+ return 0;
+}
+
+/* new reference */
+/* doesn't alter refcount of chktype or mintype ---
+ unless one of them is returned */
+static PyArray_Descr *
+_array_small_type(PyArray_Descr *chktype, PyArray_Descr* mintype)
+{
+ PyArray_Descr *outtype;
+
+ if (chktype->type_num > mintype->type_num) outtype = chktype;
+ else outtype = mintype;
+
+ Py_INCREF(outtype);
+ if (PyTypeNum_ISEXTENDED(outtype->type_num) && \
+ (PyTypeNum_ISEXTENDED(mintype->type_num) || \
+ mintype->type_num==0)) {
+ int testsize = outtype->elsize;
+ register int chksize, minsize;
+ chksize = chktype->elsize;
+ minsize = mintype->elsize;
+ /* Handle string->unicode case separately
+ because string itemsize is twice as large */
+ if (outtype->type_num == PyArray_UNICODE &&
+ mintype->type_num == PyArray_STRING) {
+ testsize = MAX(chksize, 2*minsize);
+ }
+ else {
+ testsize = MAX(chksize, minsize);
+ }
+ if (testsize != outtype->elsize) {
+ PyArray_DESCR_REPLACE(outtype);
+ outtype->elsize = testsize;
+ Py_XDECREF(outtype->fields);
+ outtype->fields = NULL;
+ }
+ }
+ return outtype;
+}
+
+/* op is an object to be converted to an ndarray.
+
+ minitype is the minimum type-descriptor needed.
+
+ max is the maximum number of dimensions -- used for recursive call
+ to avoid infinite recursion...
+
+*/
+
+static PyArray_Descr *
+_array_find_type(PyObject *op, PyArray_Descr *minitype, int max)
+{
+ int l;
+ PyObject *ip;
+ PyArray_Descr *chktype=NULL;
+ PyArray_Descr *outtype;
+
+ if (minitype == NULL)
+ minitype = PyArray_DescrFromType(PyArray_BOOL);
+ else Py_INCREF(minitype);
+
+ if (max < 0) goto deflt;
+
+ if (PyArray_Check(op)) {
+ chktype = PyArray_DESCR(op);
+ Py_INCREF(chktype);
+ goto finish;
+ }
+
+ if (PyArray_IsScalar(op, Generic)) {
+ chktype = PyArray_DescrFromScalar(op);
+ goto finish;
+ }
+
+ if ((ip=PyObject_GetAttrString(op, "__array_typestr__"))!=NULL) {
+ if (PyString_Check(ip)) {
+ chktype =_array_typedescr_fromstr(PyString_AS_STRING(ip));
+ }
+ Py_DECREF(ip);
+ if (chktype) goto finish;
+ }
+ else PyErr_Clear();
+
+ if ((ip=PyObject_GetAttrString(op, "__array_struct__")) != NULL) {
+ PyArrayInterface *inter;
+ char buf[40];
+ if (PyCObject_Check(ip)) {
+ inter=(PyArrayInterface *)PyCObject_AsVoidPtr(ip);
+ if (inter->version == 2) {
+ snprintf(buf, 40, "|%c%d", inter->typekind,
+ inter->itemsize);
+ chktype = _array_typedescr_fromstr(buf);
+ }
+ }
+ Py_DECREF(ip);
+ if (chktype) goto finish;
+ }
+ else PyErr_Clear();
+
+ if (PyString_Check(op)) {
+ chktype = PyArray_DescrNewFromType(PyArray_STRING);
+ chktype->elsize = PyString_GET_SIZE(op);
+ goto finish;
+ }
+
+ if (PyUnicode_Check(op)) {
+ chktype = PyArray_DescrNewFromType(PyArray_UNICODE);
+ chktype->elsize = PyUnicode_GET_DATA_SIZE(op);
+ goto finish;
+ }
+
+ if (PyBuffer_Check(op)) {
+ chktype = PyArray_DescrNewFromType(PyArray_VOID);
+ chktype->elsize = op->ob_type->tp_as_sequence->sq_length(op);
+ PyErr_Clear();
+ goto finish;
+ }
+
+ if (PyObject_HasAttrString(op, "__array__")) {
+ ip = PyObject_CallMethod(op, "__array__", NULL);
+ if(ip && PyArray_Check(ip)) {
+ chktype = PyArray_DESCR(ip);
+ Py_INCREF(chktype);
+ Py_DECREF(ip);
+ goto finish;
+ }
+ Py_XDECREF(ip);
+ if (PyErr_Occurred()) PyErr_Clear();
+ }
+
+ if (PyInstance_Check(op)) goto deflt;
+
+ if (PySequence_Check(op)) {
+
+ l = PyObject_Length(op);
+ if (l < 0 && PyErr_Occurred()) {
+ PyErr_Clear();
+ goto deflt;
+ }
+ if (l == 0 && minitype->type_num == PyArray_BOOL) {
+ Py_DECREF(minitype);
+ minitype = PyArray_DescrFromType(PyArray_INTP);
+ }
+ while (--l >= 0) {
+ PyArray_Descr *newtype;
+ ip = PySequence_GetItem(op, l);
+ if (ip==NULL) {
+ PyErr_Clear();
+ goto deflt;
+ }
+ chktype = _array_find_type(ip, minitype, max-1);
+ newtype = _array_small_type(chktype, minitype);
+ Py_DECREF(minitype);
+ minitype = newtype;
+ Py_DECREF(chktype);
+ Py_DECREF(ip);
+ }
+ chktype = minitype;
+ Py_INCREF(minitype);
+ goto finish;
+ }
+
+ if (PyBool_Check(op)) {
+ chktype = PyArray_DescrFromType(PyArray_BOOL);
+ goto finish;
+ }
+ else if (PyInt_Check(op)) {
+ chktype = PyArray_DescrFromType(PyArray_LONG);
+ goto finish;
+ } else if (PyFloat_Check(op)) {
+ chktype = PyArray_DescrFromType(PyArray_DOUBLE);
+ goto finish;
+ } else if (PyComplex_Check(op)) {
+ chktype = PyArray_DescrFromType(PyArray_CDOUBLE);
+ goto finish;
+ }
+
+ deflt:
+ chktype = PyArray_DescrFromType(PyArray_OBJECT);
+
+ finish:
+
+ outtype = _array_small_type(chktype, minitype);
+ Py_DECREF(chktype);
+ Py_DECREF(minitype);
+ return outtype;
+}
+
+static int
+Assign_Array(PyArrayObject *self, PyObject *v)
+{
+ PyObject *e;
+ int l, r;
+
+ if (!PySequence_Check(v)) {
+ PyErr_SetString(PyExc_ValueError,
+ "assignment from non-sequence");
+ return -1;
+ }
+
+ l=PyObject_Length(v);
+ if(l < 0) return -1;
+
+ while(--l >= 0)
+ {
+ e=PySequence_GetItem(v,l);
+ if (e == NULL) return -1;
+ r = PySequence_SetItem((PyObject*)self,l,e);
+ Py_DECREF(e);
+ if(r == -1) return -1;
+ }
+ return 0;
+}
+
+/* "Array Scalars don't call this code" */
+/* steals reference to typecode -- no NULL*/
+static PyObject *
+Array_FromScalar(PyObject *op, PyArray_Descr *typecode)
+{
+ PyArrayObject *ret;
+ int itemsize;
+ int type;
+
+ itemsize = typecode->elsize;
+ type = typecode->type_num;
+
+ if (itemsize == 0 && PyTypeNum_ISEXTENDED(type)) {
+ itemsize = PyObject_Length(op);
+ if (type == PyArray_UNICODE) itemsize *= sizeof(Py_UNICODE);
+ }
+
+ ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, typecode,
+ 0, NULL,
+ NULL, NULL, 0, NULL);
+
+ if (ret == NULL) return NULL;
+
+ ret->descr->f->setitem(op, ret->data, ret);
+
+ if (PyErr_Occurred()) {
+ Py_DECREF(ret);
+ return NULL;
+ } else {
+ return (PyObject *)ret;
+ }
+}
+
+
+/* steals reference to typecode unless return value is NULL*/
+static PyObject *
+Array_FromSequence(PyObject *s, PyArray_Descr *typecode, int fortran,
+ int min_depth, int max_depth)
+{
+ PyArrayObject *r;
+ int nd;
+ intp d[MAX_DIMS];
+ int stop_at_string;
+ int stop_at_tuple;
+ int type = typecode->type_num;
+ int itemsize = typecode->elsize;
+ PyArray_Descr *savetype=typecode;
+
+ stop_at_string = ((type == PyArray_OBJECT) || \
+ (type == PyArray_STRING) || \
+ (type == PyArray_UNICODE) || \
+ (type == PyArray_VOID));
+
+ stop_at_tuple = (type == PyArray_VOID && ((typecode->fields && \
+ typecode->fields!=Py_None) \
+ || (typecode->subarray)));
+
+ if (!((nd=discover_depth(s, MAX_DIMS+1, stop_at_string,
+ stop_at_tuple)) > 0)) {
+ if (nd==0)
+ return Array_FromScalar(s, typecode);
+ PyErr_SetString(PyExc_ValueError,
+ "invalid input sequence");
+ return NULL;
+ }
+
+ if ((max_depth && nd > max_depth) || \
+ (min_depth && nd < min_depth)) {
+ PyErr_SetString(PyExc_ValueError,
+ "invalid number of dimensions");
+ return NULL;
+ }
+
+ if(discover_dimensions(s,nd,d, !stop_at_string) == -1) {
+ return NULL;
+ }
+ if (itemsize == 0 && PyTypeNum_ISEXTENDED(type)) {
+ if (discover_itemsize(s, nd, &itemsize) == -1) {
+ return NULL;
+ }
+ if (type == PyArray_UNICODE) itemsize*=sizeof(Py_UNICODE);
+ }
+
+ if (itemsize != typecode->elsize) {
+ PyArray_DESCR_REPLACE(typecode);
+ typecode->elsize = itemsize;
+ }
+
+ r=(PyArrayObject*)PyArray_NewFromDescr(&PyArray_Type, typecode,
+ nd, d,
+ NULL, NULL,
+ fortran, NULL);
+
+ if(!r) {Py_XINCREF(savetype); return NULL;}
+ if(Assign_Array(r,s) == -1) {
+ Py_XINCREF(savetype);
+ Py_DECREF(r);
+ return NULL;
+ }
+ return (PyObject*)r;
+}
+
+
+/*OBJECT_API
+ Is the typenum valid?
+*/
+static int
+PyArray_ValidType(int type)
+{
+ PyArray_Descr *descr;
+ int res=TRUE;
+
+ descr = PyArray_DescrFromType(type);
+ if (descr==NULL) res = FALSE;
+ Py_DECREF(descr);
+ return res;
+}
+
+
+/* If the output is not a CARRAY, then it is buffered also */
+
+static int
+_bufferedcast(PyArrayObject *out, PyArrayObject *in)
+{
+ char *inbuffer, *bptr, *optr;
+ char *outbuffer=NULL;
+ PyArrayIterObject *it_in=NULL, *it_out=NULL;
+ register intp i, index;
+ intp ncopies = PyArray_SIZE(out) / PyArray_SIZE(in);
+ int elsize=in->descr->elsize;
+ int nels = PyArray_BUFSIZE;
+ int el;
+ int inswap, outswap=0;
+ int obuf=!PyArray_ISCARRAY(out);
+ int oelsize = out->descr->elsize;
+ PyArray_VectorUnaryFunc *castfunc;
+ PyArray_CopySwapFunc *in_csn;
+ PyArray_CopySwapFunc *out_csn;
+ int retval = -1;
+
+ castfunc = in->descr->f->cast[out->descr->type_num];
+ in_csn = in->descr->f->copyswap;
+ out_csn = out->descr->f->copyswap;
+
+ /* If the input or output is STRING, UNICODE, or VOID */
+ /* then getitem and setitem are used for the cast */
+ /* and byteswapping is handled by those methods */
+
+ inswap = !(PyArray_ISFLEXIBLE(in) || PyArray_ISNOTSWAPPED(in));
+
+ inbuffer = PyDataMem_NEW(PyArray_BUFSIZE*elsize);
+ if (inbuffer == NULL) return -1;
+ if (PyArray_ISOBJECT(in))
+ memset(inbuffer, 0, PyArray_BUFSIZE*elsize);
+ it_in = (PyArrayIterObject *)PyArray_IterNew((PyObject *)in);
+ if (it_in == NULL) goto exit;
+
+ if (obuf) {
+ outswap = !(PyArray_ISFLEXIBLE(out) || \
+ PyArray_ISNOTSWAPPED(out));
+ outbuffer = PyDataMem_NEW(PyArray_BUFSIZE*oelsize);
+ if (outbuffer == NULL) goto exit;
+ if (PyArray_ISOBJECT(out))
+ memset(outbuffer, 0, PyArray_BUFSIZE*oelsize);
+
+ it_out = (PyArrayIterObject *)PyArray_IterNew((PyObject *)out);
+ if (it_out == NULL) goto exit;
+
+ nels = MIN(nels, PyArray_BUFSIZE);
+ }
+
+ optr = (obuf) ? outbuffer: out->data;
+ bptr = inbuffer;
+ el = 0;
+ while(ncopies--) {
+ index = it_in->size;
+ PyArray_ITER_RESET(it_in);
+ while(index--) {
+ in_csn(bptr, it_in->dataptr, inswap, elsize);
+ bptr += elsize;
+ PyArray_ITER_NEXT(it_in);
+ el += 1;
+ if ((el == nels) || (index == 0)) {
+ /* buffer filled, do cast */
+
+ castfunc(inbuffer, optr, el, in, out);
+
+ if (obuf) {
+ /* Copy from outbuffer to array */
+ for(i=0; i<el; i++) {
+ out_csn(it_out->dataptr,
+ optr, outswap,
+ oelsize);
+ optr += oelsize;
+ PyArray_ITER_NEXT(it_out);
+ }
+ optr = outbuffer;
+ }
+ else {
+ optr += out->descr->elsize * nels;
+ }
+ el = 0;
+ bptr = inbuffer;
+ }
+ }
+ }
+ retval = 0;
+ exit:
+ Py_XDECREF(it_in);
+ PyDataMem_FREE(inbuffer);
+ PyDataMem_FREE(outbuffer);
+ if (obuf) {
+ Py_XDECREF(it_out);
+ }
+ return retval;
+}
+
+
+/* For backward compatibility */
+
+/* steals reference to at --- cannot be NULL*/
+/*OBJECT_API
+ Cast an array using typecode structure.
+*/
+static PyObject *
+PyArray_CastToType(PyArrayObject *mp, PyArray_Descr *at, int fortran)
+{
+ PyObject *out;
+ int ret;
+ PyArray_Descr *mpd;
+
+ mpd = mp->descr;
+
+ if (((mpd == at) || ((mpd->type_num == at->type_num) && \
+ PyArray_EquivByteorders(mpd->byteorder,\
+ at->byteorder) && \
+ ((mpd->elsize == at->elsize) || \
+ (at->elsize==0)))) && \
+ PyArray_ISBEHAVED_RO(mp)) {
+ Py_DECREF(at);
+ Py_INCREF(mp);
+ return (PyObject *)mp;
+ }
+
+ if (at->elsize == 0) {
+ PyArray_DESCR_REPLACE(at);
+ if (at == NULL) return NULL;
+ if (mpd->type_num == PyArray_STRING && \
+ at->type_num == PyArray_UNICODE)
+ at->elsize = mpd->elsize*sizeof(Py_UNICODE);
+ if (mpd->type_num == PyArray_UNICODE &&
+ at->type_num == PyArray_STRING)
+ at->elsize = mpd->elsize/sizeof(Py_UNICODE);
+ if (at->type_num == PyArray_VOID)
+ at->elsize = mpd->elsize;
+ }
+
+ out = PyArray_NewFromDescr(mp->ob_type, at,
+ mp->nd,
+ mp->dimensions,
+ NULL, NULL,
+ fortran,
+ (PyObject *)mp);
+
+ if (out == NULL) return NULL;
+ ret = PyArray_CastTo((PyArrayObject *)out, mp);
+ if (ret != -1) return out;
+
+ Py_DECREF(out);
+ return NULL;
+
+}
+
+/* The number of elements in out must be an integer multiple
+ of the number of elements in mp.
+*/
+
+/*OBJECT_API
+ Cast to an already created array.
+*/
+static int
+PyArray_CastTo(PyArrayObject *out, PyArrayObject *mp)
+{
+
+ int simple;
+ intp mpsize = PyArray_SIZE(mp);
+ intp outsize = PyArray_SIZE(out);
+
+ if (mpsize == 0) return 0;
+ if (!PyArray_ISWRITEABLE(out)) {
+ PyErr_SetString(PyExc_ValueError,
+ "output array is not writeable");
+ return -1;
+ }
+ if (outsize % mpsize != 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "output array must have an integer-multiple"\
+ " of the number of elements in the input "\
+ "array");
+ return -1;
+ }
+
+ if (out->descr->type_num >= PyArray_NTYPES) {
+ PyErr_SetString(PyExc_ValueError,
+ "Can only cast to builtin types.");
+ return -1;
+
+ }
+
+ simple = ((PyArray_ISCARRAY_RO(mp) && PyArray_ISCARRAY(out)) || \
+ (PyArray_ISFARRAY_RO(mp) && PyArray_ISFARRAY(out)));
+
+ if (simple) {
+ char *inptr;
+ char *optr = out->data;
+ intp obytes = out->descr->elsize * outsize;
+ intp ncopies = outsize / mpsize;
+
+ while(ncopies--) {
+ inptr = mp->data;
+ mp->descr->f->cast[out->descr->type_num](inptr,
+ optr,
+ mpsize,
+ mp, out);
+ optr += obytes;
+ }
+ return 0;
+ }
+
+ /* If not a well-behaved cast, then use buffers */
+ if (_bufferedcast(out, mp) == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+/* steals reference to newtype --- acc. NULL */
+static PyObject *
+array_fromarray(PyArrayObject *arr, PyArray_Descr *newtype, int flags)
+{
+
+ PyArrayObject *ret=NULL;
+ int type, itemsize;
+ int copy = 0;
+ int arrflags;
+ PyArray_Descr *oldtype;
+ char *msg = "cannot copy back to a read-only array";
+ PyTypeObject *subtype;
+
+ oldtype = PyArray_DESCR(arr);
+
+ subtype = arr->ob_type;
+
+ if (newtype == NULL) {newtype = oldtype; Py_INCREF(oldtype);}
+ type = newtype->type_num;
+ itemsize = newtype->elsize;
+
+ /* Don't copy if sizes are compatible */
+ if (PyArray_EquivTypes(oldtype, newtype)) {
+ arrflags = arr->flags;
+
+ copy = (flags & ENSURECOPY) || \
+ ((flags & CONTIGUOUS) && (!(arrflags & CONTIGUOUS))) \
+ || ((flags & ALIGNED) && (!(arrflags & ALIGNED))) \
+ || (arr->nd > 1 && \
+ ((flags & FORTRAN) != (arrflags & FORTRAN))) || \
+ ((flags & WRITEABLE) && (!(arrflags & WRITEABLE)));
+
+ if (copy) {
+ if ((flags & UPDATEIFCOPY) && \
+ (!PyArray_ISWRITEABLE(arr))) {
+ Py_DECREF(newtype);
+ PyErr_SetString(PyExc_ValueError, msg);
+ return NULL;
+ }
+ if ((flags & ENSUREARRAY) && \
+ (subtype != &PyBigArray_Type)) {
+ subtype = &PyArray_Type;
+ }
+ ret = (PyArrayObject *) \
+ PyArray_NewFromDescr(subtype, newtype,
+ arr->nd,
+ arr->dimensions,
+ NULL, NULL,
+ flags & FORTRAN,
+ (PyObject *)arr);
+ if (ret == NULL) return NULL;
+ if (PyArray_CopyInto(ret, arr) == -1)
+ {Py_DECREF(ret); return NULL;}
+ if (flags & UPDATEIFCOPY) {
+ ret->flags |= UPDATEIFCOPY;
+ ret->base = (PyObject *)arr;
+ PyArray_FLAGS(ret->base) &= ~WRITEABLE;
+ Py_INCREF(arr);
+ }
+ }
+ /* If no copy then just increase the reference
+ count and return the input */
+ else {
+ if ((flags & ENSUREARRAY) && \
+ (subtype != &PyBigArray_Type)) {
+ Py_DECREF(newtype);
+ Py_INCREF(arr->descr);
+ ret = (PyArrayObject *) \
+ PyArray_NewFromDescr(&PyArray_Type,
+ arr->descr,
+ arr->nd,
+ arr->dimensions,
+ arr->strides,
+ arr->data,
+ arr->flags,NULL);
+ if (ret == NULL) return NULL;
+ ret->base = (PyObject *)arr;
+ }
+ else {
+ ret = arr;
+ }
+ Py_INCREF(arr);
+ }
+ }
+
+ /* The desired output type is different than the input
+ array type */
+ else {
+ /* Cast to the desired type if we can do it safely
+ Also cast if source is a ndim-0 array to mimic
+ behavior with Python scalars */
+ if (flags & FORCECAST || PyArray_NDIM(arr)==0 ||
+ PyArray_CanCastTo(oldtype, newtype)) {
+ if ((flags & UPDATEIFCOPY) && \
+ (!PyArray_ISWRITEABLE(arr))) {
+ Py_DECREF(newtype);
+ PyErr_SetString(PyExc_ValueError, msg);
+ return NULL;
+ }
+ if ((flags & ENSUREARRAY) && \
+ (subtype != &PyBigArray_Type)) {
+ subtype = &PyArray_Type;
+ }
+ ret = (PyArrayObject *)\
+ PyArray_NewFromDescr(subtype,
+ newtype,
+ arr->nd,
+ arr->dimensions,
+ NULL, NULL,
+ flags & FORTRAN,
+ (PyObject *)arr);
+ if (ret == NULL) return NULL;
+ if (PyArray_CastTo(ret, arr) < 0) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+ if (flags & UPDATEIFCOPY) {
+ ret->flags |= UPDATEIFCOPY;
+ ret->base = (PyObject *)arr;
+ PyArray_FLAGS(ret->base) &= ~WRITEABLE;
+ Py_INCREF(arr);
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "array cannot be safely cast " \
+ "to required type");
+ ret = NULL;
+ }
+ }
+ return (PyObject *)ret;
+}
+
+/* new reference */
+static PyArray_Descr *
+_array_typedescr_fromstr(char *str)
+{
+ PyArray_Descr *descr;
+ int type_num;
+ char typechar;
+ int size;
+ char msg[] = "unsupported typestring";
+ int swap;
+ char swapchar;
+
+ swapchar = str[0];
+ str += 1;
+
+#define _MY_FAIL { \
+ PyErr_SetString(PyExc_ValueError, msg); \
+ return NULL; \
+ }
+
+ typechar = str[0];
+ size = atoi(str + 1);
+ switch (typechar) {
+ case 'b':
+ if (size == sizeof(Bool))
+ type_num = PyArray_BOOL;
+ else _MY_FAIL
+ break;
+ case 'u':
+ if (size == sizeof(uintp))
+ type_num = PyArray_UINTP;
+ else if (size == sizeof(char))
+ type_num = PyArray_UBYTE;
+ else if (size == sizeof(short))
+ type_num = PyArray_USHORT;
+ else if (size == sizeof(ulong))
+ type_num = PyArray_ULONG;
+ else if (size == sizeof(int))
+ type_num = PyArray_UINT;
+ else if (size == sizeof(ulonglong))
+ type_num = PyArray_ULONGLONG;
+ else _MY_FAIL
+ break;
+ case 'i':
+ if (size == sizeof(intp))
+ type_num = PyArray_INTP;
+ else if (size == sizeof(char))
+ type_num = PyArray_BYTE;
+ else if (size == sizeof(short))
+ type_num = PyArray_SHORT;
+ else if (size == sizeof(long))
+ type_num = PyArray_LONG;
+ else if (size == sizeof(int))
+ type_num = PyArray_INT;
+ else if (size == sizeof(longlong))
+ type_num = PyArray_LONGLONG;
+ else _MY_FAIL
+ break;
+ case 'f':
+ if (size == sizeof(float))
+ type_num = PyArray_FLOAT;
+ else if (size == sizeof(double))
+ type_num = PyArray_DOUBLE;
+ else if (size == sizeof(longdouble))
+ type_num = PyArray_LONGDOUBLE;
+ else _MY_FAIL
+ break;
+ case 'c':
+ if (size == sizeof(float)*2)
+ type_num = PyArray_CFLOAT;
+ else if (size == sizeof(double)*2)
+ type_num = PyArray_CDOUBLE;
+ else if (size == sizeof(longdouble)*2)
+ type_num = PyArray_CLONGDOUBLE;
+ else _MY_FAIL
+ break;
+ case 'O':
+ if (size == sizeof(PyObject *))
+ type_num = PyArray_OBJECT;
+ else _MY_FAIL
+ break;
+ case 'S':
+ type_num = PyArray_STRING;
+ break;
+ case 'U':
+ type_num = PyArray_UNICODE;
+ size *= sizeof(Py_UNICODE);
+ break;
+ case 'V':
+ type_num = PyArray_VOID;
+ break;
+ default:
+ _MY_FAIL
+ }
+
+#undef _MY_FAIL
+
+ descr = PyArray_DescrFromType(type_num);
+ if (descr == NULL) return NULL;
+ swap = !PyArray_ISNBO(swapchar);
+ if (descr->elsize == 0 || swap) {
+ /* Need to make a new PyArray_Descr */
+ PyArray_DESCR_REPLACE(descr);
+ if (descr==NULL) return NULL;
+ if (descr->elsize == 0)
+ descr->elsize = size;
+ if (swap)
+ descr->byteorder = swapchar;
+ }
+ return descr;
+}
+
+/* steals a reference to intype unless NotImplemented */
+static PyObject *
+array_fromstructinterface(PyObject *input, PyArray_Descr *intype, int flags)
+{
+ PyArray_Descr *thetype;
+ char buf[40];
+ PyArrayInterface *inter;
+ PyObject *attr, *r, *ret;
+ char endian = PyArray_NATBYTE;
+
+ attr = PyObject_GetAttrString(input, "__array_struct__");
+ if (attr == NULL) {
+ PyErr_Clear();
+ return Py_NotImplemented;
+ }
+ if (!PyCObject_Check(attr) || \
+ ((inter=((PyArrayInterface *)\
+ PyCObject_AsVoidPtr(attr)))->version != 2)) {
+ PyErr_SetString(PyExc_ValueError, "invalid __array_struct__");
+ Py_XDECREF(intype);
+ Py_DECREF(attr);
+ return NULL;
+ }
+ if ((inter->flags & NOTSWAPPED) != NOTSWAPPED) {
+ endian = PyArray_OPPBYTE;
+ inter->flags &= ~NOTSWAPPED;
+ }
+
+ snprintf(buf, 40, "%c%c%d", endian, inter->typekind, inter->itemsize);
+ if (!(thetype=_array_typedescr_fromstr(buf))) {
+ Py_XDECREF(intype);
+ Py_DECREF(attr);
+ return NULL;
+ }
+
+ r = PyArray_NewFromDescr(&PyArray_Type, thetype,
+ inter->nd, inter->shape,
+ inter->strides, inter->data,
+ inter->flags, NULL);
+ Py_INCREF(input);
+ PyArray_BASE(r) = input;
+ Py_DECREF(attr);
+ PyArray_UpdateFlags((PyArrayObject *)r, UPDATE_ALL_FLAGS);
+ ret = array_fromarray((PyArrayObject*)r, intype, flags);
+ Py_DECREF(r);
+ return ret;
+}
+
+/* steals a reference to intype unless NotImplemented */
+static PyObject *
+array_frominterface(PyObject *input, PyArray_Descr *intype, int flags)
+{
+ PyObject *attr=NULL, *item=NULL, *r;
+ PyObject *tstr=NULL, *shape=NULL;
+ PyArrayObject *ret=NULL;
+ PyArray_Descr *type=NULL;
+ char *data;
+ int buffer_len;
+ int res, i, n;
+ intp dims[MAX_DIMS], strides[MAX_DIMS];
+ int dataflags = BEHAVED_FLAGS;
+
+ /* Get the memory from __array_data__ and __array_offset__ */
+ /* Get the shape */
+ /* Get the typestring -- ignore array_descr */
+ /* Get the strides */
+
+ shape = PyObject_GetAttrString(input, "__array_shape__");
+ if (shape == NULL) {PyErr_Clear(); return Py_NotImplemented;}
+ tstr = PyObject_GetAttrString(input, "__array_typestr__");
+ if (tstr == NULL) {Py_DECREF(shape); PyErr_Clear(); return Py_NotImplemented;}
+
+ attr = PyObject_GetAttrString(input, "__array_data__");
+ if ((attr == NULL) || (attr==Py_None) || (!PyTuple_Check(attr))) {
+ if (attr && (attr != Py_None)) item=attr;
+ else item=input;
+ res = PyObject_AsWriteBuffer(item, (void **)&data,
+ &buffer_len);
+ if (res < 0) {
+ PyErr_Clear();
+ res = PyObject_AsReadBuffer(item, (const void **)&data,
+ &buffer_len);
+ if (res < 0) goto fail;
+ dataflags &= ~WRITEABLE;
+ }
+ Py_XDECREF(attr);
+ attr = PyObject_GetAttrString(input, "__array_offset__");
+ if (attr) {
+ long num = PyInt_AsLong(attr);
+ if (error_converting(num)) {
+ PyErr_SetString(PyExc_TypeError,
+ "__array_offset__ "\
+ "must be an integer");
+ goto fail;
+ }
+ data += num;
+ }
+ else PyErr_Clear();
+ }
+ else {
+ if (PyTuple_GET_SIZE(attr) != 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "__array_data__ must return " \
+ "a 2-tuple with ('data pointer "\
+ "string', read-only flag)");
+ goto fail;
+ }
+ res = sscanf(PyString_AsString(PyTuple_GET_ITEM(attr,0)),
+ "%p", (void **)&data);
+ if (res < 1) {
+ PyErr_SetString(PyExc_TypeError,
+ "__array_data__ string cannot be " \
+ "converted");
+ goto fail;
+ }
+ if (PyObject_IsTrue(PyTuple_GET_ITEM(attr,1))) {
+ dataflags &= ~WRITEABLE;
+ }
+ }
+ Py_XDECREF(attr);
+ attr = tstr;
+ if (!PyString_Check(attr)) {
+ PyErr_SetString(PyExc_TypeError, "__array_typestr__ must be a string");
+ Py_INCREF(attr); /* decref'd twice below */
+ goto fail;
+ }
+ type = _array_typedescr_fromstr(PyString_AS_STRING(attr));
+ Py_DECREF(attr); attr=NULL; tstr=NULL;
+ if (type==NULL) goto fail;
+ attr = shape;
+ if (!PyTuple_Check(attr)) {
+ PyErr_SetString(PyExc_TypeError, "__array_shape__ must be a tuple");
+ Py_INCREF(attr); /* decref'd twice below */
+ Py_DECREF(type);
+ goto fail;
+ }
+ n = PyTuple_GET_SIZE(attr);
+ for (i=0; i<n; i++) {
+ item = PyTuple_GET_ITEM(attr, i);
+ dims[i] = PyArray_PyIntAsIntp(item);
+ if (error_converting(dims[i])) break;
+ }
+ Py_DECREF(attr); shape=NULL;
+
+ ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, type,
+ n, dims,
+ NULL, data,
+ dataflags, NULL);
+ if (ret == NULL) {Py_XDECREF(intype); return NULL;}
+ Py_INCREF(input);
+ ret->base = input;
+
+ attr = PyObject_GetAttrString(input, "__array_strides__");
+ if (attr != NULL && attr != Py_None) {
+ if (!PyTuple_Check(attr)) {
+ PyErr_SetString(PyExc_TypeError,
+ "__array_strides__ must be a tuple");
+ Py_DECREF(attr);
+ Py_DECREF(ret);
+ Py_XDECREF(intype);
+ return NULL;
+ }
+ if (n != PyTuple_GET_SIZE(attr)) {
+ PyErr_SetString(PyExc_ValueError,
+ "mismatch in length of "\
+ "__array_strides__ and "\
+ "__array_shape__");
+ Py_DECREF(attr);
+ Py_DECREF(ret);
+ Py_XDECREF(intype);
+ return NULL;
+ }
+ for (i=0; i<n; i++) {
+ item = PyTuple_GET_ITEM(attr, i);
+ strides[i] = PyArray_PyIntAsIntp(item);
+ if (error_converting(strides[i])) break;
+ }
+ Py_DECREF(attr);
+ if (PyErr_Occurred()) PyErr_Clear();
+ memcpy(ret->strides, strides, n*sizeof(intp));
+ }
+ else PyErr_Clear();
+ PyArray_UpdateFlags(ret, UPDATE_ALL_FLAGS);
+ r = array_fromarray(ret, intype, flags);
+ Py_DECREF(ret);
+ return r;
+
+ fail:
+ Py_XDECREF(intype);
+ Py_XDECREF(attr);
+ Py_XDECREF(shape);
+ Py_XDECREF(tstr);
+ return NULL;
+}
+
+/* steals a reference to typecode */
+static PyObject *
+array_fromattr(PyObject *op, PyArray_Descr *typecode, int flags)
+{
+ PyObject *new, *r;
+
+ if (typecode == NULL) {
+ new = PyObject_CallMethod(op, "__array__", NULL);
+ } else {
+ PyObject *obj;
+
+ if (PyTypeNum_ISEXTENDED(typecode->type_num)) {
+ obj = PyString_FromFormat("%c%d", typecode->type,
+ typecode->elsize);
+ }
+ else {
+ obj = (PyObject *)(typecode->typeobj); Py_INCREF(obj);
+ }
+ new = PyObject_CallMethod(op, "__array__", "N", obj);
+ }
+ if (new == NULL) {Py_XDECREF(typecode); return NULL;}
+ if (!PyArray_Check(new)) {
+ PyErr_SetString(PyExc_ValueError,
+ "object __array__ method not " \
+ "producing an array");
+ Py_DECREF(new);
+ Py_DECREF(typecode);
+ return NULL;
+ }
+ r = array_fromarray((PyArrayObject *)new, typecode, flags);
+ Py_DECREF(new);
+ return r;
+}
+
+/* Steals a reference to newtype --- which can be NULL */
+static PyObject *
+array_fromobject(PyObject *op, PyArray_Descr *newtype, int min_depth,
+ int max_depth, int flags)
+{
+ /* This is the main code to make a SciPy array from a Python
+ Object. It is called from lot's of different places which
+ is why there are so many checks. The comments try to
+ explain some of the checks. */
+
+ PyObject *r=NULL;
+ int seq = FALSE;
+
+ /* Is input object already an array? */
+ /* This is where the flags are used */
+ if (PyArray_Check(op))
+ r = array_fromarray((PyArrayObject *)op, newtype, flags);
+ else if (PyArray_IsScalar(op, Generic)) {
+ r = PyArray_FromScalar(op, newtype);
+ }
+ else if ((r = array_fromstructinterface(op, newtype, flags)) != \
+ Py_NotImplemented) {
+ }
+ else if ((r = array_frominterface(op, newtype, flags)) != \
+ Py_NotImplemented) {
+ }
+ else if (PyObject_HasAttrString(op, "__array__")) {
+ /* Code that returns the object to convert for a non
+ multiarray input object from the __array__ attribute of the
+ object. */
+ r = array_fromattr(op, newtype, flags);
+ }
+ else {
+ if (newtype == NULL) {
+ newtype = _array_find_type(op, NULL, MAX_DIMS);
+ }
+ if (PySequence_Check(op)) {
+ /* necessary but not sufficient */
+
+ r = Array_FromSequence(op, newtype, flags & FORTRAN,
+ min_depth, max_depth);
+ if (PyErr_Occurred() && r == NULL)
+ /* It wasn't really a sequence after all.
+ * Try interpreting it as a scalar */
+ PyErr_Clear();
+ else
+ seq = TRUE;
+ }
+ if (!seq)
+ r = Array_FromScalar(op, newtype);
+ }
+
+ /* If we didn't succeed return NULL */
+ if (r == NULL) return NULL;
+
+ /* Be sure we succeed here */
+
+ if(!PyArray_Check(r)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "internal error: array_fromobject "\
+ "not producing an array");
+ Py_DECREF(r);
+ return NULL;
+ }
+
+ if (min_depth != 0 && ((PyArrayObject *)r)->nd < min_depth) {
+ PyErr_SetString(PyExc_ValueError,
+ "object of too small depth for desired array");
+ Py_DECREF(r);
+ return NULL;
+ }
+ if (max_depth != 0 && ((PyArrayObject *)r)->nd > max_depth) {
+ PyErr_SetString(PyExc_ValueError,
+ "object too deep for desired array");
+ Py_DECREF(r);
+ return NULL;
+ }
+ return r;
+}
+
+/* new reference -- accepts NULL for mintype*/
+/*OBJECT_API*/
+static PyArray_Descr *
+PyArray_DescrFromObject(PyObject *op, PyArray_Descr *mintype)
+{
+ return _array_find_type(op, mintype, MAX_DIMS);
+}
+
+/*OBJECT_API
+ Return the typecode of the array a Python object would be converted
+ to
+*/
+static int
+PyArray_ObjectType(PyObject *op, int minimum_type)
+{
+ PyArray_Descr *intype;
+ PyArray_Descr *outtype;
+ int ret;
+
+ intype = PyArray_DescrFromType(minimum_type);
+ if (intype == NULL) PyErr_Clear();
+ outtype = _array_find_type(op, intype, MAX_DIMS);
+ ret = outtype->type_num;
+ Py_DECREF(outtype);
+ Py_DECREF(intype);
+ return ret;
+}
+
+
+/* flags is any of
+ CONTIGUOUS,
+ FORTRAN,
+ ALIGNED,
+ WRITEABLE,
+ NOTSWAPPED,
+ ENSURECOPY,
+ UPDATEIFCOPY,
+ FORCECAST,
+ ENSUREARRAY
+
+ or'd (|) together
+
+ Any of these flags present means that the returned array should
+ guarantee that aspect of the array. Otherwise the returned array
+ won't guarantee it -- it will depend on the object as to whether or
+ not it has such features.
+
+ Note that ENSURECOPY is enough
+ to guarantee CONTIGUOUS, ALIGNED and WRITEABLE
+ and therefore it is redundant to include those as well.
+
+ BEHAVED_FLAGS == ALIGNED | WRITEABLE
+ CARRAY_FLAGS = CONTIGUOUS | BEHAVED_FLAGS
+ FARRAY_FLAGS = FORTRAN | BEHAVED_FLAGS
+
+ FORTRAN can be set in the FLAGS to request a FORTRAN array.
+ Fortran arrays are always behaved (aligned,
+ notswapped, and writeable) and not (C) CONTIGUOUS (if > 1d).
+
+ UPDATEIFCOPY flag sets this flag in the returned array if a copy is
+ made and the base argument points to the (possibly) misbehaved array.
+ When the new array is deallocated, the original array held in base
+ is updated with the contents of the new array.
+
+ FORCECAST will cause a cast to occur regardless of whether or not
+ it is safe.
+*/
+
+
+/* steals a reference to descr -- accepts NULL */
+/*OBJECT_API*/
+static PyObject *
+PyArray_FromAny(PyObject *op, PyArray_Descr *descr, int min_depth,
+ int max_depth, int requires)
+{
+ if (requires & ENSURECOPY) {
+ requires |= DEFAULT_FLAGS;
+ }
+ if (requires & NOTSWAPPED) {
+ if (!descr && PyArray_Check(op) && \
+ !PyArray_ISNBO(PyArray_DESCR(op)->byteorder)) {
+ descr = PyArray_DescrNew(PyArray_DESCR(op));
+ }
+ else if ((descr && !PyArray_ISNBO(descr->byteorder))) {
+ PyArray_DESCR_REPLACE(descr);
+ }
+ descr->byteorder = PyArray_NATIVE;
+ }
+
+ return array_fromobject(op, descr, min_depth, max_depth,
+ requires);
+}
+
+/* This is a quick wrapper around PyArray_FromAny(op, NULL, 0, 0,
+ ENSUREARRAY) */
+/* that special cases Arrays and PyArray_Scalars up front */
+/* It *steals a reference* to the object */
+/* It also guarantees that the result is PyArray_Type or PyBigArray_Type */
+
+/* Because it decrefs op if any conversion needs to take place
+ so it can be used like PyArray_EnsureArray(some_function(...)) */
+
+/*OBJECT_API*/
+static PyObject *
+PyArray_EnsureArray(PyObject *op)
+{
+ PyObject *new;
+
+ if (op == NULL) return NULL;
+
+ if (PyArray_CheckExact(op) || PyBigArray_CheckExact(op)) return op;
+
+ if (PyArray_IsScalar(op, Generic)) {
+ new = PyArray_FromScalar(op, NULL);
+ Py_DECREF(op);
+ return new;
+ }
+ new = PyArray_FROM_OF(op, ENSUREARRAY);
+ Py_DECREF(op);
+ return new;
+}
+
+
+
+/*OBJECT_API
+ Check the type coercion rules.
+*/
+static int
+PyArray_CanCastSafely(int fromtype, int totype)
+{
+ PyArray_Descr *from, *to;
+ register int felsize, telsize;
+
+ if (fromtype == totype) return 1;
+ if (fromtype == PyArray_BOOL) return 1;
+ if (totype == PyArray_BOOL) return 0;
+ if (totype == PyArray_OBJECT || totype == PyArray_VOID) return 1;
+ if (fromtype == PyArray_OBJECT || fromtype == PyArray_VOID) return 0;
+
+ from = PyArray_DescrFromType(fromtype);
+ to = PyArray_DescrFromType(totype);
+ telsize = to->elsize;
+ felsize = from->elsize;
+ Py_DECREF(from);
+ Py_DECREF(to);
+
+ switch(fromtype) {
+ case PyArray_BYTE:
+ case PyArray_SHORT:
+ case PyArray_INT:
+ case PyArray_LONG:
+ case PyArray_LONGLONG:
+ if (PyTypeNum_ISINTEGER(totype)) {
+ if (PyTypeNum_ISUNSIGNED(totype)) {
+ return (telsize > felsize);
+ }
+ else {
+ return (telsize >= felsize);
+ }
+ }
+ else if (PyTypeNum_ISFLOAT(totype)) {
+ if (felsize < 8)
+ return (telsize > felsize);
+ else
+ return (telsize >= felsize);
+ }
+ else if (PyTypeNum_ISCOMPLEX(totype)) {
+ if (felsize < 8)
+ return ((telsize >> 1) > felsize);
+ else
+ return ((telsize >> 1) >= felsize);
+ }
+ else return totype > fromtype;
+ case PyArray_UBYTE:
+ case PyArray_USHORT:
+ case PyArray_UINT:
+ case PyArray_ULONG:
+ case PyArray_ULONGLONG:
+ if (PyTypeNum_ISINTEGER(totype)) {
+ if (PyTypeNum_ISSIGNED(totype)) {
+ return (telsize > felsize);
+ }
+ else {
+ return (telsize >= felsize);
+ }
+ }
+ else if (PyTypeNum_ISFLOAT(totype)) {
+ if (felsize < 8)
+ return (telsize > felsize);
+ else
+ return (telsize >= felsize);
+ }
+ else if (PyTypeNum_ISCOMPLEX(totype)) {
+ if (felsize < 8)
+ return ((telsize >> 1) > felsize);
+ else
+ return ((telsize >> 1) >= felsize);
+ }
+ else return totype > fromtype;
+ case PyArray_FLOAT:
+ case PyArray_DOUBLE:
+ case PyArray_LONGDOUBLE:
+ if (PyTypeNum_ISCOMPLEX(totype))
+ return ((telsize >> 1) >= felsize);
+ else
+ return (totype > fromtype);
+ case PyArray_CFLOAT:
+ case PyArray_CDOUBLE:
+ case PyArray_CLONGDOUBLE:
+ return (totype > fromtype);
+ case PyArray_STRING:
+ case PyArray_UNICODE:
+ return (totype > fromtype);
+ default:
+ return 0;
+ }
+}
+
+/* leaves reference count alone --- cannot be NULL*/
+/*OBJECT_API*/
+static Bool
+PyArray_CanCastTo(PyArray_Descr *from, PyArray_Descr *to)
+{
+ int fromtype=from->type_num;
+ int totype=to->type_num;
+ Bool ret;
+
+ ret = (Bool) PyArray_CanCastSafely(fromtype, totype);
+ if (ret) { /* Check String and Unicode more closely */
+ if (fromtype == PyArray_STRING) {
+ if (totype == PyArray_STRING) {
+ ret = (from->elsize <= to->elsize);
+ }
+ else if (totype == PyArray_UNICODE) {
+ ret = (from->elsize * sizeof(Py_UNICODE)\
+ <= to->elsize);
+ }
+ }
+ else if (fromtype == PyArray_UNICODE) {
+ if (totype == PyArray_UNICODE) {
+ ret = (from->elsize <= to->elsize);
+ }
+ }
+ /* TODO: If totype is STRING or unicode
+ see if the length is long enough to hold the
+ stringified value of the object.
+ */
+ }
+ return ret;
+}
+
+
+
+/*********************** Element-wise Array Iterator ***********************/
+/* Aided by Peter J. Verveer's nd_image package and scipy's arraymap ****/
+/* and Python's array iterator ***/
+
+
+/*OBJECT_API
+ Get Iterator.
+*/
+static PyObject *
+PyArray_IterNew(PyObject *obj)
+{
+ PyArrayIterObject *it;
+ int i, nd;
+ PyArrayObject *ao = (PyArrayObject *)obj;
+
+ if (!PyArray_Check(ao)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ it = (PyArrayIterObject *)_pya_malloc(sizeof(PyArrayIterObject));
+ PyObject_Init((PyObject *)it, &PyArrayIter_Type);
+ /* it = PyObject_New(PyArrayIterObject, &PyArrayIter_Type);*/
+ if (it == NULL)
+ return NULL;
+
+ nd = ao->nd;
+ PyArray_UpdateFlags(ao, CONTIGUOUS);
+ it->contiguous = 0;
+ if PyArray_ISCONTIGUOUS(ao) it->contiguous = 1;
+ Py_INCREF(ao);
+ it->ao = ao;
+ it->size = PyArray_SIZE(ao);
+ it->nd_m1 = nd - 1;
+ it->factors[nd-1] = 1;
+ for (i=0; i < nd; i++) {
+ it->dims_m1[i] = it->ao->dimensions[i] - 1;
+ it->strides[i] = it->ao->strides[i];
+ it->backstrides[i] = it->strides[i] * \
+ it->dims_m1[i];
+ if (i > 0)
+ it->factors[nd-i-1] = it->factors[nd-i] * \
+ it->ao->dimensions[nd-i];
+ }
+ PyArray_ITER_RESET(it);
+
+ return (PyObject *)it;
+}
+
+
+/*OBJECT_API
+ Get Iterator that iterates over all but one axis (don't use this with
+ PyArray_ITER_GOTO1D)
+*/
+static PyObject *
+PyArray_IterAllButAxis(PyObject *obj, int axis)
+{
+ PyArrayIterObject *it;
+ it = (PyArrayIterObject *)PyArray_IterNew(obj);
+ if (it == NULL) return NULL;
+
+ /* adjust so that will not iterate over axis */
+ it->contiguous = 0;
+ if (it->size != 0) {
+ it->size /= PyArray_DIM(obj,axis);
+ }
+ it->dims_m1[axis] = 0;
+ it->backstrides[axis] = 0;
+
+ /* (won't fix factors so don't use
+ PyArray_ITER_GOTO1D with this iterator) */
+ return (PyObject *)it;
+}
+
+/* Returns an array scalar holding the element desired */
+
+static PyObject *
+arrayiter_next(PyArrayIterObject *it)
+{
+ PyObject *ret;
+
+ if (it->index < it->size) {
+ ret = PyArray_ToScalar(it->dataptr, it->ao);
+ PyArray_ITER_NEXT(it);
+ return ret;
+ }
+ return NULL;
+}
+
+static void
+arrayiter_dealloc(PyArrayIterObject *it)
+{
+ Py_XDECREF(it->ao);
+ _pya_free(it);
+}
+
+static int
+iter_length(PyArrayIterObject *self)
+{
+ return (int) self->size;
+}
+
+
+static PyObject *
+iter_subscript_Bool(PyArrayIterObject *self, PyArrayObject *ind)
+{
+ int index, strides, itemsize;
+ intp count=0;
+ char *dptr, *optr;
+ PyObject *r;
+ int swap;
+ PyArray_CopySwapFunc *copyswap;
+
+
+ if (ind->nd != 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "boolean index array should have 1 dimension");
+ return NULL;
+ }
+ index = (ind->dimensions[0]);
+ strides = ind->strides[0];
+ dptr = ind->data;
+ /* Get size of return array */
+ while(index--) {
+ if (*((Bool *)dptr) != 0)
+ count++;
+ dptr += strides;
+ }
+ itemsize = self->ao->descr->elsize;
+ Py_INCREF(self->ao->descr);
+ r = PyArray_NewFromDescr(self->ao->ob_type,
+ self->ao->descr, 1, &count,
+ NULL, NULL,
+ 0, (PyObject *)self->ao);
+ if (r==NULL) return NULL;
+
+ /* Set up loop */
+ optr = PyArray_DATA(r);
+ index = ind->dimensions[0];
+ dptr = ind->data;
+
+ copyswap = self->ao->descr->f->copyswap;
+ /* Loop over Boolean array */
+ swap = !(PyArray_ISNOTSWAPPED(self->ao));
+ while(index--) {
+ if (*((Bool *)dptr) != 0) {
+ copyswap(optr, self->dataptr, swap, itemsize);
+ optr += itemsize;
+ }
+ dptr += strides;
+ PyArray_ITER_NEXT(self);
+ }
+ PyArray_ITER_RESET(self);
+ return r;
+}
+
+static PyObject *
+iter_subscript_int(PyArrayIterObject *self, PyArrayObject *ind)
+{
+ intp num;
+ PyObject *r;
+ PyArrayIterObject *ind_it;
+ int itemsize;
+ int swap;
+ char *optr;
+ int index;
+ PyArray_CopySwapFunc *copyswap;
+
+ itemsize = self->ao->descr->elsize;
+ if (ind->nd == 0) {
+ num = *((intp *)ind->data);
+ PyArray_ITER_GOTO1D(self, num);
+ r = PyArray_ToScalar(self->dataptr, self->ao);
+ PyArray_ITER_RESET(self);
+ return r;
+ }
+
+ Py_INCREF(self->ao->descr);
+ r = PyArray_NewFromDescr(self->ao->ob_type, self->ao->descr,
+ ind->nd, ind->dimensions,
+ NULL, NULL,
+ 0, (PyObject *)self->ao);
+ if (r==NULL) return NULL;
+
+ optr = PyArray_DATA(r);
+ ind_it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)ind);
+ if (ind_it == NULL) {Py_DECREF(r); return NULL;}
+ index = ind_it->size;
+ copyswap = PyArray_DESCR(r)->f->copyswap;
+ swap = !PyArray_ISNOTSWAPPED(self->ao);
+ while(index--) {
+ num = *((intp *)(ind_it->dataptr));
+ if (num < 0) num += self->size;
+ if (num < 0 || num >= self->size) {
+ PyErr_Format(PyExc_IndexError,
+ "index %d out of bounds" \
+ " 0<=index<%d", (int) num,
+ (int) self->size);
+ Py_DECREF(ind_it);
+ Py_DECREF(r);
+ PyArray_ITER_RESET(self);
+ return NULL;
+ }
+ PyArray_ITER_GOTO1D(self, num);
+ copyswap(optr, self->dataptr, swap, itemsize);
+ optr += itemsize;
+ PyArray_ITER_NEXT(ind_it);
+ }
+ Py_DECREF(ind_it);
+ PyArray_ITER_RESET(self);
+ return r;
+}
+
+
+static PyObject *
+iter_subscript(PyArrayIterObject *self, PyObject *ind)
+{
+ PyArray_Descr *indtype=NULL;
+ intp start, step_size;
+ intp n_steps;
+ PyObject *r;
+ char *dptr;
+ int size;
+ PyObject *obj = NULL;
+ int swap;
+ PyArray_CopySwapFunc *copyswap;
+
+ if (ind == Py_Ellipsis) {
+ ind = PySlice_New(NULL, NULL, NULL);
+ obj = iter_subscript(self, ind);
+ Py_DECREF(ind);
+ return obj;
+ }
+ if (PyTuple_Check(ind)) {
+ int len;
+ len = PyTuple_GET_SIZE(ind);
+ if (len > 1) goto fail;
+ ind = PyTuple_GET_ITEM(ind, 0);
+ }
+
+ /* Tuples >1d not accepted --- i.e. no NewAxis */
+ /* Could implement this with adjusted strides
+ and dimensions in iterator */
+
+ /* Check for Boolean -- this is first becasue
+ Bool is a subclass of Int */
+ PyArray_ITER_RESET(self);
+
+ if (PyBool_Check(ind)) {
+ if (PyObject_IsTrue(ind)) {
+ return PyArray_ToScalar(self->dataptr, self->ao);
+ }
+ else { /* empty array */
+ intp ii = 0;
+ Py_INCREF(self->ao->descr);
+ r = PyArray_NewFromDescr(self->ao->ob_type,
+ self->ao->descr,
+ 1, &ii,
+ NULL, NULL, 0,
+ (PyObject *)self->ao);
+ return r;
+ }
+ }
+
+ /* Check for Integer or Slice */
+
+ if (PyLong_Check(ind) || PyInt_Check(ind) || PySlice_Check(ind)) {
+ start = parse_subindex(ind, &step_size, &n_steps,
+ self->size);
+ if (start == -1)
+ goto fail;
+ if (n_steps == RubberIndex || n_steps == PseudoIndex) {
+ PyErr_SetString(PyExc_IndexError,
+ "cannot use Ellipsis or NewAxes here");
+ goto fail;
+ }
+ PyArray_ITER_GOTO1D(self, start)
+ if (n_steps == SingleIndex) { /* Integer */
+ r = PyArray_ToScalar(self->dataptr, self->ao);
+ PyArray_ITER_RESET(self);
+ return r;
+ }
+ size = self->ao->descr->elsize;
+ Py_INCREF(self->ao->descr);
+ r = PyArray_NewFromDescr(self->ao->ob_type,
+ self->ao->descr,
+ 1, &n_steps,
+ NULL, NULL,
+ 0, (PyObject *)self->ao);
+ if (r==NULL) goto fail;
+ dptr = PyArray_DATA(r);
+ swap = !PyArray_ISNOTSWAPPED(self->ao);
+ copyswap = PyArray_DESCR(r)->f->copyswap;
+ while(n_steps--) {
+ copyswap(dptr, self->dataptr, swap, size);
+ start += step_size;
+ PyArray_ITER_GOTO1D(self, start)
+ dptr += size;
+ }
+ PyArray_ITER_RESET(self);
+ return r;
+ }
+
+ /* convert to INTP array if Integer array scalar or List */
+
+ indtype = PyArray_DescrFromType(PyArray_INTP);
+ if (PyArray_IsScalar(ind, Integer) || PyList_Check(ind)) {
+ Py_INCREF(indtype);
+ obj = PyArray_FromAny(ind, indtype, 0, 0, FORCECAST);
+ if (obj == NULL) goto fail;
+ }
+ else {
+ Py_INCREF(ind);
+ obj = ind;
+ }
+
+ if (PyArray_Check(obj)) {
+ /* Check for Boolean object */
+ if (PyArray_TYPE(obj)==PyArray_BOOL) {
+ r = iter_subscript_Bool(self, (PyArrayObject *)obj);
+ Py_DECREF(indtype);
+ }
+ /* Check for integer array */
+ else if (PyArray_ISINTEGER(obj)) {
+ PyObject *new;
+ new = PyArray_FromAny(obj, indtype, 0, 0,
+ FORCECAST | ALIGNED);
+ if (new==NULL) goto fail;
+ Py_DECREF(obj);
+ obj = new;
+ r = iter_subscript_int(self, (PyArrayObject *)obj);
+ }
+ else {
+ goto fail;
+ }
+ Py_DECREF(obj);
+ return r;
+ }
+ else Py_DECREF(indtype);
+
+
+ fail:
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_IndexError, "unsupported iterator index");
+ Py_XDECREF(indtype);
+ Py_XDECREF(obj);
+ return NULL;
+
+}
+
+
+static int
+iter_ass_sub_Bool(PyArrayIterObject *self, PyArrayObject *ind,
+ PyArrayIterObject *val, int swap)
+{
+ int index, strides, itemsize;
+ char *dptr;
+ PyArray_CopySwapFunc *copyswap;
+
+ if (ind->nd != 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "boolean index array should have 1 dimension");
+ return -1;
+ }
+ itemsize = self->ao->descr->elsize;
+ index = ind->dimensions[0];
+ strides = ind->strides[0];
+ dptr = ind->data;
+ PyArray_ITER_RESET(self);
+ /* Loop over Boolean array */
+ copyswap = self->ao->descr->f->copyswap;
+ while(index--) {
+ if (*((Bool *)dptr) != 0) {
+ copyswap(self->dataptr, val->dataptr, swap,
+ itemsize);
+ PyArray_ITER_NEXT(val);
+ if (val->index==val->size)
+ PyArray_ITER_RESET(val);
+ }
+ dptr += strides;
+ PyArray_ITER_NEXT(self);
+ }
+ PyArray_ITER_RESET(self);
+ return 0;
+}
+
+static int
+iter_ass_sub_int(PyArrayIterObject *self, PyArrayObject *ind,
+ PyArrayIterObject *val, int swap)
+{
+ PyArray_Descr *typecode;
+ intp num;
+ PyArrayIterObject *ind_it;
+ int itemsize;
+ int index;
+ PyArray_CopySwapFunc *copyswap;
+
+ typecode = self->ao->descr;
+ itemsize = typecode->elsize;
+ copyswap = self->ao->descr->f->copyswap;
+ if (ind->nd == 0) {
+ num = *((intp *)ind->data);
+ PyArray_ITER_GOTO1D(self, num);
+ copyswap(self->dataptr, val->dataptr, swap, itemsize);
+ return 0;
+ }
+ ind_it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)ind);
+ if (ind_it == NULL) return -1;
+ index = ind_it->size;
+ while(index--) {
+ num = *((intp *)(ind_it->dataptr));
+ if (num < 0) num += self->size;
+ if ((num < 0) || (num >= self->size)) {
+ PyErr_Format(PyExc_IndexError,
+ "index %d out of bounds" \
+ " 0<=index<%d", (int) num,
+ (int) self->size);
+ Py_DECREF(ind_it);
+ return -1;
+ }
+ PyArray_ITER_GOTO1D(self, num);
+ copyswap(self->dataptr, val->dataptr, swap, itemsize);
+ PyArray_ITER_NEXT(ind_it);
+ PyArray_ITER_NEXT(val);
+ if (val->index == val->size)
+ PyArray_ITER_RESET(val);
+ }
+ Py_DECREF(ind_it);
+ return 0;
+}
+
+static int
+iter_ass_subscript(PyArrayIterObject *self, PyObject *ind, PyObject *val)
+{
+ PyObject *arrval=NULL;
+ PyArrayIterObject *val_it=NULL;
+ PyArray_Descr *type;
+ PyArray_Descr *indtype=NULL;
+ int swap, retval=-1;
+ int itemsize;
+ intp start, step_size;
+ intp n_steps;
+ PyObject *obj=NULL;
+ PyArray_CopySwapFunc *copyswap;
+
+
+ if (ind == Py_Ellipsis) {
+ ind = PySlice_New(NULL, NULL, NULL);
+ retval = iter_ass_subscript(self, ind, val);
+ Py_DECREF(ind);
+ return retval;
+ }
+
+ if (PyTuple_Check(ind)) {
+ int len;
+ len = PyTuple_GET_SIZE(ind);
+ if (len > 1) goto finish;
+ ind = PyTuple_GET_ITEM(ind, 0);
+ }
+
+ type = self->ao->descr;
+ itemsize = type->elsize;
+
+ Py_INCREF(type);
+ arrval = PyArray_FromAny(val, type, 0, 0, 0);
+ if (arrval==NULL) return -1;
+ val_it = (PyArrayIterObject *)PyArray_IterNew(arrval);
+ if (val_it==NULL) goto finish;
+
+ /* Check for Boolean -- this is first becasue
+ Bool is a subclass of Int */
+
+ copyswap = PyArray_DESCR(arrval)->f->copyswap;
+ swap = (PyArray_ISNOTSWAPPED(self->ao)!=PyArray_ISNOTSWAPPED(arrval));
+ if (PyBool_Check(ind)) {
+ if (PyObject_IsTrue(ind)) {
+ copyswap(self->dataptr, PyArray_DATA(arrval),
+ swap, itemsize);
+ }
+ retval=0;
+ goto finish;
+ }
+
+ /* Check for Integer or Slice */
+
+ if (PyLong_Check(ind) || PyInt_Check(ind) || PySlice_Check(ind)) {
+ start = parse_subindex(ind, &step_size, &n_steps,
+ self->size);
+ if (start == -1) goto finish;
+ if (n_steps == RubberIndex || n_steps == PseudoIndex) {
+ PyErr_SetString(PyExc_IndexError,
+ "cannot use Ellipsis or NewAxes here");
+ goto finish;
+ }
+ PyArray_ITER_GOTO1D(self, start);
+ if (n_steps == SingleIndex) { /* Integer */
+ copyswap(self->dataptr, PyArray_DATA(arrval),
+ swap, itemsize);
+ PyArray_ITER_RESET(self);
+ retval=0;
+ goto finish;
+ }
+ while(n_steps--) {
+ copyswap(self->dataptr, val_it->dataptr,
+ swap, itemsize);
+ start += step_size;
+ PyArray_ITER_GOTO1D(self, start)
+ PyArray_ITER_NEXT(val_it);
+ if (val_it->index == val_it->size)
+ PyArray_ITER_RESET(val_it);
+ }
+ PyArray_ITER_RESET(self);
+ retval = 0;
+ goto finish;
+ }
+
+ /* convert to INTP array if Integer array scalar or List */
+
+ indtype = PyArray_DescrFromType(PyArray_INTP);
+ if (PyArray_IsScalar(ind, Integer)) {
+ Py_INCREF(indtype);
+ obj = PyArray_FromScalar(ind, indtype);
+ }
+ else if (PyList_Check(ind)) {
+ Py_INCREF(indtype);
+ obj = PyArray_FromAny(ind, indtype, 0, 0, FORCECAST);
+ }
+ else {
+ Py_INCREF(ind);
+ obj = ind;
+ }
+
+ if (PyArray_Check(obj)) {
+ /* Check for Boolean object */
+ if (PyArray_TYPE(obj)==PyArray_BOOL) {
+ if (iter_ass_sub_Bool(self, (PyArrayObject *)obj,
+ val_it, swap) < 0)
+ goto finish;
+ retval=0;
+ }
+ /* Check for integer array */
+ else if (PyArray_ISINTEGER(obj)) {
+ PyObject *new;
+ Py_INCREF(indtype);
+ new = PyArray_FromAny(obj, indtype, 0, 0,
+ FORCECAST | BEHAVED_FLAGS);
+ Py_DECREF(obj);
+ obj = new;
+ if (new==NULL) goto finish;
+ if (iter_ass_sub_int(self, (PyArrayObject *)obj,
+ val_it, swap) < 0)
+ goto finish;
+ retval=0;
+ }
+ }
+
+ finish:
+ if (!PyErr_Occurred() && retval < 0)
+ PyErr_SetString(PyExc_IndexError,
+ "unsupported iterator index");
+ Py_XDECREF(indtype);
+ Py_XDECREF(obj);
+ Py_XDECREF(val_it);
+ Py_XDECREF(arrval);
+ return retval;
+
+}
+
+
+static PyMappingMethods iter_as_mapping = {
+ (inquiry)iter_length, /*mp_length*/
+ (binaryfunc)iter_subscript, /*mp_subscript*/
+ (objobjargproc)iter_ass_subscript, /*mp_ass_subscript*/
+};
+
+static char doc_iter_array[] = "__array__(type=None)\n Get array "\
+ "from iterator";
+
+static PyObject *
+iter_array(PyArrayIterObject *it, PyObject *op)
+{
+
+ PyObject *r;
+ intp size;
+
+ /* Any argument ignored */
+
+ /* Two options:
+ 1) underlying array is contiguous
+ -- return 1-d wrapper around it
+ 2) underlying array is not contiguous
+ -- make new 1-d contiguous array with updateifcopy flag set
+ to copy back to the old array
+ */
+
+ size = PyArray_SIZE(it->ao);
+ Py_INCREF(it->ao->descr);
+ if (PyArray_ISCONTIGUOUS(it->ao)) {
+ r = PyArray_NewFromDescr(it->ao->ob_type,
+ it->ao->descr,
+ 1, &size,
+ NULL, it->ao->data,
+ it->ao->flags,
+ (PyObject *)it->ao);
+ if (r==NULL) return NULL;
+ }
+ else {
+ r = PyArray_NewFromDescr(it->ao->ob_type,
+ it->ao->descr,
+ 1, &size,
+ NULL, NULL,
+ 0, (PyObject *)it->ao);
+ if (r==NULL) return NULL;
+ if (PyArray_CopyInto((PyArrayObject *)r, it->ao) < 0) {
+ Py_DECREF(r);
+ return NULL;
+ }
+ PyArray_FLAGS(r) |= UPDATEIFCOPY;
+ it->ao->flags &= ~WRITEABLE;
+ }
+ Py_INCREF(it->ao);
+ PyArray_BASE(r) = (PyObject *)it->ao;
+ return r;
+
+}
+
+static char doc_iter_copy[] = "copy()\n Get a copy of 1-d array";
+
+static PyObject *
+iter_copy(PyArrayIterObject *it, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ return PyArray_Flatten(it->ao, 0);
+}
+
+static PyMethodDef iter_methods[] = {
+ /* to get array */
+ {"__array__", (PyCFunction)iter_array, 1, doc_iter_array},
+ {"copy", (PyCFunction)iter_copy, 1, doc_iter_copy},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyMemberDef iter_members[] = {
+ {"base", T_OBJECT, offsetof(PyArrayIterObject, ao), RO, NULL},
+ {NULL},
+};
+
+static PyTypeObject PyArrayIter_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "scipy.flatiter", /* tp_name */
+ sizeof(PyArrayIterObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)arrayiter_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ &iter_as_mapping, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ (iternextfunc)arrayiter_next, /* tp_iternext */
+ iter_methods, /* tp_methods */
+ iter_members, /* tp_members */
+ 0, /* tp_getset */
+
+};
+
+/** END of Array Iterator **/
+
+
+
+/*********************** Subscript Array Iterator *************************
+ * *
+ * This object handles subscript behavior for array objects. *
+ * It is an iterator object with a next method *
+ * It abstracts the n-dimensional mapping behavior to make the looping *
+ * code more understandable (maybe) *
+ * and so that indexing can be set up ahead of time *
+ */
+
+/* This checks the args for any fancy indexing objects */
+
+#define SOBJ_NOTFANCY 0
+#define SOBJ_ISFANCY 1
+#define SOBJ_BADARRAY 2
+#define SOBJ_TOOMANY 3
+#define SOBJ_LISTTUP 4
+
+static int
+fancy_indexing_check(PyObject *args)
+{
+ int i, n;
+ PyObject *obj;
+ int retval = SOBJ_NOTFANCY;
+
+ if (PyTuple_Check(args)) {
+ n = PyTuple_GET_SIZE(args);
+ if (n >= MAX_DIMS) return SOBJ_TOOMANY;
+ for (i=0; i<n; i++) {
+ obj = PyTuple_GET_ITEM(args,i);
+ if (PyArray_Check(obj)) {
+ if (PyArray_ISINTEGER(obj))
+ retval = SOBJ_ISFANCY;
+ else {
+ retval = SOBJ_BADARRAY;
+ break;
+ }
+ }
+ else if (PySequence_Check(obj)) {
+ retval = SOBJ_ISFANCY;
+ }
+ }
+ }
+ else if (PyArray_Check(args)) {
+ if ((PyArray_TYPE(args)==PyArray_BOOL) ||
+ (PyArray_ISINTEGER(args)))
+ return SOBJ_ISFANCY;
+ else
+ return SOBJ_BADARRAY;
+ }
+ else if (PySequence_Check(args)) {
+ /* Sequences < MAX_DIMS with any slice objects
+ or NewAxis, or Ellipsis is considered standard
+ as long as there are also no Arrays and or additional
+ sequences embedded.
+ */
+ retval = SOBJ_ISFANCY;
+ n = PySequence_Size(args);
+ if (n<0 || n>=MAX_DIMS) return SOBJ_ISFANCY;
+ for (i=0; i<n; i++) {
+ obj = PySequence_GetItem(args, i);
+ if (obj == NULL) return SOBJ_ISFANCY;
+ if (PyArray_Check(obj)) {
+ if (PyArray_ISINTEGER(obj))
+ retval = SOBJ_LISTTUP;
+ else
+ retval = SOBJ_BADARRAY;
+ }
+ else if (PySequence_Check(obj)) {
+ retval = SOBJ_LISTTUP;
+ }
+ else if (PySlice_Check(obj) || obj == Py_Ellipsis || \
+ obj == Py_None) {
+ retval = SOBJ_NOTFANCY;
+ }
+ Py_DECREF(obj);
+ if (retval > SOBJ_ISFANCY) return retval;
+ }
+ }
+
+ return retval;
+}
+
+/* convert an indexing object to an INTP indexing array iterator
+ if possible -- otherwise, it is a Slice or Ellipsis object
+ and has to be interpreted on bind to a particular
+ array so leave it NULL for now.
+ */
+static int
+_convert_obj(PyObject *obj, PyArrayIterObject **iter)
+{
+ PyArray_Descr *indtype;
+ PyObject *arr;
+
+ if (PySlice_Check(obj) || (obj == Py_Ellipsis))
+ *iter = NULL;
+ else {
+ indtype = PyArray_DescrFromType(PyArray_INTP);
+ arr = PyArray_FromAny(obj, indtype, 0, 0, FORCECAST);
+ if (arr == NULL) return -1;
+ *iter = (PyArrayIterObject *)PyArray_IterNew(arr);
+ Py_DECREF(arr);
+ if (*iter == NULL) return -1;
+ }
+ return 0;
+}
+
+/* Adjust dimensionality and strides for index object iterators
+ --- i.e. broadcast
+ */
+/*OBJECT_API*/
+static int
+PyArray_Broadcast(PyArrayMultiIterObject *mit)
+{
+ int i, nd, k, j;
+ intp tmp;
+ PyArrayIterObject *it;
+
+ /* Discover the broadcast number of dimensions */
+ for (i=0, nd=0; i<mit->numiter; i++)
+ nd = MAX(nd, mit->iters[i]->ao->nd);
+ mit->nd = nd;
+
+ /* Discover the broadcast shape in each dimension */
+ for (i=0; i<nd; i++) {
+ mit->dimensions[i] = 1;
+ for (j=0; j<mit->numiter; j++) {
+ it = mit->iters[j];
+ /* This prepends 1 to shapes not already
+ equal to nd */
+ k = i + it->ao->nd - nd;
+ if (k>=0) {
+ tmp = it->ao->dimensions[k];
+ if (tmp == 1) continue;
+ if (mit->dimensions[i] == 1)
+ mit->dimensions[i] = tmp;
+ else if (mit->dimensions[i] != tmp) {
+ PyErr_SetString(PyExc_ValueError,
+ "index objects are " \
+ "not broadcastable " \
+ "to a single shape");
+ return -1;
+ }
+ }
+ }
+ }
+
+ /* Reset the iterator dimensions and strides of each iterator
+ object -- using 0 valued strides for broadcasting */
+
+ tmp = PyArray_MultiplyList(mit->dimensions, mit->nd);
+ mit->size = tmp;
+ for (i=0; i<mit->numiter; i++) {
+ it = mit->iters[i];
+ it->nd_m1 = mit->nd - 1;
+ it->size = tmp;
+ nd = it->ao->nd;
+ it->factors[mit->nd-1] = 1;
+ for (j=0; j < mit->nd; j++) {
+ it->dims_m1[j] = mit->dimensions[j] - 1;
+ k = j + nd - mit->nd;
+ /* If this dimension was added or shape
+ of underlying array was 1 */
+ if ((k < 0) || \
+ it->ao->dimensions[k] != mit->dimensions[j]) {
+ it->contiguous = 0;
+ it->strides[j] = 0;
+ }
+ else {
+ it->strides[j] = it->ao->strides[k];
+ }
+ it->backstrides[j] = it->strides[j] * \
+ it->dims_m1[j];
+ if (j > 0)
+ it->factors[mit->nd-j-1] = \
+ it->factors[mit->nd-j] * \
+ mit->dimensions[mit->nd-j];
+ }
+ PyArray_ITER_RESET(it);
+ }
+ return 0;
+}
+
+/* Reset the map iterator to the beginning */
+static void
+PyArray_MapIterReset(PyArrayMapIterObject *mit)
+{
+ int i,j; intp coord[MAX_DIMS];
+ PyArrayIterObject *it;
+ PyArray_CopySwapFunc *copyswap;
+
+ mit->index = 0;
+
+ copyswap = mit->iters[0]->ao->descr->f->copyswap;
+
+ if (mit->subspace != NULL) {
+ memcpy(coord, mit->bscoord, sizeof(intp)*mit->ait->ao->nd);
+ PyArray_ITER_RESET(mit->subspace);
+ for (i=0; i<mit->numiter; i++) {
+ it = mit->iters[i];
+ PyArray_ITER_RESET(it);
+ j = mit->iteraxes[i];
+ copyswap(coord+j,it->dataptr,
+ !PyArray_ISNOTSWAPPED(it->ao),
+ sizeof(intp));
+ }
+ PyArray_ITER_GOTO(mit->ait, coord);
+ mit->subspace->dataptr = mit->ait->dataptr;
+ mit->dataptr = mit->subspace->dataptr;
+ }
+ else {
+ for (i=0; i<mit->numiter; i++) {
+ it = mit->iters[i];
+ PyArray_ITER_RESET(it);
+ copyswap(coord+i,it->dataptr,
+ !PyArray_ISNOTSWAPPED(it->ao),
+ sizeof(intp));
+ }
+ PyArray_ITER_GOTO(mit->ait, coord);
+ mit->dataptr = mit->ait->dataptr;
+ }
+ return;
+}
+
+/* This function needs to update the state of the map iterator
+ and point mit->dataptr to the memory-location of the next object
+*/
+static void
+PyArray_MapIterNext(PyArrayMapIterObject *mit)
+{
+ int i, j;
+ intp coord[MAX_DIMS];
+ PyArrayIterObject *it;
+ PyArray_CopySwapFunc *copyswap;
+
+ mit->index += 1;
+ if (mit->index >= mit->size) return;
+ copyswap = mit->iters[0]->ao->descr->f->copyswap;
+ /* Sub-space iteration */
+ if (mit->subspace != NULL) {
+ PyArray_ITER_NEXT(mit->subspace);
+ if (mit->subspace->index == mit->subspace->size) {
+ /* reset coord to coordinates of
+ beginning of the subspace */
+ memcpy(coord, mit->bscoord,
+ sizeof(intp)*mit->ait->ao->nd);
+ PyArray_ITER_RESET(mit->subspace);
+ for (i=0; i<mit->numiter; i++) {
+ it = mit->iters[i];
+ PyArray_ITER_NEXT(it);
+ j = mit->iteraxes[i];
+ copyswap(coord+j,it->dataptr,
+ !PyArray_ISNOTSWAPPED(it->ao),
+ sizeof(intp));
+ }
+ PyArray_ITER_GOTO(mit->ait, coord);
+ mit->subspace->dataptr = mit->ait->dataptr;
+ }
+ mit->dataptr = mit->subspace->dataptr;
+ }
+ else {
+ for (i=0; i<mit->numiter; i++) {
+ it = mit->iters[i];
+ PyArray_ITER_NEXT(it);
+ copyswap(coord+i,it->dataptr,
+ !PyArray_ISNOTSWAPPED(it->ao),
+ sizeof(intp));
+ }
+ PyArray_ITER_GOTO(mit->ait, coord);
+ mit->dataptr = mit->ait->dataptr;
+ }
+ return;
+}
+
+/* Bind a mapiteration to a particular array */
+
+/* Determine if subspace iteration is necessary. If so,
+ 1) Fill in mit->iteraxes
+ 2) Create subspace iterator
+ 3) Update nd, dimensions, and size.
+
+ Subspace iteration is necessary if: arr->nd > mit->numiter
+*/
+
+/* Need to check for index-errors somewhere.
+
+ Let's do it at bind time and also convert all <0 values to >0 here
+ as well.
+*/
+static void
+PyArray_MapIterBind(PyArrayMapIterObject *mit, PyArrayObject *arr)
+{
+ int subnd;
+ PyObject *sub, *obj=NULL;
+ int i, j, n, curraxis, ellipexp, noellip;
+ PyArrayIterObject *it;
+ intp dimsize;
+ intp *indptr;
+
+ subnd = arr->nd - mit->numiter;
+ if (subnd < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "too many indices for array");
+ return;
+ }
+
+ mit->ait = (PyArrayIterObject *)PyArray_IterNew((PyObject *)arr);
+ if (mit->ait == NULL) return;
+
+ /* If this is just a view, then do nothing more */
+ /* views are handled by just adjusting the strides
+ and dimensions of the object.
+ */
+
+ if (mit->view) return;
+
+ /* no subspace iteration needed. Finish up and Return */
+ if (subnd == 0) {
+ n = arr->nd;
+ for (i=0; i<n; i++) {
+ mit->iteraxes[i] = i;
+ }
+ goto finish;
+ }
+
+ /* all indexing arrays have been converted to 0
+ therefore we can extract the subspace with a simple
+ getitem call which will use view semantics
+ */
+
+ sub = PyObject_GetItem((PyObject *)arr, mit->indexobj);
+ if (sub == NULL) goto fail;
+ mit->subspace = (PyArrayIterObject *)PyArray_IterNew(sub);
+ Py_DECREF(sub);
+ if (mit->subspace == NULL) goto fail;
+
+ /* Expand dimensions of result */
+ n = mit->subspace->ao->nd;
+ for (i=0; i<n; i++)
+ mit->dimensions[mit->nd+i] = mit->subspace->ao->dimensions[i];
+ mit->nd += n;
+
+ /* Now, we still need to interpret the ellipsis and slice objects
+ to determine which axes the indexing arrays are referring to
+ */
+ n = PyTuple_GET_SIZE(mit->indexobj);
+
+ /* The number of dimensions an ellipsis takes up */
+ ellipexp = arr->nd - n + 1;
+ /* Now fill in iteraxes -- remember indexing arrays have been
+ converted to 0's in mit->indexobj */
+ curraxis = 0;
+ j = 0;
+ noellip = 1; /* Only expand the first ellipsis */
+ memset(mit->bscoord, 0, sizeof(intp)*arr->nd);
+ for (i=0; i<n; i++) {
+ /* We need to fill in the starting coordinates for
+ the subspace */
+ obj = PyTuple_GET_ITEM(mit->indexobj, i);
+ if (PyInt_Check(obj) || PyLong_Check(obj))
+ mit->iteraxes[j++] = curraxis++;
+ else if (noellip && obj == Py_Ellipsis) {
+ curraxis += ellipexp;
+ noellip = 0;
+ }
+ else {
+ intp start=0;
+ intp stop, step;
+ /* Should be slice object or
+ another Ellipsis */
+ if (obj == Py_Ellipsis) {
+ mit->bscoord[curraxis] = 0;
+ }
+ else if (!PySlice_Check(obj) || \
+ (slice_GetIndices((PySliceObject *)obj,
+ arr->dimensions[curraxis],
+ &start, &stop, &step,
+ &dimsize) < 0)) {
+ PyErr_Format(PyExc_ValueError,
+ "unexpected object " \
+ "(%s) in selection position %d",
+ obj->ob_type->tp_name, i);
+ goto fail;
+ }
+ else {
+ mit->bscoord[curraxis] = start;
+ }
+ curraxis += 1;
+ }
+ }
+ finish:
+ /* Here check the indexes (now that we have iteraxes) */
+ mit->size = PyArray_MultiplyList(mit->dimensions, mit->nd);
+ for (i=0; i<mit->numiter; i++) {
+ it = mit->iters[i];
+ PyArray_ITER_RESET(it);
+ dimsize = arr->dimensions[mit->iteraxes[i]];
+ while(it->index < it->size) {
+ indptr = ((intp *)it->dataptr);
+ if (*indptr < 0) *indptr += dimsize;
+ if (*indptr < 0 || *indptr >= dimsize) {
+ PyErr_Format(PyExc_IndexError,
+ "index (%d) out of range "\
+ "(0<=index<=%d) in dimension %d",
+ (int) *indptr, (int) (dimsize-1),
+ mit->iteraxes[i]);
+ goto fail;
+ }
+ PyArray_ITER_NEXT(it);
+ }
+ PyArray_ITER_RESET(it);
+ }
+ return;
+
+ fail:
+ Py_XDECREF(mit->subspace);
+ Py_XDECREF(mit->ait);
+ mit->subspace = NULL;
+ mit->ait = NULL;
+ return;
+}
+
+/* This function takes a Boolean array and constructs index objects and
+ iterators as if nonzero(Bool) had been called
+*/
+static int
+_nonzero_indices(PyObject *myBool, PyArrayIterObject **iters)
+{
+ PyArray_Descr *typecode;
+ PyArrayObject *ba =NULL, *new=NULL;
+ int nd, j;
+ intp size, i, count;
+ Bool *ptr;
+ intp coords[MAX_DIMS], dims_m1[MAX_DIMS];
+ intp *dptr[MAX_DIMS];
+
+ typecode=PyArray_DescrFromType(PyArray_BOOL);
+ ba = (PyArrayObject *)PyArray_FromAny(myBool, typecode, 0, 0,
+ CARRAY_FLAGS);
+ if (ba == NULL) return -1;
+ nd = ba->nd;
+ for (j=0; j<nd; j++) iters[j] = NULL;
+ size = PyArray_SIZE(ba);
+ ptr = (Bool *)ba->data;
+ count = 0;
+
+ /* pre-determine how many nonzero entries there are */
+ for (i=0; i<size; i++)
+ if (*(ptr++)) count++;
+
+ /* create count-sized index arrays for each dimension */
+ for (j=0; j<nd; j++) {
+ new = (PyArrayObject *)PyArray_New(&PyArray_Type, 1, &count,
+ PyArray_INTP, NULL, NULL,
+ 0, 0, NULL);
+ if (new == NULL) goto fail;
+ iters[j] = (PyArrayIterObject *) \
+ PyArray_IterNew((PyObject *)new);
+ Py_DECREF(new);
+ if (iters[j] == NULL) goto fail;
+ dptr[j] = (intp *)iters[j]->ao->data;
+ coords[j] = 0;
+ dims_m1[j] = ba->dimensions[j]-1;
+ }
+
+ ptr = (Bool *)ba->data;
+
+ if (count == 0) goto finish;
+
+ /* Loop through the Boolean array and copy coordinates
+ for non-zero entries */
+ for (i=0; i<size; i++) {
+ if (*(ptr++)) {
+ for (j=0; j<nd; j++)
+ *(dptr[j]++) = coords[j];
+ }
+ /* Borrowed from ITER_NEXT macro */
+ for (j=nd-1; j>=0; j--) {
+ if (coords[j] < dims_m1[j]) {
+ coords[j]++;
+ break;
+ }
+ else {
+ coords[j] = 0;
+ }
+ }
+ }
+
+ finish:
+ Py_DECREF(ba);
+ return nd;
+
+ fail:
+ for (j=0; j<nd; j++) {
+ Py_XDECREF(iters[j]);
+ }
+ Py_XDECREF(ba);
+ return -1;
+
+}
+
+static PyObject *
+PyArray_MapIterNew(PyObject *indexobj, int oned)
+{
+ PyArrayMapIterObject *mit;
+ int fancy=0;
+ PyArray_Descr *indtype;
+ PyObject *arr = NULL;
+ int i, n, started, nonindex;
+
+
+ mit = (PyArrayMapIterObject *)_pya_malloc(sizeof(PyArrayMapIterObject));
+ PyObject_Init((PyObject *)mit, &PyArrayMapIter_Type);
+ if (mit == NULL)
+ return NULL;
+ for (i=0; i<MAX_DIMS; i++)
+ mit->iters[i] = NULL;
+ mit->view = 0;
+ mit->index = 0;
+ mit->ait = NULL;
+ mit->subspace = NULL;
+ mit->numiter = 0;
+ mit->consec = 1;
+ fancy = fancy_indexing_check(indexobj);
+ Py_INCREF(indexobj);
+ mit->indexobj = indexobj;
+ if (fancy == SOBJ_NOTFANCY) { /* bail out */
+ mit->view = 1;
+ goto ret;
+ }
+
+ if (fancy == SOBJ_BADARRAY) {
+ PyErr_SetString(PyExc_IndexError, \
+ "arrays used as indices must be of " \
+ "integer type");
+ goto fail;
+ }
+ if (fancy == SOBJ_TOOMANY) {
+ PyErr_SetString(PyExc_IndexError, "too many indices");
+ goto fail;
+ }
+
+ if (fancy == SOBJ_LISTTUP) {
+ PyObject *newobj;
+ newobj = PySequence_Tuple(indexobj);
+ if (newobj == NULL) goto fail;
+ Py_DECREF(indexobj);
+ indexobj = newobj;
+ mit->indexobj = indexobj;
+ }
+
+#undef SOBJ_NOTFANCY
+#undef SOBJ_ISFANCY
+#undef SOBJ_BADARRAY
+#undef SOBJ_TOOMANY
+#undef SOBJ_LISTTUP
+
+ if (oned) return (PyObject *)mit;
+
+ /* Must have some kind of fancy indexing if we are here */
+ /* indexobj is either a list, an arrayobject, or a tuple
+ (with at least 1 list or arrayobject or Bool object), */
+
+ /* convert all inputs to iterators */
+ if (PyArray_Check(indexobj) && \
+ (PyArray_TYPE(indexobj) == PyArray_BOOL)) {
+ mit->numiter = _nonzero_indices(indexobj, mit->iters);
+ if (mit->numiter < 0) goto fail;
+ mit->nd = 1;
+ mit->dimensions[0] = mit->iters[0]->dims_m1[0]+1;
+ Py_DECREF(mit->indexobj);
+ mit->indexobj = PyTuple_New(mit->numiter);
+ if (mit->indexobj == NULL) goto fail;
+ for (i=0; i<mit->numiter; i++) {
+ PyTuple_SET_ITEM(mit->indexobj, i,
+ PyInt_FromLong(0));
+ }
+ }
+
+ else if (PyArray_Check(indexobj) || !PyTuple_Check(indexobj)) {
+ mit->numiter = 1;
+ indtype = PyArray_DescrFromType(PyArray_INTP);
+ arr = PyArray_FromAny(indexobj, indtype, 0, 0, FORCECAST);
+ if (arr == NULL) goto fail;
+ mit->iters[0] = (PyArrayIterObject *)PyArray_IterNew(arr);
+ if (mit->iters[0] == NULL) {Py_DECREF(arr); goto fail;}
+ mit->nd = PyArray_NDIM(arr);
+ memcpy(mit->dimensions,PyArray_DIMS(arr),mit->nd*sizeof(intp));
+ mit->size = PyArray_SIZE(arr);
+ Py_DECREF(arr);
+ Py_DECREF(mit->indexobj);
+ mit->indexobj = Py_BuildValue("(N)", PyInt_FromLong(0));
+ }
+ else { /* must be a tuple */
+ PyObject *obj;
+ PyArrayIterObject *iter;
+ PyObject *new;
+ /* Make a copy of the tuple -- we will be replacing
+ index objects with 0's */
+ n = PyTuple_GET_SIZE(indexobj);
+ new = PyTuple_New(n);
+ if (new == NULL) goto fail;
+ started = 0;
+ nonindex = 0;
+ for (i=0; i<n; i++) {
+ obj = PyTuple_GET_ITEM(indexobj,i);
+ if (_convert_obj(obj, &iter) < 0) {
+ Py_DECREF(new);
+ goto fail;
+ }
+ if (iter!= NULL) {
+ started = 1;
+ if (nonindex) mit->consec = 0;
+ mit->iters[(mit->numiter)++] = iter;
+ PyTuple_SET_ITEM(new,i,
+ PyInt_FromLong(0));
+ }
+ else {
+ if (started) nonindex = 1;
+ Py_INCREF(obj);
+ PyTuple_SET_ITEM(new,i,obj);
+ }
+ }
+ Py_DECREF(mit->indexobj);
+ mit->indexobj = new;
+ /* Store the number of iterators actually converted */
+ /* These will be mapped to actual axes at bind time */
+ if (PyArray_Broadcast((PyArrayMultiIterObject *)mit) < 0)
+ goto fail;
+ }
+
+ ret:
+ return (PyObject *)mit;
+
+ fail:
+ Py_DECREF(mit);
+ return NULL;
+}
+
+
+static void
+arraymapiter_dealloc(PyArrayMapIterObject *mit)
+{
+ int i;
+ Py_XDECREF(mit->indexobj);
+ Py_XDECREF(mit->ait);
+ Py_XDECREF(mit->subspace);
+ for (i=0; i<mit->numiter; i++)
+ Py_XDECREF(mit->iters[i]);
+ _pya_free(mit);
+}
+
+/* The mapiter object must be created new each time. It does not work
+ to bind to a new array, and continue.
+
+ This was the orginal intention, but currently that does not work.
+ Do not expose the MapIter_Type to Python.
+
+ It's not very useful anyway, since mapiter(indexobj); mapiter.bind(a);
+ mapiter is equivalent to a[indexobj].flat but the latter gets to use
+ slice syntax.
+*/
+
+static PyTypeObject PyArrayMapIter_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "scipy.mapiter", /* tp_name */
+ sizeof(PyArrayIterObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)arraymapiter_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ (traverseproc)0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0 /* tp_weaklist */
+
+};
+
+/** END of Subscript Iterator **/
+
+
+/*OBJECT_API
+ Get MultiIterator,
+*/
+static PyObject *
+PyArray_MultiIterNew(int n, ...)
+{
+ va_list va;
+ PyArrayMultiIterObject *multi;
+ PyObject *current;
+ PyObject *arr;
+
+ int i, err=0;
+
+ if (n < 2 || n > MAX_DIMS) {
+ PyErr_Format(PyExc_ValueError,
+ "Need between 2 and (%d) " \
+ "array objects (inclusive).", MAX_DIMS);
+ }
+
+ /* fprintf(stderr, "multi new...");*/
+ multi = PyObject_New(PyArrayMultiIterObject, &PyArrayMultiIter_Type);
+ if (multi == NULL)
+ return NULL;
+
+ for (i=0; i<n; i++) multi->iters[i] = NULL;
+ multi->numiter = n;
+ multi->index = 0;
+
+ va_start(va, n);
+ for (i=0; i<n; i++) {
+ current = va_arg(va, PyObject *);
+ arr = PyArray_FROM_O(current);
+ if (arr==NULL) {
+ err=1; break;
+ }
+ else {
+ multi->iters[i] = (PyArrayIterObject *)PyArray_IterNew(arr);
+ Py_DECREF(arr);
+ }
+ }
+
+ va_end(va);
+
+ if (!err && PyArray_Broadcast(multi) < 0) err=1;
+
+ if (err) {
+ Py_DECREF(multi);
+ return NULL;
+ }
+
+ PyArray_MultiIter_RESET(multi);
+
+ return (PyObject *)multi;
+}
+
+static PyObject *
+arraymultiter_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
+{
+
+ int n, i;
+ PyArrayMultiIterObject *multi;
+ PyObject *arr;
+
+ if (kwds != NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "keyword arguments not accepted.");
+ return NULL;
+ }
+
+ n = PyTuple_Size(args);
+ if (n < 2 || n > MAX_DIMS) {
+ if (PyErr_Occurred()) return NULL;
+ PyErr_Format(PyExc_ValueError,
+ "Need at least two and fewer than (%d) " \
+ "array objects.", MAX_DIMS);
+ return NULL;
+ }
+
+ multi = _pya_malloc(sizeof(PyArrayMultiIterObject));
+ if (multi == NULL) return PyErr_NoMemory();
+ PyObject_Init((PyObject *)multi, &PyArrayMultiIter_Type);
+
+ multi->numiter = n;
+ multi->index = 0;
+ for (i=0; i<n; i++) multi->iters[i] = NULL;
+ for (i=0; i<n; i++) {
+ arr = PyArray_FromAny(PyTuple_GET_ITEM(args, i), NULL, 0, 0, 0);
+ if (arr == NULL) goto fail;
+ if ((multi->iters[i] = \
+ (PyArrayIterObject *)PyArray_IterNew(arr))==NULL)
+ goto fail;
+ Py_DECREF(arr);
+ }
+ if (PyArray_Broadcast(multi) < 0) goto fail;
+ PyArray_MultiIter_RESET(multi);
+
+ return (PyObject *)multi;
+
+ fail:
+ Py_DECREF(multi);
+ return NULL;
+}
+
+static PyObject *
+arraymultiter_next(PyArrayMultiIterObject *multi)
+{
+ PyObject *ret;
+ int i, n;
+
+ n = multi->numiter;
+ ret = PyTuple_New(n);
+ if (ret == NULL) return NULL;
+ if (multi->index < multi->size) {
+ for (i=0; i < n; i++) {
+ PyArrayIterObject *it=multi->iters[i];
+ PyTuple_SET_ITEM(ret, i,
+ PyArray_ToScalar(it->dataptr, it->ao));
+ PyArray_ITER_NEXT(it);
+ }
+ multi->index++;
+ return ret;
+ }
+ return NULL;
+}
+
+static void
+arraymultiter_dealloc(PyArrayMultiIterObject *multi)
+{
+ int i;
+
+ for (i=0; i<multi->numiter; i++)
+ Py_XDECREF(multi->iters[i]);
+ _pya_free(multi);
+}
+
+static PyObject *
+arraymultiter_size_get(PyArrayMultiIterObject *self)
+{
+#if SIZEOF_INTP <= SIZEOF_LONG
+ return PyInt_FromLong((long) self->size);
+#else
+ if (self->size < MAX_LONG)
+ return PyInt_FromLong((long) self->size);
+ else
+ return PyLong_FromLongLong((longlong) self->size);
+#endif
+}
+
+static PyObject *
+arraymultiter_index_get(PyArrayMultiIterObject *self)
+{
+#if SIZEOF_INTP <= SIZEOF_LONG
+ return PyInt_FromLong((long) self->index);
+#else
+ if (self->size < MAX_LONG)
+ return PyInt_FromLong((long) self->index);
+ else
+ return PyLong_FromLongLong((longlong) self->index);
+#endif
+}
+
+static PyObject *
+arraymultiter_shape_get(PyArrayMultiIterObject *self)
+{
+ return PyArray_IntTupleFromIntp(self->nd, self->dimensions);
+}
+
+static PyObject *
+arraymultiter_iters_get(PyArrayMultiIterObject *self)
+{
+ PyObject *res;
+ int i, n;
+ n = self->numiter;
+ res = PyTuple_New(n);
+ if (res == NULL) return res;
+ for (i=0; i<n; i++) {
+ Py_INCREF(self->iters[i]);
+ PyTuple_SET_ITEM(res, i, (PyObject *)self->iters[i]);
+ }
+ return res;
+}
+
+static PyGetSetDef arraymultiter_getsetlist[] = {
+ {"size",
+ (getter)arraymultiter_size_get,
+ NULL,
+ "total size of broadcasted result"},
+ {"index",
+ (getter)arraymultiter_index_get,
+ NULL,
+ "current index in broadcasted result"},
+ {"shape",
+ (getter)arraymultiter_shape_get,
+ NULL,
+ "shape of broadcasted result"},
+ {"iters",
+ (getter)arraymultiter_iters_get,
+ NULL,
+ "tuple of individual iterators"},
+ {NULL, NULL, NULL, NULL},
+};
+
+static PyMemberDef arraymultiter_members[] = {
+ {"numiter", T_INT, offsetof(PyArrayMultiIterObject, numiter),
+ RO, NULL},
+ {"nd", T_INT, offsetof(PyArrayMultiIterObject, nd), RO, NULL},
+ {NULL},
+};
+
+static PyObject *
+arraymultiter_reset(PyArrayMultiIterObject *self, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+
+ PyArray_MultiIter_RESET(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMethodDef arraymultiter_methods[] = {
+ {"reset", (PyCFunction) arraymultiter_reset, METH_VARARGS, NULL},
+ {NULL, NULL},
+};
+
+static PyTypeObject PyArrayMultiIter_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "scipy.broadcast", /* tp_name */
+ sizeof(PyArrayMultiIterObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)arraymultiter_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ (iternextfunc)arraymultiter_next, /* tp_iternext */
+ arraymultiter_methods, /* tp_methods */
+ arraymultiter_members, /* tp_members */
+ arraymultiter_getsetlist, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ 0, /* tp_alloc */
+ arraymultiter_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0 /* tp_weaklist */
+};
+
+/*OBJECT_API*/
+static PyArray_Descr *
+PyArray_DescrNewFromType(int type_num)
+{
+ PyArray_Descr *old;
+ PyArray_Descr *new;
+
+ old = PyArray_DescrFromType(type_num);
+ new = PyArray_DescrNew(old);
+ Py_DECREF(old);
+ return new;
+}
+
+/*** Array Descr Objects for dynamic types **/
+
+/** There are some statically-defined PyArray_Descr objects corresponding
+ to the basic built-in types.
+ These can and should be DECREF'd and INCREF'd as appropriate, anyway.
+ If a mistake is made in reference counting, deallocation on these
+ builtins will be attempted leading to problems.
+
+ This let's us deal with all PyArray_Descr objects using reference
+ counting (regardless of whether they are statically or dynamically
+ allocated).
+**/
+
+/* base cannot be NULL */
+/*OBJECT_API*/
+static PyArray_Descr *
+PyArray_DescrNew(PyArray_Descr *base)
+{
+ PyArray_Descr *new;
+
+ new = PyObject_New(PyArray_Descr, &PyArrayDescr_Type);
+ if (new == NULL) return NULL;
+ /* Don't copy PyObject_HEAD part */
+ memcpy((char *)new+sizeof(PyObject),
+ (char *)base+sizeof(PyObject),
+ sizeof(PyArray_Descr)-sizeof(PyObject));
+
+ if (new->fields == Py_None) new->fields = NULL;
+ Py_XINCREF(new->fields);
+ if (new->subarray) {
+ new->subarray = _pya_malloc(sizeof(PyArray_ArrayDescr));
+ memcpy(new->subarray, base->subarray,
+ sizeof(PyArray_ArrayDescr));
+ Py_INCREF(new->subarray->shape);
+ Py_INCREF(new->subarray->base);
+ }
+ Py_INCREF(new->typeobj);
+ return new;
+}
+
+/* should never be called for builtin-types unless
+ there is a reference-count problem
+*/
+static void
+arraydescr_dealloc(PyArray_Descr *self)
+{
+ Py_XDECREF(self->typeobj);
+ Py_XDECREF(self->fields);
+ if (self->subarray) {
+ Py_DECREF(self->subarray->shape);
+ Py_DECREF(self->subarray->base);
+ _pya_free(self->subarray);
+ }
+ self->ob_type->tp_free(self);
+}
+
+/* we need to be careful about setting attributes because these
+ objects are pointed to by arrays that depend on them for interpreting
+ data. Currently no attributes of dtypedescr objects can be set.
+*/
+static PyMemberDef arraydescr_members[] = {
+ {"dtype", T_OBJECT, offsetof(PyArray_Descr, typeobj), RO, NULL},
+ {"kind", T_CHAR, offsetof(PyArray_Descr, kind), RO, NULL},
+ {"char", T_CHAR, offsetof(PyArray_Descr, type), RO, NULL},
+ {"num", T_INT, offsetof(PyArray_Descr, type_num), RO, NULL},
+ {"byteorder", T_CHAR, offsetof(PyArray_Descr, byteorder), RO, NULL},
+ {"itemsize", T_INT, offsetof(PyArray_Descr, elsize), RO, NULL},
+ {"alignment", T_INT, offsetof(PyArray_Descr, alignment), RO, NULL},
+ {NULL},
+};
+
+static PyObject *
+arraydescr_subdescr_get(PyArray_Descr *self)
+{
+ if (self->subarray == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return Py_BuildValue("OO", (PyObject *)self->subarray->base,
+ self->subarray->shape);
+}
+
+static PyObject *
+arraydescr_protocol_typestr_get(PyArray_Descr *self)
+{
+ char basic_=self->kind;
+ char endian = self->byteorder;
+
+ if (endian == '=') {
+ endian = '<';
+ if (!PyArray_IsNativeByteOrder(endian)) endian = '>';
+ }
+
+ return PyString_FromFormat("%c%c%d", endian, basic_,
+ self->elsize);
+}
+
+static PyObject *
+arraydescr_protocol_descr_get(PyArray_Descr *self)
+{
+ PyObject *dobj, *res;
+
+ if (self->fields == NULL || self->fields == Py_None) {
+ /* get default */
+ dobj = PyTuple_New(2);
+ if (dobj == NULL) return NULL;
+ PyTuple_SET_ITEM(dobj, 0, PyString_FromString(""));
+ PyTuple_SET_ITEM(dobj, 1, \
+ arraydescr_protocol_typestr_get(self));
+ res = PyList_New(1);
+ if (res == NULL) {Py_DECREF(dobj); return NULL;}
+ PyList_SET_ITEM(res, 0, dobj);
+ return res;
+ }
+
+ return PyObject_CallMethod(_scipy_internal, "_array_descr",
+ "O", self);
+}
+
+/* returns 1 for a builtin type
+ and 2 for a user-defined data-type descriptor
+ return 0 if neither (i.e. it's a copy of one)
+*/
+static PyObject *
+arraydescr_isbuiltin_get(PyArray_Descr *self)
+{
+ long val;
+ val = 0;
+ if (self->fields == Py_None) val = 1;
+ if (PyTypeNum_ISUSERDEF(self->type_num)) val = 2;
+ return PyInt_FromLong(val);
+}
+
+static PyObject *
+arraydescr_isnative_get(PyArray_Descr *self)
+{
+ PyObject *ret;
+
+ ret = (PyArray_ISNBO(self->byteorder) ? Py_True : Py_False);
+ Py_INCREF(ret);
+ return ret;
+}
+
+static PyObject *
+arraydescr_fields_get(PyArray_Descr *self)
+{
+ if (self->fields == NULL || self->fields == Py_None) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return PyDictProxy_New(self->fields);
+}
+
+static PyGetSetDef arraydescr_getsets[] = {
+ {"subdescr",
+ (getter)arraydescr_subdescr_get,
+ NULL,
+ "A tuple of (descr, shape) or None."},
+ {"arrdescr",
+ (getter)arraydescr_protocol_descr_get,
+ NULL,
+ "The array_protocol type descriptor."},
+ {"dtypestr",
+ (getter)arraydescr_protocol_typestr_get,
+ NULL,
+ "The array_protocol typestring."},
+ {"isbuiltin",
+ (getter)arraydescr_isbuiltin_get,
+ NULL,
+ "Is this a buillt-in data-type descriptor?"},
+ {"isnative",
+ (getter)arraydescr_isnative_get,
+ NULL,
+ "Is the byte-order of this descriptor native?"},
+ {"fields",
+ (getter)arraydescr_fields_get,
+ NULL,
+ NULL},
+ {NULL, NULL, NULL, NULL},
+};
+
+static PyArray_Descr *_convert_from_list(PyObject *obj, int align, int try_descr);
+static PyArray_Descr *_convert_from_dict(PyObject *obj, int align);
+static PyArray_Descr *_convert_from_commastring(PyObject *obj, int align);
+static PyArray_Descr *_convert_from_array_descr(PyObject *obj);
+
+static PyObject *
+arraydescr_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
+{
+ PyObject *odescr;
+ PyArray_Descr *descr, *conv;
+ int align=0;
+ Bool copy=FALSE;
+
+ if (!PyArg_ParseTuple(args, "O|iO&", &odescr, &align,
+ PyArray_BoolConverter, &copy))
+ return NULL;
+
+ if (align) {
+ conv = NULL;
+ if PyDict_Check(odescr)
+ conv = _convert_from_dict(odescr, 1);
+ else if PyList_Check(odescr)
+ conv = _convert_from_list(odescr, 1, 0);
+ else if PyString_Check(odescr)
+ conv = _convert_from_commastring(odescr,
+ 1);
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "align can only be non-zero for" \
+ "dictionary, list, and string objects.");
+ }
+ if (conv) return (PyObject *)conv;
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_ValueError,
+ "data-type-descriptor not understood");
+ }
+ return NULL;
+ }
+
+ if PyList_Check(odescr) {
+ conv = _convert_from_array_descr(odescr);
+ if (!conv) {
+ PyErr_Clear();
+ conv = _convert_from_list(odescr, 0, 0);
+ }
+ return (PyObject *)conv;
+ }
+
+ if (!PyArray_DescrConverter(odescr, &conv))
+ return NULL;
+ /* Get a new copy of it unless it's already a copy */
+ if (copy && conv->fields == Py_None) {
+ descr = PyArray_DescrNew(conv);
+ Py_DECREF(conv);
+ conv = descr;
+ }
+ return (PyObject *)conv;
+}
+
+static char doc_arraydescr_reduce[] = "self.__reduce__() for pickling.";
+
+/* return a tuple of (callable object, args, state) */
+static PyObject *
+arraydescr_reduce(PyArray_Descr *self, PyObject *args)
+{
+ PyObject *ret, *mod, *obj;
+ PyObject *state;
+ char endian;
+ int elsize, alignment;
+
+ ret = PyTuple_New(3);
+ if (ret == NULL) return NULL;
+ mod = PyImport_ImportModule("scipy.base.multiarray");
+ if (mod == NULL) {Py_DECREF(ret); return NULL;}
+ obj = PyObject_GetAttrString(mod, "dtypedescr");
+ Py_DECREF(mod);
+ if (obj == NULL) {Py_DECREF(ret); return NULL;}
+ PyTuple_SET_ITEM(ret, 0, obj);
+ if (PyTypeNum_ISUSERDEF(self->type_num) || \
+ ((self->type_num == PyArray_VOID && \
+ self->typeobj != &PyVoidArrType_Type))) {
+ obj = (PyObject *)self->typeobj;
+ Py_INCREF(obj);
+ }
+ else {
+ obj = PyString_FromFormat("%c%d",self->kind, self->elsize);
+ }
+ PyTuple_SET_ITEM(ret, 1, Py_BuildValue("(Nii)", obj, 0, 1));
+
+ /* Now return the state which is at least
+ byteorder, subarray, and fields */
+ endian = self->byteorder;
+ if (endian == '=') {
+ endian = '<';
+ if (!PyArray_IsNativeByteOrder(endian)) endian = '>';
+ }
+ state = PyTuple_New(5);
+ PyTuple_SET_ITEM(state, 0, PyString_FromFormat("%c", endian));
+ PyTuple_SET_ITEM(state, 1, arraydescr_subdescr_get(self));
+ if (self->fields && self->fields != Py_None) {
+ Py_INCREF(self->fields);
+ PyTuple_SET_ITEM(state, 2, self->fields);
+ }
+ else {
+ PyTuple_SET_ITEM(state, 2, Py_None);
+ Py_INCREF(Py_None);
+ }
+
+ /* for extended types it also includes elsize and alignment */
+ if (PyTypeNum_ISEXTENDED(self->type_num)) {
+ elsize = self->elsize;
+ alignment = self->alignment;
+ }
+ else {elsize = -1; alignment = -1;}
+
+ PyTuple_SET_ITEM(state, 3, PyInt_FromLong(elsize));
+ PyTuple_SET_ITEM(state, 4, PyInt_FromLong(alignment));
+
+ PyTuple_SET_ITEM(ret, 2, state);
+ return ret;
+}
+
+/* state is at least byteorder, subarray, and fields but could include elsize
+ and alignment for EXTENDED arrays
+*/
+static char doc_arraydescr_setstate[] = "self.__setstate__() for pickling.";
+
+static PyObject *
+arraydescr_setstate(PyArray_Descr *self, PyObject *args)
+{
+ int elsize = -1, alignment = -1;
+ char endian;
+ PyObject *subarray, *fields;
+
+ if (self->fields == Py_None) {Py_INCREF(Py_None); return Py_None;}
+
+ if (!PyArg_ParseTuple(args, "(cOOii)", &endian, &subarray, &fields,
+ &elsize, &alignment)) return NULL;
+
+ if (PyArray_IsNativeByteOrder(endian)) endian = '=';
+
+ self->byteorder = endian;
+ if (self->subarray) {
+ Py_XDECREF(self->subarray->base);
+ Py_XDECREF(self->subarray->shape);
+ _pya_free(self->subarray);
+ }
+ self->subarray = NULL;
+
+ if (subarray != Py_None) {
+ self->subarray = _pya_malloc(sizeof(PyArray_ArrayDescr));
+ self->subarray->base = (PyArray_Descr *)PyTuple_GET_ITEM(subarray, 0);
+ Py_INCREF(self->subarray->base);
+ self->subarray->shape = PyTuple_GET_ITEM(subarray, 1);
+ Py_INCREF(self->subarray->shape);
+ }
+
+ if (fields != Py_None) {
+ Py_XDECREF(self->fields);
+ self->fields = fields;
+ Py_INCREF(fields);
+ }
+
+ if (PyTypeNum_ISEXTENDED(self->type_num)) {
+ self->elsize = elsize;
+ self->alignment = alignment;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/* returns a copy of the PyArray_Descr structure with the byteorder
+ altered:
+ no arguments: The byteorder is swapped (in all subfields as well)
+ single argument: The byteorder is forced to the given state
+ (in all subfields as well)
+
+ Valid states: ('big', '>') or ('little' or '<')
+ ('native', or '=')
+
+ If a descr structure with | is encountered it's own
+ byte-order is not changed but any fields are:
+*/
+
+/*OBJECT_API
+ Deep bytorder change of a data-type descriptor
+*/
+static PyArray_Descr *
+PyArray_DescrNewByteorder(PyArray_Descr *self, char newendian)
+{
+ PyArray_Descr *new;
+ char endian;
+
+ new = PyArray_DescrNew(self);
+ endian = new->byteorder;
+ if (endian != PyArray_IGNORE) {
+ if (newendian == PyArray_SWAP) { /* swap byteorder */
+ if PyArray_ISNBO(endian) endian = PyArray_OPPBYTE;
+ else endian = PyArray_NATBYTE;
+ new->byteorder = endian;
+ }
+ else if (newendian != PyArray_IGNORE) {
+ new->byteorder = newendian;
+ }
+ }
+ if (new->fields) {
+ PyObject *newfields;
+ PyObject *key, *value;
+ PyObject *newvalue;
+ PyObject *old;
+ PyArray_Descr *newdescr;
+ int pos = 0, len, i;
+ newfields = PyDict_New();
+ /* make new dictionary with replaced */
+ /* PyArray_Descr Objects */
+ while(PyDict_Next(self->fields, &pos, &key, &value)) {
+ if (PyInt_Check(key) && \
+ PyInt_AsLong(key) == -1) {
+ PyDict_SetItem(newfields, key, value);
+ continue;
+ }
+ if (!PyString_Check(key) || \
+ !PyTuple_Check(value) || \
+ ((len=PyTuple_GET_SIZE(value)) < 2))
+ continue;
+
+ old = PyTuple_GET_ITEM(value, 0);
+ if (!PyArray_DescrCheck(old)) continue;
+ newdescr = PyArray_DescrNewByteorder \
+ ((PyArray_Descr *)old, newendian);
+ if (newdescr == NULL) {
+ Py_DECREF(newfields); Py_DECREF(new);
+ return NULL;
+ }
+ newvalue = PyTuple_New(len);
+ PyTuple_SET_ITEM(newvalue, 0, \
+ (PyObject *)newdescr);
+ for(i=1; i<len; i++) {
+ old = PyTuple_GET_ITEM(value, i);
+ Py_INCREF(old);
+ PyTuple_SET_ITEM(newvalue, i, old);
+ }
+ PyDict_SetItem(newfields, key, newvalue);
+ Py_DECREF(newvalue);
+ }
+ Py_DECREF(new->fields);
+ new->fields = newfields;
+ }
+ if (new->subarray) {
+ Py_DECREF(new->subarray->base);
+ new->subarray->base = PyArray_DescrNewByteorder \
+ (self->subarray->base, newendian);
+ }
+ return new;
+}
+
+
+static char doc_arraydescr_newbyteorder[] = "self.newbyteorder(<endian>)"
+ " returns a copy of the dtypedescr object\n"
+ " with altered byteorders. If <endian> is not given all byteorders\n"
+ " are swapped. Otherwise endian can be '>', '<', or '=' to force\n"
+ " a byteorder. Descriptors in all fields are also updated in the\n"
+ " new dtypedescr object.";
+
+static PyObject *
+arraydescr_newbyteorder(PyArray_Descr *self, PyObject *args)
+{
+ char endian=PyArray_SWAP;
+
+ if (!PyArg_ParseTuple(args, "|O&", PyArray_ByteorderConverter,
+ &endian)) return NULL;
+
+ return (PyObject *)PyArray_DescrNewByteorder(self, endian);
+}
+
+static PyMethodDef arraydescr_methods[] = {
+ /* for pickling */
+ {"__reduce__", (PyCFunction)arraydescr_reduce, METH_VARARGS,
+ doc_arraydescr_reduce},
+ {"__setstate__", (PyCFunction)arraydescr_setstate, METH_VARARGS,
+ doc_arraydescr_setstate},
+
+ {"newbyteorder", (PyCFunction)arraydescr_newbyteorder, METH_VARARGS,
+ doc_arraydescr_newbyteorder},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyObject *
+arraydescr_str(PyArray_Descr *self)
+{
+ PyObject *sub;
+
+ if (self->fields && self->fields != Py_None) {
+ PyObject *lst;
+ lst = arraydescr_protocol_descr_get(self);
+ if (!lst) sub = PyString_FromString("<err>");
+ else sub = PyObject_Str(lst);
+ Py_XDECREF(lst);
+ if (self->type_num != PyArray_VOID) {
+ PyObject *p;
+ PyObject *t=PyString_FromString("'");
+ p = arraydescr_protocol_typestr_get(self);
+ PyString_Concat(&p, t);
+ PyString_ConcatAndDel(&t, p);
+ p = PyString_FromString("(");
+ PyString_ConcatAndDel(&p, t);
+ PyString_ConcatAndDel(&p, PyString_FromString(", "));
+ PyString_ConcatAndDel(&p, sub);
+ PyString_ConcatAndDel(&p, PyString_FromString(")"));
+ sub = p;
+ }
+ }
+ else if (self->subarray) {
+ PyObject *p;
+ PyObject *t = PyString_FromString("(");
+ p = arraydescr_str(self->subarray->base);
+ PyString_ConcatAndDel(&t, p);
+ PyString_ConcatAndDel(&t, PyString_FromString(","));
+ PyString_ConcatAndDel(&t, PyObject_Str(self->subarray->shape));
+ PyString_ConcatAndDel(&t, PyString_FromString(")"));
+ sub = t;
+ }
+ else {
+ PyObject *t=PyString_FromString("'");
+ sub = arraydescr_protocol_typestr_get(self);
+ PyString_Concat(&sub, t);
+ PyString_ConcatAndDel(&t, sub);
+ sub = t;
+ }
+ return sub;
+}
+
+static PyObject *
+arraydescr_repr(PyArray_Descr *self)
+{
+ PyObject *sub, *s;
+ s = PyString_FromString("dtypedescr(");
+ sub = arraydescr_str(self);
+ PyString_ConcatAndDel(&s, sub);
+ sub = PyString_FromString(")");
+ PyString_ConcatAndDel(&s, sub);
+ return s;
+}
+
+static int
+arraydescr_compare(PyArray_Descr *self, PyObject *other)
+{
+ if (!PyArray_DescrCheck(other)) {
+ PyErr_SetString(PyExc_TypeError,
+ "not a dtypedescr object.");
+ return -1;
+ }
+ if (PyArray_EquivTypes(self, (PyArray_Descr *)other)) return 0;
+ if (PyArray_CanCastTo(self, (PyArray_Descr *)other)) return -1;
+ return 1;
+}
+
+static PyTypeObject PyArrayDescr_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "scipy.dtypedescr", /* tp_name */
+ sizeof(PyArray_Descr), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)arraydescr_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ (cmpfunc)arraydescr_compare, /* tp_compare */
+ (reprfunc)arraydescr_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ (reprfunc)arraydescr_str, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ arraydescr_methods, /* tp_methods */
+ arraydescr_members, /* tp_members */
+ arraydescr_getsets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ arraydescr_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0 /* tp_weaklist */
+};