From 91be9a9ace3e532a40a93f0c00d71fa34adce009 Mon Sep 17 00:00:00 2001 From: David Cournapeau Date: Thu, 30 Apr 2009 08:36:59 +0000 Subject: Put number protocol and array attributes get/set in separate files. --- numpy/core/src/arrayobject.c | 5310 +++++++++++++++--------------------------- 1 file changed, 1819 insertions(+), 3491 deletions(-) (limited to 'numpy/core/src/arrayobject.c') diff --git a/numpy/core/src/arrayobject.c b/numpy/core/src/arrayobject.c index 1d9256b28..be4932551 100644 --- a/numpy/core/src/arrayobject.c +++ b/numpy/core/src/arrayobject.c @@ -34,6 +34,7 @@ maintainer email: oliphant.travis@ieee.org #include "arraydescr.h" #include "arrayiterators.h" #include "arraymapping.h" +#include "arraygetset.h" #ifndef Py_UNICODE_WIDE #include "ucsnarrow.h" #endif @@ -652,9 +653,6 @@ PyArray_PyIntAsIntp(PyObject *o) return (intp) long_value; } - -static PyObject *array_int(PyArrayObject *v); - /*NUMPY_API*/ NPY_NO_EXPORT int PyArray_PyIntAsInt(PyObject *o) @@ -2221,3900 +2219,2230 @@ static PyBufferProcs array_as_buffer = { /************************************************************************* - **************** Implement Number Protocol **************************** + **************** Implement Sequence Protocol ************************** *************************************************************************/ -NPY_NO_EXPORT NumericOps n_ops; /* NB: static objects initialized to zero */ - -/* Dictionary can contain any of the numeric operations, by name. - Those not present will not be changed +/* Some of this is repeated in the array_as_mapping protocol. But + we fill it in here so that PySequence_XXXX calls work as expected */ -#define SET(op) temp=PyDict_GetItemString(dict, #op); \ - if (temp != NULL) { \ - if (!(PyCallable_Check(temp))) return -1; \ - Py_XDECREF(n_ops.op); \ - n_ops.op = temp; \ - } - -/*NUMPY_API - Set internal structure with number functions that all arrays will use -*/ -NPY_NO_EXPORT int -PyArray_SetNumericOps(PyObject *dict) +static PyObject * +array_slice(PyArrayObject *self, Py_ssize_t ilow, + Py_ssize_t ihigh) { - PyObject *temp = NULL; - SET(add); - SET(subtract); - SET(multiply); - SET(divide); - SET(remainder); - SET(power); - SET(square); - SET(reciprocal); - SET(ones_like); - SET(sqrt); - SET(negative); - SET(absolute); - SET(invert); - SET(left_shift); - SET(right_shift); - SET(bitwise_and); - SET(bitwise_or); - SET(bitwise_xor); - SET(less); - SET(less_equal); - SET(equal); - SET(not_equal); - SET(greater); - SET(greater_equal); - SET(floor_divide); - SET(true_divide); - SET(logical_or); - SET(logical_and); - SET(floor); - SET(ceil); - SET(maximum); - SET(minimum); - SET(rint); - SET(conjugate); - return 0; -} - -#define GET(op) if (n_ops.op && \ - (PyDict_SetItemString(dict, #op, n_ops.op)==-1)) \ - goto fail; + PyArrayObject *r; + Py_ssize_t l; + char *data; -/*NUMPY_API - Get dictionary showing number functions that all arrays will use -*/ -NPY_NO_EXPORT PyObject * -PyArray_GetNumericOps(void) -{ - PyObject *dict; - if ((dict = PyDict_New())==NULL) + if (self->nd == 0) { + PyErr_SetString(PyExc_ValueError, "cannot slice a 0-d array"); return NULL; - GET(add); - GET(subtract); - GET(multiply); - GET(divide); - GET(remainder); - GET(power); - GET(square); - GET(reciprocal); - GET(ones_like); - GET(sqrt); - GET(negative); - GET(absolute); - GET(invert); - GET(left_shift); - GET(right_shift); - GET(bitwise_and); - GET(bitwise_or); - GET(bitwise_xor); - GET(less); - GET(less_equal); - GET(equal); - GET(not_equal); - GET(greater); - GET(greater_equal); - GET(floor_divide); - GET(true_divide); - GET(logical_or); - GET(logical_and); - GET(floor); - GET(ceil); - GET(maximum); - GET(minimum); - GET(rint); - GET(conjugate); - return dict; + } - fail: - Py_DECREF(dict); - return NULL; -} + l=self->dimensions[0]; + if (ilow < 0) { + ilow = 0; + } + else if (ilow > l) { + ilow = l; + } + if (ihigh < ilow) { + ihigh = ilow; + } + else if (ihigh > l) { + ihigh = l; + } -static PyObject * -_get_keywords(int rtype, PyArrayObject *out) -{ - PyObject *kwds = NULL; - if (rtype != PyArray_NOTYPE || out != NULL) { - kwds = PyDict_New(); - if (rtype != PyArray_NOTYPE) { - PyArray_Descr *descr; - descr = PyArray_DescrFromType(rtype); - if (descr) { - PyDict_SetItemString(kwds, "dtype", (PyObject *)descr); - Py_DECREF(descr); - } - } - if (out != NULL) { - PyDict_SetItemString(kwds, "out", (PyObject *)out); + if (ihigh != ilow) { + data = index2ptr(self, ilow); + if (data == NULL) { + return NULL; } } - return kwds; -} - -NPY_NO_EXPORT PyObject * -PyArray_GenericReduceFunction(PyArrayObject *m1, PyObject *op, int axis, - int rtype, PyArrayObject *out) -{ - PyObject *args, *ret = NULL, *meth; - PyObject *kwds; - if (op == NULL) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; + else { + data = self->data; } - args = Py_BuildValue("(Oi)", m1, axis); - kwds = _get_keywords(rtype, out); - meth = PyObject_GetAttrString(op, "reduce"); - if (meth && PyCallable_Check(meth)) { - ret = PyObject_Call(meth, args, kwds); + + self->dimensions[0] = ihigh-ilow; + Py_INCREF(self->descr); + r = (PyArrayObject *) \ + PyArray_NewFromDescr(self->ob_type, self->descr, + self->nd, self->dimensions, + self->strides, data, + self->flags, (PyObject *)self); + self->dimensions[0] = l; + if (r == NULL) { + return NULL; } - Py_DECREF(args); - Py_DECREF(meth); - Py_XDECREF(kwds); - return ret; + r->base = (PyObject *)self; + Py_INCREF(self); + PyArray_UpdateFlags(r, UPDATE_ALL); + return (PyObject *)r; } -NPY_NO_EXPORT PyObject * -PyArray_GenericAccumulateFunction(PyArrayObject *m1, PyObject *op, int axis, - int rtype, PyArrayObject *out) -{ - PyObject *args, *ret = NULL, *meth; - PyObject *kwds; - if (op == NULL) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; +static int +array_ass_slice(PyArrayObject *self, Py_ssize_t ilow, + Py_ssize_t ihigh, PyObject *v) { + int ret; + PyArrayObject *tmp; + + if (v == NULL) { + PyErr_SetString(PyExc_ValueError, + "cannot delete array elements"); + return -1; } - args = Py_BuildValue("(Oi)", m1, axis); - kwds = _get_keywords(rtype, out); - meth = PyObject_GetAttrString(op, "accumulate"); - if (meth && PyCallable_Check(meth)) { - ret = PyObject_Call(meth, args, kwds); + if (!PyArray_ISWRITEABLE(self)) { + PyErr_SetString(PyExc_RuntimeError, + "array is not writeable"); + return -1; } - Py_DECREF(args); - Py_DECREF(meth); - Py_XDECREF(kwds); - return ret; -} - - -NPY_NO_EXPORT PyObject * -PyArray_GenericBinaryFunction(PyArrayObject *m1, PyObject *m2, PyObject *op) -{ - if (op == NULL) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; + if ((tmp = (PyArrayObject *)array_slice(self, ilow, ihigh)) == NULL) { + return -1; } - return PyObject_CallFunction(op, "OO", m1, m2); -} + ret = PyArray_CopyObject(tmp, v); + Py_DECREF(tmp); -NPY_NO_EXPORT PyObject * -PyArray_GenericUnaryFunction(PyArrayObject *m1, PyObject *op) -{ - if (op == NULL) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return PyObject_CallFunction(op, "(O)", m1); + return ret; } -static PyObject * -PyArray_GenericInplaceBinaryFunction(PyArrayObject *m1, - PyObject *m2, PyObject *op) +static int +array_contains(PyArrayObject *self, PyObject *el) { - if (op == NULL) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return PyObject_CallFunction(op, "OOO", m1, m2, m1); -} + /* equivalent to (self == el).any() */ -static PyObject * -PyArray_GenericInplaceUnaryFunction(PyArrayObject *m1, PyObject *op) -{ - if (op == NULL) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return PyObject_CallFunction(op, "OO", m1, m1); -} + PyObject *res; + int ret; -static PyObject * -array_add(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.add); + res = PyArray_EnsureAnyArray(PyObject_RichCompare((PyObject *)self, + el, Py_EQ)); + if (res == NULL) { + return -1; + } + ret = array_any_nonzero((PyArrayObject *)res); + Py_DECREF(res); + return ret; } -static PyObject * -array_subtract(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.subtract); -} +static PySequenceMethods array_as_sequence = { +#if PY_VERSION_HEX >= 0x02050000 + (lenfunc)array_length, /*sq_length*/ + (binaryfunc)NULL, /*sq_concat is handled by nb_add*/ + (ssizeargfunc)NULL, + (ssizeargfunc)array_item_nice, + (ssizessizeargfunc)array_slice, + (ssizeobjargproc)array_ass_item, /*sq_ass_item*/ + (ssizessizeobjargproc)array_ass_slice, /*sq_ass_slice*/ + (objobjproc) array_contains, /*sq_contains */ + (binaryfunc) NULL, /*sg_inplace_concat */ + (ssizeargfunc)NULL, +#else + (inquiry)array_length, /*sq_length*/ + (binaryfunc)NULL, /*sq_concat is handled by nb_add*/ + (intargfunc)NULL, /*sq_repeat is handled nb_multiply*/ + (intargfunc)array_item_nice, /*sq_item*/ + (intintargfunc)array_slice, /*sq_slice*/ + (intobjargproc)array_ass_item, /*sq_ass_item*/ + (intintobjargproc)array_ass_slice, /*sq_ass_slice*/ + (objobjproc) array_contains, /*sq_contains */ + (binaryfunc) NULL, /*sg_inplace_concat */ + (intargfunc) NULL /*sg_inplace_repeat */ +#endif +}; -static PyObject * -array_multiply(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.multiply); -} -static PyObject * -array_divide(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.divide); -} +/****************** End of Sequence Protocol ****************************/ -static PyObject * -array_remainder(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.remainder); -} static int -array_power_is_scalar(PyObject *o2, double* exp) +dump_data(char **string, int *n, int *max_n, char *data, int nd, + intp *dimensions, intp *strides, PyArrayObject* self) { - PyObject *temp; - const int optimize_fpexps = 1; + PyArray_Descr *descr=self->descr; + PyObject *op, *sp; + char *ostring; + intp i, N; - if (PyInt_Check(o2)) { - *exp = (double)PyInt_AsLong(o2); - return 1; - } - if (optimize_fpexps && PyFloat_Check(o2)) { - *exp = PyFloat_AsDouble(o2); - return 1; - } - if ((PyArray_IsZeroDim(o2) && - ((PyArray_ISINTEGER(o2) || - (optimize_fpexps && PyArray_ISFLOAT(o2))))) || - PyArray_IsScalar(o2, Integer) || - (optimize_fpexps && PyArray_IsScalar(o2, Floating))) { - temp = o2->ob_type->tp_as_number->nb_float(o2); - if (temp != NULL) { - *exp = PyFloat_AsDouble(o2); - Py_DECREF(temp); - return 1; +#define CHECK_MEMORY do { if (*n >= *max_n-16) { \ + *max_n *= 2; \ + *string = (char *)_pya_realloc(*string, *max_n); \ + }} while (0) + + if (nd == 0) { + if ((op = descr->f->getitem(data, self)) == NULL) { + return -1; + } + sp = PyObject_Repr(op); + if (sp == NULL) { + Py_DECREF(op); + return -1; } + ostring = PyString_AsString(sp); + N = PyString_Size(sp)*sizeof(char); + *n += N; + CHECK_MEMORY; + memmove(*string + (*n - N), ostring, N); + Py_DECREF(sp); + Py_DECREF(op); + return 0; } -#if (PY_VERSION_HEX >= 0x02050000) - if (PyIndex_Check(o2)) { - PyObject* value = PyNumber_Index(o2); - Py_ssize_t val; - if (value==NULL) { - if (PyErr_Occurred()) { - PyErr_Clear(); + else { + CHECK_MEMORY; + (*string)[*n] = '['; + *n += 1; + for (i = 0; i < dimensions[0]; i++) { + if (dump_data(string, n, max_n, + data + (*strides)*i, + nd - 1, dimensions + 1, + strides + 1, self) < 0) { + return -1; + } + CHECK_MEMORY; + if (i < dimensions[0] - 1) { + (*string)[*n] = ','; + (*string)[*n+1] = ' '; + *n += 2; } - return 0; - } - val = PyInt_AsSsize_t(value); - if (val == -1 && PyErr_Occurred()) { - PyErr_Clear(); - return 0; } - *exp = (double) val; - return 1; + CHECK_MEMORY; + (*string)[*n] = ']'; + *n += 1; + return 0; } -#endif - return 0; + +#undef CHECK_MEMORY } -/* optimize float array or complex array to a scalar power */ static PyObject * -fast_scalar_power(PyArrayObject *a1, PyObject *o2, int inplace) +array_repr_builtin(PyArrayObject *self, int repr) { - double exp; - - if (PyArray_Check(a1) && array_power_is_scalar(o2, &exp)) { - PyObject *fastop = NULL; - if (PyArray_ISFLOAT(a1) || PyArray_ISCOMPLEX(a1)) { - if (exp == 1.0) { - /* we have to do this one special, as the - "copy" method of array objects isn't set - up early enough to be added - by PyArray_SetNumericOps. - */ - if (inplace) { - Py_INCREF(a1); - return (PyObject *)a1; - } else { - return PyArray_Copy(a1); - } - } - else if (exp == -1.0) { - fastop = n_ops.reciprocal; - } - else if (exp == 0.0) { - fastop = n_ops.ones_like; - } - else if (exp == 0.5) { - fastop = n_ops.sqrt; - } - else if (exp == 2.0) { - fastop = n_ops.square; - } - else { - return NULL; - } + PyObject *ret; + char *string; + int n, max_n; - if (inplace) { - return PyArray_GenericInplaceUnaryFunction(a1, fastop); - } else { - return PyArray_GenericUnaryFunction(a1, fastop); - } - } - else if (exp==2.0) { - fastop = n_ops.multiply; - if (inplace) { - return PyArray_GenericInplaceBinaryFunction - (a1, (PyObject *)a1, fastop); - } - else { - return PyArray_GenericBinaryFunction - (a1, (PyObject *)a1, fastop); - } - } - } - return NULL; -} + max_n = PyArray_NBYTES(self)*4*sizeof(char) + 7; -static PyObject * -array_power(PyArrayObject *a1, PyObject *o2, PyObject *NPY_UNUSED(modulo)) -{ - /* modulo is ignored! */ - PyObject *value; - value = fast_scalar_power(a1, o2, 0); - if (!value) { - value = PyArray_GenericBinaryFunction(a1, o2, n_ops.power); + if ((string = (char *)_pya_malloc(max_n)) == NULL) { + PyErr_SetString(PyExc_MemoryError, "out of memory"); + return NULL; } - return value; -} - - -static PyObject * -array_negative(PyArrayObject *m1) -{ - return PyArray_GenericUnaryFunction(m1, n_ops.negative); -} - -static PyObject * -array_absolute(PyArrayObject *m1) -{ - return PyArray_GenericUnaryFunction(m1, n_ops.absolute); -} - -static PyObject * -array_invert(PyArrayObject *m1) -{ - return PyArray_GenericUnaryFunction(m1, n_ops.invert); -} - -static PyObject * -array_left_shift(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.left_shift); -} -static PyObject * -array_right_shift(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.right_shift); -} - -static PyObject * -array_bitwise_and(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_and); -} - -static PyObject * -array_bitwise_or(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_or); -} - -static PyObject * -array_bitwise_xor(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_xor); -} + if (repr) { + n = 6; + sprintf(string, "array("); + } + else { + n = 0; + } + if (dump_data(&string, &n, &max_n, self->data, + self->nd, self->dimensions, + self->strides, self) < 0) { + _pya_free(string); + return NULL; + } -static PyObject * -array_inplace_add(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.add); -} + if (repr) { + if (PyArray_ISEXTENDED(self)) { + char buf[100]; + PyOS_snprintf(buf, sizeof(buf), "%d", self->descr->elsize); + sprintf(string+n, ", '%c%s')", self->descr->type, buf); + ret = PyString_FromStringAndSize(string, n + 6 + strlen(buf)); + } + else { + sprintf(string+n, ", '%c')", self->descr->type); + ret = PyString_FromStringAndSize(string, n+6); + } + } + else { + ret = PyString_FromStringAndSize(string, n); + } -static PyObject * -array_inplace_subtract(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.subtract); + _pya_free(string); + return ret; } -static PyObject * -array_inplace_multiply(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.multiply); -} +static PyObject *PyArray_StrFunction = NULL; +static PyObject *PyArray_ReprFunction = NULL; -static PyObject * -array_inplace_divide(PyArrayObject *m1, PyObject *m2) +/*NUMPY_API + * Set the array print function to be a Python function. + */ +NPY_NO_EXPORT void +PyArray_SetStringFunction(PyObject *op, int repr) { - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.divide); + if (repr) { + /* Dispose of previous callback */ + Py_XDECREF(PyArray_ReprFunction); + /* Add a reference to new callback */ + Py_XINCREF(op); + /* Remember new callback */ + PyArray_ReprFunction = op; + } + else { + /* Dispose of previous callback */ + Py_XDECREF(PyArray_StrFunction); + /* Add a reference to new callback */ + Py_XINCREF(op); + /* Remember new callback */ + PyArray_StrFunction = op; + } } static PyObject * -array_inplace_remainder(PyArrayObject *m1, PyObject *m2) +array_repr(PyArrayObject *self) { - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.remainder); -} + PyObject *s, *arglist; -static PyObject * -array_inplace_power(PyArrayObject *a1, PyObject *o2, PyObject *NPY_UNUSED(modulo)) -{ - /* modulo is ignored! */ - PyObject *value; - value = fast_scalar_power(a1, o2, 1); - if (!value) { - value = PyArray_GenericInplaceBinaryFunction(a1, o2, n_ops.power); + if (PyArray_ReprFunction == NULL) { + s = array_repr_builtin(self, 1); } - return value; -} - -static PyObject * -array_inplace_left_shift(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.left_shift); + else { + arglist = Py_BuildValue("(O)", self); + s = PyEval_CallObject(PyArray_ReprFunction, arglist); + Py_DECREF(arglist); + } + return s; } static PyObject * -array_inplace_right_shift(PyArrayObject *m1, PyObject *m2) +array_str(PyArrayObject *self) { - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.right_shift); -} + PyObject *s, *arglist; -static PyObject * -array_inplace_bitwise_and(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_and); + if (PyArray_StrFunction == NULL) { + s = array_repr_builtin(self, 0); + } + else { + arglist = Py_BuildValue("(O)", self); + s = PyEval_CallObject(PyArray_StrFunction, arglist); + Py_DECREF(arglist); + } + return s; } -static PyObject * -array_inplace_bitwise_or(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_or); -} -static PyObject * -array_inplace_bitwise_xor(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_xor); -} -static PyObject * -array_floor_divide(PyArrayObject *m1, PyObject *m2) +/*NUMPY_API + */ +NPY_NO_EXPORT int +PyArray_CompareUCS4(npy_ucs4 *s1, npy_ucs4 *s2, size_t len) { - return PyArray_GenericBinaryFunction(m1, m2, n_ops.floor_divide); + PyArray_UCS4 c1, c2; + while(len-- > 0) { + c1 = *s1++; + c2 = *s2++; + if (c1 != c2) { + return (c1 < c2) ? -1 : 1; + } + } + return 0; } -static PyObject * -array_true_divide(PyArrayObject *m1, PyObject *m2) +/*NUMPY_API + */ +NPY_NO_EXPORT int +PyArray_CompareString(char *s1, char *s2, size_t len) { - return PyArray_GenericBinaryFunction(m1, m2, n_ops.true_divide); -} + const unsigned char *c1 = (unsigned char *)s1; + const unsigned char *c2 = (unsigned char *)s2; + size_t i; -static PyObject * -array_inplace_floor_divide(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, - n_ops.floor_divide); + for(i = 0; i < len; ++i) { + if (c1[i] != c2[i]) { + return (c1[i] > c2[i]) ? 1 : -1; + } + } + return 0; } -static PyObject * -array_inplace_true_divide(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, - n_ops.true_divide); -} -/* Array evaluates as "TRUE" if any of the elements are non-zero*/ +/* This also handles possibly mis-aligned data */ +/* Compare s1 and s2 which are not necessarily NULL-terminated. + s1 is of length len1 + s2 is of length len2 + If they are NULL terminated, then stop comparison. +*/ static int -array_any_nonzero(PyArrayObject *mp) +_myunincmp(PyArray_UCS4 *s1, PyArray_UCS4 *s2, int len1, int len2) { - intp index; - PyArrayIterObject *it; - Bool anyTRUE = FALSE; + PyArray_UCS4 *sptr; + PyArray_UCS4 *s1t=s1, *s2t=s2; + int val; + intp size; + int diff; - it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp); - if (it == NULL) { - return anyTRUE; + if ((intp)s1 % sizeof(PyArray_UCS4) != 0) { + size = len1*sizeof(PyArray_UCS4); + s1t = malloc(size); + memcpy(s1t, s1, size); } - index = it->size; - while(index--) { - if (mp->descr->f->nonzero(it->dataptr, mp)) { - anyTRUE = TRUE; - break; - } - PyArray_ITER_NEXT(it); + if ((intp)s2 % sizeof(PyArray_UCS4) != 0) { + size = len2*sizeof(PyArray_UCS4); + s2t = malloc(size); + memcpy(s2t, s2, size); } - Py_DECREF(it); - return anyTRUE; -} - -static int -_array_nonzero(PyArrayObject *mp) -{ - intp n; - - n = PyArray_SIZE(mp); - if (n == 1) { - return mp->descr->f->nonzero(mp->data, mp); + val = PyArray_CompareUCS4(s1t, s2t, MIN(len1,len2)); + if ((val != 0) || (len1 == len2)) { + goto finish; } - else if (n == 0) { - return 0; + if (len2 > len1) { + sptr = s2t+len1; + val = -1; + diff = len2-len1; } else { - PyErr_SetString(PyExc_ValueError, - "The truth value of an array " \ - "with more than one element is ambiguous. " \ - "Use a.any() or a.all()"); - return -1; + sptr = s1t+len2; + val = 1; + diff=len1-len2; } -} - - - -static PyObject * -array_divmod(PyArrayObject *op1, PyObject *op2) -{ - PyObject *divp, *modp, *result; + while (diff--) { + if (*sptr != 0) { + goto finish; + } + sptr++; + } + val = 0; - divp = array_floor_divide(op1, op2); - if (divp == NULL) { - return NULL; + finish: + if (s1t != s1) { + free(s1t); } - modp = array_remainder(op1, op2); - if (modp == NULL) { - Py_DECREF(divp); - return NULL; + if (s2t != s2) { + free(s2t); } - result = Py_BuildValue("OO", divp, modp); - Py_DECREF(divp); - Py_DECREF(modp); - return result; + return val; } -static PyObject * -array_int(PyArrayObject *v) -{ - PyObject *pv, *pv2; - if (PyArray_SIZE(v) != 1) { - PyErr_SetString(PyExc_TypeError, "only length-1 arrays can be"\ - " converted to Python scalars"); - return NULL; - } - pv = v->descr->f->getitem(v->data, v); - if (pv == NULL) { - return NULL; - } - if (pv->ob_type->tp_as_number == 0) { - PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\ - "scalar object is not a number"); - Py_DECREF(pv); - return NULL; - } - if (pv->ob_type->tp_as_number->nb_int == 0) { - PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ - "scalar number to int"); - Py_DECREF(pv); - return NULL; - } - pv2 = pv->ob_type->tp_as_number->nb_int(pv); - Py_DECREF(pv); - return pv2; -} -static PyObject * -array_float(PyArrayObject *v) +/* + * Compare s1 and s2 which are not necessarily NULL-terminated. + * s1 is of length len1 + * s2 is of length len2 + * If they are NULL terminated, then stop comparison. + */ +static int +_mystrncmp(char *s1, char *s2, int len1, int len2) { - PyObject *pv, *pv2; - if (PyArray_SIZE(v) != 1) { - PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\ - "be converted to Python scalars"); - return NULL; + char *sptr; + int val; + int diff; + + val = memcmp(s1, s2, MIN(len1, len2)); + if ((val != 0) || (len1 == len2)) { + return val; } - pv = v->descr->f->getitem(v->data, v); - if (pv == NULL) { - return NULL; + if (len2 > len1) { + sptr = s2 + len1; + val = -1; + diff = len2 - len1; } - if (pv->ob_type->tp_as_number == 0) { - PyErr_SetString(PyExc_TypeError, "cannot convert to a "\ - "float; scalar object is not a number"); - Py_DECREF(pv); - return NULL; + else { + sptr = s1 + len2; + val = 1; + diff = len1 - len2; } - if (pv->ob_type->tp_as_number->nb_float == 0) { - PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ - "scalar number to float"); - Py_DECREF(pv); - return NULL; + while (diff--) { + if (*sptr != 0) { + return val; + } + sptr++; } - pv2 = pv->ob_type->tp_as_number->nb_float(pv); - Py_DECREF(pv); - return pv2; + return 0; /* Only happens if NULLs are everywhere */ } -static PyObject * -array_long(PyArrayObject *v) -{ - PyObject *pv, *pv2; - if (PyArray_SIZE(v) != 1) { - PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\ - "be converted to Python scalars"); - return NULL; - } - pv = v->descr->f->getitem(v->data, v); - if (pv->ob_type->tp_as_number == 0) { - PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\ - "scalar object is not a number"); - return NULL; - } - if (pv->ob_type->tp_as_number->nb_long == 0) { - PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ - "scalar number to long"); - return NULL; - } - pv2 = pv->ob_type->tp_as_number->nb_long(pv); - Py_DECREF(pv); - return pv2; -} +/* Borrowed from Numarray */ -static PyObject * -array_oct(PyArrayObject *v) +#define SMALL_STRING 2048 + +#if defined(isspace) +#undef isspace +#define isspace(c) ((c==' ')||(c=='\t')||(c=='\n')||(c=='\r')||(c=='\v')||(c=='\f')) +#endif + +static void _rstripw(char *s, int n) { - PyObject *pv, *pv2; - if (PyArray_SIZE(v) != 1) { - PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\ - "be converted to Python scalars"); - return NULL; - } - pv = v->descr->f->getitem(v->data, v); - if (pv->ob_type->tp_as_number == 0) { - PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\ - "scalar object is not a number"); - return NULL; - } - if (pv->ob_type->tp_as_number->nb_oct == 0) { - PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ - "scalar number to oct"); - return NULL; + int i; + for (i = n - 1; i >= 1; i--) { /* Never strip to length 0. */ + int c = s[i]; + + if (!c || isspace(c)) { + s[i] = 0; + } + else { + break; + } } - pv2 = pv->ob_type->tp_as_number->nb_oct(pv); - Py_DECREF(pv); - return pv2; } -static PyObject * -array_hex(PyArrayObject *v) +static void _unistripw(PyArray_UCS4 *s, int n) { - PyObject *pv, *pv2; - if (PyArray_SIZE(v) != 1) { - PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\ - "be converted to Python scalars"); - return NULL; - } - pv = v->descr->f->getitem(v->data, v); - if (pv->ob_type->tp_as_number == 0) { - PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\ - "scalar object is not a number"); - return NULL; - } - if (pv->ob_type->tp_as_number->nb_hex == 0) { - PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ - "scalar number to hex"); - return NULL; + int i; + for (i = n - 1; i >= 1; i--) { /* Never strip to length 0. */ + PyArray_UCS4 c = s[i]; + if (!c || isspace(c)) { + s[i] = 0; + } + else { + break; + } } - pv2 = pv->ob_type->tp_as_number->nb_hex(pv); - Py_DECREF(pv); - return pv2; } -static PyObject * -_array_copy_nice(PyArrayObject *self) -{ - return PyArray_Return((PyArrayObject *) PyArray_Copy(self)); -} -#if PY_VERSION_HEX >= 0x02050000 -static PyObject * -array_index(PyArrayObject *v) +static char * +_char_copy_n_strip(char *original, char *temp, int nc) { - if (!PyArray_ISINTEGER(v) || PyArray_SIZE(v) != 1) { - PyErr_SetString(PyExc_TypeError, "only integer arrays with " \ - "one element can be converted to an index"); - return NULL; + if (nc > SMALL_STRING) { + temp = malloc(nc); + if (!temp) { + PyErr_NoMemory(); + return NULL; + } } - return v->descr->f->getitem(v->data, v); + memcpy(temp, original, nc); + _rstripw(temp, nc); + return temp; } -#endif - - -static PyNumberMethods array_as_number = { - (binaryfunc)array_add, /*nb_add*/ - (binaryfunc)array_subtract, /*nb_subtract*/ - (binaryfunc)array_multiply, /*nb_multiply*/ - (binaryfunc)array_divide, /*nb_divide*/ - (binaryfunc)array_remainder, /*nb_remainder*/ - (binaryfunc)array_divmod, /*nb_divmod*/ - (ternaryfunc)array_power, /*nb_power*/ - (unaryfunc)array_negative, /*nb_neg*/ - (unaryfunc)_array_copy_nice, /*nb_pos*/ - (unaryfunc)array_absolute, /*(unaryfunc)array_abs,*/ - (inquiry)_array_nonzero, /*nb_nonzero*/ - (unaryfunc)array_invert, /*nb_invert*/ - (binaryfunc)array_left_shift, /*nb_lshift*/ - (binaryfunc)array_right_shift, /*nb_rshift*/ - (binaryfunc)array_bitwise_and, /*nb_and*/ - (binaryfunc)array_bitwise_xor, /*nb_xor*/ - (binaryfunc)array_bitwise_or, /*nb_or*/ - 0, /*nb_coerce*/ - (unaryfunc)array_int, /*nb_int*/ - (unaryfunc)array_long, /*nb_long*/ - (unaryfunc)array_float, /*nb_float*/ - (unaryfunc)array_oct, /*nb_oct*/ - (unaryfunc)array_hex, /*nb_hex*/ - - /* - * This code adds augmented assignment functionality - * that was made available in Python 2.0 - */ - (binaryfunc)array_inplace_add, /*inplace_add*/ - (binaryfunc)array_inplace_subtract, /*inplace_subtract*/ - (binaryfunc)array_inplace_multiply, /*inplace_multiply*/ - (binaryfunc)array_inplace_divide, /*inplace_divide*/ - (binaryfunc)array_inplace_remainder, /*inplace_remainder*/ - (ternaryfunc)array_inplace_power, /*inplace_power*/ - (binaryfunc)array_inplace_left_shift, /*inplace_lshift*/ - (binaryfunc)array_inplace_right_shift, /*inplace_rshift*/ - (binaryfunc)array_inplace_bitwise_and, /*inplace_and*/ - (binaryfunc)array_inplace_bitwise_xor, /*inplace_xor*/ - (binaryfunc)array_inplace_bitwise_or, /*inplace_or*/ - - (binaryfunc)array_floor_divide, /*nb_floor_divide*/ - (binaryfunc)array_true_divide, /*nb_true_divide*/ - (binaryfunc)array_inplace_floor_divide, /*nb_inplace_floor_divide*/ - (binaryfunc)array_inplace_true_divide, /*nb_inplace_true_divide*/ - -#if PY_VERSION_HEX >= 0x02050000 - (unaryfunc)array_index, /* nb_index */ -#endif -}; - -/****************** End of Buffer Protocol *******************************/ - - -/************************************************************************* - **************** Implement Sequence Protocol ************************** - *************************************************************************/ - -/* Some of this is repeated in the array_as_mapping protocol. But - we fill it in here so that PySequence_XXXX calls work as expected -*/ - - -static PyObject * -array_slice(PyArrayObject *self, Py_ssize_t ilow, - Py_ssize_t ihigh) +static void +_char_release(char *ptr, int nc) { - PyArrayObject *r; - Py_ssize_t l; - char *data; - - if (self->nd == 0) { - PyErr_SetString(PyExc_ValueError, "cannot slice a 0-d array"); - return NULL; - } - - l=self->dimensions[0]; - if (ilow < 0) { - ilow = 0; - } - else if (ilow > l) { - ilow = l; - } - if (ihigh < ilow) { - ihigh = ilow; - } - else if (ihigh > l) { - ihigh = l; + if (nc > SMALL_STRING) { + free(ptr); } +} - if (ihigh != ilow) { - data = index2ptr(self, ilow); - if (data == NULL) { +static char * +_uni_copy_n_strip(char *original, char *temp, int nc) +{ + if (nc*sizeof(PyArray_UCS4) > SMALL_STRING) { + temp = malloc(nc*sizeof(PyArray_UCS4)); + if (!temp) { + PyErr_NoMemory(); return NULL; } } - else { - data = self->data; - } + memcpy(temp, original, nc*sizeof(PyArray_UCS4)); + _unistripw((PyArray_UCS4 *)temp, nc); + return temp; +} - self->dimensions[0] = ihigh-ilow; - Py_INCREF(self->descr); - r = (PyArrayObject *) \ - PyArray_NewFromDescr(self->ob_type, self->descr, - self->nd, self->dimensions, - self->strides, data, - self->flags, (PyObject *)self); - self->dimensions[0] = l; - if (r == NULL) { - return NULL; +static void +_uni_release(char *ptr, int nc) +{ + if (nc*sizeof(PyArray_UCS4) > SMALL_STRING) { + free(ptr); } - r->base = (PyObject *)self; - Py_INCREF(self); - PyArray_UpdateFlags(r, UPDATE_ALL); - return (PyObject *)r; } -static int -array_ass_slice(PyArrayObject *self, Py_ssize_t ilow, - Py_ssize_t ihigh, PyObject *v) { - int ret; - PyArrayObject *tmp; +/* End borrowed from numarray */ - if (v == NULL) { - PyErr_SetString(PyExc_ValueError, - "cannot delete array elements"); - return -1; - } - if (!PyArray_ISWRITEABLE(self)) { - PyErr_SetString(PyExc_RuntimeError, - "array is not writeable"); - return -1; +#define _rstrip_loop(CMP) { \ + void *aptr, *bptr; \ + char atemp[SMALL_STRING], btemp[SMALL_STRING]; \ + while(size--) { \ + aptr = stripfunc(iself->dataptr, atemp, N1); \ + if (!aptr) return -1; \ + bptr = stripfunc(iother->dataptr, btemp, N2); \ + if (!bptr) { \ + relfunc(aptr, N1); \ + return -1; \ + } \ + val = cmpfunc(aptr, bptr, N1, N2); \ + *dptr = (val CMP 0); \ + PyArray_ITER_NEXT(iself); \ + PyArray_ITER_NEXT(iother); \ + dptr += 1; \ + relfunc(aptr, N1); \ + relfunc(bptr, N2); \ + } \ } - if ((tmp = (PyArrayObject *)array_slice(self, ilow, ihigh)) == NULL) { - return -1; + +#define _reg_loop(CMP) { \ + while(size--) { \ + val = cmpfunc((void *)iself->dataptr, \ + (void *)iother->dataptr, \ + N1, N2); \ + *dptr = (val CMP 0); \ + PyArray_ITER_NEXT(iself); \ + PyArray_ITER_NEXT(iother); \ + dptr += 1; \ + } \ } - ret = PyArray_CopyObject(tmp, v); - Py_DECREF(tmp); - return ret; -} +#define _loop(CMP) if (rstrip) _rstrip_loop(CMP) \ + else _reg_loop(CMP) static int -array_contains(PyArrayObject *self, PyObject *el) +_compare_strings(PyObject *result, PyArrayMultiIterObject *multi, + int cmp_op, void *func, int rstrip) { - /* equivalent to (self == el).any() */ + PyArrayIterObject *iself, *iother; + Bool *dptr; + intp size; + int val; + int N1, N2; + int (*cmpfunc)(void *, void *, int, int); + void (*relfunc)(char *, int); + char* (*stripfunc)(char *, char *, int); - PyObject *res; - int ret; - - res = PyArray_EnsureAnyArray(PyObject_RichCompare((PyObject *)self, - el, Py_EQ)); - if (res == NULL) { + cmpfunc = func; + dptr = (Bool *)PyArray_DATA(result); + iself = multi->iters[0]; + iother = multi->iters[1]; + size = multi->size; + N1 = iself->ao->descr->elsize; + N2 = iother->ao->descr->elsize; + if ((void *)cmpfunc == (void *)_myunincmp) { + N1 >>= 2; + N2 >>= 2; + stripfunc = _uni_copy_n_strip; + relfunc = _uni_release; + } + else { + stripfunc = _char_copy_n_strip; + relfunc = _char_release; + } + switch (cmp_op) { + case Py_EQ: + _loop(==) + break; + case Py_NE: + _loop(!=) + break; + case Py_LT: + _loop(<) + break; + case Py_LE: + _loop(<=) + break; + case Py_GT: + _loop(>) + break; + case Py_GE: + _loop(>=) + break; + default: + PyErr_SetString(PyExc_RuntimeError, "bad comparison operator"); return -1; } - ret = array_any_nonzero((PyArrayObject *)res); - Py_DECREF(res); - return ret; + return 0; } -static PySequenceMethods array_as_sequence = { -#if PY_VERSION_HEX >= 0x02050000 - (lenfunc)array_length, /*sq_length*/ - (binaryfunc)NULL, /*sq_concat is handled by nb_add*/ - (ssizeargfunc)NULL, - (ssizeargfunc)array_item_nice, - (ssizessizeargfunc)array_slice, - (ssizeobjargproc)array_ass_item, /*sq_ass_item*/ - (ssizessizeobjargproc)array_ass_slice, /*sq_ass_slice*/ - (objobjproc) array_contains, /*sq_contains */ - (binaryfunc) NULL, /*sg_inplace_concat */ - (ssizeargfunc)NULL, -#else - (inquiry)array_length, /*sq_length*/ - (binaryfunc)NULL, /*sq_concat is handled by nb_add*/ - (intargfunc)NULL, /*sq_repeat is handled nb_multiply*/ - (intargfunc)array_item_nice, /*sq_item*/ - (intintargfunc)array_slice, /*sq_slice*/ - (intobjargproc)array_ass_item, /*sq_ass_item*/ - (intintobjargproc)array_ass_slice, /*sq_ass_slice*/ - (objobjproc) array_contains, /*sq_contains */ - (binaryfunc) NULL, /*sg_inplace_concat */ - (intargfunc) NULL /*sg_inplace_repeat */ -#endif -}; - - -/****************** End of Sequence Protocol ****************************/ - +#undef _loop +#undef _reg_loop +#undef _rstrip_loop +#undef SMALL_STRING -static int -dump_data(char **string, int *n, int *max_n, char *data, int nd, - intp *dimensions, intp *strides, PyArrayObject* self) +NPY_NO_EXPORT PyObject * +_strings_richcompare(PyArrayObject *self, PyArrayObject *other, int cmp_op, + int rstrip) { - PyArray_Descr *descr=self->descr; - PyObject *op, *sp; - char *ostring; - intp i, N; - -#define CHECK_MEMORY do { if (*n >= *max_n-16) { \ - *max_n *= 2; \ - *string = (char *)_pya_realloc(*string, *max_n); \ - }} while (0) + PyObject *result; + PyArrayMultiIterObject *mit; + int val; - if (nd == 0) { - if ((op = descr->f->getitem(data, self)) == NULL) { - return -1; + /* Cast arrays to a common type */ + if (self->descr->type_num != other->descr->type_num) { + PyObject *new; + if (self->descr->type_num == PyArray_STRING && + other->descr->type_num == PyArray_UNICODE) { + Py_INCREF(other->descr); + new = PyArray_FromAny((PyObject *)self, other->descr, + 0, 0, 0, NULL); + if (new == NULL) { + return NULL; + } + Py_INCREF(other); + self = (PyArrayObject *)new; } - sp = PyObject_Repr(op); - if (sp == NULL) { - Py_DECREF(op); - return -1; + else if (self->descr->type_num == PyArray_UNICODE && + other->descr->type_num == PyArray_STRING) { + Py_INCREF(self->descr); + new = PyArray_FromAny((PyObject *)other, self->descr, + 0, 0, 0, NULL); + if (new == NULL) { + return NULL; + } + Py_INCREF(self); + other = (PyArrayObject *)new; + } + else { + PyErr_SetString(PyExc_TypeError, + "invalid string data-types " + "in comparison"); + return NULL; } - ostring = PyString_AsString(sp); - N = PyString_Size(sp)*sizeof(char); - *n += N; - CHECK_MEMORY; - memmove(*string + (*n - N), ostring, N); - Py_DECREF(sp); - Py_DECREF(op); - return 0; } else { - CHECK_MEMORY; - (*string)[*n] = '['; - *n += 1; - for (i = 0; i < dimensions[0]; i++) { - if (dump_data(string, n, max_n, - data + (*strides)*i, - nd - 1, dimensions + 1, - strides + 1, self) < 0) { - return -1; - } - CHECK_MEMORY; - if (i < dimensions[0] - 1) { - (*string)[*n] = ','; - (*string)[*n+1] = ' '; - *n += 2; - } - } - CHECK_MEMORY; - (*string)[*n] = ']'; - *n += 1; - return 0; + Py_INCREF(self); + Py_INCREF(other); } -#undef CHECK_MEMORY -} - -static PyObject * -array_repr_builtin(PyArrayObject *self, int repr) -{ - PyObject *ret; - char *string; - int n, max_n; - - max_n = PyArray_NBYTES(self)*4*sizeof(char) + 7; - - if ((string = (char *)_pya_malloc(max_n)) == NULL) { - PyErr_SetString(PyExc_MemoryError, "out of memory"); + /* Broad-cast the arrays to a common shape */ + mit = (PyArrayMultiIterObject *)PyArray_MultiIterNew(2, self, other); + Py_DECREF(self); + Py_DECREF(other); + if (mit == NULL) { return NULL; } - if (repr) { - n = 6; - sprintf(string, "array("); - } - else { - n = 0; - } - if (dump_data(&string, &n, &max_n, self->data, - self->nd, self->dimensions, - self->strides, self) < 0) { - _pya_free(string); - return NULL; + result = PyArray_NewFromDescr(&PyArray_Type, + PyArray_DescrFromType(PyArray_BOOL), + mit->nd, + mit->dimensions, + NULL, NULL, 0, + NULL); + if (result == NULL) { + goto finish; } - if (repr) { - if (PyArray_ISEXTENDED(self)) { - char buf[100]; - PyOS_snprintf(buf, sizeof(buf), "%d", self->descr->elsize); - sprintf(string+n, ", '%c%s')", self->descr->type, buf); - ret = PyString_FromStringAndSize(string, n + 6 + strlen(buf)); - } - else { - sprintf(string+n, ", '%c')", self->descr->type); - ret = PyString_FromStringAndSize(string, n+6); - } + if (self->descr->type_num == PyArray_UNICODE) { + val = _compare_strings(result, mit, cmp_op, _myunincmp, rstrip); } else { - ret = PyString_FromStringAndSize(string, n); + val = _compare_strings(result, mit, cmp_op, _mystrncmp, rstrip); } - _pya_free(string); - return ret; -} + if (val < 0) { + Py_DECREF(result); result = NULL; + } -static PyObject *PyArray_StrFunction = NULL; -static PyObject *PyArray_ReprFunction = NULL; + finish: + Py_DECREF(mit); + return result; +} -/*NUMPY_API - * Set the array print function to be a Python function. +/* + * VOID-type arrays can only be compared equal and not-equal + * in which case the fields are all compared by extracting the fields + * and testing one at a time... + * equality testing is performed using logical_ands on all the fields. + * in-equality testing is performed using logical_ors on all the fields. + * + * VOID-type arrays without fields are compared for equality by comparing their + * memory at each location directly (using string-code). */ -NPY_NO_EXPORT void -PyArray_SetStringFunction(PyObject *op, int repr) +static PyObject * +_void_compare(PyArrayObject *self, PyArrayObject *other, int cmp_op) { - if (repr) { - /* Dispose of previous callback */ - Py_XDECREF(PyArray_ReprFunction); - /* Add a reference to new callback */ - Py_XINCREF(op); - /* Remember new callback */ - PyArray_ReprFunction = op; - } - else { - /* Dispose of previous callback */ - Py_XDECREF(PyArray_StrFunction); - /* Add a reference to new callback */ - Py_XINCREF(op); - /* Remember new callback */ - PyArray_StrFunction = op; - } -} - -static PyObject * -array_repr(PyArrayObject *self) -{ - PyObject *s, *arglist; - - if (PyArray_ReprFunction == NULL) { - s = array_repr_builtin(self, 1); - } - else { - arglist = Py_BuildValue("(O)", self); - s = PyEval_CallObject(PyArray_ReprFunction, arglist); - Py_DECREF(arglist); - } - return s; -} - -static PyObject * -array_str(PyArrayObject *self) -{ - PyObject *s, *arglist; - - if (PyArray_StrFunction == NULL) { - s = array_repr_builtin(self, 0); - } - else { - arglist = Py_BuildValue("(O)", self); - s = PyEval_CallObject(PyArray_StrFunction, arglist); - Py_DECREF(arglist); - } - return s; -} - - - -/*NUMPY_API - */ -NPY_NO_EXPORT int -PyArray_CompareUCS4(npy_ucs4 *s1, npy_ucs4 *s2, size_t len) -{ - PyArray_UCS4 c1, c2; - while(len-- > 0) { - c1 = *s1++; - c2 = *s2++; - if (c1 != c2) { - return (c1 < c2) ? -1 : 1; - } - } - return 0; -} - -/*NUMPY_API - */ -NPY_NO_EXPORT int -PyArray_CompareString(char *s1, char *s2, size_t len) -{ - const unsigned char *c1 = (unsigned char *)s1; - const unsigned char *c2 = (unsigned char *)s2; - size_t i; - - for(i = 0; i < len; ++i) { - if (c1[i] != c2[i]) { - return (c1[i] > c2[i]) ? 1 : -1; - } - } - return 0; -} - - -/* This also handles possibly mis-aligned data */ -/* Compare s1 and s2 which are not necessarily NULL-terminated. - s1 is of length len1 - s2 is of length len2 - If they are NULL terminated, then stop comparison. -*/ -static int -_myunincmp(PyArray_UCS4 *s1, PyArray_UCS4 *s2, int len1, int len2) -{ - PyArray_UCS4 *sptr; - PyArray_UCS4 *s1t=s1, *s2t=s2; - int val; - intp size; - int diff; - - if ((intp)s1 % sizeof(PyArray_UCS4) != 0) { - size = len1*sizeof(PyArray_UCS4); - s1t = malloc(size); - memcpy(s1t, s1, size); - } - if ((intp)s2 % sizeof(PyArray_UCS4) != 0) { - size = len2*sizeof(PyArray_UCS4); - s2t = malloc(size); - memcpy(s2t, s2, size); - } - val = PyArray_CompareUCS4(s1t, s2t, MIN(len1,len2)); - if ((val != 0) || (len1 == len2)) { - goto finish; - } - if (len2 > len1) { - sptr = s2t+len1; - val = -1; - diff = len2-len1; - } - else { - sptr = s1t+len2; - val = 1; - diff=len1-len2; - } - while (diff--) { - if (*sptr != 0) { - goto finish; - } - sptr++; - } - val = 0; - - finish: - if (s1t != s1) { - free(s1t); - } - if (s2t != s2) { - free(s2t); - } - return val; -} - - - - -/* - * Compare s1 and s2 which are not necessarily NULL-terminated. - * s1 is of length len1 - * s2 is of length len2 - * If they are NULL terminated, then stop comparison. - */ -static int -_mystrncmp(char *s1, char *s2, int len1, int len2) -{ - char *sptr; - int val; - int diff; - - val = memcmp(s1, s2, MIN(len1, len2)); - if ((val != 0) || (len1 == len2)) { - return val; - } - if (len2 > len1) { - sptr = s2 + len1; - val = -1; - diff = len2 - len1; - } - else { - sptr = s1 + len2; - val = 1; - diff = len1 - len2; - } - while (diff--) { - if (*sptr != 0) { - return val; - } - sptr++; - } - return 0; /* Only happens if NULLs are everywhere */ -} - -/* Borrowed from Numarray */ - -#define SMALL_STRING 2048 - -#if defined(isspace) -#undef isspace -#define isspace(c) ((c==' ')||(c=='\t')||(c=='\n')||(c=='\r')||(c=='\v')||(c=='\f')) -#endif - -static void _rstripw(char *s, int n) -{ - int i; - for (i = n - 1; i >= 1; i--) { /* Never strip to length 0. */ - int c = s[i]; - - if (!c || isspace(c)) { - s[i] = 0; - } - else { - break; - } - } -} - -static void _unistripw(PyArray_UCS4 *s, int n) -{ - int i; - for (i = n - 1; i >= 1; i--) { /* Never strip to length 0. */ - PyArray_UCS4 c = s[i]; - if (!c || isspace(c)) { - s[i] = 0; - } - else { - break; - } - } -} - - -static char * -_char_copy_n_strip(char *original, char *temp, int nc) -{ - if (nc > SMALL_STRING) { - temp = malloc(nc); - if (!temp) { - PyErr_NoMemory(); - return NULL; - } - } - memcpy(temp, original, nc); - _rstripw(temp, nc); - return temp; -} - -static void -_char_release(char *ptr, int nc) -{ - if (nc > SMALL_STRING) { - free(ptr); - } -} - -static char * -_uni_copy_n_strip(char *original, char *temp, int nc) -{ - if (nc*sizeof(PyArray_UCS4) > SMALL_STRING) { - temp = malloc(nc*sizeof(PyArray_UCS4)); - if (!temp) { - PyErr_NoMemory(); - return NULL; - } - } - memcpy(temp, original, nc*sizeof(PyArray_UCS4)); - _unistripw((PyArray_UCS4 *)temp, nc); - return temp; -} - -static void -_uni_release(char *ptr, int nc) -{ - if (nc*sizeof(PyArray_UCS4) > SMALL_STRING) { - free(ptr); - } -} - - -/* End borrowed from numarray */ - -#define _rstrip_loop(CMP) { \ - void *aptr, *bptr; \ - char atemp[SMALL_STRING], btemp[SMALL_STRING]; \ - while(size--) { \ - aptr = stripfunc(iself->dataptr, atemp, N1); \ - if (!aptr) return -1; \ - bptr = stripfunc(iother->dataptr, btemp, N2); \ - if (!bptr) { \ - relfunc(aptr, N1); \ - return -1; \ - } \ - val = cmpfunc(aptr, bptr, N1, N2); \ - *dptr = (val CMP 0); \ - PyArray_ITER_NEXT(iself); \ - PyArray_ITER_NEXT(iother); \ - dptr += 1; \ - relfunc(aptr, N1); \ - relfunc(bptr, N2); \ - } \ - } - -#define _reg_loop(CMP) { \ - while(size--) { \ - val = cmpfunc((void *)iself->dataptr, \ - (void *)iother->dataptr, \ - N1, N2); \ - *dptr = (val CMP 0); \ - PyArray_ITER_NEXT(iself); \ - PyArray_ITER_NEXT(iother); \ - dptr += 1; \ - } \ - } - -#define _loop(CMP) if (rstrip) _rstrip_loop(CMP) \ - else _reg_loop(CMP) - -static int -_compare_strings(PyObject *result, PyArrayMultiIterObject *multi, - int cmp_op, void *func, int rstrip) -{ - PyArrayIterObject *iself, *iother; - Bool *dptr; - intp size; - int val; - int N1, N2; - int (*cmpfunc)(void *, void *, int, int); - void (*relfunc)(char *, int); - char* (*stripfunc)(char *, char *, int); - - cmpfunc = func; - dptr = (Bool *)PyArray_DATA(result); - iself = multi->iters[0]; - iother = multi->iters[1]; - size = multi->size; - N1 = iself->ao->descr->elsize; - N2 = iother->ao->descr->elsize; - if ((void *)cmpfunc == (void *)_myunincmp) { - N1 >>= 2; - N2 >>= 2; - stripfunc = _uni_copy_n_strip; - relfunc = _uni_release; - } - else { - stripfunc = _char_copy_n_strip; - relfunc = _char_release; - } - switch (cmp_op) { - case Py_EQ: - _loop(==) - break; - case Py_NE: - _loop(!=) - break; - case Py_LT: - _loop(<) - break; - case Py_LE: - _loop(<=) - break; - case Py_GT: - _loop(>) - break; - case Py_GE: - _loop(>=) - break; - default: - PyErr_SetString(PyExc_RuntimeError, "bad comparison operator"); - return -1; - } - return 0; -} - -#undef _loop -#undef _reg_loop -#undef _rstrip_loop -#undef SMALL_STRING - -NPY_NO_EXPORT PyObject * -_strings_richcompare(PyArrayObject *self, PyArrayObject *other, int cmp_op, - int rstrip) -{ - PyObject *result; - PyArrayMultiIterObject *mit; - int val; - - /* Cast arrays to a common type */ - if (self->descr->type_num != other->descr->type_num) { - PyObject *new; - if (self->descr->type_num == PyArray_STRING && - other->descr->type_num == PyArray_UNICODE) { - Py_INCREF(other->descr); - new = PyArray_FromAny((PyObject *)self, other->descr, - 0, 0, 0, NULL); - if (new == NULL) { - return NULL; - } - Py_INCREF(other); - self = (PyArrayObject *)new; - } - else if (self->descr->type_num == PyArray_UNICODE && - other->descr->type_num == PyArray_STRING) { - Py_INCREF(self->descr); - new = PyArray_FromAny((PyObject *)other, self->descr, - 0, 0, 0, NULL); - if (new == NULL) { - return NULL; - } - Py_INCREF(self); - other = (PyArrayObject *)new; - } - else { - PyErr_SetString(PyExc_TypeError, - "invalid string data-types " - "in comparison"); - return NULL; - } - } - else { - Py_INCREF(self); - Py_INCREF(other); - } - - /* Broad-cast the arrays to a common shape */ - mit = (PyArrayMultiIterObject *)PyArray_MultiIterNew(2, self, other); - Py_DECREF(self); - Py_DECREF(other); - if (mit == NULL) { - return NULL; - } - - result = PyArray_NewFromDescr(&PyArray_Type, - PyArray_DescrFromType(PyArray_BOOL), - mit->nd, - mit->dimensions, - NULL, NULL, 0, - NULL); - if (result == NULL) { - goto finish; - } - - if (self->descr->type_num == PyArray_UNICODE) { - val = _compare_strings(result, mit, cmp_op, _myunincmp, rstrip); - } - else { - val = _compare_strings(result, mit, cmp_op, _mystrncmp, rstrip); - } - - if (val < 0) { - Py_DECREF(result); result = NULL; - } - - finish: - Py_DECREF(mit); - return result; -} - -/* - * VOID-type arrays can only be compared equal and not-equal - * in which case the fields are all compared by extracting the fields - * and testing one at a time... - * equality testing is performed using logical_ands on all the fields. - * in-equality testing is performed using logical_ors on all the fields. - * - * VOID-type arrays without fields are compared for equality by comparing their - * memory at each location directly (using string-code). - */ -static PyObject * -_void_compare(PyArrayObject *self, PyArrayObject *other, int cmp_op) -{ - if (!(cmp_op == Py_EQ || cmp_op == Py_NE)) { - PyErr_SetString(PyExc_ValueError, - "Void-arrays can only be compared for equality."); - return NULL; - } - if (PyArray_HASFIELDS(self)) { - PyObject *res = NULL, *temp, *a, *b; - PyObject *key, *value, *temp2; - PyObject *op; - Py_ssize_t pos = 0; - - op = (cmp_op == Py_EQ ? n_ops.logical_and : n_ops.logical_or); - while (PyDict_Next(self->descr->fields, &pos, &key, &value)) { - if NPY_TITLE_KEY(key, value) { - continue; - } - a = PyArray_EnsureAnyArray(array_subscript(self, key)); - if (a == NULL) { - Py_XDECREF(res); - return NULL; - } - b = array_subscript(other, key); - if (b == NULL) { - Py_XDECREF(res); - Py_DECREF(a); - return NULL; - } - temp = array_richcompare((PyArrayObject *)a,b,cmp_op); - Py_DECREF(a); - Py_DECREF(b); - if (temp == NULL) { - Py_XDECREF(res); - return NULL; - } - if (res == NULL) { - res = temp; - } - else { - temp2 = PyObject_CallFunction(op, "OO", res, temp); - Py_DECREF(temp); - Py_DECREF(res); - if (temp2 == NULL) { - return NULL; - } - res = temp2; - } - } - if (res == NULL && !PyErr_Occurred()) { - PyErr_SetString(PyExc_ValueError, "No fields found."); - } - return res; - } - else { - /* - * compare as a string. Assumes self and - * other have same descr->type - */ - return _strings_richcompare(self, other, cmp_op, 0); - } -} - -NPY_NO_EXPORT PyObject * -array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op) -{ - PyObject *array_other, *result = NULL; - int typenum; - - switch (cmp_op) { - case Py_LT: - result = PyArray_GenericBinaryFunction(self, other, - n_ops.less); - break; - case Py_LE: - result = PyArray_GenericBinaryFunction(self, other, - n_ops.less_equal); - break; - case Py_EQ: - if (other == Py_None) { - Py_INCREF(Py_False); - return Py_False; - } - /* Try to convert other to an array */ - if (!PyArray_Check(other)) { - typenum = self->descr->type_num; - if (typenum != PyArray_OBJECT) { - typenum = PyArray_NOTYPE; - } - array_other = PyArray_FromObject(other, - typenum, 0, 0); - /* - * If not successful, then return False. This fixes code - * that used to allow equality comparisons between arrays - * and other objects which would give a result of False. - */ - if ((array_other == NULL) || - (array_other == Py_None)) { - Py_XDECREF(array_other); - PyErr_Clear(); - Py_INCREF(Py_False); - return Py_False; - } - } - else { - Py_INCREF(other); - array_other = other; - } - result = PyArray_GenericBinaryFunction(self, - array_other, - n_ops.equal); - if ((result == Py_NotImplemented) && - (self->descr->type_num == PyArray_VOID)) { - int _res; - - _res = PyObject_RichCompareBool - ((PyObject *)self->descr, - (PyObject *)\ - PyArray_DESCR(array_other), - Py_EQ); - if (_res < 0) { - Py_DECREF(result); - Py_DECREF(array_other); - return NULL; - } - if (_res) { - Py_DECREF(result); - result = _void_compare - (self, - (PyArrayObject *)array_other, - cmp_op); - Py_DECREF(array_other); - } - return result; - } - /* - * If the comparison results in NULL, then the - * two array objects can not be compared together so - * return zero - */ - Py_DECREF(array_other); - if (result == NULL) { - PyErr_Clear(); - Py_INCREF(Py_False); - return Py_False; - } - break; - case Py_NE: - if (other == Py_None) { - Py_INCREF(Py_True); - return Py_True; - } - /* Try to convert other to an array */ - if (!PyArray_Check(other)) { - typenum = self->descr->type_num; - if (typenum != PyArray_OBJECT) { - typenum = PyArray_NOTYPE; - } - array_other = PyArray_FromObject(other, typenum, 0, 0); - /* - * If not successful, then objects cannot be - * compared and cannot be equal, therefore, - * return True; - */ - if ((array_other == NULL) || (array_other == Py_None)) { - Py_XDECREF(array_other); - PyErr_Clear(); - Py_INCREF(Py_True); - return Py_True; - } - } - else { - Py_INCREF(other); - array_other = other; - } - result = PyArray_GenericBinaryFunction(self, - array_other, - n_ops.not_equal); - if ((result == Py_NotImplemented) && - (self->descr->type_num == PyArray_VOID)) { - int _res; - - _res = PyObject_RichCompareBool( - (PyObject *)self->descr, - (PyObject *) - PyArray_DESCR(array_other), - Py_EQ); - if (_res < 0) { - Py_DECREF(result); - Py_DECREF(array_other); - return NULL; - } - if (_res) { - Py_DECREF(result); - result = _void_compare( - self, - (PyArrayObject *)array_other, - cmp_op); - Py_DECREF(array_other); - } - return result; - } - - Py_DECREF(array_other); - if (result == NULL) { - PyErr_Clear(); - Py_INCREF(Py_True); - return Py_True; - } - break; - case Py_GT: - result = PyArray_GenericBinaryFunction(self, other, - n_ops.greater); - break; - case Py_GE: - result = PyArray_GenericBinaryFunction(self, other, - n_ops.greater_equal); - break; - default: - result = Py_NotImplemented; - Py_INCREF(result); - } - if (result == Py_NotImplemented) { - /* Try to handle string comparisons */ - if (self->descr->type_num == PyArray_OBJECT) { - return result; - } - array_other = PyArray_FromObject(other,PyArray_NOTYPE, 0, 0); - if (PyArray_ISSTRING(self) && PyArray_ISSTRING(array_other)) { - Py_DECREF(result); - result = _strings_richcompare(self, (PyArrayObject *) - array_other, cmp_op, 0); - } - Py_DECREF(array_other); - } - return result; -} - - -/*NUMPY_API - PyArray_CheckAxis -*/ -NPY_NO_EXPORT PyObject * -PyArray_CheckAxis(PyArrayObject *arr, int *axis, int flags) -{ - PyObject *temp1, *temp2; - int n = arr->nd; - - if ((*axis >= MAX_DIMS) || (n==0)) { - if (n != 1) { - temp1 = PyArray_Ravel(arr,0); - if (temp1 == NULL) { - *axis = 0; - return NULL; - } - *axis = PyArray_NDIM(temp1)-1; - } - else { - temp1 = (PyObject *)arr; - Py_INCREF(temp1); - *axis = 0; - } - if (!flags) { - return temp1; - } - } - else { - temp1 = (PyObject *)arr; - Py_INCREF(temp1); - } - if (flags) { - temp2 = PyArray_CheckFromAny((PyObject *)temp1, NULL, - 0, 0, flags, NULL); - Py_DECREF(temp1); - if (temp2 == NULL) { - return NULL; - } - } - else { - temp2 = (PyObject *)temp1; - } - n = PyArray_NDIM(temp2); - if (*axis < 0) { - *axis += n; - } - if ((*axis < 0) || (*axis >= n)) { - PyErr_Format(PyExc_ValueError, - "axis(=%d) out of bounds", *axis); - Py_DECREF(temp2); - return NULL; - } - return temp2; -} - -#define _check_axis PyArray_CheckAxis - -#include "arraymethods.c" - -/* Lifted from numarray */ -/*NUMPY_API - PyArray_IntTupleFromIntp -*/ -NPY_NO_EXPORT PyObject * -PyArray_IntTupleFromIntp(int len, intp *vals) -{ - int i; - PyObject *intTuple = PyTuple_New(len); - - if (!intTuple) { - goto fail; - } - for (i = 0; i < len; i++) { -#if SIZEOF_INTP <= SIZEOF_LONG - PyObject *o = PyInt_FromLong((long) vals[i]); -#else - PyObject *o = PyLong_FromLongLong((longlong) vals[i]); -#endif - if (!o) { - Py_DECREF(intTuple); - intTuple = NULL; - goto fail; - } - PyTuple_SET_ITEM(intTuple, i, o); - } - - fail: - return intTuple; -} - -/*NUMPY_API - * PyArray_IntpFromSequence - * Returns the number of dimensions or -1 if an error occurred. - * vals must be large enough to hold maxvals - */ -NPY_NO_EXPORT int -PyArray_IntpFromSequence(PyObject *seq, intp *vals, int maxvals) -{ - int nd, i; - PyObject *op, *err; - - /* - * Check to see if sequence is a single integer first. - * or, can be made into one - */ - if ((nd=PySequence_Length(seq)) == -1) { - if (PyErr_Occurred()) PyErr_Clear(); -#if SIZEOF_LONG >= SIZEOF_INTP - if (!(op = PyNumber_Int(seq))) { - return -1; - } -#else - if (!(op = PyNumber_Long(seq))) { - return -1; - } -#endif - nd = 1; -#if SIZEOF_LONG >= SIZEOF_INTP - vals[0] = (intp ) PyInt_AsLong(op); -#else - vals[0] = (intp ) PyLong_AsLongLong(op); -#endif - Py_DECREF(op); - - /* - * Check wether there was an error - if the error was an overflow, raise - * a ValueError instead to be more helpful - */ - if(vals[0] == -1) { - err = PyErr_Occurred(); - if (err && - PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) { - PyErr_SetString(PyExc_ValueError, - "Maximum allowed dimension exceeded"); - } - if(err != NULL) { - return -1; - } - } - } - else { - for (i = 0; i < MIN(nd,maxvals); i++) { - op = PySequence_GetItem(seq, i); - if (op == NULL) { - return -1; - } -#if SIZEOF_LONG >= SIZEOF_INTP - vals[i]=(intp )PyInt_AsLong(op); -#else - vals[i]=(intp )PyLong_AsLongLong(op); -#endif - Py_DECREF(op); - - /* - * Check wether there was an error - if the error was an overflow, - * raise a ValueError instead to be more helpful - */ - if(vals[0] == -1) { - err = PyErr_Occurred(); - if (err && - PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) { - PyErr_SetString(PyExc_ValueError, - "Maximum allowed dimension exceeded"); - } - if(err != NULL) { - return -1; - } - } - } - } - return nd; -} - - - -/* - * Check whether the given array is stored contiguously - * (row-wise) in memory. - * - * 0-strided arrays are not contiguous (even if dimension == 1) - */ -static int -_IsContiguous(PyArrayObject *ap) -{ - intp sd; - intp dim; - int i; - - if (ap->nd == 0) { - return 1; - } - sd = ap->descr->elsize; - if (ap->nd == 1) { - return ap->dimensions[0] == 1 || sd == ap->strides[0]; - } - for (i = ap->nd - 1; i >= 0; --i) { - dim = ap->dimensions[i]; - /* contiguous by definition */ - if (dim == 0) { - return 1; - } - if (ap->strides[i] != sd) { - return 0; - } - sd *= dim; - } - return 1; -} - - -/* 0-strided arrays are not contiguous (even if dimension == 1) */ -static int -_IsFortranContiguous(PyArrayObject *ap) -{ - intp sd; - intp dim; - int i; - - if (ap->nd == 0) { - return 1; - } - sd = ap->descr->elsize; - if (ap->nd == 1) { - return ap->dimensions[0] == 1 || sd == ap->strides[0]; - } - for (i = 0; i < ap->nd; ++i) { - dim = ap->dimensions[i]; - /* fortran contiguous by definition */ - if (dim == 0) { - return 1; - } - if (ap->strides[i] != sd) { - return 0; - } - sd *= dim; - } - return 1; -} - -static int -_IsAligned(PyArrayObject *ap) -{ - int i, alignment, aligned = 1; - intp ptr; - int type = ap->descr->type_num; - - if ((type == PyArray_STRING) || (type == PyArray_VOID)) { - return 1; - } - alignment = ap->descr->alignment; - if (alignment == 1) { - return 1; - } - ptr = (intp) ap->data; - aligned = (ptr % alignment) == 0; - for (i = 0; i < ap->nd; i++) { - aligned &= ((ap->strides[i] % alignment) == 0); - } - return aligned != 0; -} - -static Bool -_IsWriteable(PyArrayObject *ap) -{ - PyObject *base=ap->base; - void *dummy; - Py_ssize_t n; - - /* If we own our own data, then no-problem */ - if ((base == NULL) || (ap->flags & OWNDATA)) { - return TRUE; - } - /* - * Get to the final base object - * If it is a writeable array, then return TRUE - * If we can find an array object - * or a writeable buffer object as the final base object - * or a string object (for pickling support memory savings). - * - this last could be removed if a proper pickleable - * buffer was added to Python. - */ - - while(PyArray_Check(base)) { - if (PyArray_CHKFLAGS(base, OWNDATA)) { - return (Bool) (PyArray_ISWRITEABLE(base)); - } - base = PyArray_BASE(base); - } - - /* - * here so pickle support works seamlessly - * and unpickled array can be set and reset writeable - * -- could be abused -- - */ - if PyString_Check(base) { - return TRUE; - } - if (PyObject_AsWriteBuffer(base, &dummy, &n) < 0) { - return FALSE; - } - return TRUE; -} - - -/*NUMPY_API - */ -NPY_NO_EXPORT int -PyArray_ElementStrides(PyObject *arr) -{ - int itemsize = PyArray_ITEMSIZE(arr); - int i, N = PyArray_NDIM(arr); - intp *strides = PyArray_STRIDES(arr); - - for (i = 0; i < N; i++) { - if ((strides[i] % itemsize) != 0) { - return 0; - } - } - return 1; -} - -/*NUMPY_API - * Update Several Flags at once. - */ -NPY_NO_EXPORT void -PyArray_UpdateFlags(PyArrayObject *ret, int flagmask) -{ - - if (flagmask & FORTRAN) { - if (_IsFortranContiguous(ret)) { - ret->flags |= FORTRAN; - if (ret->nd > 1) { - ret->flags &= ~CONTIGUOUS; - } - } - else { - ret->flags &= ~FORTRAN; - } - } - if (flagmask & CONTIGUOUS) { - if (_IsContiguous(ret)) { - ret->flags |= CONTIGUOUS; - if (ret->nd > 1) { - ret->flags &= ~FORTRAN; - } - } - else { - ret->flags &= ~CONTIGUOUS; - } - } - if (flagmask & ALIGNED) { - if (_IsAligned(ret)) { - ret->flags |= ALIGNED; - } - else { - ret->flags &= ~ALIGNED; - } - } - /* - * This is not checked by default WRITEABLE is not - * part of UPDATE_ALL - */ - if (flagmask & WRITEABLE) { - if (_IsWriteable(ret)) { - ret->flags |= WRITEABLE; - } - else { - ret->flags &= ~WRITEABLE; - } - } - return; -} - -/* - * This routine checks to see if newstrides (of length nd) will not - * ever be able to walk outside of the memory implied numbytes and offset. - * - * The available memory is assumed to start at -offset and proceed - * to numbytes-offset. The strides are checked to ensure - * that accessing memory using striding will not try to reach beyond - * this memory for any of the axes. - * - * If numbytes is 0 it will be calculated using the dimensions and - * element-size. - * - * This function checks for walking beyond the beginning and right-end - * of the buffer and therefore works for any integer stride (positive - * or negative). - */ - -/*NUMPY_API*/ -NPY_NO_EXPORT Bool -PyArray_CheckStrides(int elsize, int nd, intp numbytes, intp offset, - intp *dims, intp *newstrides) -{ - int i; - intp byte_begin; - intp begin; - intp end; - - if (numbytes == 0) { - numbytes = PyArray_MultiplyList(dims, nd) * elsize; - } - begin = -offset; - end = numbytes - offset - elsize; - for (i = 0; i < nd; i++) { - byte_begin = newstrides[i]*(dims[i] - 1); - if ((byte_begin < begin) || (byte_begin > end)) { - return FALSE; - } - } - return TRUE; -} - - -/* - * This is the main array creation routine. - * - * Flags argument has multiple related meanings - * depending on data and strides: - * - * If data is given, then flags is flags associated with data. - * If strides is not given, then a contiguous strides array will be created - * and the CONTIGUOUS bit will be set. If the flags argument - * has the FORTRAN bit set, then a FORTRAN-style strides array will be - * created (and of course the FORTRAN flag bit will be set). - * - * If data is not given but created here, then flags will be DEFAULT - * and a non-zero flags argument can be used to indicate a FORTRAN style - * array is desired. - */ - -static size_t -_array_fill_strides(intp *strides, intp *dims, int nd, size_t itemsize, - int inflag, int *objflags) -{ - int i; - /* Only make Fortran strides if not contiguous as well */ - if ((inflag & FORTRAN) && !(inflag & CONTIGUOUS)) { - for (i = 0; i < nd; i++) { - strides[i] = itemsize; - itemsize *= dims[i] ? dims[i] : 1; - } - *objflags |= FORTRAN; - if (nd > 1) { - *objflags &= ~CONTIGUOUS; - } - else { - *objflags |= CONTIGUOUS; - } - } - else { - for (i = nd - 1; i >= 0; i--) { - strides[i] = itemsize; - itemsize *= dims[i] ? dims[i] : 1; - } - *objflags |= CONTIGUOUS; - if (nd > 1) { - *objflags &= ~FORTRAN; - } - else { - *objflags |= FORTRAN; - } - } - return itemsize; -} - -/*NUMPY_API - * Generic new array creation routine. - */ -NPY_NO_EXPORT PyObject * -PyArray_New(PyTypeObject *subtype, int nd, intp *dims, int type_num, - intp *strides, void *data, int itemsize, int flags, - PyObject *obj) -{ - PyArray_Descr *descr; - PyObject *new; - - descr = PyArray_DescrFromType(type_num); - if (descr == NULL) { + if (!(cmp_op == Py_EQ || cmp_op == Py_NE)) { + PyErr_SetString(PyExc_ValueError, + "Void-arrays can only be compared for equality."); return NULL; } - if (descr->elsize == 0) { - if (itemsize < 1) { - PyErr_SetString(PyExc_ValueError, - "data type must provide an itemsize"); - Py_DECREF(descr); - return NULL; - } - PyArray_DESCR_REPLACE(descr); - descr->elsize = itemsize; - } - new = PyArray_NewFromDescr(subtype, descr, nd, dims, strides, - data, flags, obj); - return new; -} - -/* - * Change a sub-array field to the base descriptor - * - * and update the dimensions and strides - * appropriately. Dimensions and strides are added - * to the end unless we have a FORTRAN array - * and then they are added to the beginning - * - * Strides are only added if given (because data is given). - */ -static int -_update_descr_and_dimensions(PyArray_Descr **des, intp *newdims, - intp *newstrides, int oldnd, int isfortran) -{ - PyArray_Descr *old; - int newnd; - int numnew; - intp *mydim; - int i; - int tuple; - - old = *des; - *des = old->subarray->base; - - - mydim = newdims + oldnd; - tuple = PyTuple_Check(old->subarray->shape); - if (tuple) { - numnew = PyTuple_GET_SIZE(old->subarray->shape); - } - else { - numnew = 1; - } - - - newnd = oldnd + numnew; - if (newnd > MAX_DIMS) { - goto finish; - } - if (isfortran) { - memmove(newdims+numnew, newdims, oldnd*sizeof(intp)); - mydim = newdims; - } - if (tuple) { - for (i = 0; i < numnew; i++) { - mydim[i] = (intp) PyInt_AsLong( - PyTuple_GET_ITEM(old->subarray->shape, i)); - } - } - else { - mydim[0] = (intp) PyInt_AsLong(old->subarray->shape); - } - - if (newstrides) { - intp tempsize; - intp *mystrides; + if (PyArray_HASFIELDS(self)) { + PyObject *res = NULL, *temp, *a, *b; + PyObject *key, *value, *temp2; + PyObject *op; + Py_ssize_t pos = 0; - mystrides = newstrides + oldnd; - if (isfortran) { - memmove(newstrides+numnew, newstrides, oldnd*sizeof(intp)); - mystrides = newstrides; - } - /* Make new strides -- alwasy C-contiguous */ - tempsize = (*des)->elsize; - for (i = numnew - 1; i >= 0; i--) { - mystrides[i] = tempsize; - tempsize *= mydim[i] ? mydim[i] : 1; + op = (cmp_op == Py_EQ ? n_ops.logical_and : n_ops.logical_or); + while (PyDict_Next(self->descr->fields, &pos, &key, &value)) { + if NPY_TITLE_KEY(key, value) { + continue; + } + a = PyArray_EnsureAnyArray(array_subscript(self, key)); + if (a == NULL) { + Py_XDECREF(res); + return NULL; + } + b = array_subscript(other, key); + if (b == NULL) { + Py_XDECREF(res); + Py_DECREF(a); + return NULL; + } + temp = array_richcompare((PyArrayObject *)a,b,cmp_op); + Py_DECREF(a); + Py_DECREF(b); + if (temp == NULL) { + Py_XDECREF(res); + return NULL; + } + if (res == NULL) { + res = temp; + } + else { + temp2 = PyObject_CallFunction(op, "OO", res, temp); + Py_DECREF(temp); + Py_DECREF(res); + if (temp2 == NULL) { + return NULL; + } + res = temp2; + } } - } - - finish: - Py_INCREF(*des); - Py_DECREF(old); - return newnd; -} - - -/*NUMPY_API - * Generic new array creation routine. - * - * steals a reference to descr (even on failure) - */ -NPY_NO_EXPORT PyObject * -PyArray_NewFromDescr(PyTypeObject *subtype, PyArray_Descr *descr, int nd, - intp *dims, intp *strides, void *data, - int flags, PyObject *obj) -{ - PyArrayObject *self; - int i; - size_t sd; - intp largest; - intp size; - - if (descr->subarray) { - PyObject *ret; - intp newdims[2*MAX_DIMS]; - intp *newstrides = NULL; - int isfortran = 0; - isfortran = (data && (flags & FORTRAN) && !(flags & CONTIGUOUS)) || - (!data && flags); - memcpy(newdims, dims, nd*sizeof(intp)); - if (strides) { - newstrides = newdims + MAX_DIMS; - memcpy(newstrides, strides, nd*sizeof(intp)); + if (res == NULL && !PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "No fields found."); } - nd =_update_descr_and_dimensions(&descr, newdims, - newstrides, nd, isfortran); - ret = PyArray_NewFromDescr(subtype, descr, nd, newdims, - newstrides, - data, flags, obj); - return ret; - } - if (nd < 0) { - PyErr_SetString(PyExc_ValueError, - "number of dimensions must be >=0"); - Py_DECREF(descr); - return NULL; + return res; } - if (nd > MAX_DIMS) { - PyErr_Format(PyExc_ValueError, - "maximum number of dimensions is %d", MAX_DIMS); - Py_DECREF(descr); - return NULL; + else { + /* + * compare as a string. Assumes self and + * other have same descr->type + */ + return _strings_richcompare(self, other, cmp_op, 0); } +} - /* Check dimensions */ - size = 1; - sd = (size_t) descr->elsize; - if (sd == 0) { - if (!PyDataType_ISSTRING(descr)) { - PyErr_SetString(PyExc_ValueError, "Empty data-type"); - Py_DECREF(descr); - return NULL; +NPY_NO_EXPORT PyObject * +array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op) +{ + PyObject *array_other, *result = NULL; + int typenum; + + switch (cmp_op) { + case Py_LT: + result = PyArray_GenericBinaryFunction(self, other, + n_ops.less); + break; + case Py_LE: + result = PyArray_GenericBinaryFunction(self, other, + n_ops.less_equal); + break; + case Py_EQ: + if (other == Py_None) { + Py_INCREF(Py_False); + return Py_False; } - PyArray_DESCR_REPLACE(descr); - if (descr->type_num == NPY_STRING) { - descr->elsize = 1; + /* Try to convert other to an array */ + if (!PyArray_Check(other)) { + typenum = self->descr->type_num; + if (typenum != PyArray_OBJECT) { + typenum = PyArray_NOTYPE; + } + array_other = PyArray_FromObject(other, + typenum, 0, 0); + /* + * If not successful, then return False. This fixes code + * that used to allow equality comparisons between arrays + * and other objects which would give a result of False. + */ + if ((array_other == NULL) || + (array_other == Py_None)) { + Py_XDECREF(array_other); + PyErr_Clear(); + Py_INCREF(Py_False); + return Py_False; + } } else { - descr->elsize = sizeof(PyArray_UCS4); + Py_INCREF(other); + array_other = other; } - sd = descr->elsize; - } - - largest = NPY_MAX_INTP / sd; - for (i = 0; i < nd; i++) { - intp dim = dims[i]; + result = PyArray_GenericBinaryFunction(self, + array_other, + n_ops.equal); + if ((result == Py_NotImplemented) && + (self->descr->type_num == PyArray_VOID)) { + int _res; - if (dim == 0) { + _res = PyObject_RichCompareBool + ((PyObject *)self->descr, + (PyObject *)\ + PyArray_DESCR(array_other), + Py_EQ); + if (_res < 0) { + Py_DECREF(result); + Py_DECREF(array_other); + return NULL; + } + if (_res) { + Py_DECREF(result); + result = _void_compare + (self, + (PyArrayObject *)array_other, + cmp_op); + Py_DECREF(array_other); + } + return result; + } + /* + * If the comparison results in NULL, then the + * two array objects can not be compared together so + * return zero + */ + Py_DECREF(array_other); + if (result == NULL) { + PyErr_Clear(); + Py_INCREF(Py_False); + return Py_False; + } + break; + case Py_NE: + if (other == Py_None) { + Py_INCREF(Py_True); + return Py_True; + } + /* Try to convert other to an array */ + if (!PyArray_Check(other)) { + typenum = self->descr->type_num; + if (typenum != PyArray_OBJECT) { + typenum = PyArray_NOTYPE; + } + array_other = PyArray_FromObject(other, typenum, 0, 0); /* - * Compare to PyArray_OverflowMultiplyList that - * returns 0 in this case. + * If not successful, then objects cannot be + * compared and cannot be equal, therefore, + * return True; */ - continue; - } - if (dim < 0) { - PyErr_SetString(PyExc_ValueError, - "negative dimensions " \ - "are not allowed"); - Py_DECREF(descr); - return NULL; + if ((array_other == NULL) || (array_other == Py_None)) { + Py_XDECREF(array_other); + PyErr_Clear(); + Py_INCREF(Py_True); + return Py_True; + } } - if (dim > largest) { - PyErr_SetString(PyExc_ValueError, - "array is too big."); - Py_DECREF(descr); - return NULL; + else { + Py_INCREF(other); + array_other = other; } - size *= dim; - largest /= dim; - } + result = PyArray_GenericBinaryFunction(self, + array_other, + n_ops.not_equal); + if ((result == Py_NotImplemented) && + (self->descr->type_num == PyArray_VOID)) { + int _res; - self = (PyArrayObject *) subtype->tp_alloc(subtype, 0); - if (self == NULL) { - Py_DECREF(descr); - return NULL; - } - self->nd = nd; - self->dimensions = NULL; - self->data = NULL; - if (data == NULL) { - self->flags = DEFAULT; - if (flags) { - self->flags |= FORTRAN; - if (nd > 1) { - self->flags &= ~CONTIGUOUS; + _res = PyObject_RichCompareBool( + (PyObject *)self->descr, + (PyObject *) + PyArray_DESCR(array_other), + Py_EQ); + if (_res < 0) { + Py_DECREF(result); + Py_DECREF(array_other); + return NULL; } - flags = FORTRAN; + if (_res) { + Py_DECREF(result); + result = _void_compare( + self, + (PyArrayObject *)array_other, + cmp_op); + Py_DECREF(array_other); + } + return result; + } + + Py_DECREF(array_other); + if (result == NULL) { + PyErr_Clear(); + Py_INCREF(Py_True); + return Py_True; } + break; + case Py_GT: + result = PyArray_GenericBinaryFunction(self, other, + n_ops.greater); + break; + case Py_GE: + result = PyArray_GenericBinaryFunction(self, other, + n_ops.greater_equal); + break; + default: + result = Py_NotImplemented; + Py_INCREF(result); } - else { - self->flags = (flags & ~UPDATEIFCOPY); + if (result == Py_NotImplemented) { + /* Try to handle string comparisons */ + if (self->descr->type_num == PyArray_OBJECT) { + return result; + } + array_other = PyArray_FromObject(other,PyArray_NOTYPE, 0, 0); + if (PyArray_ISSTRING(self) && PyArray_ISSTRING(array_other)) { + Py_DECREF(result); + result = _strings_richcompare(self, (PyArrayObject *) + array_other, cmp_op, 0); + } + Py_DECREF(array_other); } - self->descr = descr; - self->base = (PyObject *)NULL; - self->weakreflist = (PyObject *)NULL; + return result; +} - if (nd > 0) { - self->dimensions = PyDimMem_NEW(2*nd); - if (self->dimensions == NULL) { - PyErr_NoMemory(); - goto fail; - } - self->strides = self->dimensions + nd; - memcpy(self->dimensions, dims, sizeof(intp)*nd); - if (strides == NULL) { /* fill it in */ - sd = _array_fill_strides(self->strides, dims, nd, sd, - flags, &(self->flags)); + +/*NUMPY_API + PyArray_CheckAxis +*/ +NPY_NO_EXPORT PyObject * +PyArray_CheckAxis(PyArrayObject *arr, int *axis, int flags) +{ + PyObject *temp1, *temp2; + int n = arr->nd; + + if ((*axis >= MAX_DIMS) || (n==0)) { + if (n != 1) { + temp1 = PyArray_Ravel(arr,0); + if (temp1 == NULL) { + *axis = 0; + return NULL; + } + *axis = PyArray_NDIM(temp1)-1; } else { - /* - * we allow strides even when we create - * the memory, but be careful with this... - */ - memcpy(self->strides, strides, sizeof(intp)*nd); - sd *= size; + temp1 = (PyObject *)arr; + Py_INCREF(temp1); + *axis = 0; + } + if (!flags) { + return temp1; } } else { - self->dimensions = self->strides = NULL; + temp1 = (PyObject *)arr; + Py_INCREF(temp1); } - - if (data == NULL) { - /* - * Allocate something even for zero-space arrays - * e.g. shape=(0,) -- otherwise buffer exposure - * (a.data) doesn't work as it should. - */ - - if (sd == 0) { - sd = descr->elsize; - } - if ((data = PyDataMem_NEW(sd)) == NULL) { - PyErr_NoMemory(); - goto fail; - } - self->flags |= OWNDATA; - - /* - * It is bad to have unitialized OBJECT pointers - * which could also be sub-fields of a VOID array - */ - if (PyDataType_FLAGCHK(descr, NPY_NEEDS_INIT)) { - memset(data, 0, sd); + if (flags) { + temp2 = PyArray_CheckFromAny((PyObject *)temp1, NULL, + 0, 0, flags, NULL); + Py_DECREF(temp1); + if (temp2 == NULL) { + return NULL; } } else { - /* - * If data is passed in, this object won't own it by default. - * Caller must arrange for this to be reset if truly desired - */ - self->flags &= ~OWNDATA; + temp2 = (PyObject *)temp1; } - self->data = data; + n = PyArray_NDIM(temp2); + if (*axis < 0) { + *axis += n; + } + if ((*axis < 0) || (*axis >= n)) { + PyErr_Format(PyExc_ValueError, + "axis(=%d) out of bounds", *axis); + Py_DECREF(temp2); + return NULL; + } + return temp2; +} - /* - * call the __array_finalize__ - * method if a subtype. - * If obj is NULL, then call method with Py_None - */ - if ((subtype != &PyArray_Type)) { - PyObject *res, *func, *args; - static PyObject *str = NULL; +#define _check_axis PyArray_CheckAxis - if (str == NULL) { - str = PyString_InternFromString("__array_finalize__"); - } - func = PyObject_GetAttr((PyObject *)self, str); - if (func && func != Py_None) { - if (strides != NULL) { - /* - * did not allocate own data or funny strides - * update flags before finalize function - */ - PyArray_UpdateFlags(self, UPDATE_ALL); - } - if PyCObject_Check(func) { - /* A C-function is stored here */ - PyArray_FinalizeFunc *cfunc; - cfunc = PyCObject_AsVoidPtr(func); - Py_DECREF(func); - if (cfunc(self, obj) < 0) { - goto fail; - } - } - else { - args = PyTuple_New(1); - if (obj == NULL) { - obj=Py_None; - } - Py_INCREF(obj); - PyTuple_SET_ITEM(args, 0, obj); - res = PyObject_Call(func, args, NULL); - Py_DECREF(args); - Py_DECREF(func); - if (res == NULL) { - goto fail; - } - else { - Py_DECREF(res); - } - } +#include "arraymethods.c" + +/* Lifted from numarray */ +/*NUMPY_API + PyArray_IntTupleFromIntp +*/ +NPY_NO_EXPORT PyObject * +PyArray_IntTupleFromIntp(int len, intp *vals) +{ + int i; + PyObject *intTuple = PyTuple_New(len); + + if (!intTuple) { + goto fail; + } + for (i = 0; i < len; i++) { +#if SIZEOF_INTP <= SIZEOF_LONG + PyObject *o = PyInt_FromLong((long) vals[i]); +#else + PyObject *o = PyLong_FromLongLong((longlong) vals[i]); +#endif + if (!o) { + Py_DECREF(intTuple); + intTuple = NULL; + goto fail; } - else Py_XDECREF(func); + PyTuple_SET_ITEM(intTuple, i, o); } - return (PyObject *)self; fail: - Py_DECREF(self); - return NULL; + return intTuple; } -static void -_putzero(char *optr, PyObject *zero, PyArray_Descr *dtype) +/*NUMPY_API + * PyArray_IntpFromSequence + * Returns the number of dimensions or -1 if an error occurred. + * vals must be large enough to hold maxvals + */ +NPY_NO_EXPORT int +PyArray_IntpFromSequence(PyObject *seq, intp *vals, int maxvals) { - if (!PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)) { - memset(optr, 0, dtype->elsize); - } - else if (PyDescr_HASFIELDS(dtype)) { - PyObject *key, *value, *title = NULL; - PyArray_Descr *new; - int offset; - Py_ssize_t pos = 0; - while (PyDict_Next(dtype->fields, &pos, &key, &value)) { - if NPY_TITLE_KEY(key, value) { - continue; + int nd, i; + PyObject *op, *err; + + /* + * Check to see if sequence is a single integer first. + * or, can be made into one + */ + if ((nd=PySequence_Length(seq)) == -1) { + if (PyErr_Occurred()) PyErr_Clear(); +#if SIZEOF_LONG >= SIZEOF_INTP + if (!(op = PyNumber_Int(seq))) { + return -1; + } +#else + if (!(op = PyNumber_Long(seq))) { + return -1; + } +#endif + nd = 1; +#if SIZEOF_LONG >= SIZEOF_INTP + vals[0] = (intp ) PyInt_AsLong(op); +#else + vals[0] = (intp ) PyLong_AsLongLong(op); +#endif + Py_DECREF(op); + + /* + * Check wether there was an error - if the error was an overflow, raise + * a ValueError instead to be more helpful + */ + if(vals[0] == -1) { + err = PyErr_Occurred(); + if (err && + PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) { + PyErr_SetString(PyExc_ValueError, + "Maximum allowed dimension exceeded"); } - if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) { - return; + if(err != NULL) { + return -1; } - _putzero(optr + offset, zero, new); } } else { - PyObject **temp; - Py_INCREF(zero); - temp = (PyObject **)optr; - *temp = zero; + for (i = 0; i < MIN(nd,maxvals); i++) { + op = PySequence_GetItem(seq, i); + if (op == NULL) { + return -1; + } +#if SIZEOF_LONG >= SIZEOF_INTP + vals[i]=(intp )PyInt_AsLong(op); +#else + vals[i]=(intp )PyLong_AsLongLong(op); +#endif + Py_DECREF(op); + + /* + * Check wether there was an error - if the error was an overflow, + * raise a ValueError instead to be more helpful + */ + if(vals[0] == -1) { + err = PyErr_Occurred(); + if (err && + PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) { + PyErr_SetString(PyExc_ValueError, + "Maximum allowed dimension exceeded"); + } + if(err != NULL) { + return -1; + } + } + } } - return; + return nd; } -/*NUMPY_API - * Resize (reallocate data). Only works if nothing else is referencing this - * array and it is contiguous. If refcheck is 0, then the reference count is - * not checked and assumed to be 1. You still must own this data and have no - * weak-references and no base object. - */ -NPY_NO_EXPORT PyObject * -PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, - NPY_ORDER fortran) -{ - intp oldsize, newsize; - int new_nd=newshape->len, k, n, elsize; - int refcnt; - intp* new_dimensions=newshape->ptr; - intp new_strides[MAX_DIMS]; - size_t sd; - intp *dimptr; - char *new_data; - intp largest; - if (!PyArray_ISONESEGMENT(self)) { - PyErr_SetString(PyExc_ValueError, - "resize only works on single-segment arrays"); - return NULL; - } +/* + * Check whether the given array is stored contiguously + * (row-wise) in memory. + * + * 0-strided arrays are not contiguous (even if dimension == 1) + */ +static int +_IsContiguous(PyArrayObject *ap) +{ + intp sd; + intp dim; + int i; - if (fortran == PyArray_ANYORDER) { - fortran = PyArray_CORDER; + if (ap->nd == 0) { + return 1; } - if (self->descr->elsize == 0) { - PyErr_SetString(PyExc_ValueError, "Bad data-type size."); - return NULL; + sd = ap->descr->elsize; + if (ap->nd == 1) { + return ap->dimensions[0] == 1 || sd == ap->strides[0]; } - newsize = 1; - largest = MAX_INTP / self->descr->elsize; - for(k=0; knd - 1; i >= 0; --i) { + dim = ap->dimensions[i]; + /* contiguous by definition */ + if (dim == 0) { + return 1; } - newsize *= new_dimensions[k]; - if (newsize <=0 || newsize > largest) { - return PyErr_NoMemory(); + if (ap->strides[i] != sd) { + return 0; } + sd *= dim; } - oldsize = PyArray_SIZE(self); + return 1; +} - if (oldsize != newsize) { - if (!(self->flags & OWNDATA)) { - PyErr_SetString(PyExc_ValueError, - "cannot resize this array: " \ - "it does not own its data"); - return NULL; - } - if (refcheck) { - refcnt = REFCOUNT(self); - } - else { - refcnt = 1; - } - if ((refcnt > 2) || (self->base != NULL) || - (self->weakreflist != NULL)) { - PyErr_SetString(PyExc_ValueError, - "cannot resize an array that has "\ - "been referenced or is referencing\n"\ - "another array in this way. Use the "\ - "resize function"); - return NULL; - } +/* 0-strided arrays are not contiguous (even if dimension == 1) */ +static int +_IsFortranContiguous(PyArrayObject *ap) +{ + intp sd; + intp dim; + int i; - if (newsize == 0) { - sd = self->descr->elsize; - } - else { - sd = newsize*self->descr->elsize; - } - /* Reallocate space if needed */ - new_data = PyDataMem_RENEW(self->data, sd); - if (new_data == NULL) { - PyErr_SetString(PyExc_MemoryError, - "cannot allocate memory for array"); - return NULL; - } - self->data = new_data; + if (ap->nd == 0) { + return 1; } - - if ((newsize > oldsize) && PyArray_ISWRITEABLE(self)) { - /* Fill new memory with zeros */ - elsize = self->descr->elsize; - if (PyDataType_FLAGCHK(self->descr, NPY_ITEM_REFCOUNT)) { - PyObject *zero = PyInt_FromLong(0); - char *optr; - optr = self->data + oldsize*elsize; - n = newsize - oldsize; - for (k = 0; k < n; k++) { - _putzero((char *)optr, zero, self->descr); - optr += elsize; - } - Py_DECREF(zero); - } - else{ - memset(self->data+oldsize*elsize, 0, (newsize-oldsize)*elsize); - } + sd = ap->descr->elsize; + if (ap->nd == 1) { + return ap->dimensions[0] == 1 || sd == ap->strides[0]; } - - if (self->nd != new_nd) { - /* Different number of dimensions. */ - self->nd = new_nd; - /* Need new dimensions and strides arrays */ - dimptr = PyDimMem_RENEW(self->dimensions, 2*new_nd); - if (dimptr == NULL) { - PyErr_SetString(PyExc_MemoryError, - "cannot allocate memory for array " \ - "(array may be corrupted)"); - return NULL; + for (i = 0; i < ap->nd; ++i) { + dim = ap->dimensions[i]; + /* fortran contiguous by definition */ + if (dim == 0) { + return 1; } - self->dimensions = dimptr; - self->strides = dimptr + new_nd; + if (ap->strides[i] != sd) { + return 0; + } + sd *= dim; } - - /* make new_strides variable */ - sd = (size_t) self->descr->elsize; - sd = (size_t) _array_fill_strides(new_strides, new_dimensions, new_nd, sd, - self->flags, &(self->flags)); - memmove(self->dimensions, new_dimensions, new_nd*sizeof(intp)); - memmove(self->strides, new_strides, new_nd*sizeof(intp)); - Py_INCREF(Py_None); - return Py_None; + return 1; } -static void -_fillobject(char *optr, PyObject *obj, PyArray_Descr *dtype) +static int +_IsAligned(PyArrayObject *ap) { - if (!PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)) { - if ((obj == Py_None) || (PyInt_Check(obj) && PyInt_AsLong(obj)==0)) { - return; - } - else { - PyObject *arr; - Py_INCREF(dtype); - arr = PyArray_NewFromDescr(&PyArray_Type, dtype, - 0, NULL, NULL, NULL, - 0, NULL); - if (arr!=NULL) { - dtype->f->setitem(obj, optr, arr); - } - Py_XDECREF(arr); - } - } - else if (PyDescr_HASFIELDS(dtype)) { - PyObject *key, *value, *title = NULL; - PyArray_Descr *new; - int offset; - Py_ssize_t pos = 0; + int i, alignment, aligned = 1; + intp ptr; + int type = ap->descr->type_num; - while (PyDict_Next(dtype->fields, &pos, &key, &value)) { - if NPY_TITLE_KEY(key, value) { - continue; - } - if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) { - return; - } - _fillobject(optr + offset, obj, new); - } + if ((type == PyArray_STRING) || (type == PyArray_VOID)) { + return 1; } - else { - PyObject **temp; - Py_XINCREF(obj); - temp = (PyObject **)optr; - *temp = obj; - return; + alignment = ap->descr->alignment; + if (alignment == 1) { + return 1; + } + ptr = (intp) ap->data; + aligned = (ptr % alignment) == 0; + for (i = 0; i < ap->nd; i++) { + aligned &= ((ap->strides[i] % alignment) == 0); } + return aligned != 0; } -/*NUMPY_API - * Assumes contiguous - */ -NPY_NO_EXPORT void -PyArray_FillObjectArray(PyArrayObject *arr, PyObject *obj) +static Bool +_IsWriteable(PyArrayObject *ap) { - intp i,n; - n = PyArray_SIZE(arr); - if (arr->descr->type_num == PyArray_OBJECT) { - PyObject **optr; - optr = (PyObject **)(arr->data); - n = PyArray_SIZE(arr); - if (obj == NULL) { - for (i = 0; i < n; i++) { - *optr++ = NULL; - } - } - else { - for (i = 0; i < n; i++) { - Py_INCREF(obj); - *optr++ = obj; - } - } + PyObject *base=ap->base; + void *dummy; + Py_ssize_t n; + + /* If we own our own data, then no-problem */ + if ((base == NULL) || (ap->flags & OWNDATA)) { + return TRUE; } - else { - char *optr; - optr = arr->data; - for (i = 0; i < n; i++) { - _fillobject(optr, obj, arr->descr); - optr += arr->descr->elsize; + /* + * Get to the final base object + * If it is a writeable array, then return TRUE + * If we can find an array object + * or a writeable buffer object as the final base object + * or a string object (for pickling support memory savings). + * - this last could be removed if a proper pickleable + * buffer was added to Python. + */ + + while(PyArray_Check(base)) { + if (PyArray_CHKFLAGS(base, OWNDATA)) { + return (Bool) (PyArray_ISWRITEABLE(base)); } + base = PyArray_BASE(base); + } + + /* + * here so pickle support works seamlessly + * and unpickled array can be set and reset writeable + * -- could be abused -- + */ + if PyString_Check(base) { + return TRUE; + } + if (PyObject_AsWriteBuffer(base, &dummy, &n) < 0) { + return FALSE; } + return TRUE; } -/*NUMPY_API*/ + +/*NUMPY_API + */ NPY_NO_EXPORT int -PyArray_FillWithScalar(PyArrayObject *arr, PyObject *obj) +PyArray_ElementStrides(PyObject *arr) { - PyObject *newarr; - int itemsize, swap; - void *fromptr; - PyArray_Descr *descr; - intp size; - PyArray_CopySwapFunc *copyswap; + int itemsize = PyArray_ITEMSIZE(arr); + int i, N = PyArray_NDIM(arr); + intp *strides = PyArray_STRIDES(arr); - itemsize = arr->descr->elsize; - if (PyArray_ISOBJECT(arr)) { - fromptr = &obj; - swap = 0; - newarr = NULL; - } - else { - descr = PyArray_DESCR(arr); - Py_INCREF(descr); - newarr = PyArray_FromAny(obj, descr, 0,0, ALIGNED, NULL); - if (newarr == NULL) { - return -1; + for (i = 0; i < N; i++) { + if ((strides[i] % itemsize) != 0) { + return 0; } - fromptr = PyArray_DATA(newarr); - swap = (PyArray_ISNOTSWAPPED(arr) != PyArray_ISNOTSWAPPED(newarr)); } - size=PyArray_SIZE(arr); - copyswap = arr->descr->f->copyswap; - if (PyArray_ISONESEGMENT(arr)) { - char *toptr=PyArray_DATA(arr); - PyArray_FillWithScalarFunc* fillwithscalar = - arr->descr->f->fillwithscalar; - if (fillwithscalar && PyArray_ISALIGNED(arr)) { - copyswap(fromptr, NULL, swap, newarr); - fillwithscalar(toptr, size, fromptr, arr); + return 1; +} + +/*NUMPY_API + * Update Several Flags at once. + */ +NPY_NO_EXPORT void +PyArray_UpdateFlags(PyArrayObject *ret, int flagmask) +{ + + if (flagmask & FORTRAN) { + if (_IsFortranContiguous(ret)) { + ret->flags |= FORTRAN; + if (ret->nd > 1) { + ret->flags &= ~CONTIGUOUS; + } } else { - while (size--) { - copyswap(toptr, fromptr, swap, arr); - toptr += itemsize; + ret->flags &= ~FORTRAN; + } + } + if (flagmask & CONTIGUOUS) { + if (_IsContiguous(ret)) { + ret->flags |= CONTIGUOUS; + if (ret->nd > 1) { + ret->flags &= ~FORTRAN; } } + else { + ret->flags &= ~CONTIGUOUS; + } } - else { - PyArrayIterObject *iter; - - iter = (PyArrayIterObject *)\ - PyArray_IterNew((PyObject *)arr); - if (iter == NULL) { - Py_XDECREF(newarr); - return -1; + if (flagmask & ALIGNED) { + if (_IsAligned(ret)) { + ret->flags |= ALIGNED; } - while (size--) { - copyswap(iter->dataptr, fromptr, swap, arr); - PyArray_ITER_NEXT(iter); + else { + ret->flags &= ~ALIGNED; } - Py_DECREF(iter); } - Py_XDECREF(newarr); - return 0; -} - -static PyObject * -array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"shape", "dtype", "buffer", - "offset", "strides", - "order", NULL}; - PyArray_Descr *descr=NULL; - int itemsize; - PyArray_Dims dims = {NULL, 0}; - PyArray_Dims strides = {NULL, 0}; - PyArray_Chunk buffer; - longlong offset=0; - NPY_ORDER order=PyArray_CORDER; - int fortran = 0; - PyArrayObject *ret; - - buffer.ptr = NULL; /* - * Usually called with shape and type but can also be called with buffer, - * strides, and swapped info For now, let's just use this to create an - * empty, contiguous array of a specific type and shape. + * This is not checked by default WRITEABLE is not + * part of UPDATE_ALL */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&LO&O&", - kwlist, PyArray_IntpConverter, - &dims, - PyArray_DescrConverter, - &descr, - PyArray_BufferConverter, - &buffer, - &offset, - &PyArray_IntpConverter, - &strides, - &PyArray_OrderConverter, - &order)) { - goto fail; - } - if (order == PyArray_FORTRANORDER) { - fortran = 1; - } - if (descr == NULL) { - descr = PyArray_DescrFromType(PyArray_DEFAULT); - } - - itemsize = descr->elsize; - if (itemsize == 0) { - PyErr_SetString(PyExc_ValueError, - "data-type with unspecified variable length"); - goto fail; - } - - if (strides.ptr != NULL) { - intp nb, off; - if (strides.len != dims.len) { - PyErr_SetString(PyExc_ValueError, - "strides, if given, must be " \ - "the same length as shape"); - goto fail; - } - - if (buffer.ptr == NULL) { - nb = 0; - off = 0; + if (flagmask & WRITEABLE) { + if (_IsWriteable(ret)) { + ret->flags |= WRITEABLE; } else { - nb = buffer.len; - off = (intp) offset; + ret->flags &= ~WRITEABLE; } + } + return; +} +/* + * This routine checks to see if newstrides (of length nd) will not + * ever be able to walk outside of the memory implied numbytes and offset. + * + * The available memory is assumed to start at -offset and proceed + * to numbytes-offset. The strides are checked to ensure + * that accessing memory using striding will not try to reach beyond + * this memory for any of the axes. + * + * If numbytes is 0 it will be calculated using the dimensions and + * element-size. + * + * This function checks for walking beyond the beginning and right-end + * of the buffer and therefore works for any integer stride (positive + * or negative). + */ - if (!PyArray_CheckStrides(itemsize, dims.len, - nb, off, - dims.ptr, strides.ptr)) { - PyErr_SetString(PyExc_ValueError, - "strides is incompatible " \ - "with shape of requested " \ - "array and size of buffer"); - goto fail; +/*NUMPY_API*/ +NPY_NO_EXPORT Bool +PyArray_CheckStrides(int elsize, int nd, intp numbytes, intp offset, + intp *dims, intp *newstrides) +{ + int i; + intp byte_begin; + intp begin; + intp end; + + if (numbytes == 0) { + numbytes = PyArray_MultiplyList(dims, nd) * elsize; + } + begin = -offset; + end = numbytes - offset - elsize; + for (i = 0; i < nd; i++) { + byte_begin = newstrides[i]*(dims[i] - 1); + if ((byte_begin < begin) || (byte_begin > end)) { + return FALSE; } } + return TRUE; +} - if (buffer.ptr == NULL) { - ret = (PyArrayObject *) - PyArray_NewFromDescr(subtype, descr, - (int)dims.len, - dims.ptr, - strides.ptr, NULL, fortran, NULL); - if (ret == NULL) { - descr = NULL; - goto fail; + +/* + * This is the main array creation routine. + * + * Flags argument has multiple related meanings + * depending on data and strides: + * + * If data is given, then flags is flags associated with data. + * If strides is not given, then a contiguous strides array will be created + * and the CONTIGUOUS bit will be set. If the flags argument + * has the FORTRAN bit set, then a FORTRAN-style strides array will be + * created (and of course the FORTRAN flag bit will be set). + * + * If data is not given but created here, then flags will be DEFAULT + * and a non-zero flags argument can be used to indicate a FORTRAN style + * array is desired. + */ + +static size_t +_array_fill_strides(intp *strides, intp *dims, int nd, size_t itemsize, + int inflag, int *objflags) +{ + int i; + /* Only make Fortran strides if not contiguous as well */ + if ((inflag & FORTRAN) && !(inflag & CONTIGUOUS)) { + for (i = 0; i < nd; i++) { + strides[i] = itemsize; + itemsize *= dims[i] ? dims[i] : 1; } - if (PyDataType_FLAGCHK(descr, NPY_ITEM_HASOBJECT)) { - /* place Py_None in object positions */ - PyArray_FillObjectArray(ret, Py_None); - if (PyErr_Occurred()) { - descr = NULL; - goto fail; - } + *objflags |= FORTRAN; + if (nd > 1) { + *objflags &= ~CONTIGUOUS; + } + else { + *objflags |= CONTIGUOUS; } } else { - /* buffer given -- use it */ - if (dims.len == 1 && dims.ptr[0] == -1) { - dims.ptr[0] = (buffer.len-(intp)offset) / itemsize; - } - else if ((strides.ptr == NULL) && - (buffer.len < ((intp)itemsize)* - PyArray_MultiplyList(dims.ptr, dims.len))) { - PyErr_SetString(PyExc_TypeError, - "buffer is too small for " \ - "requested array"); - goto fail; + for (i = nd - 1; i >= 0; i--) { + strides[i] = itemsize; + itemsize *= dims[i] ? dims[i] : 1; } - /* get writeable and aligned */ - if (fortran) { - buffer.flags |= FORTRAN; + *objflags |= CONTIGUOUS; + if (nd > 1) { + *objflags &= ~FORTRAN; } - ret = (PyArrayObject *)\ - PyArray_NewFromDescr(subtype, descr, - dims.len, dims.ptr, - strides.ptr, - offset + (char *)buffer.ptr, - buffer.flags, NULL); - if (ret == NULL) { - descr = NULL; - goto fail; + else { + *objflags |= FORTRAN; } - PyArray_UpdateFlags(ret, UPDATE_ALL); - ret->base = buffer.base; - Py_INCREF(buffer.base); } + return itemsize; +} - PyDimMem_FREE(dims.ptr); - if (strides.ptr) { - PyDimMem_FREE(strides.ptr); - } - return (PyObject *)ret; +/*NUMPY_API + * Generic new array creation routine. + */ +NPY_NO_EXPORT PyObject * +PyArray_New(PyTypeObject *subtype, int nd, intp *dims, int type_num, + intp *strides, void *data, int itemsize, int flags, + PyObject *obj) +{ + PyArray_Descr *descr; + PyObject *new; - fail: - Py_XDECREF(descr); - if (dims.ptr) { - PyDimMem_FREE(dims.ptr); + descr = PyArray_DescrFromType(type_num); + if (descr == NULL) { + return NULL; } - if (strides.ptr) { - PyDimMem_FREE(strides.ptr); + if (descr->elsize == 0) { + if (itemsize < 1) { + PyErr_SetString(PyExc_ValueError, + "data type must provide an itemsize"); + Py_DECREF(descr); + return NULL; + } + PyArray_DESCR_REPLACE(descr); + descr->elsize = itemsize; } - return NULL; + new = PyArray_NewFromDescr(subtype, descr, nd, dims, strides, + data, flags, obj); + return new; } - -static PyObject * -array_iter(PyArrayObject *arr) +/* + * Change a sub-array field to the base descriptor + * + * and update the dimensions and strides + * appropriately. Dimensions and strides are added + * to the end unless we have a FORTRAN array + * and then they are added to the beginning + * + * Strides are only added if given (because data is given). + */ +static int +_update_descr_and_dimensions(PyArray_Descr **des, intp *newdims, + intp *newstrides, int oldnd, int isfortran) { - if (arr->nd == 0) { - PyErr_SetString(PyExc_TypeError, - "iteration over a 0-d array"); - return NULL; + PyArray_Descr *old; + int newnd; + int numnew; + intp *mydim; + int i; + int tuple; + + old = *des; + *des = old->subarray->base; + + + mydim = newdims + oldnd; + tuple = PyTuple_Check(old->subarray->shape); + if (tuple) { + numnew = PyTuple_GET_SIZE(old->subarray->shape); + } + else { + numnew = 1; } - return PySeqIter_New((PyObject *)arr); -} -/******************* array attribute get and set routines ******************/ + newnd = oldnd + numnew; + if (newnd > MAX_DIMS) { + goto finish; + } + if (isfortran) { + memmove(newdims+numnew, newdims, oldnd*sizeof(intp)); + mydim = newdims; + } + if (tuple) { + for (i = 0; i < numnew; i++) { + mydim[i] = (intp) PyInt_AsLong( + PyTuple_GET_ITEM(old->subarray->shape, i)); + } + } + else { + mydim[0] = (intp) PyInt_AsLong(old->subarray->shape); + } -static PyObject * -array_ndim_get(PyArrayObject *self) -{ - return PyInt_FromLong(self->nd); -} + if (newstrides) { + intp tempsize; + intp *mystrides; -static PyObject * -array_flags_get(PyArrayObject *self) -{ - return PyArray_NewFlagsObject((PyObject *)self); -} + mystrides = newstrides + oldnd; + if (isfortran) { + memmove(newstrides+numnew, newstrides, oldnd*sizeof(intp)); + mystrides = newstrides; + } + /* Make new strides -- alwasy C-contiguous */ + tempsize = (*des)->elsize; + for (i = numnew - 1; i >= 0; i--) { + mystrides[i] = tempsize; + tempsize *= mydim[i] ? mydim[i] : 1; + } + } -static PyObject * -array_shape_get(PyArrayObject *self) -{ - return PyArray_IntTupleFromIntp(self->nd, self->dimensions); + finish: + Py_INCREF(*des); + Py_DECREF(old); + return newnd; } -static int -array_shape_set(PyArrayObject *self, PyObject *val) +/*NUMPY_API + * Generic new array creation routine. + * + * steals a reference to descr (even on failure) + */ +NPY_NO_EXPORT PyObject * +PyArray_NewFromDescr(PyTypeObject *subtype, PyArray_Descr *descr, int nd, + intp *dims, intp *strides, void *data, + int flags, PyObject *obj) { - int nd; - PyObject *ret; + PyArrayObject *self; + int i; + size_t sd; + intp largest; + intp size; - /* Assumes C-order */ - ret = PyArray_Reshape(self, val); - if (ret == NULL) { - return -1; + if (descr->subarray) { + PyObject *ret; + intp newdims[2*MAX_DIMS]; + intp *newstrides = NULL; + int isfortran = 0; + isfortran = (data && (flags & FORTRAN) && !(flags & CONTIGUOUS)) || + (!data && flags); + memcpy(newdims, dims, nd*sizeof(intp)); + if (strides) { + newstrides = newdims + MAX_DIMS; + memcpy(newstrides, strides, nd*sizeof(intp)); + } + nd =_update_descr_and_dimensions(&descr, newdims, + newstrides, nd, isfortran); + ret = PyArray_NewFromDescr(subtype, descr, nd, newdims, + newstrides, + data, flags, obj); + return ret; } - if (PyArray_DATA(ret) != PyArray_DATA(self)) { - Py_DECREF(ret); - PyErr_SetString(PyExc_AttributeError, - "incompatible shape for a non-contiguous "\ - "array"); - return -1; + if (nd < 0) { + PyErr_SetString(PyExc_ValueError, + "number of dimensions must be >=0"); + Py_DECREF(descr); + return NULL; + } + if (nd > MAX_DIMS) { + PyErr_Format(PyExc_ValueError, + "maximum number of dimensions is %d", MAX_DIMS); + Py_DECREF(descr); + return NULL; + } + + /* Check dimensions */ + size = 1; + sd = (size_t) descr->elsize; + if (sd == 0) { + if (!PyDataType_ISSTRING(descr)) { + PyErr_SetString(PyExc_ValueError, "Empty data-type"); + Py_DECREF(descr); + return NULL; + } + PyArray_DESCR_REPLACE(descr); + if (descr->type_num == NPY_STRING) { + descr->elsize = 1; + } + else { + descr->elsize = sizeof(PyArray_UCS4); + } + sd = descr->elsize; + } + + largest = NPY_MAX_INTP / sd; + for (i = 0; i < nd; i++) { + intp dim = dims[i]; + + if (dim == 0) { + /* + * Compare to PyArray_OverflowMultiplyList that + * returns 0 in this case. + */ + continue; + } + if (dim < 0) { + PyErr_SetString(PyExc_ValueError, + "negative dimensions " \ + "are not allowed"); + Py_DECREF(descr); + return NULL; + } + if (dim > largest) { + PyErr_SetString(PyExc_ValueError, + "array is too big."); + Py_DECREF(descr); + return NULL; + } + size *= dim; + largest /= dim; } - /* Free old dimensions and strides */ - PyDimMem_FREE(self->dimensions); - nd = PyArray_NDIM(ret); + self = (PyArrayObject *) subtype->tp_alloc(subtype, 0); + if (self == NULL) { + Py_DECREF(descr); + return NULL; + } self->nd = nd; + self->dimensions = NULL; + self->data = NULL; + if (data == NULL) { + self->flags = DEFAULT; + if (flags) { + self->flags |= FORTRAN; + if (nd > 1) { + self->flags &= ~CONTIGUOUS; + } + flags = FORTRAN; + } + } + else { + self->flags = (flags & ~UPDATEIFCOPY); + } + self->descr = descr; + self->base = (PyObject *)NULL; + self->weakreflist = (PyObject *)NULL; + if (nd > 0) { - /* create new dimensions and strides */ self->dimensions = PyDimMem_NEW(2*nd); if (self->dimensions == NULL) { - Py_DECREF(ret); - PyErr_SetString(PyExc_MemoryError,""); - return -1; + PyErr_NoMemory(); + goto fail; } self->strides = self->dimensions + nd; - memcpy(self->dimensions, PyArray_DIMS(ret), nd*sizeof(intp)); - memcpy(self->strides, PyArray_STRIDES(ret), nd*sizeof(intp)); + memcpy(self->dimensions, dims, sizeof(intp)*nd); + if (strides == NULL) { /* fill it in */ + sd = _array_fill_strides(self->strides, dims, nd, sd, + flags, &(self->flags)); + } + else { + /* + * we allow strides even when we create + * the memory, but be careful with this... + */ + memcpy(self->strides, strides, sizeof(intp)*nd); + sd *= size; + } } else { - self->dimensions = NULL; - self->strides = NULL; + self->dimensions = self->strides = NULL; } - Py_DECREF(ret); - PyArray_UpdateFlags(self, CONTIGUOUS | FORTRAN); - return 0; -} + if (data == NULL) { + /* + * Allocate something even for zero-space arrays + * e.g. shape=(0,) -- otherwise buffer exposure + * (a.data) doesn't work as it should. + */ -static PyObject * -array_strides_get(PyArrayObject *self) -{ - return PyArray_IntTupleFromIntp(self->nd, self->strides); -} + if (sd == 0) { + sd = descr->elsize; + } + if ((data = PyDataMem_NEW(sd)) == NULL) { + PyErr_NoMemory(); + goto fail; + } + self->flags |= OWNDATA; -static int -array_strides_set(PyArrayObject *self, PyObject *obj) -{ - PyArray_Dims newstrides = {NULL, 0}; - PyArrayObject *new; - intp numbytes = 0; - intp offset = 0; - Py_ssize_t buf_len; - char *buf; - - if (!PyArray_IntpConverter(obj, &newstrides) || - newstrides.ptr == NULL) { - PyErr_SetString(PyExc_TypeError, "invalid strides"); - return -1; - } - if (newstrides.len != self->nd) { - PyErr_Format(PyExc_ValueError, "strides must be " \ - " same length as shape (%d)", self->nd); - goto fail; + /* + * It is bad to have unitialized OBJECT pointers + * which could also be sub-fields of a VOID array + */ + if (PyDataType_FLAGCHK(descr, NPY_NEEDS_INIT)) { + memset(data, 0, sd); + } } - new = self; - while(new->base && PyArray_Check(new->base)) { - new = (PyArrayObject *)(new->base); + else { + /* + * If data is passed in, this object won't own it by default. + * Caller must arrange for this to be reset if truly desired + */ + self->flags &= ~OWNDATA; } + self->data = data; + /* - * Get the available memory through the buffer interface on - * new->base or if that fails from the current new + * call the __array_finalize__ + * method if a subtype. + * If obj is NULL, then call method with Py_None */ - if (new->base && PyObject_AsReadBuffer(new->base, - (const void **)&buf, - &buf_len) >= 0) { - offset = self->data - buf; - numbytes = buf_len + offset; - } - else { - PyErr_Clear(); - numbytes = PyArray_MultiplyList(new->dimensions, - new->nd)*new->descr->elsize; - offset = self->data - new->data; - } + if ((subtype != &PyArray_Type)) { + PyObject *res, *func, *args; + static PyObject *str = NULL; - if (!PyArray_CheckStrides(self->descr->elsize, self->nd, numbytes, - offset, - self->dimensions, newstrides.ptr)) { - PyErr_SetString(PyExc_ValueError, "strides is not "\ - "compatible with available memory"); - goto fail; + if (str == NULL) { + str = PyString_InternFromString("__array_finalize__"); + } + func = PyObject_GetAttr((PyObject *)self, str); + if (func && func != Py_None) { + if (strides != NULL) { + /* + * did not allocate own data or funny strides + * update flags before finalize function + */ + PyArray_UpdateFlags(self, UPDATE_ALL); + } + if PyCObject_Check(func) { + /* A C-function is stored here */ + PyArray_FinalizeFunc *cfunc; + cfunc = PyCObject_AsVoidPtr(func); + Py_DECREF(func); + if (cfunc(self, obj) < 0) { + goto fail; + } + } + else { + args = PyTuple_New(1); + if (obj == NULL) { + obj=Py_None; + } + Py_INCREF(obj); + PyTuple_SET_ITEM(args, 0, obj); + res = PyObject_Call(func, args, NULL); + Py_DECREF(args); + Py_DECREF(func); + if (res == NULL) { + goto fail; + } + else { + Py_DECREF(res); + } + } + } + else Py_XDECREF(func); } - memcpy(self->strides, newstrides.ptr, sizeof(intp)*newstrides.len); - PyArray_UpdateFlags(self, CONTIGUOUS | FORTRAN); - PyDimMem_FREE(newstrides.ptr); - return 0; + return (PyObject *)self; fail: - PyDimMem_FREE(newstrides.ptr); - return -1; + Py_DECREF(self); + return NULL; } - - -static PyObject * -array_priority_get(PyArrayObject *self) +static void +_putzero(char *optr, PyObject *zero, PyArray_Descr *dtype) { - if (PyArray_CheckExact(self)) { - return PyFloat_FromDouble(PyArray_PRIORITY); + if (!PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)) { + memset(optr, 0, dtype->elsize); + } + else if (PyDescr_HASFIELDS(dtype)) { + PyObject *key, *value, *title = NULL; + PyArray_Descr *new; + int offset; + Py_ssize_t pos = 0; + while (PyDict_Next(dtype->fields, &pos, &key, &value)) { + if NPY_TITLE_KEY(key, value) { + continue; + } + if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) { + return; + } + _putzero(optr + offset, zero, new); + } } else { - return PyFloat_FromDouble(PyArray_SUBTYPE_PRIORITY); + PyObject **temp; + Py_INCREF(zero); + temp = (PyObject **)optr; + *temp = zero; } + return; } -static PyObject * -array_typestr_get(PyArrayObject *self) -{ - return arraydescr_protocol_typestr_get(self->descr); -} - -static PyObject * -array_descr_get(PyArrayObject *self) -{ - Py_INCREF(self->descr); - return (PyObject *)self->descr; -} -static PyObject * -array_protocol_descr_get(PyArrayObject *self) +/*NUMPY_API + * Resize (reallocate data). Only works if nothing else is referencing this + * array and it is contiguous. If refcheck is 0, then the reference count is + * not checked and assumed to be 1. You still must own this data and have no + * weak-references and no base object. + */ +NPY_NO_EXPORT PyObject * +PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, + NPY_ORDER fortran) { - PyObject *res; - PyObject *dobj; - - res = arraydescr_protocol_descr_get(self->descr); - if (res) { - return res; - } - PyErr_Clear(); + intp oldsize, newsize; + int new_nd=newshape->len, k, n, elsize; + int refcnt; + intp* new_dimensions=newshape->ptr; + intp new_strides[MAX_DIMS]; + size_t sd; + intp *dimptr; + char *new_data; + intp largest; - /* get default */ - dobj = PyTuple_New(2); - if (dobj == NULL) { - return NULL; - } - PyTuple_SET_ITEM(dobj, 0, PyString_FromString("")); - PyTuple_SET_ITEM(dobj, 1, array_typestr_get(self)); - res = PyList_New(1); - if (res == NULL) { - Py_DECREF(dobj); + if (!PyArray_ISONESEGMENT(self)) { + PyErr_SetString(PyExc_ValueError, + "resize only works on single-segment arrays"); return NULL; } - PyList_SET_ITEM(res, 0, dobj); - return res; -} - -static PyObject * -array_protocol_strides_get(PyArrayObject *self) -{ - if PyArray_ISCONTIGUOUS(self) { - Py_INCREF(Py_None); - return Py_None; - } - return PyArray_IntTupleFromIntp(self->nd, self->strides); -} - - - -static PyObject * -array_dataptr_get(PyArrayObject *self) -{ - return Py_BuildValue("NO", - PyLong_FromVoidPtr(self->data), - (self->flags & WRITEABLE ? Py_False : - Py_True)); -} -static PyObject * -array_ctypes_get(PyArrayObject *self) -{ - PyObject *_numpy_internal; - PyObject *ret; - _numpy_internal = PyImport_ImportModule("numpy.core._internal"); - if (_numpy_internal == NULL) { - return NULL; + if (fortran == PyArray_ANYORDER) { + fortran = PyArray_CORDER; } - ret = PyObject_CallMethod(_numpy_internal, "_ctypes", "ON", self, - PyLong_FromVoidPtr(self->data)); - Py_DECREF(_numpy_internal); - return ret; -} - -static PyObject * -array_interface_get(PyArrayObject *self) -{ - PyObject *dict; - PyObject *obj; - - dict = PyDict_New(); - if (dict == NULL) { + if (self->descr->elsize == 0) { + PyErr_SetString(PyExc_ValueError, "Bad data-type size."); return NULL; } + newsize = 1; + largest = MAX_INTP / self->descr->elsize; + for(k=0; k largest) { + return PyErr_NoMemory(); + } + } + oldsize = PyArray_SIZE(self); - /* dataptr */ - obj = array_dataptr_get(self); - PyDict_SetItemString(dict, "data", obj); - Py_DECREF(obj); - - obj = array_protocol_strides_get(self); - PyDict_SetItemString(dict, "strides", obj); - Py_DECREF(obj); - - obj = array_protocol_descr_get(self); - PyDict_SetItemString(dict, "descr", obj); - Py_DECREF(obj); - - obj = arraydescr_protocol_typestr_get(self->descr); - PyDict_SetItemString(dict, "typestr", obj); - Py_DECREF(obj); - - obj = array_shape_get(self); - PyDict_SetItemString(dict, "shape", obj); - Py_DECREF(obj); - - obj = PyInt_FromLong(3); - PyDict_SetItemString(dict, "version", obj); - Py_DECREF(obj); + if (oldsize != newsize) { + if (!(self->flags & OWNDATA)) { + PyErr_SetString(PyExc_ValueError, + "cannot resize this array: " \ + "it does not own its data"); + return NULL; + } - return dict; -} + if (refcheck) { + refcnt = REFCOUNT(self); + } + else { + refcnt = 1; + } + if ((refcnt > 2) || (self->base != NULL) || + (self->weakreflist != NULL)) { + PyErr_SetString(PyExc_ValueError, + "cannot resize an array that has "\ + "been referenced or is referencing\n"\ + "another array in this way. Use the "\ + "resize function"); + return NULL; + } -static PyObject * -array_data_get(PyArrayObject *self) -{ - intp nbytes; - if (!(PyArray_ISONESEGMENT(self))) { - PyErr_SetString(PyExc_AttributeError, "cannot get single-"\ - "segment buffer for discontiguous array"); - return NULL; - } - nbytes = PyArray_NBYTES(self); - if PyArray_ISWRITEABLE(self) { - return PyBuffer_FromReadWriteObject((PyObject *)self, 0, (Py_ssize_t) nbytes); - } - else { - return PyBuffer_FromObject((PyObject *)self, 0, (Py_ssize_t) nbytes); + if (newsize == 0) { + sd = self->descr->elsize; + } + else { + sd = newsize*self->descr->elsize; + } + /* Reallocate space if needed */ + new_data = PyDataMem_RENEW(self->data, sd); + if (new_data == NULL) { + PyErr_SetString(PyExc_MemoryError, + "cannot allocate memory for array"); + return NULL; + } + self->data = new_data; } -} -static int -array_data_set(PyArrayObject *self, PyObject *op) -{ - void *buf; - Py_ssize_t buf_len; - int writeable=1; - - if (PyObject_AsWriteBuffer(op, &buf, &buf_len) < 0) { - writeable = 0; - if (PyObject_AsReadBuffer(op, (const void **)&buf, &buf_len) < 0) { - PyErr_SetString(PyExc_AttributeError, - "object does not have single-segment " \ - "buffer interface"); - return -1; + if ((newsize > oldsize) && PyArray_ISWRITEABLE(self)) { + /* Fill new memory with zeros */ + elsize = self->descr->elsize; + if (PyDataType_FLAGCHK(self->descr, NPY_ITEM_REFCOUNT)) { + PyObject *zero = PyInt_FromLong(0); + char *optr; + optr = self->data + oldsize*elsize; + n = newsize - oldsize; + for (k = 0; k < n; k++) { + _putzero((char *)optr, zero, self->descr); + optr += elsize; + } + Py_DECREF(zero); } - } - if (!PyArray_ISONESEGMENT(self)) { - PyErr_SetString(PyExc_AttributeError, "cannot set single-" \ - "segment buffer for discontiguous array"); - return -1; - } - if (PyArray_NBYTES(self) > buf_len) { - PyErr_SetString(PyExc_AttributeError, "not enough data for array"); - return -1; - } - if (self->flags & OWNDATA) { - PyArray_XDECREF(self); - PyDataMem_FREE(self->data); - } - if (self->base) { - if (self->flags & UPDATEIFCOPY) { - ((PyArrayObject *)self->base)->flags |= WRITEABLE; - self->flags &= ~UPDATEIFCOPY; + else{ + memset(self->data+oldsize*elsize, 0, (newsize-oldsize)*elsize); } - Py_DECREF(self->base); } - Py_INCREF(op); - self->base = op; - self->data = buf; - self->flags = CARRAY; - if (!writeable) { - self->flags &= ~WRITEABLE; - } - return 0; -} + if (self->nd != new_nd) { + /* Different number of dimensions. */ + self->nd = new_nd; + /* Need new dimensions and strides arrays */ + dimptr = PyDimMem_RENEW(self->dimensions, 2*new_nd); + if (dimptr == NULL) { + PyErr_SetString(PyExc_MemoryError, + "cannot allocate memory for array " \ + "(array may be corrupted)"); + return NULL; + } + self->dimensions = dimptr; + self->strides = dimptr + new_nd; + } -static PyObject * -array_itemsize_get(PyArrayObject *self) -{ - return PyInt_FromLong((long) self->descr->elsize); + /* make new_strides variable */ + sd = (size_t) self->descr->elsize; + sd = (size_t) _array_fill_strides(new_strides, new_dimensions, new_nd, sd, + self->flags, &(self->flags)); + memmove(self->dimensions, new_dimensions, new_nd*sizeof(intp)); + memmove(self->strides, new_strides, new_nd*sizeof(intp)); + Py_INCREF(Py_None); + return Py_None; } -static PyObject * -array_size_get(PyArrayObject *self) +static void +_fillobject(char *optr, PyObject *obj, PyArray_Descr *dtype) { - intp size=PyArray_SIZE(self); -#if SIZEOF_INTP <= SIZEOF_LONG - return PyInt_FromLong((long) size); -#else - if (size > MAX_LONG || size < MIN_LONG) { - return PyLong_FromLongLong(size); - } - else { - return PyInt_FromLong((long) size); + if (!PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)) { + if ((obj == Py_None) || (PyInt_Check(obj) && PyInt_AsLong(obj)==0)) { + return; + } + else { + PyObject *arr; + Py_INCREF(dtype); + arr = PyArray_NewFromDescr(&PyArray_Type, dtype, + 0, NULL, NULL, NULL, + 0, NULL); + if (arr!=NULL) { + dtype->f->setitem(obj, optr, arr); + } + Py_XDECREF(arr); + } } -#endif -} + else if (PyDescr_HASFIELDS(dtype)) { + PyObject *key, *value, *title = NULL; + PyArray_Descr *new; + int offset; + Py_ssize_t pos = 0; -static PyObject * -array_nbytes_get(PyArrayObject *self) -{ - intp nbytes = PyArray_NBYTES(self); -#if SIZEOF_INTP <= SIZEOF_LONG - return PyInt_FromLong((long) nbytes); -#else - if (nbytes > MAX_LONG || nbytes < MIN_LONG) { - return PyLong_FromLongLong(nbytes); + while (PyDict_Next(dtype->fields, &pos, &key, &value)) { + if NPY_TITLE_KEY(key, value) { + continue; + } + if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) { + return; + } + _fillobject(optr + offset, obj, new); + } } else { - return PyInt_FromLong((long) nbytes); + PyObject **temp; + Py_XINCREF(obj); + temp = (PyObject **)optr; + *temp = obj; + return; } -#endif } - -/* - * If the type is changed. - * Also needing change: strides, itemsize - * - * Either itemsize is exactly the same or the array is single-segment - * (contiguous or fortran) with compatibile dimensions The shape and strides - * will be adjusted in that case as well. +/*NUMPY_API + * Assumes contiguous */ - -static int -array_descr_set(PyArrayObject *self, PyObject *arg) +NPY_NO_EXPORT void +PyArray_FillObjectArray(PyArrayObject *arr, PyObject *obj) { - PyArray_Descr *newtype = NULL; - intp newdim; - int index; - char *msg = "new type not compatible with array."; - - if (!(PyArray_DescrConverter(arg, &newtype)) || - newtype == NULL) { - PyErr_SetString(PyExc_TypeError, "invalid data-type for array"); - return -1; - } - if (PyDataType_FLAGCHK(newtype, NPY_ITEM_HASOBJECT) || - PyDataType_FLAGCHK(newtype, NPY_ITEM_IS_POINTER) || - PyDataType_FLAGCHK(self->descr, NPY_ITEM_HASOBJECT) || - PyDataType_FLAGCHK(self->descr, NPY_ITEM_IS_POINTER)) { - PyErr_SetString(PyExc_TypeError, \ - "Cannot change data-type for object " \ - "array."); - Py_DECREF(newtype); - return -1; - } - - if (newtype->elsize == 0) { - PyErr_SetString(PyExc_TypeError, - "data-type must not be 0-sized"); - Py_DECREF(newtype); - return -1; - } - - - if ((newtype->elsize != self->descr->elsize) && - (self->nd == 0 || !PyArray_ISONESEGMENT(self) || - newtype->subarray)) { - goto fail; - } - if (PyArray_ISCONTIGUOUS(self)) { - index = self->nd - 1; - } - else { - index = 0; - } - if (newtype->elsize < self->descr->elsize) { - /* - * if it is compatible increase the size of the - * dimension at end (or at the front for FORTRAN) - */ - if (self->descr->elsize % newtype->elsize != 0) { - goto fail; + intp i,n; + n = PyArray_SIZE(arr); + if (arr->descr->type_num == PyArray_OBJECT) { + PyObject **optr; + optr = (PyObject **)(arr->data); + n = PyArray_SIZE(arr); + if (obj == NULL) { + for (i = 0; i < n; i++) { + *optr++ = NULL; + } } - newdim = self->descr->elsize / newtype->elsize; - self->dimensions[index] *= newdim; - self->strides[index] = newtype->elsize; - } - else if (newtype->elsize > self->descr->elsize) { - /* - * Determine if last (or first if FORTRAN) dimension - * is compatible - */ - newdim = self->dimensions[index] * self->descr->elsize; - if ((newdim % newtype->elsize) != 0) { - goto fail; + else { + for (i = 0; i < n; i++) { + Py_INCREF(obj); + *optr++ = obj; + } } - self->dimensions[index] = newdim / newtype->elsize; - self->strides[index] = newtype->elsize; } - - /* fall through -- adjust type*/ - Py_DECREF(self->descr); - if (newtype->subarray) { - /* - * create new array object from data and update - * dimensions, strides and descr from it - */ - PyArrayObject *temp; - /* - * We would decref newtype here. - * temp will steal a reference to it - */ - temp = (PyArrayObject *) - PyArray_NewFromDescr(&PyArray_Type, newtype, self->nd, - self->dimensions, self->strides, - self->data, self->flags, NULL); - if (temp == NULL) { - return -1; + else { + char *optr; + optr = arr->data; + for (i = 0; i < n; i++) { + _fillobject(optr, obj, arr->descr); + optr += arr->descr->elsize; } - PyDimMem_FREE(self->dimensions); - self->dimensions = temp->dimensions; - self->nd = temp->nd; - self->strides = temp->strides; - newtype = temp->descr; - Py_INCREF(temp->descr); - /* Fool deallocator not to delete these*/ - temp->nd = 0; - temp->dimensions = NULL; - Py_DECREF(temp); } - - self->descr = newtype; - PyArray_UpdateFlags(self, UPDATE_ALL); - return 0; - - fail: - PyErr_SetString(PyExc_ValueError, msg); - Py_DECREF(newtype); - return -1; } -static PyObject * -array_struct_get(PyArrayObject *self) +/*NUMPY_API*/ +NPY_NO_EXPORT int +PyArray_FillWithScalar(PyArrayObject *arr, PyObject *obj) { - PyArrayInterface *inter; + PyObject *newarr; + int itemsize, swap; + void *fromptr; + PyArray_Descr *descr; + intp size; + PyArray_CopySwapFunc *copyswap; - inter = (PyArrayInterface *)_pya_malloc(sizeof(PyArrayInterface)); - if (inter==NULL) { - return PyErr_NoMemory(); - } - inter->two = 2; - inter->nd = self->nd; - inter->typekind = self->descr->kind; - inter->itemsize = self->descr->elsize; - inter->flags = self->flags; - /* reset unused flags */ - inter->flags &= ~(UPDATEIFCOPY | OWNDATA); - if (PyArray_ISNOTSWAPPED(self)) inter->flags |= NOTSWAPPED; - /* - * Copy shape and strides over since these can be reset - *when the array is "reshaped". - */ - if (self->nd > 0) { - inter->shape = (intp *)_pya_malloc(2*sizeof(intp)*self->nd); - if (inter->shape == NULL) { - _pya_free(inter); - return PyErr_NoMemory(); - } - inter->strides = inter->shape + self->nd; - memcpy(inter->shape, self->dimensions, sizeof(intp)*self->nd); - memcpy(inter->strides, self->strides, sizeof(intp)*self->nd); + itemsize = arr->descr->elsize; + if (PyArray_ISOBJECT(arr)) { + fromptr = &obj; + swap = 0; + newarr = NULL; } else { - inter->shape = NULL; - inter->strides = NULL; + descr = PyArray_DESCR(arr); + Py_INCREF(descr); + newarr = PyArray_FromAny(obj, descr, 0,0, ALIGNED, NULL); + if (newarr == NULL) { + return -1; + } + fromptr = PyArray_DATA(newarr); + swap = (PyArray_ISNOTSWAPPED(arr) != PyArray_ISNOTSWAPPED(newarr)); } - inter->data = self->data; - if (self->descr->names) { - inter->descr = arraydescr_protocol_descr_get(self->descr); - if (inter->descr == NULL) { - PyErr_Clear(); + size=PyArray_SIZE(arr); + copyswap = arr->descr->f->copyswap; + if (PyArray_ISONESEGMENT(arr)) { + char *toptr=PyArray_DATA(arr); + PyArray_FillWithScalarFunc* fillwithscalar = + arr->descr->f->fillwithscalar; + if (fillwithscalar && PyArray_ISALIGNED(arr)) { + copyswap(fromptr, NULL, swap, newarr); + fillwithscalar(toptr, size, fromptr, arr); } else { - inter->flags &= ARR_HAS_DESCR; + while (size--) { + copyswap(toptr, fromptr, swap, arr); + toptr += itemsize; + } } } else { - inter->descr = NULL; - } - Py_INCREF(self); - return PyCObject_FromVoidPtrAndDesc(inter, self, gentype_struct_free); -} - -static PyObject * -array_base_get(PyArrayObject *self) -{ - if (self->base == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - else { - Py_INCREF(self->base); - return self->base; - } -} - + PyArrayIterObject *iter; -NPY_NO_EXPORT int -_zerofill(PyArrayObject *ret) -{ - if (PyDataType_REFCHK(ret->descr)) { - PyObject *zero = PyInt_FromLong(0); - PyArray_FillObjectArray(ret, zero); - Py_DECREF(zero); - if (PyErr_Occurred()) { - Py_DECREF(ret); + iter = (PyArrayIterObject *)\ + PyArray_IterNew((PyObject *)arr); + if (iter == NULL) { + Py_XDECREF(newarr); return -1; } + while (size--) { + copyswap(iter->dataptr, fromptr, swap, arr); + PyArray_ITER_NEXT(iter); + } + Py_DECREF(iter); } - else { - intp n = PyArray_NBYTES(ret); - memset(ret->data, 0, n); - } + Py_XDECREF(newarr); return 0; } - -/* - * Create a view of a complex array with an equivalent data-type - * except it is real instead of complex. - */ -static PyArrayObject * -_get_part(PyArrayObject *self, int imag) -{ - PyArray_Descr *type; - PyArrayObject *ret; - int offset; - - type = PyArray_DescrFromType(self->descr->type_num - - PyArray_NUM_FLOATTYPE); - offset = (imag ? type->elsize : 0); - - if (!PyArray_ISNBO(self->descr->byteorder)) { - PyArray_Descr *new; - new = PyArray_DescrNew(type); - new->byteorder = self->descr->byteorder; - Py_DECREF(type); - type = new; - } - ret = (PyArrayObject *) - PyArray_NewFromDescr(self->ob_type, - type, - self->nd, - self->dimensions, - self->strides, - self->data + offset, - self->flags, (PyObject *)self); - if (ret == NULL) { - return NULL; - } - ret->flags &= ~CONTIGUOUS; - ret->flags &= ~FORTRAN; - Py_INCREF(self); - ret->base = (PyObject *)self; - return ret; -} - static PyObject * -array_real_get(PyArrayObject *self) +array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) { + static char *kwlist[] = {"shape", "dtype", "buffer", + "offset", "strides", + "order", NULL}; + PyArray_Descr *descr=NULL; + int itemsize; + PyArray_Dims dims = {NULL, 0}; + PyArray_Dims strides = {NULL, 0}; + PyArray_Chunk buffer; + longlong offset=0; + NPY_ORDER order=PyArray_CORDER; + int fortran = 0; PyArrayObject *ret; - if (PyArray_ISCOMPLEX(self)) { - ret = _get_part(self, 0); - return (PyObject *)ret; + buffer.ptr = NULL; + /* + * Usually called with shape and type but can also be called with buffer, + * strides, and swapped info For now, let's just use this to create an + * empty, contiguous array of a specific type and shape. + */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&LO&O&", + kwlist, PyArray_IntpConverter, + &dims, + PyArray_DescrConverter, + &descr, + PyArray_BufferConverter, + &buffer, + &offset, + &PyArray_IntpConverter, + &strides, + &PyArray_OrderConverter, + &order)) { + goto fail; } - else { - Py_INCREF(self); - return (PyObject *)self; + if (order == PyArray_FORTRANORDER) { + fortran = 1; + } + if (descr == NULL) { + descr = PyArray_DescrFromType(PyArray_DEFAULT); } -} + itemsize = descr->elsize; + if (itemsize == 0) { + PyErr_SetString(PyExc_ValueError, + "data-type with unspecified variable length"); + goto fail; + } -static int -array_real_set(PyArrayObject *self, PyObject *val) -{ - PyArrayObject *ret; - PyArrayObject *new; - int rint; + if (strides.ptr != NULL) { + intp nb, off; + if (strides.len != dims.len) { + PyErr_SetString(PyExc_ValueError, + "strides, if given, must be " \ + "the same length as shape"); + goto fail; + } - if (PyArray_ISCOMPLEX(self)) { - ret = _get_part(self, 0); - if (ret == NULL) { - return -1; + if (buffer.ptr == NULL) { + nb = 0; + off = 0; + } + else { + nb = buffer.len; + off = (intp) offset; } - } - else { - Py_INCREF(self); - ret = self; - } - new = (PyArrayObject *)PyArray_FromAny(val, NULL, 0, 0, 0, NULL); - if (new == NULL) { - Py_DECREF(ret); - return -1; - } - rint = PyArray_MoveInto(ret, new); - Py_DECREF(ret); - Py_DECREF(new); - return rint; -} -static PyObject * -array_imag_get(PyArrayObject *self) -{ - PyArrayObject *ret; - if (PyArray_ISCOMPLEX(self)) { - ret = _get_part(self, 1); - } - else { - Py_INCREF(self->descr); - ret = (PyArrayObject *)PyArray_NewFromDescr(self->ob_type, - self->descr, - self->nd, - self->dimensions, - NULL, NULL, - PyArray_ISFORTRAN(self), - (PyObject *)self); - if (ret == NULL) { - return NULL; - } - if (_zerofill(ret) < 0) { - return NULL; + if (!PyArray_CheckStrides(itemsize, dims.len, + nb, off, + dims.ptr, strides.ptr)) { + PyErr_SetString(PyExc_ValueError, + "strides is incompatible " \ + "with shape of requested " \ + "array and size of buffer"); + goto fail; } - ret->flags &= ~WRITEABLE; } - return (PyObject *) ret; -} - -static int -array_imag_set(PyArrayObject *self, PyObject *val) -{ - if (PyArray_ISCOMPLEX(self)) { - PyArrayObject *ret; - PyArrayObject *new; - int rint; - ret = _get_part(self, 1); + if (buffer.ptr == NULL) { + ret = (PyArrayObject *) + PyArray_NewFromDescr(subtype, descr, + (int)dims.len, + dims.ptr, + strides.ptr, NULL, fortran, NULL); if (ret == NULL) { - return -1; + descr = NULL; + goto fail; } - new = (PyArrayObject *)PyArray_FromAny(val, NULL, 0, 0, 0, NULL); - if (new == NULL) { - Py_DECREF(ret); - return -1; + if (PyDataType_FLAGCHK(descr, NPY_ITEM_HASOBJECT)) { + /* place Py_None in object positions */ + PyArray_FillObjectArray(ret, Py_None); + if (PyErr_Occurred()) { + descr = NULL; + goto fail; + } } - rint = PyArray_MoveInto(ret, new); - Py_DECREF(ret); - Py_DECREF(new); - return rint; } else { - PyErr_SetString(PyExc_TypeError, "array does not have "\ - "imaginary part to set"); - return -1; - } -} - -static PyObject * -array_flat_get(PyArrayObject *self) -{ - return PyArray_IterNew((PyObject *)self); -} - -static int -array_flat_set(PyArrayObject *self, PyObject *val) -{ - PyObject *arr = NULL; - int retval = -1; - PyArrayIterObject *selfit = NULL, *arrit = NULL; - PyArray_Descr *typecode; - int swap; - PyArray_CopySwapFunc *copyswap; - - typecode = self->descr; - Py_INCREF(typecode); - arr = PyArray_FromAny(val, typecode, - 0, 0, FORCECAST | FORTRAN_IF(self), NULL); - if (arr == NULL) { - return -1; - } - arrit = (PyArrayIterObject *)PyArray_IterNew(arr); - if (arrit == NULL) { - goto exit; - } - selfit = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self); - if (selfit == NULL) { - goto exit; - } - if (arrit->size == 0) { - retval = 0; - goto exit; - } - swap = PyArray_ISNOTSWAPPED(self) != PyArray_ISNOTSWAPPED(arr); - copyswap = self->descr->f->copyswap; - if (PyDataType_REFCHK(self->descr)) { - while (selfit->index < selfit->size) { - PyArray_Item_XDECREF(selfit->dataptr, self->descr); - PyArray_Item_INCREF(arrit->dataptr, PyArray_DESCR(arr)); - memmove(selfit->dataptr, arrit->dataptr, sizeof(PyObject **)); - if (swap) { - copyswap(selfit->dataptr, NULL, swap, self); - } - PyArray_ITER_NEXT(selfit); - PyArray_ITER_NEXT(arrit); - if (arrit->index == arrit->size) { - PyArray_ITER_RESET(arrit); - } + /* buffer given -- use it */ + if (dims.len == 1 && dims.ptr[0] == -1) { + dims.ptr[0] = (buffer.len-(intp)offset) / itemsize; } - retval = 0; - goto exit; - } - - while(selfit->index < selfit->size) { - memmove(selfit->dataptr, arrit->dataptr, self->descr->elsize); - if (swap) { - copyswap(selfit->dataptr, NULL, swap, self); + else if ((strides.ptr == NULL) && + (buffer.len < ((intp)itemsize)* + PyArray_MultiplyList(dims.ptr, dims.len))) { + PyErr_SetString(PyExc_TypeError, + "buffer is too small for " \ + "requested array"); + goto fail; + } + /* get writeable and aligned */ + if (fortran) { + buffer.flags |= FORTRAN; } - PyArray_ITER_NEXT(selfit); - PyArray_ITER_NEXT(arrit); - if (arrit->index == arrit->size) { - PyArray_ITER_RESET(arrit); + ret = (PyArrayObject *)\ + PyArray_NewFromDescr(subtype, descr, + dims.len, dims.ptr, + strides.ptr, + offset + (char *)buffer.ptr, + buffer.flags, NULL); + if (ret == NULL) { + descr = NULL; + goto fail; } + PyArray_UpdateFlags(ret, UPDATE_ALL); + ret->base = buffer.base; + Py_INCREF(buffer.base); } - retval = 0; - exit: - Py_XDECREF(selfit); - Py_XDECREF(arrit); - Py_XDECREF(arr); - return retval; -} + PyDimMem_FREE(dims.ptr); + if (strides.ptr) { + PyDimMem_FREE(strides.ptr); + } + return (PyObject *)ret; -static PyObject * -array_transpose_get(PyArrayObject *self) -{ - return PyArray_Transpose(self, NULL); + fail: + Py_XDECREF(descr); + if (dims.ptr) { + PyDimMem_FREE(dims.ptr); + } + if (strides.ptr) { + PyDimMem_FREE(strides.ptr); + } + return NULL; } -/* If this is None, no function call is made - --- default sub-class behavior -*/ + static PyObject * -array_finalize_get(PyArrayObject *NPY_UNUSED(self)) +array_iter(PyArrayObject *arr) { - Py_INCREF(Py_None); - return Py_None; + if (arr->nd == 0) { + PyErr_SetString(PyExc_TypeError, + "iteration over a 0-d array"); + return NULL; + } + return PySeqIter_New((PyObject *)arr); } -static PyGetSetDef array_getsetlist[] = { - {"ndim", - (getter)array_ndim_get, - NULL, NULL, NULL}, - {"flags", - (getter)array_flags_get, - NULL, NULL, NULL}, - {"shape", - (getter)array_shape_get, - (setter)array_shape_set, - NULL, NULL}, - {"strides", - (getter)array_strides_get, - (setter)array_strides_set, - NULL, NULL}, - {"data", - (getter)array_data_get, - (setter)array_data_set, - NULL, NULL}, - {"itemsize", - (getter)array_itemsize_get, - NULL, NULL, NULL}, - {"size", - (getter)array_size_get, - NULL, NULL, NULL}, - {"nbytes", - (getter)array_nbytes_get, - NULL, NULL, NULL}, - {"base", - (getter)array_base_get, - NULL, NULL, NULL}, - {"dtype", - (getter)array_descr_get, - (setter)array_descr_set, - NULL, NULL}, - {"real", - (getter)array_real_get, - (setter)array_real_set, - NULL, NULL}, - {"imag", - (getter)array_imag_get, - (setter)array_imag_set, - NULL, NULL}, - {"flat", - (getter)array_flat_get, - (setter)array_flat_set, - NULL, NULL}, - {"ctypes", - (getter)array_ctypes_get, - NULL, NULL, NULL}, - {"T", - (getter)array_transpose_get, - NULL, NULL, NULL}, - {"__array_interface__", - (getter)array_interface_get, - NULL, NULL, NULL}, - {"__array_struct__", - (getter)array_struct_get, - NULL, NULL, NULL}, - {"__array_priority__", - (getter)array_priority_get, - NULL, NULL, NULL}, - {"__array_finalize__", - (getter)array_finalize_get, - NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL}, /* Sentinel */ -}; - -/****************** end of attribute get and set routines *******************/ - - static PyObject * array_alloc(PyTypeObject *type, Py_ssize_t NPY_UNUSED(nitems)) { -- cgit v1.2.1