summaryrefslogtreecommitdiff
path: root/numpy/core/src
diff options
context:
space:
mode:
authorDavid Cournapeau <cournape@gmail.com>2009-04-30 08:36:36 +0000
committerDavid Cournapeau <cournape@gmail.com>2009-04-30 08:36:36 +0000
commitefd5b424216fb0ce6aa3c7529d8c3e1d5ae34116 (patch)
treef2a4e44ebcdaf4a90fb59c1f0c392728d9846239 /numpy/core/src
parentfe1f93464b6115ad441bd328ca87f78f2852de49 (diff)
downloadnumpy-efd5b424216fb0ce6aa3c7529d8c3e1d5ae34116.tar.gz
Put mapping protocol in separate file.
Diffstat (limited to 'numpy/core/src')
-rw-r--r--numpy/core/src/arraymapping.c990
-rw-r--r--numpy/core/src/arraymapping.h35
-rw-r--r--numpy/core/src/arrayobject.c996
3 files changed, 1026 insertions, 995 deletions
diff --git a/numpy/core/src/arraymapping.c b/numpy/core/src/arraymapping.c
new file mode 100644
index 000000000..3c4520e94
--- /dev/null
+++ b/numpy/core/src/arraymapping.c
@@ -0,0 +1,990 @@
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include "structmember.h"
+
+/*#include <stdio.h>*/
+#define _MULTIARRAYMODULE
+#define NPY_NO_PREFIX
+#include "numpy/arrayobject.h"
+
+#include "arrayobject.h"
+#include "arrayiterators.h"
+#include "arraymapping.h"
+
+/*************************************************************************
+ **************** Implement Mapping Protocol ***************************
+ *************************************************************************/
+
+NPY_NO_EXPORT Py_ssize_t
+array_length(PyArrayObject *self)
+{
+ if (self->nd != 0) {
+ return self->dimensions[0];
+ } else {
+ PyErr_SetString(PyExc_TypeError, "len() of unsized object");
+ return -1;
+ }
+}
+
+NPY_NO_EXPORT 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;
+}
+
+/* contains optimization for 1-d arrays */
+NPY_NO_EXPORT PyObject *
+array_item_nice(PyArrayObject *self, Py_ssize_t i)
+{
+ if (self->nd == 1) {
+ char *item;
+ if ((item = index2ptr(self, i)) == NULL) {
+ return NULL;
+ }
+ return PyArray_Scalar(item, self->descr, (PyObject *)self);
+ }
+ else {
+ return PyArray_Return(
+ (PyArrayObject *) array_big_item(self, (intp) i));
+ }
+}
+
+NPY_NO_EXPORT 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 (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;
+}
+
+/* -------------------------------------------------------------- */
+
+static void
+_swap_axes(PyArrayMapIterObject *mit, PyArrayObject **ret, int getmap)
+{
+ PyObject *new;
+ int n1, n2, n3, val, bnd;
+ int i;
+ PyArray_Dims permute;
+ intp d[MAX_DIMS];
+ PyArrayObject *arr;
+
+ permute.ptr = d;
+ permute.len = mit->nd;
+
+ /*
+ * arr might not have the right number of dimensions
+ * and need to be reshaped first by pre-pending ones
+ */
+ arr = *ret;
+ if (arr->nd != mit->nd) {
+ for (i = 1; i <= arr->nd; i++) {
+ permute.ptr[mit->nd-i] = arr->dimensions[arr->nd-i];
+ }
+ for (i = 0; i < mit->nd-arr->nd; i++) {
+ permute.ptr[i] = 1;
+ }
+ new = PyArray_Newshape(arr, &permute, PyArray_ANYORDER);
+ Py_DECREF(arr);
+ *ret = (PyArrayObject *)new;
+ if (new == NULL) {
+ return;
+ }
+ }
+
+ /*
+ * Setting and getting need to have different permutations.
+ * On the get we are permuting the returned object, but on
+ * setting we are permuting the object-to-be-set.
+ * The set permutation is the inverse of the get permutation.
+ */
+
+ /*
+ * For getting the array the tuple for transpose is
+ * (n1,...,n1+n2-1,0,...,n1-1,n1+n2,...,n3-1)
+ * n1 is the number of dimensions of the broadcast index array
+ * n2 is the number of dimensions skipped at the start
+ * n3 is the number of dimensions of the result
+ */
+
+ /*
+ * For setting the array the tuple for transpose is
+ * (n2,...,n1+n2-1,0,...,n2-1,n1+n2,...n3-1)
+ */
+ n1 = mit->iters[0]->nd_m1 + 1;
+ n2 = mit->iteraxes[0];
+ n3 = mit->nd;
+
+ /* use n1 as the boundary if getting but n2 if setting */
+ bnd = getmap ? n1 : n2;
+ val = bnd;
+ i = 0;
+ while (val < n1 + n2) {
+ permute.ptr[i++] = val++;
+ }
+ val = 0;
+ while (val < bnd) {
+ 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;
+}
+
+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);
+ 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, 1);
+ }
+ }
+ 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, NULL);
+ 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, 0);
+ if (arr == NULL) {
+ return -1;
+ }
+ }
+ }
+
+ /* Be sure values array is "broadcastable"
+ to shape of mit->dimensions, mit->nd */
+
+ if ((it = (PyArrayIterObject *)\
+ PyArray_BroadcastToShape(arr, mit->dimensions, mit->nd))==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 hasobject arrays */
+ if (PyDataType_FLAGCHK(descr, NPY_ITEM_REFCOUNT)) {
+ while (index--) {
+ PyArray_Item_XDECREF(mit->dataptr, PyArray_DESCR(arr));
+ PyArray_Item_INCREF(it->dataptr, PyArray_DESCR(arr));
+ memmove(mit->dataptr, it->dataptr, sizeof(PyObject *));
+ /* ignored unless VOID array with object's */
+ if (swap) {
+ copyswap(mit->dataptr, NULL, swap, arr);
+ }
+ PyArray_MapIterNext(mit);
+ PyArray_ITER_NEXT(it);
+ }
+ Py_DECREF(arr);
+ Py_DECREF(it);
+ return 0;
+ }
+ while(index--) {
+ memmove(mit->dataptr, it->dataptr, PyArray_ITEMSIZE(arr));
+ if (swap) {
+ copyswap(mit->dataptr, NULL, swap, arr);
+ }
+ PyArray_MapIterNext(mit);
+ PyArray_ITER_NEXT(it);
+ }
+ Py_DECREF(arr);
+ Py_DECREF(it);
+ return 0;
+}
+
+NPY_NO_EXPORT int
+count_new_axes_0d(PyObject *tuple)
+{
+ int i, argument_count;
+ int ellipsis_count = 0;
+ int newaxis_count = 0;
+
+ argument_count = PyTuple_GET_SIZE(tuple);
+ for (i = 0; i < argument_count; ++i) {
+ PyObject *arg = PyTuple_GET_ITEM(tuple, i);
+ if (arg == Py_Ellipsis && !ellipsis_count) {
+ ellipsis_count++;
+ }
+ else if (arg == Py_None) {
+ newaxis_count++;
+ }
+ else {
+ break;
+ }
+ }
+ if (i < argument_count) {
+ PyErr_SetString(PyExc_IndexError,
+ "0-d arrays can only use a single ()"
+ " or a list of newaxes (and a single ...)"
+ " as an index");
+ return -1;
+ }
+ if (newaxis_count > MAX_DIMS) {
+ PyErr_SetString(PyExc_IndexError, "too many dimensions");
+ return -1;
+ }
+ return newaxis_count;
+}
+
+NPY_NO_EXPORT PyObject *
+add_new_axes_0d(PyArrayObject *arr, int newaxis_count)
+{
+ PyArrayObject *other;
+ intp dimensions[MAX_DIMS];
+ int i;
+
+ for (i = 0; i < newaxis_count; ++i) {
+ dimensions[i] = 1;
+ }
+ Py_INCREF(arr->descr);
+ if ((other = (PyArrayObject *)
+ PyArray_NewFromDescr(arr->ob_type, arr->descr,
+ newaxis_count, dimensions,
+ NULL, arr->data,
+ arr->flags,
+ (PyObject *)arr)) == NULL)
+ return NULL;
+ other->base = (PyObject *)arr;
+ Py_INCREF(arr);
+ return (PyObject *)other;
+}
+
+
+/* This checks the args for any fancy indexing objects */
+
+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) ||
+ PyArray_ISBOOL(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) || PyArray_ISBOOL(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;
+}
+
+/*
+ * 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.
+ */
+
+NPY_NO_EXPORT PyObject *
+array_subscript_simple(PyArrayObject *self, PyObject *op)
+{
+ intp dimensions[MAX_DIMS], strides[MAX_DIMS];
+ intp offset;
+ int nd;
+ PyArrayObject *other;
+ intp value;
+
+ value = PyArray_PyIntAsIntp(op);
+ if (!PyErr_Occurred()) {
+ return array_big_item(self, value);
+ }
+ 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);
+ return (PyObject *)other;
+}
+
+NPY_NO_EXPORT PyObject *
+array_subscript(PyArrayObject *self, PyObject *op)
+{
+ int nd, fancy;
+ PyArrayObject *other;
+ PyArrayMapIterObject *mit;
+ PyObject *obj;
+
+ if (PyString_Check(op) || PyUnicode_Check(op)) {
+ if (self->descr->names) {
+ 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;
+ }
+
+ /* Check for multiple field access */
+ if (self->descr->names && PySequence_Check(op) && !PyTuple_Check(op)) {
+ int seqlen, i;
+ seqlen = PySequence_Size(op);
+ for (i = 0; i < seqlen; i++) {
+ obj = PySequence_GetItem(op, i);
+ if (!PyString_Check(obj) && !PyUnicode_Check(obj)) {
+ Py_DECREF(obj);
+ break;
+ }
+ Py_DECREF(obj);
+ }
+ /*
+ * extract multiple fields if all elements in sequence
+ * are either string or unicode (i.e. no break occurred).
+ */
+ fancy = ((seqlen > 0) && (i == seqlen));
+ if (fancy) {
+ PyObject *_numpy_internal;
+ _numpy_internal = PyImport_ImportModule("numpy.core._internal");
+ if (_numpy_internal == NULL) {
+ return NULL;
+ }
+ obj = PyObject_CallMethod(_numpy_internal,
+ "_index_fields", "OO", self, op);
+ Py_DECREF(_numpy_internal);
+ return obj;
+ }
+ }
+
+ if (op == Py_Ellipsis) {
+ Py_INCREF(self);
+ return (PyObject *)self;
+ }
+
+ if (self->nd == 0) {
+ if (op == Py_None) {
+ return add_new_axes_0d(self, 1);
+ }
+ if (PyTuple_Check(op)) {
+ if (0 == PyTuple_GET_SIZE(op)) {
+ Py_INCREF(self);
+ return (PyObject *)self;
+ }
+ if ((nd = count_new_axes_0d(op)) == -1) {
+ return NULL;
+ }
+ return add_new_axes_0d(self, nd);
+ }
+ /* Allow Boolean mask selection also */
+ if ((PyArray_Check(op) && (PyArray_DIMS(op)==0)
+ && PyArray_ISBOOL(op))) {
+ if (PyObject_IsTrue(op)) {
+ Py_INCREF(self);
+ return (PyObject *)self;
+ }
+ else {
+ intp oned = 0;
+ Py_INCREF(self->descr);
+ return PyArray_NewFromDescr(self->ob_type,
+ self->descr,
+ 1, &oned,
+ NULL, NULL,
+ NPY_DEFAULT,
+ NULL);
+ }
+ }
+ PyErr_SetString(PyExc_IndexError, "0-d arrays can't be indexed.");
+ return NULL;
+ }
+
+ fancy = fancy_indexing_check(op);
+ if (fancy != SOBJ_NOTFANCY) {
+ int oned;
+
+ oned = ((self->nd == 1) &&
+ !(PyTuple_Check(op) && PyTuple_GET_SIZE(op) > 1));
+
+ /* wrap arguments into a mapiter object */
+ mit = (PyArrayMapIterObject *) PyArray_MapIterNew(op, oned, fancy);
+ if (mit == NULL) {
+ return NULL;
+ }
+ 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;
+ }
+
+ return array_subscript_simple(self, op);
+}
+
+
+/*
+ * 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
+array_ass_sub_simple(PyArrayObject *self, PyObject *index, PyObject *op)
+{
+ int ret;
+ PyArrayObject *tmp;
+ intp value;
+
+ value = PyArray_PyIntAsIntp(index);
+ if (!error_converting(value)) {
+ return array_ass_big_item(self, value, op);
+ }
+ PyErr_Clear();
+
+ /* Rest of standard (view-based) indexing */
+
+ if (PyArray_CheckExact(self)) {
+ tmp = (PyArrayObject *)array_subscript_simple(self, index);
+ if (tmp == NULL) {
+ return -1;
+ }
+ }
+ else {
+ PyObject *tmp0;
+ tmp0 = PyObject_GetItem((PyObject *)self, index);
+ if (tmp0 == NULL) {
+ return -1;
+ }
+ if (!PyArray_Check(tmp0)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Getitem not returning array.");
+ Py_DECREF(tmp0);
+ return -1;
+ }
+ tmp = (PyArrayObject *)tmp0;
+ }
+
+ 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;
+}
+
+
+/* return -1 if tuple-object seq is not a tuple of integers.
+ otherwise fill vals with converted integers
+*/
+static int
+_tuple_of_integers(PyObject *seq, intp *vals, int maxvals)
+{
+ int i;
+ PyObject *obj;
+ intp temp;
+
+ for(i=0; i<maxvals; i++) {
+ obj = PyTuple_GET_ITEM(seq, i);
+ if ((PyArray_Check(obj) && PyArray_NDIM(obj) > 0)
+ || PyList_Check(obj)) {
+ return -1;
+ }
+ temp = PyArray_PyIntAsIntp(obj);
+ if (error_converting(temp)) {
+ return -1;
+ }
+ vals[i] = temp;
+ }
+ return 0;
+}
+
+
+static int
+array_ass_sub(PyArrayObject *self, PyObject *index, PyObject *op)
+{
+ int ret, oned, fancy;
+ PyArrayMapIterObject *mit;
+ intp vals[MAX_DIMS];
+
+ 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 (PyInt_Check(index) || PyArray_IsScalar(index, Integer) ||
+ PyLong_Check(index) || (PyIndex_Check(index) &&
+ !PySequence_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->names) {
+ 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) {
+ /*
+ * Several different exceptions to the 0-d no-indexing rule
+ *
+ * 1) ellipses
+ * 2) empty tuple
+ * 3) Using newaxis (None)
+ * 4) Boolean mask indexing
+ */
+ if (index == Py_Ellipsis || index == Py_None ||
+ (PyTuple_Check(index) && (0 == PyTuple_GET_SIZE(index) ||
+ count_new_axes_0d(index) > 0))) {
+ return self->descr->f->setitem(op, self->data, self);
+ }
+ if (PyBool_Check(index) || PyArray_IsScalar(index, Bool) ||
+ (PyArray_Check(index) && (PyArray_DIMS(index)==0) &&
+ PyArray_ISBOOL(index))) {
+ if (PyObject_IsTrue(index)) {
+ return self->descr->f->setitem(op, self->data, self);
+ }
+ else { /* don't do anything */
+ return 0;
+ }
+ }
+ PyErr_SetString(PyExc_IndexError, "0-d arrays can't be indexed.");
+ return -1;
+ }
+
+ /* optimization for integer-tuple */
+ if (self->nd > 1 &&
+ (PyTuple_Check(index) && (PyTuple_GET_SIZE(index) == self->nd))
+ && (_tuple_of_integers(index, vals, self->nd) >= 0)) {
+ int i;
+ char *item;
+
+ for (i = 0; i < self->nd; i++) {
+ if (vals[i] < 0) {
+ vals[i] += self->dimensions[i];
+ }
+ if ((vals[i] < 0) || (vals[i] >= self->dimensions[i])) {
+ PyErr_Format(PyExc_IndexError,
+ "index (%"INTP_FMT") out of range "\
+ "(0<=index<%"INTP_FMT") in dimension %d",
+ vals[i], self->dimensions[i], i);
+ return -1;
+ }
+ }
+ item = PyArray_GetPtr(self, vals);
+ return self->descr->f->setitem(op, item, self);
+ }
+ PyErr_Clear();
+
+ fancy = fancy_indexing_check(index);
+ if (fancy != SOBJ_NOTFANCY) {
+ oned = ((self->nd == 1) &&
+ !(PyTuple_Check(index) && PyTuple_GET_SIZE(index) > 1));
+ mit = (PyArrayMapIterObject *) PyArray_MapIterNew(index, oned, fancy);
+ if (mit == NULL) {
+ return -1;
+ }
+ 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;
+ }
+
+ return array_ass_sub_simple(self, index, op);
+}
+
+
+/*
+ * 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)
+{
+
+ PyArrayObject *mp;
+ intp vals[MAX_DIMS];
+
+ if (PyInt_Check(op) || PyArray_IsScalar(op, Integer) ||
+ PyLong_Check(op) || (PyIndex_Check(op) &&
+ !PySequence_Check(op))) {
+ intp value;
+ value = PyArray_PyIntAsIntp(op);
+ if (PyErr_Occurred()) {
+ PyErr_Clear();
+ }
+ else {
+ return array_item_nice(self, (Py_ssize_t) value);
+ }
+ }
+ /* optimization for a tuple of integers */
+ if (self->nd > 1 && PyTuple_Check(op) &&
+ (PyTuple_GET_SIZE(op) == self->nd)
+ && (_tuple_of_integers(op, vals, self->nd) >= 0)) {
+ int i;
+ char *item;
+
+ for (i = 0; i < self->nd; i++) {
+ if (vals[i] < 0) {
+ vals[i] += self->dimensions[i];
+ }
+ if ((vals[i] < 0) || (vals[i] >= self->dimensions[i])) {
+ PyErr_Format(PyExc_IndexError,
+ "index (%"INTP_FMT") out of range "\
+ "(0<=index<%"INTP_FMT") in dimension %d",
+ vals[i], self->dimensions[i], i);
+ return NULL;
+ }
+ }
+ item = PyArray_GetPtr(self, vals);
+ return PyArray_Scalar(item, self->descr, (PyObject *)self);
+ }
+ PyErr_Clear();
+
+ mp = (PyArrayObject *)array_subscript(self, op);
+ /*
+ * mp could be a scalar if op is not an Int, Scalar, Long or other Index
+ * object and still convertable to an integer (so that the code goes to
+ * array_subscript_simple). So, this cast is a bit dangerous..
+ */
+
+ /*
+ * The following is just a copy of PyArray_Return with an
+ * additional logic in the nd == 0 case.
+ */
+
+ if (mp == NULL) {
+ return NULL;
+ }
+ if (PyErr_Occurred()) {
+ Py_XDECREF(mp);
+ return NULL;
+ }
+ if (PyArray_Check(mp) && mp->nd == 0) {
+ Bool noellipses = TRUE;
+ if ((op == Py_Ellipsis) || PyString_Check(op) || PyUnicode_Check(op)) {
+ noellipses = FALSE;
+ }
+ else if (PyBool_Check(op) || PyArray_IsScalar(op, Bool) ||
+ (PyArray_Check(op) && (PyArray_DIMS(op)==0) &&
+ PyArray_ISBOOL(op))) {
+ noellipses = FALSE;
+ }
+ else if (PySequence_Check(op)) {
+ Py_ssize_t n, i;
+ PyObject *temp;
+
+ n = PySequence_Size(op);
+ i = 0;
+ while (i < n && noellipses) {
+ temp = PySequence_GetItem(op, i);
+ if (temp == Py_Ellipsis) {
+ noellipses = FALSE;
+ }
+ Py_DECREF(temp);
+ i++;
+ }
+ }
+ if (noellipses) {
+ PyObject *ret;
+ ret = PyArray_ToScalar(mp->data, mp);
+ Py_DECREF(mp);
+ return ret;
+ }
+ }
+ return (PyObject *)mp;
+}
+
+
+NPY_NO_EXPORT PyMappingMethods array_as_mapping = {
+#if PY_VERSION_HEX >= 0x02050000
+ (lenfunc)array_length, /*mp_length*/
+#else
+ (inquiry)array_length, /*mp_length*/
+#endif
+ (binaryfunc)array_subscript_nice, /*mp_subscript*/
+ (objobjargproc)array_ass_sub, /*mp_ass_subscript*/
+};
+
+/****************** End of Mapping Protocol ******************************/
+
+
diff --git a/numpy/core/src/arraymapping.h b/numpy/core/src/arraymapping.h
new file mode 100644
index 000000000..0b9b712fe
--- /dev/null
+++ b/numpy/core/src/arraymapping.h
@@ -0,0 +1,35 @@
+#ifndef _NPY_ARRAYMAPPING_H_
+#define _NPY_ARRAYMAPPING_H_
+
+extern NPY_NO_EXPORT PyMappingMethods array_as_mapping;
+
+NPY_NO_EXPORT Py_ssize_t
+array_length(PyArrayObject *self);
+
+NPY_NO_EXPORT PyObject *
+array_item_nice(PyArrayObject *self, Py_ssize_t i);
+
+NPY_NO_EXPORT PyObject *
+array_subscript(PyArrayObject *self, PyObject *op);
+
+NPY_NO_EXPORT int
+array_ass_big_item(PyArrayObject *self, intp i, PyObject *v);
+
+#if PY_VERSION_HEX < 0x02050000
+#if SIZEOF_INT == SIZEOF_INTP
+#define array_ass_item array_ass_big_item
+#endif
+#else
+#if SIZEOF_SIZE_T == SIZEOF_INTP
+#define array_ass_item array_ass_big_item
+#endif
+#endif
+#ifndef array_ass_item
+NPY_NO_EXPORT int
+array_ass_item(PyArrayObject *self, Py_ssize_t i, PyObject *v)
+{
+ return array_ass_big_item(self, (intp) i, v);
+}
+#endif
+
+#endif
diff --git a/numpy/core/src/arrayobject.c b/numpy/core/src/arrayobject.c
index e8d6dc541..1d9256b28 100644
--- a/numpy/core/src/arrayobject.c
+++ b/numpy/core/src/arrayobject.c
@@ -33,6 +33,7 @@ maintainer email: oliphant.travis@ieee.org
#include "arrayobject.h"
#include "arraydescr.h"
#include "arrayiterators.h"
+#include "arraymapping.h"
#ifndef Py_UNICODE_WIDE
#include "ucsnarrow.h"
#endif
@@ -2145,1001 +2146,6 @@ array_dealloc(PyArrayObject *self) {
}
/*************************************************************************
- **************** Implement Mapping Protocol ***************************
- *************************************************************************/
-
-static Py_ssize_t
-array_length(PyArrayObject *self)
-{
- if (self->nd != 0) {
- return self->dimensions[0];
- } else {
- PyErr_SetString(PyExc_TypeError, "len() of unsized object");
- return -1;
- }
-}
-
-NPY_NO_EXPORT 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;
-}
-
-/* contains optimization for 1-d arrays */
-static PyObject *
-array_item_nice(PyArrayObject *self, Py_ssize_t i)
-{
- if (self->nd == 1) {
- char *item;
- if ((item = index2ptr(self, i)) == NULL) {
- return NULL;
- }
- return PyArray_Scalar(item, self->descr, (PyObject *)self);
- }
- else {
- 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 (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 PY_VERSION_HEX < 0x02050000
-#if SIZEOF_INT == SIZEOF_INTP
-#define array_ass_item array_ass_big_item
-#endif
-#else
-#if SIZEOF_SIZE_T == SIZEOF_INTP
-#define array_ass_item array_ass_big_item
-#endif
-#endif
-#ifndef array_ass_item
-static int
-array_ass_item(PyArrayObject *self, Py_ssize_t i, PyObject *v)
-{
- return array_ass_big_item(self, (intp) i, v);
-}
-#endif
-
-
-/* -------------------------------------------------------------- */
-
-static void
-_swap_axes(PyArrayMapIterObject *mit, PyArrayObject **ret, int getmap)
-{
- PyObject *new;
- int n1, n2, n3, val, bnd;
- int i;
- PyArray_Dims permute;
- intp d[MAX_DIMS];
- PyArrayObject *arr;
-
- permute.ptr = d;
- permute.len = mit->nd;
-
- /*
- * arr might not have the right number of dimensions
- * and need to be reshaped first by pre-pending ones
- */
- arr = *ret;
- if (arr->nd != mit->nd) {
- for (i = 1; i <= arr->nd; i++) {
- permute.ptr[mit->nd-i] = arr->dimensions[arr->nd-i];
- }
- for (i = 0; i < mit->nd-arr->nd; i++) {
- permute.ptr[i] = 1;
- }
- new = PyArray_Newshape(arr, &permute, PyArray_ANYORDER);
- Py_DECREF(arr);
- *ret = (PyArrayObject *)new;
- if (new == NULL) {
- return;
- }
- }
-
- /*
- * Setting and getting need to have different permutations.
- * On the get we are permuting the returned object, but on
- * setting we are permuting the object-to-be-set.
- * The set permutation is the inverse of the get permutation.
- */
-
- /*
- * For getting the array the tuple for transpose is
- * (n1,...,n1+n2-1,0,...,n1-1,n1+n2,...,n3-1)
- * n1 is the number of dimensions of the broadcast index array
- * n2 is the number of dimensions skipped at the start
- * n3 is the number of dimensions of the result
- */
-
- /*
- * For setting the array the tuple for transpose is
- * (n2,...,n1+n2-1,0,...,n2-1,n1+n2,...n3-1)
- */
- n1 = mit->iters[0]->nd_m1 + 1;
- n2 = mit->iteraxes[0];
- n3 = mit->nd;
-
- /* use n1 as the boundary if getting but n2 if setting */
- bnd = getmap ? n1 : n2;
- val = bnd;
- i = 0;
- while (val < n1 + n2) {
- permute.ptr[i++] = val++;
- }
- val = 0;
- while (val < bnd) {
- 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;
-}
-
-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);
- 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, 1);
- }
- }
- 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, NULL);
- 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, 0);
- if (arr == NULL) {
- return -1;
- }
- }
- }
-
- /* Be sure values array is "broadcastable"
- to shape of mit->dimensions, mit->nd */
-
- if ((it = (PyArrayIterObject *)\
- PyArray_BroadcastToShape(arr, mit->dimensions, mit->nd))==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 hasobject arrays */
- if (PyDataType_FLAGCHK(descr, NPY_ITEM_REFCOUNT)) {
- while (index--) {
- PyArray_Item_XDECREF(mit->dataptr, PyArray_DESCR(arr));
- PyArray_Item_INCREF(it->dataptr, PyArray_DESCR(arr));
- memmove(mit->dataptr, it->dataptr, sizeof(PyObject *));
- /* ignored unless VOID array with object's */
- if (swap) {
- copyswap(mit->dataptr, NULL, swap, arr);
- }
- PyArray_MapIterNext(mit);
- PyArray_ITER_NEXT(it);
- }
- Py_DECREF(arr);
- Py_DECREF(it);
- return 0;
- }
- while(index--) {
- memmove(mit->dataptr, it->dataptr, PyArray_ITEMSIZE(arr));
- if (swap) {
- copyswap(mit->dataptr, NULL, swap, arr);
- }
- PyArray_MapIterNext(mit);
- PyArray_ITER_NEXT(it);
- }
- Py_DECREF(arr);
- Py_DECREF(it);
- return 0;
-}
-
-NPY_NO_EXPORT int
-count_new_axes_0d(PyObject *tuple)
-{
- int i, argument_count;
- int ellipsis_count = 0;
- int newaxis_count = 0;
-
- argument_count = PyTuple_GET_SIZE(tuple);
- for (i = 0; i < argument_count; ++i) {
- PyObject *arg = PyTuple_GET_ITEM(tuple, i);
- if (arg == Py_Ellipsis && !ellipsis_count) {
- ellipsis_count++;
- }
- else if (arg == Py_None) {
- newaxis_count++;
- }
- else {
- break;
- }
- }
- if (i < argument_count) {
- PyErr_SetString(PyExc_IndexError,
- "0-d arrays can only use a single ()"
- " or a list of newaxes (and a single ...)"
- " as an index");
- return -1;
- }
- if (newaxis_count > MAX_DIMS) {
- PyErr_SetString(PyExc_IndexError, "too many dimensions");
- return -1;
- }
- return newaxis_count;
-}
-
-NPY_NO_EXPORT PyObject *
-add_new_axes_0d(PyArrayObject *arr, int newaxis_count)
-{
- PyArrayObject *other;
- intp dimensions[MAX_DIMS];
- int i;
-
- for (i = 0; i < newaxis_count; ++i) {
- dimensions[i] = 1;
- }
- Py_INCREF(arr->descr);
- if ((other = (PyArrayObject *)
- PyArray_NewFromDescr(arr->ob_type, arr->descr,
- newaxis_count, dimensions,
- NULL, arr->data,
- arr->flags,
- (PyObject *)arr)) == NULL)
- return NULL;
- other->base = (PyObject *)arr;
- Py_INCREF(arr);
- return (PyObject *)other;
-}
-
-
-/* This checks the args for any fancy indexing objects */
-
-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) ||
- PyArray_ISBOOL(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) || PyArray_ISBOOL(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;
-}
-
-/*
- * 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.
- */
-
-NPY_NO_EXPORT PyObject *
-array_subscript_simple(PyArrayObject *self, PyObject *op)
-{
- intp dimensions[MAX_DIMS], strides[MAX_DIMS];
- intp offset;
- int nd;
- PyArrayObject *other;
- intp value;
-
- value = PyArray_PyIntAsIntp(op);
- if (!PyErr_Occurred()) {
- return array_big_item(self, value);
- }
- 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);
- return (PyObject *)other;
-}
-
-static PyObject *
-array_subscript(PyArrayObject *self, PyObject *op)
-{
- int nd, fancy;
- PyArrayObject *other;
- PyArrayMapIterObject *mit;
- PyObject *obj;
-
- if (PyString_Check(op) || PyUnicode_Check(op)) {
- if (self->descr->names) {
- 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;
- }
-
- /* Check for multiple field access */
- if (self->descr->names && PySequence_Check(op) && !PyTuple_Check(op)) {
- int seqlen, i;
- seqlen = PySequence_Size(op);
- for (i = 0; i < seqlen; i++) {
- obj = PySequence_GetItem(op, i);
- if (!PyString_Check(obj) && !PyUnicode_Check(obj)) {
- Py_DECREF(obj);
- break;
- }
- Py_DECREF(obj);
- }
- /*
- * extract multiple fields if all elements in sequence
- * are either string or unicode (i.e. no break occurred).
- */
- fancy = ((seqlen > 0) && (i == seqlen));
- if (fancy) {
- PyObject *_numpy_internal;
- _numpy_internal = PyImport_ImportModule("numpy.core._internal");
- if (_numpy_internal == NULL) {
- return NULL;
- }
- obj = PyObject_CallMethod(_numpy_internal,
- "_index_fields", "OO", self, op);
- Py_DECREF(_numpy_internal);
- return obj;
- }
- }
-
- if (op == Py_Ellipsis) {
- Py_INCREF(self);
- return (PyObject *)self;
- }
-
- if (self->nd == 0) {
- if (op == Py_None) {
- return add_new_axes_0d(self, 1);
- }
- if (PyTuple_Check(op)) {
- if (0 == PyTuple_GET_SIZE(op)) {
- Py_INCREF(self);
- return (PyObject *)self;
- }
- if ((nd = count_new_axes_0d(op)) == -1) {
- return NULL;
- }
- return add_new_axes_0d(self, nd);
- }
- /* Allow Boolean mask selection also */
- if ((PyArray_Check(op) && (PyArray_DIMS(op)==0)
- && PyArray_ISBOOL(op))) {
- if (PyObject_IsTrue(op)) {
- Py_INCREF(self);
- return (PyObject *)self;
- }
- else {
- intp oned = 0;
- Py_INCREF(self->descr);
- return PyArray_NewFromDescr(self->ob_type,
- self->descr,
- 1, &oned,
- NULL, NULL,
- NPY_DEFAULT,
- NULL);
- }
- }
- PyErr_SetString(PyExc_IndexError, "0-d arrays can't be indexed.");
- return NULL;
- }
-
- fancy = fancy_indexing_check(op);
- if (fancy != SOBJ_NOTFANCY) {
- int oned;
-
- oned = ((self->nd == 1) &&
- !(PyTuple_Check(op) && PyTuple_GET_SIZE(op) > 1));
-
- /* wrap arguments into a mapiter object */
- mit = (PyArrayMapIterObject *) PyArray_MapIterNew(op, oned, fancy);
- if (mit == NULL) {
- return NULL;
- }
- 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;
- }
-
- return array_subscript_simple(self, op);
-}
-
-
-/*
- * 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
-array_ass_sub_simple(PyArrayObject *self, PyObject *index, PyObject *op)
-{
- int ret;
- PyArrayObject *tmp;
- intp value;
-
- value = PyArray_PyIntAsIntp(index);
- if (!error_converting(value)) {
- return array_ass_big_item(self, value, op);
- }
- PyErr_Clear();
-
- /* Rest of standard (view-based) indexing */
-
- if (PyArray_CheckExact(self)) {
- tmp = (PyArrayObject *)array_subscript_simple(self, index);
- if (tmp == NULL) {
- return -1;
- }
- }
- else {
- PyObject *tmp0;
- tmp0 = PyObject_GetItem((PyObject *)self, index);
- if (tmp0 == NULL) {
- return -1;
- }
- if (!PyArray_Check(tmp0)) {
- PyErr_SetString(PyExc_RuntimeError,
- "Getitem not returning array.");
- Py_DECREF(tmp0);
- return -1;
- }
- tmp = (PyArrayObject *)tmp0;
- }
-
- 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;
-}
-
-
-/* return -1 if tuple-object seq is not a tuple of integers.
- otherwise fill vals with converted integers
-*/
-static int
-_tuple_of_integers(PyObject *seq, intp *vals, int maxvals)
-{
- int i;
- PyObject *obj;
- intp temp;
-
- for(i=0; i<maxvals; i++) {
- obj = PyTuple_GET_ITEM(seq, i);
- if ((PyArray_Check(obj) && PyArray_NDIM(obj) > 0)
- || PyList_Check(obj)) {
- return -1;
- }
- temp = PyArray_PyIntAsIntp(obj);
- if (error_converting(temp)) {
- return -1;
- }
- vals[i] = temp;
- }
- return 0;
-}
-
-
-static int
-array_ass_sub(PyArrayObject *self, PyObject *index, PyObject *op)
-{
- int ret, oned, fancy;
- PyArrayMapIterObject *mit;
- intp vals[MAX_DIMS];
-
- 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 (PyInt_Check(index) || PyArray_IsScalar(index, Integer) ||
- PyLong_Check(index) || (PyIndex_Check(index) &&
- !PySequence_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->names) {
- 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) {
- /*
- * Several different exceptions to the 0-d no-indexing rule
- *
- * 1) ellipses
- * 2) empty tuple
- * 3) Using newaxis (None)
- * 4) Boolean mask indexing
- */
- if (index == Py_Ellipsis || index == Py_None ||
- (PyTuple_Check(index) && (0 == PyTuple_GET_SIZE(index) ||
- count_new_axes_0d(index) > 0))) {
- return self->descr->f->setitem(op, self->data, self);
- }
- if (PyBool_Check(index) || PyArray_IsScalar(index, Bool) ||
- (PyArray_Check(index) && (PyArray_DIMS(index)==0) &&
- PyArray_ISBOOL(index))) {
- if (PyObject_IsTrue(index)) {
- return self->descr->f->setitem(op, self->data, self);
- }
- else { /* don't do anything */
- return 0;
- }
- }
- PyErr_SetString(PyExc_IndexError, "0-d arrays can't be indexed.");
- return -1;
- }
-
- /* optimization for integer-tuple */
- if (self->nd > 1 &&
- (PyTuple_Check(index) && (PyTuple_GET_SIZE(index) == self->nd))
- && (_tuple_of_integers(index, vals, self->nd) >= 0)) {
- int i;
- char *item;
-
- for (i = 0; i < self->nd; i++) {
- if (vals[i] < 0) {
- vals[i] += self->dimensions[i];
- }
- if ((vals[i] < 0) || (vals[i] >= self->dimensions[i])) {
- PyErr_Format(PyExc_IndexError,
- "index (%"INTP_FMT") out of range "\
- "(0<=index<%"INTP_FMT") in dimension %d",
- vals[i], self->dimensions[i], i);
- return -1;
- }
- }
- item = PyArray_GetPtr(self, vals);
- return self->descr->f->setitem(op, item, self);
- }
- PyErr_Clear();
-
- fancy = fancy_indexing_check(index);
- if (fancy != SOBJ_NOTFANCY) {
- oned = ((self->nd == 1) &&
- !(PyTuple_Check(index) && PyTuple_GET_SIZE(index) > 1));
- mit = (PyArrayMapIterObject *) PyArray_MapIterNew(index, oned, fancy);
- if (mit == NULL) {
- return -1;
- }
- 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;
- }
-
- return array_ass_sub_simple(self, index, op);
-}
-
-
-/*
- * 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)
-{
-
- PyArrayObject *mp;
- intp vals[MAX_DIMS];
-
- if (PyInt_Check(op) || PyArray_IsScalar(op, Integer) ||
- PyLong_Check(op) || (PyIndex_Check(op) &&
- !PySequence_Check(op))) {
- intp value;
- value = PyArray_PyIntAsIntp(op);
- if (PyErr_Occurred()) {
- PyErr_Clear();
- }
- else {
- return array_item_nice(self, (Py_ssize_t) value);
- }
- }
- /* optimization for a tuple of integers */
- if (self->nd > 1 && PyTuple_Check(op) &&
- (PyTuple_GET_SIZE(op) == self->nd)
- && (_tuple_of_integers(op, vals, self->nd) >= 0)) {
- int i;
- char *item;
-
- for (i = 0; i < self->nd; i++) {
- if (vals[i] < 0) {
- vals[i] += self->dimensions[i];
- }
- if ((vals[i] < 0) || (vals[i] >= self->dimensions[i])) {
- PyErr_Format(PyExc_IndexError,
- "index (%"INTP_FMT") out of range "\
- "(0<=index<%"INTP_FMT") in dimension %d",
- vals[i], self->dimensions[i], i);
- return NULL;
- }
- }
- item = PyArray_GetPtr(self, vals);
- return PyArray_Scalar(item, self->descr, (PyObject *)self);
- }
- PyErr_Clear();
-
- mp = (PyArrayObject *)array_subscript(self, op);
- /*
- * mp could be a scalar if op is not an Int, Scalar, Long or other Index
- * object and still convertable to an integer (so that the code goes to
- * array_subscript_simple). So, this cast is a bit dangerous..
- */
-
- /*
- * The following is just a copy of PyArray_Return with an
- * additional logic in the nd == 0 case.
- */
-
- if (mp == NULL) {
- return NULL;
- }
- if (PyErr_Occurred()) {
- Py_XDECREF(mp);
- return NULL;
- }
- if (PyArray_Check(mp) && mp->nd == 0) {
- Bool noellipses = TRUE;
- if ((op == Py_Ellipsis) || PyString_Check(op) || PyUnicode_Check(op)) {
- noellipses = FALSE;
- }
- else if (PyBool_Check(op) || PyArray_IsScalar(op, Bool) ||
- (PyArray_Check(op) && (PyArray_DIMS(op)==0) &&
- PyArray_ISBOOL(op))) {
- noellipses = FALSE;
- }
- else if (PySequence_Check(op)) {
- Py_ssize_t n, i;
- PyObject *temp;
-
- n = PySequence_Size(op);
- i = 0;
- while (i < n && noellipses) {
- temp = PySequence_GetItem(op, i);
- if (temp == Py_Ellipsis) {
- noellipses = FALSE;
- }
- Py_DECREF(temp);
- i++;
- }
- }
- if (noellipses) {
- PyObject *ret;
- ret = PyArray_ToScalar(mp->data, mp);
- Py_DECREF(mp);
- return ret;
- }
- }
- return (PyObject *)mp;
-}
-
-
-static PyMappingMethods array_as_mapping = {
-#if PY_VERSION_HEX >= 0x02050000
- (lenfunc)array_length, /*mp_length*/
-#else
- (inquiry)array_length, /*mp_length*/
-#endif
- (binaryfunc)array_subscript_nice, /*mp_subscript*/
- (objobjargproc)array_ass_sub, /*mp_ass_subscript*/
-};
-
-/****************** End of Mapping Protocol ******************************/
-
-
-/*************************************************************************
**************** Implement Buffer Protocol ****************************
*************************************************************************/