summaryrefslogtreecommitdiff
path: root/numpy/core/src/arrayobject.c
diff options
context:
space:
mode:
authorDavid Cournapeau <cournape@gmail.com>2009-04-30 08:35:40 +0000
committerDavid Cournapeau <cournape@gmail.com>2009-04-30 08:35:40 +0000
commit44ff04765d36fe39859452aace91480f74292905 (patch)
tree5386eb4d55b3ec16015ca047210e5900d3358d50 /numpy/core/src/arrayobject.c
parent64aa641a8a17097bfd7fbc686245eb5970ef21bd (diff)
downloadnumpy-44ff04765d36fe39859452aace91480f74292905.tar.gz
Put array iterator code in separate source file.
Diffstat (limited to 'numpy/core/src/arrayobject.c')
-rw-r--r--numpy/core/src/arrayobject.c2400
1 files changed, 3 insertions, 2397 deletions
diff --git a/numpy/core/src/arrayobject.c b/numpy/core/src/arrayobject.c
index e831a2242..befd8b27e 100644
--- a/numpy/core/src/arrayobject.c
+++ b/numpy/core/src/arrayobject.c
@@ -32,6 +32,7 @@ maintainer email: oliphant.travis@ieee.org
#include "arrayobject.h"
#include "arraydescr.h"
+#include "arrayiterators.h"
/*NUMPY_API
* Get Priority from object
@@ -2267,254 +2268,6 @@ array_ass_item(PyArrayObject *self, Py_ssize_t i, PyObject *v)
/* -------------------------------------------------------------- */
-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 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, int getmap)
@@ -2592,15 +2345,6 @@ _swap_axes(PyArrayMapIterObject *mit, PyArrayObject **ret, int getmap)
*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, int);
-
static PyObject *
PyArray_GetMap(PyArrayMapIterObject *mit)
{
@@ -2795,12 +2539,6 @@ add_new_axes_0d(PyArrayObject *arr, int newaxis_count)
/* 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)
{
@@ -2894,11 +2632,7 @@ fancy_indexing_check(PyObject *args)
* therefore a new array is created and returned.
*/
-/* Always returns arrays */
-static PyObject *iter_subscript(PyArrayIterObject *, PyObject *);
-
-
-static PyObject *
+NPY_NO_EXPORT PyObject *
array_subscript_simple(PyArrayObject *self, PyObject *op)
{
intp dimensions[MAX_DIMS], strides[MAX_DIMS];
@@ -3075,7 +2809,6 @@ array_subscript(PyArrayObject *self, PyObject *op)
* 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_simple(PyArrayObject *self, PyObject *index, PyObject *op)
@@ -4989,9 +4722,6 @@ _strings_richcompare(PyArrayObject *self, PyArrayObject *other, int cmp_op,
* VOID-type arrays without fields are compared for equality by comparing their
* memory at each location directly (using string-code).
*/
-static PyObject *array_richcompare(PyArrayObject *, PyObject *, int);
-
-
static PyObject *
_void_compare(PyArrayObject *self, PyArrayObject *other, int cmp_op)
{
@@ -5056,7 +4786,7 @@ _void_compare(PyArrayObject *self, PyArrayObject *other, int cmp_op)
}
}
-static PyObject *
+NPY_NO_EXPORT PyObject *
array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op)
{
PyObject *array_other, *result = NULL;
@@ -9769,2127 +9499,3 @@ PyArray_CanCastScalar(PyTypeObject *from, PyTypeObject *to)
}
return (Bool) PyArray_CanCastSafely(fromtype, totype);
}
-
-
-/*********************** Element-wise Array Iterator ***********************/
-/* Aided by Peter J. Verveer's nd_image package and numpy's arraymap ****/
-/* and Python's array iterator ***/
-
-/*NUMPY_API
- * Get Iterator.
- */
-NPY_NO_EXPORT 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);
- if (PyArray_ISCONTIGUOUS(ao)) {
- it->contiguous = 1;
- }
- else {
- it->contiguous = 0;
- }
- 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] = ao->dimensions[i] - 1;
- it->strides[i] = 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] * ao->dimensions[nd-i];
- }
- }
- PyArray_ITER_RESET(it);
-
- return (PyObject *)it;
-}
-
-/*NUMPY_API
- * Get Iterator broadcast to a particular shape
- */
-NPY_NO_EXPORT PyObject *
-PyArray_BroadcastToShape(PyObject *obj, intp *dims, int nd)
-{
- PyArrayIterObject *it;
- int i, diff, j, compat, k;
- PyArrayObject *ao = (PyArrayObject *)obj;
-
- if (ao->nd > nd) {
- goto err;
- }
- compat = 1;
- diff = j = nd - ao->nd;
- for (i = 0; i < ao->nd; i++, j++) {
- if (ao->dimensions[i] == 1) {
- continue;
- }
- if (ao->dimensions[i] != dims[j]) {
- compat = 0;
- break;
- }
- }
- if (!compat) {
- goto err;
- }
- it = (PyArrayIterObject *)_pya_malloc(sizeof(PyArrayIterObject));
- PyObject_Init((PyObject *)it, &PyArrayIter_Type);
-
- if (it == NULL) {
- return NULL;
- }
- PyArray_UpdateFlags(ao, CONTIGUOUS);
- if (PyArray_ISCONTIGUOUS(ao)) {
- it->contiguous = 1;
- }
- else {
- it->contiguous = 0;
- }
- Py_INCREF(ao);
- it->ao = ao;
- it->size = PyArray_MultiplyList(dims, nd);
- it->nd_m1 = nd - 1;
- it->factors[nd-1] = 1;
- for (i = 0; i < nd; i++) {
- it->dims_m1[i] = dims[i] - 1;
- k = i - diff;
- if ((k < 0) || ao->dimensions[k] != dims[i]) {
- it->contiguous = 0;
- it->strides[i] = 0;
- }
- else {
- it->strides[i] = ao->strides[k];
- }
- it->backstrides[i] = it->strides[i] * it->dims_m1[i];
- if (i > 0) {
- it->factors[nd-i-1] = it->factors[nd-i] * dims[nd-i];
- }
- }
- PyArray_ITER_RESET(it);
- return (PyObject *)it;
-
- err:
- PyErr_SetString(PyExc_ValueError, "array is not broadcastable to "\
- "correct shape");
- return NULL;
-}
-
-
-
-
-
-/*NUMPY_API
- * Get Iterator that iterates over all but one axis (don't use this with
- * PyArray_ITER_GOTO1D). The axis will be over-written if negative
- * with the axis having the smallest stride.
- */
-NPY_NO_EXPORT PyObject *
-PyArray_IterAllButAxis(PyObject *obj, int *inaxis)
-{
- PyArrayIterObject *it;
- int axis;
- it = (PyArrayIterObject *)PyArray_IterNew(obj);
- if (it == NULL) {
- return NULL;
- }
- if (PyArray_NDIM(obj)==0) {
- return (PyObject *)it;
- }
- if (*inaxis < 0) {
- int i, minaxis = 0;
- intp minstride = 0;
- i = 0;
- while (minstride == 0 && i < PyArray_NDIM(obj)) {
- minstride = PyArray_STRIDE(obj,i);
- i++;
- }
- for (i = 1; i < PyArray_NDIM(obj); i++) {
- if (PyArray_STRIDE(obj,i) > 0 &&
- PyArray_STRIDE(obj, i) < minstride) {
- minaxis = i;
- minstride = PyArray_STRIDE(obj,i);
- }
- }
- *inaxis = minaxis;
- }
- axis = *inaxis;
- /* 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;
-}
-
-/*NUMPY_API
- * Adjusts previously broadcasted iterators so that the axis with
- * the smallest sum of iterator strides is not iterated over.
- * Returns dimension which is smallest in the range [0,multi->nd).
- * A -1 is returned if multi->nd == 0.
- *
- * don't use with PyArray_ITER_GOTO1D because factors are not adjusted
- */
-NPY_NO_EXPORT int
-PyArray_RemoveSmallest(PyArrayMultiIterObject *multi)
-{
- PyArrayIterObject *it;
- int i, j;
- int axis;
- intp smallest;
- intp sumstrides[NPY_MAXDIMS];
-
- if (multi->nd == 0) {
- return -1;
- }
- for (i = 0; i < multi->nd; i++) {
- sumstrides[i] = 0;
- for (j = 0; j < multi->numiter; j++) {
- sumstrides[i] += multi->iters[j]->strides[i];
- }
- }
- axis = 0;
- smallest = sumstrides[0];
- /* Find longest dimension */
- for (i = 1; i < multi->nd; i++) {
- if (sumstrides[i] < smallest) {
- axis = i;
- smallest = sumstrides[i];
- }
- }
- for(i = 0; i < multi->numiter; i++) {
- it = multi->iters[i];
- it->contiguous = 0;
- if (it->size != 0) {
- it->size /= (it->dims_m1[axis]+1);
- }
- it->dims_m1[axis] = 0;
- it->backstrides[axis] = 0;
- }
- multi->size = multi->iters[0]->size;
- return axis;
-}
-
-/* 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 Py_ssize_t
-iter_length(PyArrayIterObject *self)
-{
- return self->size;
-}
-
-
-static PyObject *
-iter_subscript_Bool(PyArrayIterObject *self, PyArrayObject *ind)
-{
- intp index, strides;
- int 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];
- if (index > self->size) {
- PyErr_SetString(PyExc_ValueError,
- "too many boolean indices");
- return NULL;
- }
-
- 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) != PyArray_ISNOTSWAPPED(r));
- while (index--) {
- if (*((Bool *)dptr) != 0) {
- copyswap(optr, self->dataptr, swap, self->ao);
- 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;
- intp index;
- PyArray_CopySwapFunc *copyswap;
-
- itemsize = self->ao->descr->elsize;
- if (ind->nd == 0) {
- num = *((intp *)ind->data);
- if (num < 0) {
- num += self->size;
- }
- if (num < 0 || num >= self->size) {
- PyErr_Format(PyExc_IndexError,
- "index %"INTP_FMT" out of bounds" \
- " 0<=index<%"INTP_FMT,
- num, self->size);
- r = NULL;
- }
- else {
- 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(r) != 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 %"INTP_FMT" out of bounds" \
- " 0<=index<%"INTP_FMT,
- num, 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, r);
- 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;
- 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;
- }
- if (len == 0) {
- Py_INCREF(self->ao);
- return (PyObject *)self->ao;
- }
- 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);
- copyswap = PyArray_DESCR(r)->f->copyswap;
- while (n_steps--) {
- copyswap(dptr, self->dataptr, 0, r);
- 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, NULL);
- 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, NULL);
- 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)
-{
- intp index, strides;
- char *dptr;
- PyArray_CopySwapFunc *copyswap;
-
- if (ind->nd != 1) {
- PyErr_SetString(PyExc_ValueError,
- "boolean index array should have 1 dimension");
- return -1;
- }
-
- index = ind->dimensions[0];
- if (index > self->size) {
- PyErr_SetString(PyExc_ValueError,
- "boolean index array has too many values");
- return -1;
- }
-
- 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, self->ao);
- 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;
- intp index;
- PyArray_CopySwapFunc *copyswap;
-
- typecode = self->ao->descr;
- 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, self->ao);
- 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 %"INTP_FMT" out of bounds" \
- " 0<=index<%"INTP_FMT, num,
- self->size);
- Py_DECREF(ind_it);
- return -1;
- }
- PyArray_ITER_GOTO1D(self, num);
- copyswap(self->dataptr, val->dataptr, swap, self->ao);
- 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;
- 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;
-
- /*
- * Check for Boolean -- this is first becasue
- * Bool is a subclass of Int
- */
- if (PyBool_Check(ind)) {
- retval = 0;
- if (PyObject_IsTrue(ind)) {
- retval = type->f->setitem(val, self->dataptr, self->ao);
- }
- goto finish;
- }
-
- if (PySequence_Check(ind) || PySlice_Check(ind)) {
- goto skip;
- }
- start = PyArray_PyIntAsIntp(ind);
- if (start==-1 && PyErr_Occurred()) {
- PyErr_Clear();
- }
- else {
- if (start < -self->size || start >= self->size) {
- PyErr_Format(PyExc_ValueError,
- "index (%" NPY_INTP_FMT \
- ") out of range", start);
- goto finish;
- }
- retval = 0;
- PyArray_ITER_GOTO1D(self, start);
- retval = type->f->setitem(val, self->dataptr, self->ao);
- PyArray_ITER_RESET(self);
- if (retval < 0) {
- PyErr_SetString(PyExc_ValueError,
- "Error setting single item of array.");
- }
- goto finish;
- }
-
- skip:
- Py_INCREF(type);
- arrval = PyArray_FromAny(val, type, 0, 0, 0, NULL);
- if (arrval == NULL) {
- return -1;
- }
- val_it = (PyArrayIterObject *)PyArray_IterNew(arrval);
- if (val_it == NULL) {
- goto finish;
- }
- if (val_it->size == 0) {
- retval = 0;
- goto finish;
- }
-
- copyswap = PyArray_DESCR(arrval)->f->copyswap;
- swap = (PyArray_ISNOTSWAPPED(self->ao)!=PyArray_ISNOTSWAPPED(arrval));
-
- /* Check Slice */
- if (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, arrval);
- PyArray_ITER_RESET(self);
- retval = 0;
- goto finish;
- }
- while (n_steps--) {
- copyswap(self->dataptr, val_it->dataptr, swap, arrval);
- 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 (PyList_Check(ind)) {
- Py_INCREF(indtype);
- obj = PyArray_FromAny(ind, indtype, 0, 0, FORCECAST, NULL);
- }
- else {
- Py_INCREF(ind);
- obj = ind;
- }
-
- if (obj != NULL && 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_CheckFromAny(obj, indtype, 0, 0,
- FORCECAST | BEHAVED_NS, NULL);
- 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 = {
-#if PY_VERSION_HEX >= 0x02050000
- (lenfunc)iter_length, /*mp_length*/
-#else
- (inquiry)iter_length, /*mp_length*/
-#endif
- (binaryfunc)iter_subscript, /*mp_subscript*/
- (objobjargproc)iter_ass_subscript, /*mp_ass_subscript*/
-};
-
-
-
-static PyObject *
-iter_array(PyArrayIterObject *it, PyObject *NPY_UNUSED(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(&PyArray_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(&PyArray_Type,
- it->ao->descr,
- 1, &size,
- NULL, NULL,
- 0, (PyObject *)it->ao);
- if (r == NULL) {
- return NULL;
- }
- if (_flat_copyinto(r, (PyObject *)it->ao,
- PyArray_CORDER) < 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 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, NULL},
- {"copy", (PyCFunction)iter_copy, 1, NULL},
- {NULL, NULL, 0, NULL} /* sentinel */
-};
-
-static PyObject *
-iter_richcompare(PyArrayIterObject *self, PyObject *other, int cmp_op)
-{
- PyArrayObject *new;
- PyObject *ret;
- new = (PyArrayObject *)iter_array(self, NULL);
- if (new == NULL) {
- return NULL;
- }
- ret = array_richcompare(new, other, cmp_op);
- Py_DECREF(new);
- return ret;
-}
-
-
-static PyMemberDef iter_members[] = {
- {"base", T_OBJECT, offsetof(PyArrayIterObject, ao), RO, NULL},
- {"index", T_INT, offsetof(PyArrayIterObject, index), RO, NULL},
- {NULL, 0, 0, 0, NULL},
-};
-
-static PyObject *
-iter_coords_get(PyArrayIterObject *self)
-{
- int nd;
- nd = self->ao->nd;
- if (self->contiguous) {
- /*
- * coordinates not kept track of ---
- * need to generate from index
- */
- intp val;
- int i;
- val = self->index;
- for (i = 0; i < nd; i++) {
- self->coordinates[i] = val / self->factors[i];
- val = val % self->factors[i];
- }
- }
- return PyArray_IntTupleFromIntp(nd, self->coordinates);
-}
-
-static PyGetSetDef iter_getsets[] = {
- {"coords",
- (getter)iter_coords_get,
- NULL, NULL, NULL},
- {NULL, NULL, NULL, NULL, NULL},
-};
-
-NPY_NO_EXPORT PyTypeObject PyArrayIter_Type = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "numpy.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 */
- (richcmpfunc)iter_richcompare, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- (iternextfunc)arrayiter_next, /* tp_iternext */
- iter_methods, /* tp_methods */
- iter_members, /* tp_members */
- iter_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 */
- 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 */
- 0, /* tp_del */
-#ifdef COUNT_ALLOCS
- /* these must be last and never explicitly initialized */
- 0, /* tp_allocs */
- 0, /* tp_frees */
- 0, /* tp_maxalloc */
- 0, /* tp_prev */
- 0, /* *tp_next */
-#endif
-
-};
-
-/** 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 *
- */
-
-
-static int _nonzero_indices(PyObject *myBool, PyArrayIterObject **iters);
-/* 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)) {
- return 0;
- }
- else if (PyArray_Check(obj) && PyArray_ISBOOL(obj)) {
- return _nonzero_indices(obj, iter);
- }
- else {
- indtype = PyArray_DescrFromType(PyArray_INTP);
- arr = PyArray_FromAny(obj, indtype, 0, 0, FORCECAST, NULL);
- if (arr == NULL) {
- return -1;
- }
- *iter = (PyArrayIterObject *)PyArray_IterNew(arr);
- Py_DECREF(arr);
- if (*iter == NULL) {
- return -1;
- }
- }
- return 1;
-}
-
-/* Adjust dimensionality and strides for index object iterators
- --- i.e. broadcast
-*/
-/*NUMPY_API*/
-NPY_NO_EXPORT 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,
- "shape mismatch: objects" \
- " cannot be broadcast" \
- " to a single shape");
- return -1;
- }
- }
- }
- }
-
- /*
- * Reset the iterator dimensions and strides of each iterator
- * object -- using 0 valued strides for broadcasting
- * Need to check for overflow
- */
- tmp = PyArray_OverflowMultiplyList(mit->dimensions, mit->nd);
- if (tmp < 0) {
- PyErr_SetString(PyExc_ValueError,
- "broadcast dimensions too large.");
- return -1;
- }
- 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),
- it->ao);
- }
- 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];
- if (it->size != 0) {
- PyArray_ITER_RESET(it);
- copyswap(coord+i,it->dataptr, !PyArray_ISNOTSWAPPED(it->ao),
- it->ao);
- }
- else {
- coord[i] = 0;
- }
- }
- 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),
- it->ao);
- }
- 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),
- it->ao);
- }
- 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;
- }
- /* 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
- *
- * But, be sure to do it with a true array.
- */
- if (PyArray_CheckExact(arr)) {
- sub = array_subscript_simple(arr, mit->indexobj);
- }
- else {
- Py_INCREF(arr);
- obj = PyArray_EnsureArray((PyObject *)arr);
- if (obj == NULL) {
- goto fail;
- }
- sub = array_subscript_simple((PyArrayObject *)obj, mit->indexobj);
- Py_DECREF(obj);
- }
-
- 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;
- /* Only expand the first ellipsis */
- noellip = 1;
- 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_OverflowMultiplyList(mit->dimensions, mit->nd);
- if (mit->size < 0) {
- PyErr_SetString(PyExc_ValueError,
- "dimensions too large in fancy indexing");
- goto fail;
- }
- if (mit->ait->size == 0 && mit->size != 0) {
- PyErr_SetString(PyExc_ValueError,
- "invalid index into a 0-size array");
- goto fail;
- }
-
- for (i = 0; i < mit->numiter; i++) {
- intp indval;
- it = mit->iters[i];
- PyArray_ITER_RESET(it);
- dimsize = arr->dimensions[mit->iteraxes[i]];
- while (it->index < it->size) {
- indptr = ((intp *)it->dataptr);
- indval = *indptr;
- if (indval < 0) {
- indval += dimsize;
- }
- if (indval < 0 || indval >= dimsize) {
- PyErr_Format(PyExc_IndexError,
- "index (%"INTP_FMT") out of range "\
- "(0<=index<%"INTP_FMT") in dimension %d",
- indval, (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, NULL);
- 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, int fancy)
-{
- PyArrayMapIterObject *mit;
- PyArray_Descr *indtype;
- PyObject *arr = NULL;
- int i, n, started, nonindex;
-
- if (fancy == SOBJ_BADARRAY) {
- PyErr_SetString(PyExc_IndexError, \
- "arrays used as indices must be of " \
- "integer (or boolean) type");
- return NULL;
- }
- if (fancy == SOBJ_TOOMANY) {
- PyErr_SetString(PyExc_IndexError, "too many indices");
- return NULL;
- }
-
- 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->index = 0;
- mit->ait = NULL;
- mit->subspace = NULL;
- mit->numiter = 0;
- mit->consec = 1;
- Py_INCREF(indexobj);
- mit->indexobj = indexobj;
-
- 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, NULL);
- 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 **iterp;
- PyObject *new;
- int numiters, j, n2;
- /*
- * Make a copy of the tuple -- we will be replacing
- * index objects with 0's
- */
- n = PyTuple_GET_SIZE(indexobj);
- n2 = n;
- new = PyTuple_New(n2);
- if (new == NULL) {
- goto fail;
- }
- started = 0;
- nonindex = 0;
- j = 0;
- for (i = 0; i < n; i++) {
- obj = PyTuple_GET_ITEM(indexobj,i);
- iterp = mit->iters + mit->numiter;
- if ((numiters=_convert_obj(obj, iterp)) < 0) {
- Py_DECREF(new);
- goto fail;
- }
- if (numiters > 0) {
- started = 1;
- if (nonindex) {
- mit->consec = 0;
- }
- mit->numiter += numiters;
- if (numiters == 1) {
- PyTuple_SET_ITEM(new,j++, PyInt_FromLong(0));
- }
- else {
- /*
- * we need to grow the new indexing object and fill
- * it with 0s for each of the iterators produced
- */
- int k;
- n2 += numiters - 1;
- if (_PyTuple_Resize(&new, n2) < 0) {
- goto fail;
- }
- for (k = 0; k < numiters; k++) {
- PyTuple_SET_ITEM(new, j++, PyInt_FromLong(0));
- }
- }
- }
- else {
- if (started) {
- nonindex = 1;
- }
- Py_INCREF(obj);
- PyTuple_SET_ITEM(new,j++,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;
- }
- }
-
- 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.
- */
-NPY_NO_EXPORT PyTypeObject PyArrayMapIter_Type = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "numpy.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 */
- 0, /* tp_del */
-
-#ifdef COUNT_ALLOCS
- /* these must be last and never explicitly initialized */
- 0, /* tp_allocs */
- 0, /* tp_frees */
- 0, /* tp_maxalloc */
- 0, /* tp_prev */
- 0, /* *tp_next */
-#endif
-};
-
-/** END of Subscript Iterator **/
-
-
-/*NUMPY_API
- * Get MultiIterator from array of Python objects and any additional
- *
- * PyObject **mps -- array of PyObjects
- * int n - number of PyObjects in the array
- * int nadd - number of additional arrays to include in the iterator.
- *
- * Returns a multi-iterator object.
- */
-NPY_NO_EXPORT PyObject *
-PyArray_MultiIterFromObjects(PyObject **mps, int n, int nadd, ...)
-{
- va_list va;
- PyArrayMultiIterObject *multi;
- PyObject *current;
- PyObject *arr;
-
- int i, ntot, err=0;
-
- ntot = n + nadd;
- if (ntot < 2 || ntot > NPY_MAXARGS) {
- PyErr_Format(PyExc_ValueError,
- "Need between 2 and (%d) " \
- "array objects (inclusive).", NPY_MAXARGS);
- return NULL;
- }
- multi = _pya_malloc(sizeof(PyArrayMultiIterObject));
- if (multi == NULL) {
- return PyErr_NoMemory();
- }
- PyObject_Init((PyObject *)multi, &PyArrayMultiIter_Type);
-
- for (i = 0; i < ntot; i++) {
- multi->iters[i] = NULL;
- }
- multi->numiter = ntot;
- multi->index = 0;
-
- va_start(va, nadd);
- for (i = 0; i < ntot; i++) {
- if (i < n) {
- current = mps[i];
- }
- else {
- 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;
-}
-
-/*NUMPY_API
- * Get MultiIterator,
- */
-NPY_NO_EXPORT PyObject *
-PyArray_MultiIterNew(int n, ...)
-{
- va_list va;
- PyArrayMultiIterObject *multi;
- PyObject *current;
- PyObject *arr;
-
- int i, err = 0;
-
- if (n < 2 || n > NPY_MAXARGS) {
- PyErr_Format(PyExc_ValueError,
- "Need between 2 and (%d) " \
- "array objects (inclusive).", NPY_MAXARGS);
- return NULL;
- }
-
- /* fprintf(stderr, "multi new...");*/
-
- multi = _pya_malloc(sizeof(PyArrayMultiIterObject));
- if (multi == NULL) {
- return PyErr_NoMemory();
- }
- PyObject_Init((PyObject *)multi, &PyArrayMultiIter_Type);
-
- 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 *NPY_UNUSED(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 > NPY_MAXARGS) {
- if (PyErr_Occurred()) {
- return NULL;
- }
- PyErr_Format(PyExc_ValueError,
- "Need at least two and fewer than (%d) " \
- "array objects.", NPY_MAXARGS);
- 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, NULL);
- 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]);
- }
- multi->ob_type->tp_free((PyObject *)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, NULL, NULL},
- {"index",
- (getter)arraymultiter_index_get,
- NULL, NULL, NULL},
- {"shape",
- (getter)arraymultiter_shape_get,
- NULL, NULL, NULL},
- {"iters",
- (getter)arraymultiter_iters_get,
- NULL, NULL, NULL},
- {NULL, 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, 0, 0, 0, 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, 0, NULL},
-};
-
-NPY_NO_EXPORT PyTypeObject PyArrayMultiIter_Type = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "numpy.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 */
- 0, /* tp_del */
-
-#ifdef COUNT_ALLOCS
- /* these must be last and never explicitly initialized */
- 0, /* tp_allocs */
- 0, /* tp_frees */
- 0, /* tp_maxalloc */
- 0, /* tp_prev */
- 0, /* *tp_next */
-#endif
-};