summaryrefslogtreecommitdiff
path: root/scipy/base/src
diff options
context:
space:
mode:
Diffstat (limited to 'scipy/base/src')
-rw-r--r--scipy/base/src/arrayobject.c20
-rw-r--r--scipy/base/src/ufuncobject.c65
2 files changed, 75 insertions, 10 deletions
diff --git a/scipy/base/src/arrayobject.c b/scipy/base/src/arrayobject.c
index 4f52c276a..ae8c48f1d 100644
--- a/scipy/base/src/arrayobject.c
+++ b/scipy/base/src/arrayobject.c
@@ -1164,8 +1164,10 @@ array_dealloc(PyArrayObject *self) {
((PyArrayObject *)self->base)->flags |= WRITEABLE;
Py_INCREF(self); /* hold on to self in next call */
PyArray_CopyInto((PyArrayObject *)self->base, self);
+ /* Don't need to DECREF -- because we are deleting
+ self already... */
}
- /* Other wise base is pointing to something that we need
+ /* In any case base is pointing to something that we need
to DECREF -- either a view or a buffer object */
Py_DECREF(self->base);
}
@@ -4905,6 +4907,7 @@ array_fromarray(PyArrayObject *arr, PyArray_Typecode *typecode, int flags)
int copy = 0;
int arrflags;
PyArray_Typecode oldtype={PyArray_TYPE(arr),PyArray_ITEMSIZE(arr),0};
+ char *msg = "Cannot copy-back to a read-only array.";
if (type == PyArray_NOTYPE) type = arr->descr->type_num;
if (itemsize == 0) itemsize = arr->itemsize;
@@ -4927,9 +4930,7 @@ array_fromarray(PyArrayObject *arr, PyArray_Typecode *typecode, int flags)
if (copy) {
if ((flags & UPDATEIFCOPY) && \
(!PyArray_ISWRITEABLE(arr))) {
- PyErr_SetString(PyExc_ValueError,
- "Cannot copy-back to a read-"\
- "only array.");
+ PyErr_SetString(PyExc_ValueError, msg);
return NULL;
}
ret = (PyArrayObject *)\
@@ -4965,8 +4966,19 @@ array_fromarray(PyArrayObject *arr, PyArray_Typecode *typecode, int flags)
behavior with Python scalars */
if (flags & FORCECAST || PyArray_NDIM(arr)==0 ||
PyArray_CanCastSafely(PyArray_TYPE(arr), type)) {
+ if ((flags & UPDATEIFCOPY) && \
+ (!PyArray_ISWRITEABLE(arr))) {
+ PyErr_SetString(PyExc_ValueError, msg);
+ return NULL;
+ }
ret = (PyArrayObject *)\
PyArray_CastToType(arr, typecode);
+ if (flags & UPDATEIFCOPY) {
+ ret->flags |= UPDATEIFCOPY;
+ ret->base = (PyObject *)arr;
+ PyArray_FLAGS(ret->base) &= ~WRITEABLE;
+ Py_INCREF(arr);
+ }
}
else {
PyErr_SetString(PyExc_TypeError,
diff --git a/scipy/base/src/ufuncobject.c b/scipy/base/src/ufuncobject.c
index 1ce8a1b40..31b0dc579 100644
--- a/scipy/base/src/ufuncobject.c
+++ b/scipy/base/src/ufuncobject.c
@@ -678,7 +678,7 @@ select_types(PyUFuncObject *self, int *arg_types,
*data = self->data[i];
*function = self->functions[i];
-
+
return 0;
}
@@ -908,6 +908,7 @@ construct_matrices(PyUFuncLoopObject *loop, PyObject *args, PyArrayObject **mps)
PyErr_SetString(PyExc_TypeError,
"return arrays must be "\
"of ArrayType");
+ Py_DECREF(mps[i]);
return -1;
}
}
@@ -915,11 +916,13 @@ construct_matrices(PyUFuncLoopObject *loop, PyObject *args, PyArrayObject **mps)
loop->dimensions, loop->nd)) {
PyErr_SetString(PyExc_ValueError,
"invalid return array shape");
+ Py_DECREF(mps[i]);
return -1;
}
if (!PyArray_ISWRITEABLE(mps[i])) {
PyErr_SetString(PyExc_ValueError,
"return array is not writeable");
+ Py_DECREF(mps[i]);
return -1;
}
}
@@ -927,6 +930,8 @@ construct_matrices(PyUFuncLoopObject *loop, PyObject *args, PyArrayObject **mps)
/* construct any missing return arrays and make output iterators */
for (i=self->nin; i<self->nargs; i++) {
+ PyArray_Typecode ntype = {PyArray_NOTYPE, 0, 0};
+
if (mps[i] == NULL) {
mps[i] = (PyArrayObject *)PyArray_New(subtype,
loop->nd,
@@ -937,9 +942,46 @@ construct_matrices(PyUFuncLoopObject *loop, PyObject *args, PyArrayObject **mps)
if (mps[i] == NULL) return -1;
}
- loop->iters[i] = (PyArrayIterObject *)\
+ /* reset types for outputs that are equivalent
+ -- no sense casting uselessly
+ */
+ if (mps[i]->descr->type_num != arg_types[i]) {
+ PyArray_Typecode atype = {PyArray_NOTYPE, 0, 0};
+ ntype.type_num = PyArray_TYPE(mps[i]);
+ ntype.itemsize = PyArray_ITEMSIZE(mps[i]);
+ atype.type_num = arg_types[i];
+ atype.itemsize = \
+ PyArray_DescrFromType(arg_types[i])->elsize;
+ if (PyArray_EquivalentTypes(&atype, &ntype)) {
+ arg_types[i] = PyArray_TYPE(mps[i]);
+ }
+ }
+
+ /* still not the same -- or will we have to use buffers?*/
+ if (mps[i]->descr->type_num != arg_types[i] ||
+ !PyArray_ISBEHAVED_RO(mps[i])) {
+ if (loop->size < loop->bufsize) {
+ PyObject *new;
+ /* Copy the array to a temporary copy
+ and set the UPDATEIFCOPY flag
+ */
+ ntype.type_num = arg_types[i];
+ ntype.itemsize = 0;
+ new = PyArray_FromAny((PyObject *)mps[i],
+ &ntype, 0, 0,
+ FORCECAST |
+ BEHAVED_FLAGS_RO |
+ UPDATEIFCOPY);
+ if (new == NULL) return -1;
+ Py_DECREF(mps[i]);
+ mps[i] = (PyArrayObject *)new;
+ }
+ }
+
+ loop->iters[i] = (PyArrayIterObject *) \
PyArray_IterNew((PyObject *)mps[i]);
if (loop->iters[i] == NULL) return -1;
+
}
@@ -1294,7 +1336,7 @@ PyUFunc_GenericFunction(PyUFuncObject *self, PyObject *args,
d. copy output buffer back to output arrays.
3. goto next position
*/
- /* fprintf(stderr, "BUFFER...%d\n", loop->size);*/
+ fprintf(stderr, "BUFFER...%d\n", loop->size);
while (index < size) {
/*copy input data */
for (i=0; i<self->nin; i++) {
@@ -2290,18 +2332,29 @@ ufunc_generic_call(PyUFuncObject *self, PyObject *args)
/* wrap outputs */
for (i=0; i<self->nout; i++) {
+ int j=self->nin+i;
+ /* check to see if any UPDATEIFCOPY flags are set
+ which meant that a temporary output was generated
+ */
+ if (mps[j]->flags & UPDATEIFCOPY) {
+ PyObject *old = mps[j]->base;
+ Py_INCREF(old); /* we want to hang on to this */
+ Py_DECREF(mps[j]); /* should trigger the copy
+ back into old */
+ mps[j] = (PyArrayObject *)old;
+ }
if (obj != NULL) {
res = PyObject_CallMethod(obj, "__array_wrap__",
- "O", mps[self->nin+i]);
+ "O", mps[j]);
if (res == NULL) PyErr_Clear();
else if (res == Py_None) Py_DECREF(res);
else {
- Py_DECREF(mps[self->nin+i]);
+ Py_DECREF(mps[j]);
retobj[i] = res;
continue;
}
}
- retobj[i] = PyArray_Return(mps[self->nin+i]);
+ retobj[i] = PyArray_Return(mps[j]);
}
if (self->nout == 1) {