diff options
Diffstat (limited to 'numpy/core/src')
-rw-r--r-- | numpy/core/src/arrayctors.c | 2258 | ||||
-rw-r--r-- | numpy/core/src/arrayctors.h | 48 | ||||
-rw-r--r-- | numpy/core/src/arrayobject.c | 2260 | ||||
-rw-r--r-- | numpy/core/src/arrayobject.h | 9 |
4 files changed, 2319 insertions, 2256 deletions
diff --git a/numpy/core/src/arrayctors.c b/numpy/core/src/arrayctors.c new file mode 100644 index 000000000..4e3450a75 --- /dev/null +++ b/numpy/core/src/arrayctors.c @@ -0,0 +1,2258 @@ +#define PY_SSIZE_T_CLEAN +#include <Python.h> +#include "structmember.h" + +#define _MULTIARRAYMODULE +#define NPY_NO_PREFIX +#include "numpy/arrayobject.h" +#include "numpy/arrayscalars.h" + +#include "arrayobject.h" + +#include "arrayctors.h" + +/* + * 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; + + 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; + } + } + + finish: + Py_INCREF(*des); + Py_DECREF(old); + return newnd; +} + +/* + * If s is not a list, return 0 + * Otherwise: + * + * run object_depth_and_dimension on all the elements + * and make sure the returned shape and size is the + * same for each element + */ +static int +object_depth_and_dimension(PyObject *s, int max, intp *dims) +{ + intp *newdims, *test_dims; + int nd, test_nd; + int i, islist, istuple; + intp size; + PyObject *obj; + + islist = PyList_Check(s); + istuple = PyTuple_Check(s); + if (!(islist || istuple)) { + return 0; + } + + size = PySequence_Size(s); + if (size == 0) { + return 0; + } + if (max < 1) { + return 0; + } + if (max < 2) { + dims[0] = size; + return 1; + } + + newdims = PyDimMem_NEW(2*(max - 1)); + test_dims = newdims + (max - 1); + if (islist) { + obj = PyList_GET_ITEM(s, 0); + } + else { + obj = PyTuple_GET_ITEM(s, 0); + } + nd = object_depth_and_dimension(obj, max - 1, newdims); + + for (i = 1; i < size; i++) { + if (islist) { + obj = PyList_GET_ITEM(s, i); + } + else { + obj = PyTuple_GET_ITEM(s, i); + } + test_nd = object_depth_and_dimension(obj, max-1, test_dims); + + if ((nd != test_nd) || + (!PyArray_CompareLists(newdims, test_dims, nd))) { + nd = 0; + break; + } + } + + for (i = 1; i <= nd; i++) { + dims[i] = newdims[i-1]; + } + dims[0] = size; + PyDimMem_FREE(newdims); + return nd + 1; +} + +static void +_strided_byte_copy(char *dst, intp outstrides, char *src, intp instrides, + intp N, int elsize) +{ + intp i, j; + char *tout = dst; + char *tin = src; + +#define _FAST_MOVE(_type_) \ + for(i=0; i<N; i++) { \ + ((_type_ *)tout)[0] = ((_type_ *)tin)[0]; \ + tin += instrides; \ + tout += outstrides; \ + } \ + return + + switch(elsize) { + case 8: + _FAST_MOVE(Int64); + case 4: + _FAST_MOVE(Int32); + case 1: + _FAST_MOVE(Int8); + case 2: + _FAST_MOVE(Int16); + case 16: + for (i = 0; i < N; i++) { + ((Int64 *)tout)[0] = ((Int64 *)tin)[0]; + ((Int64 *)tout)[1] = ((Int64 *)tin)[1]; + tin += instrides; + tout += outstrides; + } + return; + default: + for(i = 0; i < N; i++) { + for(j=0; j<elsize; j++) { + *tout++ = *tin++; + } + tin = tin + instrides - elsize; + tout = tout + outstrides - elsize; + } + } +#undef _FAST_MOVE + +} + +static void +_unaligned_strided_byte_move(char *dst, intp outstrides, char *src, + intp instrides, intp N, int elsize) +{ + intp i; + char *tout = dst; + char *tin = src; + + +#define _MOVE_N_SIZE(size) \ + for(i=0; i<N; i++) { \ + memmove(tout, tin, size); \ + tin += instrides; \ + tout += outstrides; \ + } \ + return + + switch(elsize) { + case 8: + _MOVE_N_SIZE(8); + case 4: + _MOVE_N_SIZE(4); + case 1: + _MOVE_N_SIZE(1); + case 2: + _MOVE_N_SIZE(2); + case 16: + _MOVE_N_SIZE(16); + default: + _MOVE_N_SIZE(elsize); + } +#undef _MOVE_N_SIZE + +} + +NPY_NO_EXPORT void +_unaligned_strided_byte_copy(char *dst, intp outstrides, char *src, + intp instrides, intp N, int elsize) +{ + intp i; + char *tout = dst; + char *tin = src; + +#define _COPY_N_SIZE(size) \ + for(i=0; i<N; i++) { \ + memcpy(tout, tin, size); \ + tin += instrides; \ + tout += outstrides; \ + } \ + return + + switch(elsize) { + case 8: + _COPY_N_SIZE(8); + case 4: + _COPY_N_SIZE(4); + case 1: + _COPY_N_SIZE(1); + case 2: + _COPY_N_SIZE(2); + case 16: + _COPY_N_SIZE(16); + default: + _COPY_N_SIZE(elsize); + } +#undef _COPY_N_SIZE + +} + +NPY_NO_EXPORT void +_strided_byte_swap(void *p, intp stride, intp n, int size) +{ + char *a, *b, c = 0; + int j, m; + + switch(size) { + case 1: /* no byteswap necessary */ + break; + case 4: + for (a = (char*)p; n > 0; n--, a += stride - 1) { + b = a + 3; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a = *b; *b = c; + } + break; + case 8: + for (a = (char*)p; n > 0; n--, a += stride - 3) { + b = a + 7; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a++ = *b; *b-- = c; + c = *a; *a = *b; *b = c; + } + break; + case 2: + for (a = (char*)p; n > 0; n--, a += stride) { + b = a + 1; + c = *a; *a = *b; *b = c; + } + break; + default: + m = size/2; + for (a = (char *)p; n > 0; n--, a += stride - m) { + b = a + (size - 1); + for (j = 0; j < m; j++) { + c=*a; *a++ = *b; *b-- = c; + } + } + break; + } +} + +NPY_NO_EXPORT void +byte_swap_vector(void *p, intp n, int size) +{ + _strided_byte_swap(p, (intp) size, n, size); + return; +} + +/* If numitems > 1, then dst must be contiguous */ +NPY_NO_EXPORT void +copy_and_swap(void *dst, void *src, int itemsize, intp numitems, + intp srcstrides, int swap) +{ + intp i; + char *s1 = (char *)src; + char *d1 = (char *)dst; + + + if ((numitems == 1) || (itemsize == srcstrides)) { + memcpy(d1, s1, itemsize*numitems); + } + else { + for (i = 0; i < numitems; i++) { + memcpy(d1, s1, itemsize); + d1 += itemsize; + s1 += srcstrides; + } + } + + if (swap) { + byte_swap_vector(d1, numitems, itemsize); + } +} + +static int +_copy_from0d(PyArrayObject *dest, PyArrayObject *src, int usecopy, int swap) +{ + char *aligned = NULL; + char *sptr; + int numcopies, nbytes; + void (*myfunc)(char *, intp, char *, intp, intp, int); + int retval = -1; + NPY_BEGIN_THREADS_DEF; + + numcopies = PyArray_SIZE(dest); + if (numcopies < 1) { + return 0; + } + nbytes = PyArray_ITEMSIZE(src); + + if (!PyArray_ISALIGNED(src)) { + aligned = malloc((size_t)nbytes); + if (aligned == NULL) { + PyErr_NoMemory(); + return -1; + } + memcpy(aligned, src->data, (size_t) nbytes); + usecopy = 1; + sptr = aligned; + } + else { + sptr = src->data; + } + if (PyArray_SAFEALIGNEDCOPY(dest)) { + myfunc = _strided_byte_copy; + } + else if (usecopy) { + myfunc = _unaligned_strided_byte_copy; + } + else { + myfunc = _unaligned_strided_byte_move; + } + + if ((dest->nd < 2) || PyArray_ISONESEGMENT(dest)) { + char *dptr; + intp dstride; + + dptr = dest->data; + if (dest->nd == 1) { + dstride = dest->strides[0]; + } + else { + dstride = nbytes; + } + + /* Refcount note: src and dest may have different sizes */ + PyArray_INCREF(src); + PyArray_XDECREF(dest); + NPY_BEGIN_THREADS; + myfunc(dptr, dstride, sptr, 0, numcopies, (int) nbytes); + if (swap) { + _strided_byte_swap(dptr, dstride, numcopies, (int) nbytes); + } + NPY_END_THREADS; + PyArray_INCREF(dest); + PyArray_XDECREF(src); + } + else { + PyArrayIterObject *dit; + int axis = -1; + + dit = (PyArrayIterObject *) + PyArray_IterAllButAxis((PyObject *)dest, &axis); + if (dit == NULL) { + goto finish; + } + /* Refcount note: src and dest may have different sizes */ + PyArray_INCREF(src); + PyArray_XDECREF(dest); + NPY_BEGIN_THREADS; + while(dit->index < dit->size) { + myfunc(dit->dataptr, PyArray_STRIDE(dest, axis), sptr, 0, + PyArray_DIM(dest, axis), nbytes); + if (swap) { + _strided_byte_swap(dit->dataptr, PyArray_STRIDE(dest, axis), + PyArray_DIM(dest, axis), nbytes); + } + PyArray_ITER_NEXT(dit); + } + NPY_END_THREADS; + PyArray_INCREF(dest); + PyArray_XDECREF(src); + Py_DECREF(dit); + } + retval = 0; + +finish: + if (aligned != NULL) { + free(aligned); + } + return retval; +} + +/* + * Special-case of PyArray_CopyInto when dst is 1-d + * and contiguous (and aligned). + * PyArray_CopyInto requires broadcastable arrays while + * this one is a flattening operation... + */ +NPY_NO_EXPORT int +_flat_copyinto(PyObject *dst, PyObject *src, NPY_ORDER order) +{ + PyArrayIterObject *it; + PyObject *orig_src; + void (*myfunc)(char *, intp, char *, intp, intp, int); + char *dptr; + int axis; + int elsize; + intp nbytes; + NPY_BEGIN_THREADS_DEF; + + + orig_src = src; + if (PyArray_NDIM(src) == 0) { + /* Refcount note: src and dst have the same size */ + PyArray_INCREF((PyArrayObject *)src); + PyArray_XDECREF((PyArrayObject *)dst); + NPY_BEGIN_THREADS; + memcpy(PyArray_BYTES(dst), PyArray_BYTES(src), + PyArray_ITEMSIZE(src)); + NPY_END_THREADS; + return 0; + } + + axis = PyArray_NDIM(src)-1; + + if (order == PyArray_FORTRANORDER) { + if (PyArray_NDIM(src) <= 2) { + axis = 0; + } + /* fall back to a more general method */ + else { + src = PyArray_Transpose((PyArrayObject *)orig_src, NULL); + } + } + + it = (PyArrayIterObject *)PyArray_IterAllButAxis(src, &axis); + if (it == NULL) { + if (src != orig_src) { + Py_DECREF(src); + } + return -1; + } + + if (PyArray_SAFEALIGNEDCOPY(src)) { + myfunc = _strided_byte_copy; + } + else { + myfunc = _unaligned_strided_byte_copy; + } + + dptr = PyArray_BYTES(dst); + elsize = PyArray_ITEMSIZE(dst); + nbytes = elsize * PyArray_DIM(src, axis); + + /* Refcount note: src and dst have the same size */ + PyArray_INCREF((PyArrayObject *)src); + PyArray_XDECREF((PyArrayObject *)dst); + NPY_BEGIN_THREADS; + while(it->index < it->size) { + myfunc(dptr, elsize, it->dataptr, PyArray_STRIDE(src,axis), + PyArray_DIM(src,axis), elsize); + dptr += nbytes; + PyArray_ITER_NEXT(it); + } + NPY_END_THREADS; + + if (src != orig_src) { + Py_DECREF(src); + } + Py_DECREF(it); + return 0; +} + + +static int +_copy_from_same_shape(PyArrayObject *dest, PyArrayObject *src, + void (*myfunc)(char *, intp, char *, intp, intp, int), + int swap) +{ + int maxaxis = -1, elsize; + intp maxdim; + PyArrayIterObject *dit, *sit; + NPY_BEGIN_THREADS_DEF; + + dit = (PyArrayIterObject *) + PyArray_IterAllButAxis((PyObject *)dest, &maxaxis); + sit = (PyArrayIterObject *) + PyArray_IterAllButAxis((PyObject *)src, &maxaxis); + + maxdim = dest->dimensions[maxaxis]; + + if ((dit == NULL) || (sit == NULL)) { + Py_XDECREF(dit); + Py_XDECREF(sit); + return -1; + } + elsize = PyArray_ITEMSIZE(dest); + + /* Refcount note: src and dst have the same size */ + PyArray_INCREF(src); + PyArray_XDECREF(dest); + + NPY_BEGIN_THREADS; + while(dit->index < dit->size) { + /* strided copy of elsize bytes */ + myfunc(dit->dataptr, dest->strides[maxaxis], + sit->dataptr, src->strides[maxaxis], + maxdim, elsize); + if (swap) { + _strided_byte_swap(dit->dataptr, + dest->strides[maxaxis], + dest->dimensions[maxaxis], + elsize); + } + PyArray_ITER_NEXT(dit); + PyArray_ITER_NEXT(sit); + } + NPY_END_THREADS; + + Py_DECREF(sit); + Py_DECREF(dit); + return 0; +} + +static int +_broadcast_copy(PyArrayObject *dest, PyArrayObject *src, + void (*myfunc)(char *, intp, char *, intp, intp, int), + int swap) +{ + int elsize; + PyArrayMultiIterObject *multi; + int maxaxis; intp maxdim; + NPY_BEGIN_THREADS_DEF; + + elsize = PyArray_ITEMSIZE(dest); + multi = (PyArrayMultiIterObject *)PyArray_MultiIterNew(2, dest, src); + if (multi == NULL) { + return -1; + } + + if (multi->size != PyArray_SIZE(dest)) { + PyErr_SetString(PyExc_ValueError, + "array dimensions are not "\ + "compatible for copy"); + Py_DECREF(multi); + return -1; + } + + maxaxis = PyArray_RemoveSmallest(multi); + if (maxaxis < 0) { + /* + * copy 1 0-d array to another + * Refcount note: src and dst have the same size + */ + PyArray_INCREF(src); + PyArray_XDECREF(dest); + memcpy(dest->data, src->data, elsize); + if (swap) { + byte_swap_vector(dest->data, 1, elsize); + } + return 0; + } + maxdim = multi->dimensions[maxaxis]; + + /* + * Increment the source and decrement the destination + * reference counts + * + * Refcount note: src and dest may have different sizes + */ + PyArray_INCREF(src); + PyArray_XDECREF(dest); + + NPY_BEGIN_THREADS; + while(multi->index < multi->size) { + myfunc(multi->iters[0]->dataptr, + multi->iters[0]->strides[maxaxis], + multi->iters[1]->dataptr, + multi->iters[1]->strides[maxaxis], + maxdim, elsize); + if (swap) { + _strided_byte_swap(multi->iters[0]->dataptr, + multi->iters[0]->strides[maxaxis], + maxdim, elsize); + } + PyArray_MultiIter_NEXT(multi); + } + NPY_END_THREADS; + + PyArray_INCREF(dest); + PyArray_XDECREF(src); + + Py_DECREF(multi); + return 0; +} + +/* If destination is not the right type, then src + will be cast to destination -- this requires + src and dest to have the same shape +*/ + +/* Requires arrays to have broadcastable shapes + + The arrays are assumed to have the same number of elements + They can be different sizes and have different types however. +*/ + +static int +_array_copy_into(PyArrayObject *dest, PyArrayObject *src, int usecopy) +{ + int swap; + void (*myfunc)(char *, intp, char *, intp, intp, int); + int simple; + int same; + NPY_BEGIN_THREADS_DEF; + + + if (!PyArray_EquivArrTypes(dest, src)) { + return PyArray_CastTo(dest, src); + } + if (!PyArray_ISWRITEABLE(dest)) { + PyErr_SetString(PyExc_RuntimeError, + "cannot write to array"); + return -1; + } + same = PyArray_SAMESHAPE(dest, src); + simple = same && ((PyArray_ISCARRAY_RO(src) && PyArray_ISCARRAY(dest)) || + (PyArray_ISFARRAY_RO(src) && PyArray_ISFARRAY(dest))); + + if (simple) { + /* Refcount note: src and dest have the same size */ + PyArray_INCREF(src); + PyArray_XDECREF(dest); + NPY_BEGIN_THREADS; + if (usecopy) { + memcpy(dest->data, src->data, PyArray_NBYTES(dest)); + } + else { + memmove(dest->data, src->data, PyArray_NBYTES(dest)); + } + NPY_END_THREADS; + return 0; + } + + swap = PyArray_ISNOTSWAPPED(dest) != PyArray_ISNOTSWAPPED(src); + + if (src->nd == 0) { + return _copy_from0d(dest, src, usecopy, swap); + } + + if (PyArray_SAFEALIGNEDCOPY(dest) && PyArray_SAFEALIGNEDCOPY(src)) { + myfunc = _strided_byte_copy; + } + else if (usecopy) { + myfunc = _unaligned_strided_byte_copy; + } + else { + myfunc = _unaligned_strided_byte_move; + } + /* + * Could combine these because _broadcasted_copy would work as well. + * But, same-shape copying is so common we want to speed it up. + */ + if (same) { + return _copy_from_same_shape(dest, src, myfunc, swap); + } + else { + return _broadcast_copy(dest, src, myfunc, swap); + } +} + +/*NUMPY_API + * Move the memory of one array into another. + */ +NPY_NO_EXPORT int +PyArray_MoveInto(PyArrayObject *dest, PyArrayObject *src) +{ + return _array_copy_into(dest, src, 0); +} + + + +/* adapted from Numarray */ +static int +setArrayFromSequence(PyArrayObject *a, PyObject *s, int dim, intp offset) +{ + Py_ssize_t i, slen; + int res = 0; + + /* + * This code is to ensure that the sequence access below will + * return a lower-dimensional sequence. + */ + if (PyArray_Check(s) && !(PyArray_CheckExact(s))) { + /* + * FIXME: This could probably copy the entire subarray at once here using + * a faster algorithm. Right now, just make sure a base-class array is + * used so that the dimensionality reduction assumption is correct. + */ + s = PyArray_EnsureArray(s); + } + + if (dim > a->nd) { + PyErr_Format(PyExc_ValueError, + "setArrayFromSequence: sequence/array dimensions mismatch."); + return -1; + } + + slen = PySequence_Length(s); + if (slen != a->dimensions[dim]) { + PyErr_Format(PyExc_ValueError, + "setArrayFromSequence: sequence/array shape mismatch."); + return -1; + } + + for (i = 0; i < slen; i++) { + PyObject *o = PySequence_GetItem(s, i); + if ((a->nd - dim) > 1) { + res = setArrayFromSequence(a, o, dim+1, offset); + } + else { + res = a->descr->f->setitem(o, (a->data + offset), a); + } + Py_DECREF(o); + if (res < 0) { + return res; + } + offset += a->strides[dim]; + } + return 0; +} + +static int +Assign_Array(PyArrayObject *self, PyObject *v) +{ + if (!PySequence_Check(v)) { + PyErr_SetString(PyExc_ValueError, + "assignment from non-sequence"); + return -1; + } + if (self->nd == 0) { + PyErr_SetString(PyExc_ValueError, + "assignment to 0-d array"); + return -1; + } + return setArrayFromSequence(self, v, 0, 0); +} + +/* + * "Array Scalars don't call this code" + * steals reference to typecode -- no NULL + */ +static PyObject * +Array_FromPyScalar(PyObject *op, PyArray_Descr *typecode) +{ + PyArrayObject *ret; + int itemsize; + int type; + + itemsize = typecode->elsize; + type = typecode->type_num; + + if (itemsize == 0 && PyTypeNum_ISEXTENDED(type)) { + itemsize = PyObject_Length(op); + if (type == PyArray_UNICODE) { + itemsize *= 4; + } + if (itemsize != typecode->elsize) { + PyArray_DESCR_REPLACE(typecode); + typecode->elsize = itemsize; + } + } + + ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, typecode, + 0, NULL, + NULL, NULL, 0, NULL); + if (ret == NULL) { + return NULL; + } + if (ret->nd > 0) { + PyErr_SetString(PyExc_ValueError, + "shape-mismatch on array construction"); + Py_DECREF(ret); + return NULL; + } + + ret->descr->f->setitem(op, ret->data, ret); + if (PyErr_Occurred()) { + Py_DECREF(ret); + return NULL; + } + else { + return (PyObject *)ret; + } +} + + +static PyObject * +ObjectArray_FromNestedList(PyObject *s, PyArray_Descr *typecode, int fortran) +{ + int nd; + intp d[MAX_DIMS]; + PyArrayObject *r; + + /* Get the depth and the number of dimensions */ + nd = object_depth_and_dimension(s, MAX_DIMS, d); + if (nd < 0) { + return NULL; + } + if (nd == 0) { + return Array_FromPyScalar(s, typecode); + } + r = (PyArrayObject*)PyArray_NewFromDescr(&PyArray_Type, typecode, + nd, d, + NULL, NULL, + fortran, NULL); + if (!r) { + return NULL; + } + if(Assign_Array(r,s) == -1) { + Py_DECREF(r); + return NULL; + } + return (PyObject*)r; +} + +/* + * The rest of this code is to build the right kind of array + * from a python object. + */ + +static int +discover_depth(PyObject *s, int max, int stop_at_string, int stop_at_tuple) +{ + int d = 0; + PyObject *e; + + if(max < 1) { + return -1; + } + if(!PySequence_Check(s) || PyInstance_Check(s) || + PySequence_Length(s) < 0) { + PyErr_Clear(); + return 0; + } + if (PyArray_Check(s)) { + return PyArray_NDIM(s); + } + if (PyArray_IsScalar(s, Generic)) { + return 0; + } + if (PyString_Check(s) || PyBuffer_Check(s) || PyUnicode_Check(s)) { + return stop_at_string ? 0:1; + } + if (stop_at_tuple && PyTuple_Check(s)) { + return 0; + } + if ((e = PyObject_GetAttrString(s, "__array_struct__")) != NULL) { + d = -1; + if (PyCObject_Check(e)) { + PyArrayInterface *inter; + inter = (PyArrayInterface *)PyCObject_AsVoidPtr(e); + if (inter->two == 2) { + d = inter->nd; + } + } + Py_DECREF(e); + if (d > -1) { + return d; + } + } + else { + PyErr_Clear(); + } + if ((e=PyObject_GetAttrString(s, "__array_interface__")) != NULL) { + d = -1; + if (PyDict_Check(e)) { + PyObject *new; + new = PyDict_GetItemString(e, "shape"); + if (new && PyTuple_Check(new)) { + d = PyTuple_GET_SIZE(new); + } + } + Py_DECREF(e); + if (d>-1) { + return d; + } + } + else PyErr_Clear(); + + if (PySequence_Length(s) == 0) { + return 1; + } + if ((e=PySequence_GetItem(s,0)) == NULL) { + return -1; + } + if (e != s) { + d = discover_depth(e, max-1, stop_at_string, stop_at_tuple); + if (d >= 0) { + d++; + } + } + Py_DECREF(e); + return d; +} + +static int +discover_itemsize(PyObject *s, int nd, int *itemsize) +{ + int n, r, i; + PyObject *e; + + if (PyArray_Check(s)) { + *itemsize = MAX(*itemsize, PyArray_ITEMSIZE(s)); + return 0; + } + + n = PyObject_Length(s); + if ((nd == 0) || PyString_Check(s) || + PyUnicode_Check(s) || PyBuffer_Check(s)) { + *itemsize = MAX(*itemsize, n); + return 0; + } + for (i = 0; i < n; i++) { + if ((e = PySequence_GetItem(s,i))==NULL) { + return -1; + } + r = discover_itemsize(e,nd-1,itemsize); + Py_DECREF(e); + if (r == -1) { + return -1; + } + } + return 0; +} + +/* + * Take an arbitrary object known to represent + * an array of ndim nd, and determine the size in each dimension + */ +static int +discover_dimensions(PyObject *s, int nd, intp *d, int check_it) +{ + PyObject *e; + int r, n, i, n_lower; + + + if (PyArray_Check(s)) { + for (i=0; i<nd; i++) { + d[i] = PyArray_DIM(s,i); + } + return 0; + } + n = PyObject_Length(s); + *d = n; + if (*d < 0) { + return -1; + } + if (nd <= 1) { + return 0; + } + n_lower = 0; + for(i = 0; i < n; i++) { + if ((e = PySequence_GetItem(s,i)) == NULL) { + return -1; + } + r = discover_dimensions(e, nd - 1, d + 1, check_it); + Py_DECREF(e); + + if (r == -1) { + return -1; + } + if (check_it && n_lower != 0 && n_lower != d[1]) { + PyErr_SetString(PyExc_ValueError, + "inconsistent shape in sequence"); + return -1; + } + if (d[1] > n_lower) { + n_lower = d[1]; + } + } + d[1] = n_lower; + + return 0; +} + +/* + * isobject means that we are constructing an + * object array on-purpose with a nested list. + * Only a list is interpreted as a sequence with these rules + * steals reference to typecode + */ +static PyObject * +Array_FromSequence(PyObject *s, PyArray_Descr *typecode, int fortran, + int min_depth, int max_depth) +{ + PyArrayObject *r; + int nd; + int err; + intp d[MAX_DIMS]; + int stop_at_string; + int stop_at_tuple; + int check_it; + int type = typecode->type_num; + int itemsize = typecode->elsize; + + check_it = (typecode->type != PyArray_CHARLTR); + stop_at_string = (type != PyArray_STRING) || + (typecode->type == PyArray_STRINGLTR); + stop_at_tuple = (type == PyArray_VOID && (typecode->names + || typecode->subarray)); + + nd = discover_depth(s, MAX_DIMS + 1, stop_at_string, stop_at_tuple); + if (nd == 0) { + return Array_FromPyScalar(s, typecode); + } + else if (nd < 0) { + PyErr_SetString(PyExc_ValueError, + "invalid input sequence"); + goto fail; + } + if (max_depth && PyTypeNum_ISOBJECT(type) && (nd > max_depth)) { + nd = max_depth; + } + if ((max_depth && nd > max_depth) || (min_depth && nd < min_depth)) { + PyErr_SetString(PyExc_ValueError, + "invalid number of dimensions"); + goto fail; + } + + err = discover_dimensions(s, nd, d, check_it); + if (err == -1) { + goto fail; + } + if (typecode->type == PyArray_CHARLTR && nd > 0 && d[nd - 1] == 1) { + nd = nd - 1; + } + + if (itemsize == 0 && PyTypeNum_ISEXTENDED(type)) { + err = discover_itemsize(s, nd, &itemsize); + if (err == -1) { + goto fail; + } + if (type == PyArray_UNICODE) { + itemsize *= 4; + } + } + if (itemsize != typecode->elsize) { + PyArray_DESCR_REPLACE(typecode); + typecode->elsize = itemsize; + } + + r = (PyArrayObject*)PyArray_NewFromDescr(&PyArray_Type, typecode, + nd, d, + NULL, NULL, + fortran, NULL); + if (!r) { + return NULL; + } + + err = Assign_Array(r,s); + if (err == -1) { + Py_DECREF(r); + return NULL; + } + return (PyObject*)r; + + fail: + Py_DECREF(typecode); + return NULL; +} + + + +/*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)); + } + 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; + } + 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; + } + + 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) { + self->dimensions = PyDimMem_NEW(2*nd); + if (self->dimensions == NULL) { + PyErr_NoMemory(); + goto fail; + } + self->strides = self->dimensions + nd; + memcpy(self->dimensions, dims, sizeof(intp)*nd); + if (strides == NULL) { /* fill it in */ + sd = _array_fill_strides(self->strides, dims, nd, sd, + flags, &(self->flags)); + } + else { + /* + * 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 = self->strides = NULL; + } + + 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); + } + } + 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; + + /* + * 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; + + 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); + } + return (PyObject *)self; + + fail: + Py_DECREF(self); + return NULL; +} + +/*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) { + 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; +} + +/*NUMPY_API + * Does not check for ENSURECOPY and NOTSWAPPED in flags + * Steals a reference to newtype --- which can be NULL + */ +NPY_NO_EXPORT PyObject * +PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth, + int max_depth, int flags, PyObject *context) +{ + /* + * This is the main code to make a NumPy array from a Python + * Object. It is called from lot's of different places which + * is why there are so many checks. The comments try to + * explain some of the checks. + */ + PyObject *r = NULL; + int seq = FALSE; + + /* + * Is input object already an array? + * This is where the flags are used + */ + if (PyArray_Check(op)) { + r = PyArray_FromArray((PyArrayObject *)op, newtype, flags); + } + else if (PyArray_IsScalar(op, Generic)) { + if (flags & UPDATEIFCOPY) { + goto err; + } + r = PyArray_FromScalar(op, newtype); + } + else if (newtype == NULL && + (newtype = _array_find_python_scalar_type(op))) { + if (flags & UPDATEIFCOPY) { + goto err; + } + r = Array_FromPyScalar(op, newtype); + } + else if (PyArray_HasArrayInterfaceType(op, newtype, context, r)) { + PyObject *new; + if (r == NULL) { + Py_XDECREF(newtype); + return NULL; + } + if (newtype != NULL || flags != 0) { + new = PyArray_FromArray((PyArrayObject *)r, newtype, flags); + Py_DECREF(r); + r = new; + } + } + else { + int isobject = 0; + + if (flags & UPDATEIFCOPY) { + goto err; + } + if (newtype == NULL) { + newtype = _array_find_type(op, NULL, MAX_DIMS); + } + else if (newtype->type_num == PyArray_OBJECT) { + isobject = 1; + } + if (PySequence_Check(op)) { + PyObject *thiserr = NULL; + + /* necessary but not sufficient */ + Py_INCREF(newtype); + r = Array_FromSequence(op, newtype, flags & FORTRAN, + min_depth, max_depth); + if (r == NULL && (thiserr=PyErr_Occurred())) { + if (PyErr_GivenExceptionMatches(thiserr, + PyExc_MemoryError)) { + return NULL; + } + /* + * If object was explicitly requested, + * then try nested list object array creation + */ + PyErr_Clear(); + if (isobject) { + Py_INCREF(newtype); + r = ObjectArray_FromNestedList + (op, newtype, flags & FORTRAN); + seq = TRUE; + Py_DECREF(newtype); + } + } + else { + seq = TRUE; + Py_DECREF(newtype); + } + } + if (!seq) { + r = Array_FromPyScalar(op, newtype); + } + } + + /* If we didn't succeed return NULL */ + if (r == NULL) { + return NULL; + } + + /* Be sure we succeed here */ + if(!PyArray_Check(r)) { + PyErr_SetString(PyExc_RuntimeError, + "internal error: PyArray_FromAny "\ + "not producing an array"); + Py_DECREF(r); + return NULL; + } + + if (min_depth != 0 && ((PyArrayObject *)r)->nd < min_depth) { + PyErr_SetString(PyExc_ValueError, + "object of too small depth for desired array"); + Py_DECREF(r); + return NULL; + } + if (max_depth != 0 && ((PyArrayObject *)r)->nd > max_depth) { + PyErr_SetString(PyExc_ValueError, + "object too deep for desired array"); + Py_DECREF(r); + return NULL; + } + return r; + + err: + Py_XDECREF(newtype); + PyErr_SetString(PyExc_TypeError, + "UPDATEIFCOPY used for non-array input."); + return NULL; +} + +/*NUMPY_API + * steals a reference to descr -- accepts NULL + */ +NPY_NO_EXPORT PyObject * +PyArray_CheckFromAny(PyObject *op, PyArray_Descr *descr, int min_depth, + int max_depth, int requires, PyObject *context) +{ + PyObject *obj; + if (requires & NOTSWAPPED) { + if (!descr && PyArray_Check(op) && + !PyArray_ISNBO(PyArray_DESCR(op)->byteorder)) { + descr = PyArray_DescrNew(PyArray_DESCR(op)); + } + else if (descr && !PyArray_ISNBO(descr->byteorder)) { + PyArray_DESCR_REPLACE(descr); + } + if (descr) { + descr->byteorder = PyArray_NATIVE; + } + } + + obj = PyArray_FromAny(op, descr, min_depth, max_depth, requires, context); + if (obj == NULL) { + return NULL; + } + if ((requires & ELEMENTSTRIDES) && + !PyArray_ElementStrides(obj)) { + PyObject *new; + new = PyArray_NewCopy((PyArrayObject *)obj, PyArray_ANYORDER); + Py_DECREF(obj); + obj = new; + } + return obj; +} + +/*NUMPY_API + * steals reference to newtype --- acc. NULL + */ +NPY_NO_EXPORT PyObject * +PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags) +{ + + PyArrayObject *ret = NULL; + int itemsize; + int copy = 0; + int arrflags; + PyArray_Descr *oldtype; + char *msg = "cannot copy back to a read-only array"; + PyTypeObject *subtype; + + oldtype = PyArray_DESCR(arr); + subtype = arr->ob_type; + if (newtype == NULL) { + newtype = oldtype; Py_INCREF(oldtype); + } + itemsize = newtype->elsize; + if (itemsize == 0) { + PyArray_DESCR_REPLACE(newtype); + if (newtype == NULL) { + return NULL; + } + newtype->elsize = oldtype->elsize; + itemsize = newtype->elsize; + } + + /* + * Can't cast unless ndim-0 array, FORCECAST is specified + * or the cast is safe. + */ + if (!(flags & FORCECAST) && !PyArray_NDIM(arr) == 0 && + !PyArray_CanCastTo(oldtype, newtype)) { + Py_DECREF(newtype); + PyErr_SetString(PyExc_TypeError, + "array cannot be safely cast " \ + "to required type"); + return NULL; + } + + /* Don't copy if sizes are compatible */ + if ((flags & ENSURECOPY) || PyArray_EquivTypes(oldtype, newtype)) { + arrflags = arr->flags; + copy = (flags & ENSURECOPY) || + ((flags & CONTIGUOUS) && (!(arrflags & CONTIGUOUS))) + || ((flags & ALIGNED) && (!(arrflags & ALIGNED))) + || (arr->nd > 1 && + ((flags & FORTRAN) && (!(arrflags & FORTRAN)))) + || ((flags & WRITEABLE) && (!(arrflags & WRITEABLE))); + + if (copy) { + if ((flags & UPDATEIFCOPY) && + (!PyArray_ISWRITEABLE(arr))) { + Py_DECREF(newtype); + PyErr_SetString(PyExc_ValueError, msg); + return NULL; + } + if ((flags & ENSUREARRAY)) { + subtype = &PyArray_Type; + } + ret = (PyArrayObject *) + PyArray_NewFromDescr(subtype, newtype, + arr->nd, + arr->dimensions, + NULL, NULL, + flags & FORTRAN, + (PyObject *)arr); + if (ret == NULL) { + return NULL; + } + if (PyArray_CopyInto(ret, arr) == -1) { + Py_DECREF(ret); + return NULL; + } + if (flags & UPDATEIFCOPY) { + ret->flags |= UPDATEIFCOPY; + ret->base = (PyObject *)arr; + PyArray_FLAGS(ret->base) &= ~WRITEABLE; + Py_INCREF(arr); + } + } + /* + * If no copy then just increase the reference + * count and return the input + */ + else { + Py_DECREF(newtype); + if ((flags & ENSUREARRAY) && + !PyArray_CheckExact(arr)) { + Py_INCREF(arr->descr); + ret = (PyArrayObject *) + PyArray_NewFromDescr(&PyArray_Type, + arr->descr, + arr->nd, + arr->dimensions, + arr->strides, + arr->data, + arr->flags,NULL); + if (ret == NULL) { + return NULL; + } + ret->base = (PyObject *)arr; + } + else { + ret = arr; + } + Py_INCREF(arr); + } + } + + /* + * The desired output type is different than the input + * array type and copy was not specified + */ + else { + if ((flags & UPDATEIFCOPY) && + (!PyArray_ISWRITEABLE(arr))) { + Py_DECREF(newtype); + PyErr_SetString(PyExc_ValueError, msg); + return NULL; + } + if ((flags & ENSUREARRAY)) { + subtype = &PyArray_Type; + } + ret = (PyArrayObject *) + PyArray_NewFromDescr(subtype, newtype, + arr->nd, arr->dimensions, + NULL, NULL, + flags & FORTRAN, + (PyObject *)arr); + if (ret == NULL) { + return NULL; + } + if (PyArray_CastTo(ret, arr) < 0) { + Py_DECREF(ret); + return NULL; + } + if (flags & UPDATEIFCOPY) { + ret->flags |= UPDATEIFCOPY; + ret->base = (PyObject *)arr; + PyArray_FLAGS(ret->base) &= ~WRITEABLE; + Py_INCREF(arr); + } + } + return (PyObject *)ret; +} + +/*NUMPY_API */ +NPY_NO_EXPORT PyObject * +PyArray_FromStructInterface(PyObject *input) +{ + PyArray_Descr *thetype = NULL; + char buf[40]; + PyArrayInterface *inter; + PyObject *attr, *r; + char endian = PyArray_NATBYTE; + + attr = PyObject_GetAttrString(input, "__array_struct__"); + if (attr == NULL) { + PyErr_Clear(); + return Py_NotImplemented; + } + if (!PyCObject_Check(attr)) { + goto fail; + } + inter = PyCObject_AsVoidPtr(attr); + if (inter->two != 2) { + goto fail; + } + if ((inter->flags & NOTSWAPPED) != NOTSWAPPED) { + endian = PyArray_OPPBYTE; + inter->flags &= ~NOTSWAPPED; + } + + if (inter->flags & ARR_HAS_DESCR) { + if (PyArray_DescrConverter(inter->descr, &thetype) == PY_FAIL) { + thetype = NULL; + PyErr_Clear(); + } + } + + if (thetype == NULL) { + PyOS_snprintf(buf, sizeof(buf), + "%c%c%d", endian, inter->typekind, inter->itemsize); + if (!(thetype=_array_typedescr_fromstr(buf))) { + Py_DECREF(attr); + return NULL; + } + } + + r = PyArray_NewFromDescr(&PyArray_Type, thetype, + inter->nd, inter->shape, + inter->strides, inter->data, + inter->flags, NULL); + Py_INCREF(input); + PyArray_BASE(r) = input; + Py_DECREF(attr); + PyArray_UpdateFlags((PyArrayObject *)r, UPDATE_ALL); + return r; + + fail: + PyErr_SetString(PyExc_ValueError, "invalid __array_struct__"); + Py_DECREF(attr); + return NULL; +} + +#define PyIntOrLong_Check(obj) (PyInt_Check(obj) || PyLong_Check(obj)) + +/*NUMPY_API*/ +NPY_NO_EXPORT PyObject * +PyArray_FromInterface(PyObject *input) +{ + PyObject *attr = NULL, *item = NULL; + PyObject *tstr = NULL, *shape = NULL; + PyObject *inter = NULL; + PyObject *base = NULL; + PyArrayObject *ret; + PyArray_Descr *type=NULL; + char *data; + Py_ssize_t buffer_len; + int res, i, n; + intp dims[MAX_DIMS], strides[MAX_DIMS]; + int dataflags = BEHAVED; + + /* Get the memory from __array_data__ and __array_offset__ */ + /* Get the shape */ + /* Get the typestring -- ignore array_descr */ + /* Get the strides */ + + inter = PyObject_GetAttrString(input, "__array_interface__"); + if (inter == NULL) { + PyErr_Clear(); + return Py_NotImplemented; + } + if (!PyDict_Check(inter)) { + Py_DECREF(inter); + return Py_NotImplemented; + } + shape = PyDict_GetItemString(inter, "shape"); + if (shape == NULL) { + Py_DECREF(inter); + return Py_NotImplemented; + } + tstr = PyDict_GetItemString(inter, "typestr"); + if (tstr == NULL) { + Py_DECREF(inter); + return Py_NotImplemented; + } + + attr = PyDict_GetItemString(inter, "data"); + base = input; + if ((attr == NULL) || (attr==Py_None) || (!PyTuple_Check(attr))) { + if (attr && (attr != Py_None)) { + item = attr; + } + else { + item = input; + } + res = PyObject_AsWriteBuffer(item, (void **)&data, &buffer_len); + if (res < 0) { + PyErr_Clear(); + res = PyObject_AsReadBuffer( + item, (const void **)&data, &buffer_len); + if (res < 0) { + goto fail; + } + dataflags &= ~WRITEABLE; + } + attr = PyDict_GetItemString(inter, "offset"); + if (attr) { + longlong num = PyLong_AsLongLong(attr); + if (error_converting(num)) { + PyErr_SetString(PyExc_TypeError, + "offset "\ + "must be an integer"); + goto fail; + } + data += num; + } + base = item; + } + else { + PyObject *dataptr; + if (PyTuple_GET_SIZE(attr) != 2) { + PyErr_SetString(PyExc_TypeError, + "data must return " \ + "a 2-tuple with (data pointer "\ + "integer, read-only flag)"); + goto fail; + } + dataptr = PyTuple_GET_ITEM(attr, 0); + if (PyString_Check(dataptr)) { + res = sscanf(PyString_AsString(dataptr), + "%p", (void **)&data); + if (res < 1) { + PyErr_SetString(PyExc_TypeError, + "data string cannot be " \ + "converted"); + goto fail; + } + } + else if (PyIntOrLong_Check(dataptr)) { + data = PyLong_AsVoidPtr(dataptr); + } + else { + PyErr_SetString(PyExc_TypeError, "first element " \ + "of data tuple must be integer" \ + " or string."); + goto fail; + } + if (PyObject_IsTrue(PyTuple_GET_ITEM(attr,1))) { + dataflags &= ~WRITEABLE; + } + } + attr = tstr; + if (!PyString_Check(attr)) { + PyErr_SetString(PyExc_TypeError, "typestr must be a string"); + goto fail; + } + type = _array_typedescr_fromstr(PyString_AS_STRING(attr)); + if (type == NULL) { + goto fail; + } + attr = shape; + if (!PyTuple_Check(attr)) { + PyErr_SetString(PyExc_TypeError, "shape must be a tuple"); + Py_DECREF(type); + goto fail; + } + n = PyTuple_GET_SIZE(attr); + for (i = 0; i < n; i++) { + item = PyTuple_GET_ITEM(attr, i); + dims[i] = PyArray_PyIntAsIntp(item); + if (error_converting(dims[i])) { + break; + } + } + + ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, type, + n, dims, + NULL, data, + dataflags, NULL); + if (ret == NULL) { + return NULL; + } + Py_INCREF(base); + ret->base = base; + + attr = PyDict_GetItemString(inter, "strides"); + if (attr != NULL && attr != Py_None) { + if (!PyTuple_Check(attr)) { + PyErr_SetString(PyExc_TypeError, + "strides must be a tuple"); + Py_DECREF(ret); + return NULL; + } + if (n != PyTuple_GET_SIZE(attr)) { + PyErr_SetString(PyExc_ValueError, + "mismatch in length of "\ + "strides and shape"); + Py_DECREF(ret); + return NULL; + } + for (i = 0; i < n; i++) { + item = PyTuple_GET_ITEM(attr, i); + strides[i] = PyArray_PyIntAsIntp(item); + if (error_converting(strides[i])) { + break; + } + } + if (PyErr_Occurred()) { + PyErr_Clear(); + } + memcpy(ret->strides, strides, n*sizeof(intp)); + } + else PyErr_Clear(); + PyArray_UpdateFlags(ret, UPDATE_ALL); + Py_DECREF(inter); + return (PyObject *)ret; + + fail: + Py_XDECREF(inter); + return NULL; +} + +/*NUMPY_API*/ +NPY_NO_EXPORT PyObject * +PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context) +{ + PyObject *new; + PyObject *array_meth; + + array_meth = PyObject_GetAttrString(op, "__array__"); + if (array_meth == NULL) { + PyErr_Clear(); + return Py_NotImplemented; + } + if (context == NULL) { + if (typecode == NULL) { + new = PyObject_CallFunction(array_meth, NULL); + } + else { + new = PyObject_CallFunction(array_meth, "O", typecode); + } + } + else { + if (typecode == NULL) { + new = PyObject_CallFunction(array_meth, "OO", Py_None, context); + if (new == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + new = PyObject_CallFunction(array_meth, ""); + } + } + else { + new = PyObject_CallFunction(array_meth, "OO", typecode, context); + if (new == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + new = PyObject_CallFunction(array_meth, "O", typecode); + } + } + } + Py_DECREF(array_meth); + if (new == NULL) { + return NULL; + } + if (!PyArray_Check(new)) { + PyErr_SetString(PyExc_ValueError, + "object __array__ method not " \ + "producing an array"); + Py_DECREF(new); + return NULL; + } + return new; +} + +/*NUMPY_API +* new reference -- accepts NULL for mintype +*/ +NPY_NO_EXPORT PyArray_Descr * +PyArray_DescrFromObject(PyObject *op, PyArray_Descr *mintype) +{ + return _array_find_type(op, mintype, MAX_DIMS); +} + +/* These are also old calls (should use PyArray_NewFromDescr) */ + +/* They all zero-out the memory as previously done */ + +/* steals reference to descr -- and enforces native byteorder on it.*/ +/*NUMPY_API + Like FromDimsAndData but uses the Descr structure instead of typecode + as input. +*/ +NPY_NO_EXPORT PyObject * +PyArray_FromDimsAndDataAndDescr(int nd, int *d, + PyArray_Descr *descr, + char *data) +{ + PyObject *ret; + int i; + intp newd[MAX_DIMS]; + char msg[] = "PyArray_FromDimsAndDataAndDescr: use PyArray_NewFromDescr."; + + if (DEPRECATE(msg) < 0) { + return NULL; + } + if (!PyArray_ISNBO(descr->byteorder)) + descr->byteorder = '='; + for (i = 0; i < nd; i++) { + newd[i] = (intp) d[i]; + } + ret = PyArray_NewFromDescr(&PyArray_Type, descr, + nd, newd, + NULL, data, + (data ? CARRAY : 0), NULL); + return ret; +} + +/*NUMPY_API + Construct an empty array from dimensions and typenum +*/ +NPY_NO_EXPORT PyObject * +PyArray_FromDims(int nd, int *d, int type) +{ + PyObject *ret; + char msg[] = "PyArray_FromDims: use PyArray_SimpleNew."; + + if (DEPRECATE(msg) < 0) { + return NULL; + } + ret = PyArray_FromDimsAndDataAndDescr(nd, d, + PyArray_DescrFromType(type), + NULL); + /* + * Old FromDims set memory to zero --- some algorithms + * relied on that. Better keep it the same. If + * Object type, then it's already been set to zero, though. + */ + if (ret && (PyArray_DESCR(ret)->type_num != PyArray_OBJECT)) { + memset(PyArray_DATA(ret), 0, PyArray_NBYTES(ret)); + } + return ret; +} + +/* end old calls */ + +/*NUMPY_API + * This is a quick wrapper around PyArray_FromAny(op, NULL, 0, 0, ENSUREARRAY) + * that special cases Arrays and PyArray_Scalars up front + * It *steals a reference* to the object + * It also guarantees that the result is PyArray_Type + * Because it decrefs op if any conversion needs to take place + * so it can be used like PyArray_EnsureArray(some_function(...)) + */ +NPY_NO_EXPORT PyObject * +PyArray_EnsureArray(PyObject *op) +{ + PyObject *new; + + if (op == NULL) { + return NULL; + } + if (PyArray_CheckExact(op)) { + return op; + } + if (PyArray_Check(op)) { + new = PyArray_View((PyArrayObject *)op, NULL, &PyArray_Type); + Py_DECREF(op); + return new; + } + if (PyArray_IsScalar(op, Generic)) { + new = PyArray_FromScalar(op, NULL); + Py_DECREF(op); + return new; + } + new = PyArray_FromAny(op, NULL, 0, 0, ENSUREARRAY, NULL); + Py_DECREF(op); + return new; +} + +/*NUMPY_API*/ +NPY_NO_EXPORT PyObject * +PyArray_EnsureAnyArray(PyObject *op) +{ + if (op && PyArray_Check(op)) { + return op; + } + return PyArray_EnsureArray(op); +} + +/*NUMPY_API + * Copy an Array into another array -- memory must not overlap + * Does not require src and dest to have "broadcastable" shapes + * (only the same number of elements). + */ +NPY_NO_EXPORT int +PyArray_CopyAnyInto(PyArrayObject *dest, PyArrayObject *src) +{ + int elsize, simple; + PyArrayIterObject *idest, *isrc; + void (*myfunc)(char *, intp, char *, intp, intp, int); + NPY_BEGIN_THREADS_DEF; + + if (!PyArray_EquivArrTypes(dest, src)) { + return PyArray_CastAnyTo(dest, src); + } + if (!PyArray_ISWRITEABLE(dest)) { + PyErr_SetString(PyExc_RuntimeError, + "cannot write to array"); + return -1; + } + if (PyArray_SIZE(dest) != PyArray_SIZE(src)) { + PyErr_SetString(PyExc_ValueError, + "arrays must have the same number of elements" + " for copy"); + return -1; + } + + simple = ((PyArray_ISCARRAY_RO(src) && PyArray_ISCARRAY(dest)) || + (PyArray_ISFARRAY_RO(src) && PyArray_ISFARRAY(dest))); + if (simple) { + /* Refcount note: src and dest have the same size */ + PyArray_INCREF(src); + PyArray_XDECREF(dest); + NPY_BEGIN_THREADS; + memcpy(dest->data, src->data, PyArray_NBYTES(dest)); + NPY_END_THREADS; + return 0; + } + + if (PyArray_SAMESHAPE(dest, src)) { + int swap; + + if (PyArray_SAFEALIGNEDCOPY(dest) && PyArray_SAFEALIGNEDCOPY(src)) { + myfunc = _strided_byte_copy; + } + else { + myfunc = _unaligned_strided_byte_copy; + } + swap = PyArray_ISNOTSWAPPED(dest) != PyArray_ISNOTSWAPPED(src); + return _copy_from_same_shape(dest, src, myfunc, swap); + } + + /* Otherwise we have to do an iterator-based copy */ + idest = (PyArrayIterObject *)PyArray_IterNew((PyObject *)dest); + if (idest == NULL) { + return -1; + } + isrc = (PyArrayIterObject *)PyArray_IterNew((PyObject *)src); + if (isrc == NULL) { + Py_DECREF(idest); + return -1; + } + elsize = dest->descr->elsize; + /* Refcount note: src and dest have the same size */ + PyArray_INCREF(src); + PyArray_XDECREF(dest); + NPY_BEGIN_THREADS; + while(idest->index < idest->size) { + memcpy(idest->dataptr, isrc->dataptr, elsize); + PyArray_ITER_NEXT(idest); + PyArray_ITER_NEXT(isrc); + } + NPY_END_THREADS; + Py_DECREF(idest); + Py_DECREF(isrc); + return 0; +} + +/*NUMPY_API + * Copy an Array into another array -- memory must not overlap. + */ +NPY_NO_EXPORT int +PyArray_CopyInto(PyArrayObject *dest, PyArrayObject *src) +{ + return _array_copy_into(dest, src, 1); +} + + +/*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; +} + diff --git a/numpy/core/src/arrayctors.h b/numpy/core/src/arrayctors.h new file mode 100644 index 000000000..318d71471 --- /dev/null +++ b/numpy/core/src/arrayctors.h @@ -0,0 +1,48 @@ +#ifndef _NPY_ARRAY_CTORS_H_ +#define _NPY_ARRAY_CTORS_H_ + +NPY_NO_EXPORT PyObject * +PyArray_NewFromDescr(PyTypeObject *subtype, PyArray_Descr *descr, int nd, + intp *dims, intp *strides, void *data, + int flags, PyObject *obj); + +NPY_NO_EXPORT PyObject *PyArray_New(PyTypeObject *, int nd, intp *, + int, intp *, void *, int, int, PyObject *); + +NPY_NO_EXPORT PyObject * +PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth, + int max_depth, int flags, PyObject *context); + +NPY_NO_EXPORT PyObject * +PyArray_CheckFromAny(PyObject *op, PyArray_Descr *descr, int min_depth, + int max_depth, int requires, PyObject *context); + +NPY_NO_EXPORT PyObject * +PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags); + +NPY_NO_EXPORT PyObject * +PyArray_FromStructInterface(PyObject *input); + +NPY_NO_EXPORT PyObject * +PyArray_FromInterface(PyObject *input); + +NPY_NO_EXPORT PyObject * +PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, + PyObject *context); + +NPY_NO_EXPORT PyObject * +PyArray_EnsureArray(PyObject *op); + +NPY_NO_EXPORT PyObject * +PyArray_EnsureAnyArray(PyObject *op); + +NPY_NO_EXPORT int +PyArray_MoveInto(PyArrayObject *dest, PyArrayObject *src); + +NPY_NO_EXPORT int +PyArray_CopyAnyInto(PyArrayObject *dest, PyArrayObject *src); + +NPY_NO_EXPORT PyObject * +PyArray_CheckAxis(PyArrayObject *arr, int *axis, int flags); + +#endif diff --git a/numpy/core/src/arrayobject.c b/numpy/core/src/arrayobject.c index f15111707..acce9a417 100644 --- a/numpy/core/src/arrayobject.c +++ b/numpy/core/src/arrayobject.c @@ -31,6 +31,7 @@ maintainer email: oliphant.travis@ieee.org #include "numpy/arrayscalars.h" #include "arrayobject.h" +#include "arrayctors.h" #include "arraymethods.h" #include "arraydescr.h" #include "arrayiterators.h" @@ -38,8 +39,6 @@ maintainer email: oliphant.travis@ieee.org #include "arraygetset.h" #include "arraysequence.h" -static PyArray_Descr * _array_typedescr_fromstr(char *); - #ifndef Py_UNICODE_WIDE #include "ucsnarrow.h" #endif @@ -173,10 +172,6 @@ PyArray_One(PyArrayObject *arr) /* End deprecated */ -NPY_NO_EXPORT PyObject *PyArray_New(PyTypeObject *, int nd, intp *, - int, intp *, void *, int, int, PyObject *); - - /* Incref all objects found at this record */ /*NUMPY_API */ @@ -364,199 +359,6 @@ PyArray_XDECREF(PyArrayObject *mp) return 0; } -static void -_strided_byte_copy(char *dst, intp outstrides, char *src, intp instrides, - intp N, int elsize) -{ - intp i, j; - char *tout = dst; - char *tin = src; - -#define _FAST_MOVE(_type_) \ - for(i=0; i<N; i++) { \ - ((_type_ *)tout)[0] = ((_type_ *)tin)[0]; \ - tin += instrides; \ - tout += outstrides; \ - } \ - return - - switch(elsize) { - case 8: - _FAST_MOVE(Int64); - case 4: - _FAST_MOVE(Int32); - case 1: - _FAST_MOVE(Int8); - case 2: - _FAST_MOVE(Int16); - case 16: - for (i = 0; i < N; i++) { - ((Int64 *)tout)[0] = ((Int64 *)tin)[0]; - ((Int64 *)tout)[1] = ((Int64 *)tin)[1]; - tin += instrides; - tout += outstrides; - } - return; - default: - for(i = 0; i < N; i++) { - for(j=0; j<elsize; j++) { - *tout++ = *tin++; - } - tin = tin + instrides - elsize; - tout = tout + outstrides - elsize; - } - } -#undef _FAST_MOVE - -} - - -static void -_unaligned_strided_byte_move(char *dst, intp outstrides, char *src, - intp instrides, intp N, int elsize) -{ - intp i; - char *tout = dst; - char *tin = src; - - -#define _MOVE_N_SIZE(size) \ - for(i=0; i<N; i++) { \ - memmove(tout, tin, size); \ - tin += instrides; \ - tout += outstrides; \ - } \ - return - - switch(elsize) { - case 8: - _MOVE_N_SIZE(8); - case 4: - _MOVE_N_SIZE(4); - case 1: - _MOVE_N_SIZE(1); - case 2: - _MOVE_N_SIZE(2); - case 16: - _MOVE_N_SIZE(16); - default: - _MOVE_N_SIZE(elsize); - } -#undef _MOVE_N_SIZE - -} - -NPY_NO_EXPORT void -_unaligned_strided_byte_copy(char *dst, intp outstrides, char *src, - intp instrides, intp N, int elsize) -{ - intp i; - char *tout = dst; - char *tin = src; - -#define _COPY_N_SIZE(size) \ - for(i=0; i<N; i++) { \ - memcpy(tout, tin, size); \ - tin += instrides; \ - tout += outstrides; \ - } \ - return - - switch(elsize) { - case 8: - _COPY_N_SIZE(8); - case 4: - _COPY_N_SIZE(4); - case 1: - _COPY_N_SIZE(1); - case 2: - _COPY_N_SIZE(2); - case 16: - _COPY_N_SIZE(16); - default: - _COPY_N_SIZE(elsize); - } -#undef _COPY_N_SIZE - -} - -NPY_NO_EXPORT void -_strided_byte_swap(void *p, intp stride, intp n, int size) -{ - char *a, *b, c = 0; - int j, m; - - switch(size) { - case 1: /* no byteswap necessary */ - break; - case 4: - for (a = (char*)p; n > 0; n--, a += stride - 1) { - b = a + 3; - c = *a; *a++ = *b; *b-- = c; - c = *a; *a = *b; *b = c; - } - break; - case 8: - for (a = (char*)p; n > 0; n--, a += stride - 3) { - b = a + 7; - c = *a; *a++ = *b; *b-- = c; - c = *a; *a++ = *b; *b-- = c; - c = *a; *a++ = *b; *b-- = c; - c = *a; *a = *b; *b = c; - } - break; - case 2: - for (a = (char*)p; n > 0; n--, a += stride) { - b = a + 1; - c = *a; *a = *b; *b = c; - } - break; - default: - m = size/2; - for (a = (char *)p; n > 0; n--, a += stride - m) { - b = a + (size - 1); - for (j = 0; j < m; j++) { - c=*a; *a++ = *b; *b-- = c; - } - } - break; - } -} - -NPY_NO_EXPORT void -byte_swap_vector(void *p, intp n, int size) -{ - _strided_byte_swap(p, (intp) size, n, size); - return; -} - -/* If numitems > 1, then dst must be contiguous */ -NPY_NO_EXPORT void -copy_and_swap(void *dst, void *src, int itemsize, intp numitems, - intp srcstrides, int swap) -{ - intp i; - char *s1 = (char *)src; - char *d1 = (char *)dst; - - - if ((numitems == 1) || (itemsize == srcstrides)) { - memcpy(d1, s1, itemsize*numitems); - } - else { - for (i = 0; i < numitems; i++) { - memcpy(d1, s1, itemsize); - d1 += itemsize; - s1 += srcstrides; - } - } - - if (swap) { - byte_swap_vector(d1, numitems, itemsize); - } -} - - NPY_NO_EXPORT PyArray_Descr **userdescrs=NULL; @@ -782,483 +584,6 @@ PyArray_Size(PyObject *op) } } -static int -_copy_from0d(PyArrayObject *dest, PyArrayObject *src, int usecopy, int swap) -{ - char *aligned = NULL; - char *sptr; - int numcopies, nbytes; - void (*myfunc)(char *, intp, char *, intp, intp, int); - int retval = -1; - NPY_BEGIN_THREADS_DEF; - - numcopies = PyArray_SIZE(dest); - if (numcopies < 1) { - return 0; - } - nbytes = PyArray_ITEMSIZE(src); - - if (!PyArray_ISALIGNED(src)) { - aligned = malloc((size_t)nbytes); - if (aligned == NULL) { - PyErr_NoMemory(); - return -1; - } - memcpy(aligned, src->data, (size_t) nbytes); - usecopy = 1; - sptr = aligned; - } - else { - sptr = src->data; - } - if (PyArray_SAFEALIGNEDCOPY(dest)) { - myfunc = _strided_byte_copy; - } - else if (usecopy) { - myfunc = _unaligned_strided_byte_copy; - } - else { - myfunc = _unaligned_strided_byte_move; - } - - if ((dest->nd < 2) || PyArray_ISONESEGMENT(dest)) { - char *dptr; - intp dstride; - - dptr = dest->data; - if (dest->nd == 1) { - dstride = dest->strides[0]; - } - else { - dstride = nbytes; - } - - /* Refcount note: src and dest may have different sizes */ - PyArray_INCREF(src); - PyArray_XDECREF(dest); - NPY_BEGIN_THREADS; - myfunc(dptr, dstride, sptr, 0, numcopies, (int) nbytes); - if (swap) { - _strided_byte_swap(dptr, dstride, numcopies, (int) nbytes); - } - NPY_END_THREADS; - PyArray_INCREF(dest); - PyArray_XDECREF(src); - } - else { - PyArrayIterObject *dit; - int axis = -1; - - dit = (PyArrayIterObject *) - PyArray_IterAllButAxis((PyObject *)dest, &axis); - if (dit == NULL) { - goto finish; - } - /* Refcount note: src and dest may have different sizes */ - PyArray_INCREF(src); - PyArray_XDECREF(dest); - NPY_BEGIN_THREADS; - while(dit->index < dit->size) { - myfunc(dit->dataptr, PyArray_STRIDE(dest, axis), sptr, 0, - PyArray_DIM(dest, axis), nbytes); - if (swap) { - _strided_byte_swap(dit->dataptr, PyArray_STRIDE(dest, axis), - PyArray_DIM(dest, axis), nbytes); - } - PyArray_ITER_NEXT(dit); - } - NPY_END_THREADS; - PyArray_INCREF(dest); - PyArray_XDECREF(src); - Py_DECREF(dit); - } - retval = 0; - -finish: - if (aligned != NULL) { - free(aligned); - } - return retval; -} - -/* - * Special-case of PyArray_CopyInto when dst is 1-d - * and contiguous (and aligned). - * PyArray_CopyInto requires broadcastable arrays while - * this one is a flattening operation... - */ -NPY_NO_EXPORT int -_flat_copyinto(PyObject *dst, PyObject *src, NPY_ORDER order) -{ - PyArrayIterObject *it; - PyObject *orig_src; - void (*myfunc)(char *, intp, char *, intp, intp, int); - char *dptr; - int axis; - int elsize; - intp nbytes; - NPY_BEGIN_THREADS_DEF; - - - orig_src = src; - if (PyArray_NDIM(src) == 0) { - /* Refcount note: src and dst have the same size */ - PyArray_INCREF((PyArrayObject *)src); - PyArray_XDECREF((PyArrayObject *)dst); - NPY_BEGIN_THREADS; - memcpy(PyArray_BYTES(dst), PyArray_BYTES(src), - PyArray_ITEMSIZE(src)); - NPY_END_THREADS; - return 0; - } - - axis = PyArray_NDIM(src)-1; - - if (order == PyArray_FORTRANORDER) { - if (PyArray_NDIM(src) <= 2) { - axis = 0; - } - /* fall back to a more general method */ - else { - src = PyArray_Transpose((PyArrayObject *)orig_src, NULL); - } - } - - it = (PyArrayIterObject *)PyArray_IterAllButAxis(src, &axis); - if (it == NULL) { - if (src != orig_src) { - Py_DECREF(src); - } - return -1; - } - - if (PyArray_SAFEALIGNEDCOPY(src)) { - myfunc = _strided_byte_copy; - } - else { - myfunc = _unaligned_strided_byte_copy; - } - - dptr = PyArray_BYTES(dst); - elsize = PyArray_ITEMSIZE(dst); - nbytes = elsize * PyArray_DIM(src, axis); - - /* Refcount note: src and dst have the same size */ - PyArray_INCREF((PyArrayObject *)src); - PyArray_XDECREF((PyArrayObject *)dst); - NPY_BEGIN_THREADS; - while(it->index < it->size) { - myfunc(dptr, elsize, it->dataptr, PyArray_STRIDE(src,axis), - PyArray_DIM(src,axis), elsize); - dptr += nbytes; - PyArray_ITER_NEXT(it); - } - NPY_END_THREADS; - - if (src != orig_src) { - Py_DECREF(src); - } - Py_DECREF(it); - return 0; -} - - -static int -_copy_from_same_shape(PyArrayObject *dest, PyArrayObject *src, - void (*myfunc)(char *, intp, char *, intp, intp, int), - int swap) -{ - int maxaxis = -1, elsize; - intp maxdim; - PyArrayIterObject *dit, *sit; - NPY_BEGIN_THREADS_DEF; - - dit = (PyArrayIterObject *) - PyArray_IterAllButAxis((PyObject *)dest, &maxaxis); - sit = (PyArrayIterObject *) - PyArray_IterAllButAxis((PyObject *)src, &maxaxis); - - maxdim = dest->dimensions[maxaxis]; - - if ((dit == NULL) || (sit == NULL)) { - Py_XDECREF(dit); - Py_XDECREF(sit); - return -1; - } - elsize = PyArray_ITEMSIZE(dest); - - /* Refcount note: src and dst have the same size */ - PyArray_INCREF(src); - PyArray_XDECREF(dest); - - NPY_BEGIN_THREADS; - while(dit->index < dit->size) { - /* strided copy of elsize bytes */ - myfunc(dit->dataptr, dest->strides[maxaxis], - sit->dataptr, src->strides[maxaxis], - maxdim, elsize); - if (swap) { - _strided_byte_swap(dit->dataptr, - dest->strides[maxaxis], - dest->dimensions[maxaxis], - elsize); - } - PyArray_ITER_NEXT(dit); - PyArray_ITER_NEXT(sit); - } - NPY_END_THREADS; - - Py_DECREF(sit); - Py_DECREF(dit); - return 0; -} - -static int -_broadcast_copy(PyArrayObject *dest, PyArrayObject *src, - void (*myfunc)(char *, intp, char *, intp, intp, int), - int swap) -{ - int elsize; - PyArrayMultiIterObject *multi; - int maxaxis; intp maxdim; - NPY_BEGIN_THREADS_DEF; - - elsize = PyArray_ITEMSIZE(dest); - multi = (PyArrayMultiIterObject *)PyArray_MultiIterNew(2, dest, src); - if (multi == NULL) { - return -1; - } - - if (multi->size != PyArray_SIZE(dest)) { - PyErr_SetString(PyExc_ValueError, - "array dimensions are not "\ - "compatible for copy"); - Py_DECREF(multi); - return -1; - } - - maxaxis = PyArray_RemoveSmallest(multi); - if (maxaxis < 0) { - /* - * copy 1 0-d array to another - * Refcount note: src and dst have the same size - */ - PyArray_INCREF(src); - PyArray_XDECREF(dest); - memcpy(dest->data, src->data, elsize); - if (swap) { - byte_swap_vector(dest->data, 1, elsize); - } - return 0; - } - maxdim = multi->dimensions[maxaxis]; - - /* - * Increment the source and decrement the destination - * reference counts - * - * Refcount note: src and dest may have different sizes - */ - PyArray_INCREF(src); - PyArray_XDECREF(dest); - - NPY_BEGIN_THREADS; - while(multi->index < multi->size) { - myfunc(multi->iters[0]->dataptr, - multi->iters[0]->strides[maxaxis], - multi->iters[1]->dataptr, - multi->iters[1]->strides[maxaxis], - maxdim, elsize); - if (swap) { - _strided_byte_swap(multi->iters[0]->dataptr, - multi->iters[0]->strides[maxaxis], - maxdim, elsize); - } - PyArray_MultiIter_NEXT(multi); - } - NPY_END_THREADS; - - PyArray_INCREF(dest); - PyArray_XDECREF(src); - - Py_DECREF(multi); - return 0; -} - -/* If destination is not the right type, then src - will be cast to destination -- this requires - src and dest to have the same shape -*/ - -/* Requires arrays to have broadcastable shapes - - The arrays are assumed to have the same number of elements - They can be different sizes and have different types however. -*/ - -static int -_array_copy_into(PyArrayObject *dest, PyArrayObject *src, int usecopy) -{ - int swap; - void (*myfunc)(char *, intp, char *, intp, intp, int); - int simple; - int same; - NPY_BEGIN_THREADS_DEF; - - - if (!PyArray_EquivArrTypes(dest, src)) { - return PyArray_CastTo(dest, src); - } - if (!PyArray_ISWRITEABLE(dest)) { - PyErr_SetString(PyExc_RuntimeError, - "cannot write to array"); - return -1; - } - same = PyArray_SAMESHAPE(dest, src); - simple = same && ((PyArray_ISCARRAY_RO(src) && PyArray_ISCARRAY(dest)) || - (PyArray_ISFARRAY_RO(src) && PyArray_ISFARRAY(dest))); - - if (simple) { - /* Refcount note: src and dest have the same size */ - PyArray_INCREF(src); - PyArray_XDECREF(dest); - NPY_BEGIN_THREADS; - if (usecopy) { - memcpy(dest->data, src->data, PyArray_NBYTES(dest)); - } - else { - memmove(dest->data, src->data, PyArray_NBYTES(dest)); - } - NPY_END_THREADS; - return 0; - } - - swap = PyArray_ISNOTSWAPPED(dest) != PyArray_ISNOTSWAPPED(src); - - if (src->nd == 0) { - return _copy_from0d(dest, src, usecopy, swap); - } - - if (PyArray_SAFEALIGNEDCOPY(dest) && PyArray_SAFEALIGNEDCOPY(src)) { - myfunc = _strided_byte_copy; - } - else if (usecopy) { - myfunc = _unaligned_strided_byte_copy; - } - else { - myfunc = _unaligned_strided_byte_move; - } - /* - * Could combine these because _broadcasted_copy would work as well. - * But, same-shape copying is so common we want to speed it up. - */ - if (same) { - return _copy_from_same_shape(dest, src, myfunc, swap); - } - else { - return _broadcast_copy(dest, src, myfunc, swap); - } -} - -/*NUMPY_API - * Copy an Array into another array -- memory must not overlap - * Does not require src and dest to have "broadcastable" shapes - * (only the same number of elements). - */ -NPY_NO_EXPORT int -PyArray_CopyAnyInto(PyArrayObject *dest, PyArrayObject *src) -{ - int elsize, simple; - PyArrayIterObject *idest, *isrc; - void (*myfunc)(char *, intp, char *, intp, intp, int); - NPY_BEGIN_THREADS_DEF; - - if (!PyArray_EquivArrTypes(dest, src)) { - return PyArray_CastAnyTo(dest, src); - } - if (!PyArray_ISWRITEABLE(dest)) { - PyErr_SetString(PyExc_RuntimeError, - "cannot write to array"); - return -1; - } - if (PyArray_SIZE(dest) != PyArray_SIZE(src)) { - PyErr_SetString(PyExc_ValueError, - "arrays must have the same number of elements" - " for copy"); - return -1; - } - - simple = ((PyArray_ISCARRAY_RO(src) && PyArray_ISCARRAY(dest)) || - (PyArray_ISFARRAY_RO(src) && PyArray_ISFARRAY(dest))); - if (simple) { - /* Refcount note: src and dest have the same size */ - PyArray_INCREF(src); - PyArray_XDECREF(dest); - NPY_BEGIN_THREADS; - memcpy(dest->data, src->data, PyArray_NBYTES(dest)); - NPY_END_THREADS; - return 0; - } - - if (PyArray_SAMESHAPE(dest, src)) { - int swap; - - if (PyArray_SAFEALIGNEDCOPY(dest) && PyArray_SAFEALIGNEDCOPY(src)) { - myfunc = _strided_byte_copy; - } - else { - myfunc = _unaligned_strided_byte_copy; - } - swap = PyArray_ISNOTSWAPPED(dest) != PyArray_ISNOTSWAPPED(src); - return _copy_from_same_shape(dest, src, myfunc, swap); - } - - /* Otherwise we have to do an iterator-based copy */ - idest = (PyArrayIterObject *)PyArray_IterNew((PyObject *)dest); - if (idest == NULL) { - return -1; - } - isrc = (PyArrayIterObject *)PyArray_IterNew((PyObject *)src); - if (isrc == NULL) { - Py_DECREF(idest); - return -1; - } - elsize = dest->descr->elsize; - /* Refcount note: src and dest have the same size */ - PyArray_INCREF(src); - PyArray_XDECREF(dest); - NPY_BEGIN_THREADS; - while(idest->index < idest->size) { - memcpy(idest->dataptr, isrc->dataptr, elsize); - PyArray_ITER_NEXT(idest); - PyArray_ITER_NEXT(isrc); - } - NPY_END_THREADS; - Py_DECREF(idest); - Py_DECREF(isrc); - return 0; -} - -/*NUMPY_API - * Copy an Array into another array -- memory must not overlap. - */ -NPY_NO_EXPORT int -PyArray_CopyInto(PyArrayObject *dest, PyArrayObject *src) -{ - return _array_copy_into(dest, src, 1); -} - - -/*NUMPY_API - * Move the memory of one array into another. - */ -NPY_NO_EXPORT int -PyArray_MoveInto(PyArrayObject *dest, PyArrayObject *src) -{ - return _array_copy_into(dest, src, 0); -} - - /*NUMPY_API*/ NPY_NO_EXPORT int PyArray_CopyObject(PyArrayObject *dest, PyObject *src_object) @@ -1316,69 +641,6 @@ PyArray_CopyObject(PyArrayObject *dest, PyObject *src_object) } -/* These are also old calls (should use PyArray_NewFromDescr) */ - -/* They all zero-out the memory as previously done */ - -/* steals reference to descr -- and enforces native byteorder on it.*/ -/*NUMPY_API - Like FromDimsAndData but uses the Descr structure instead of typecode - as input. -*/ -NPY_NO_EXPORT PyObject * -PyArray_FromDimsAndDataAndDescr(int nd, int *d, - PyArray_Descr *descr, - char *data) -{ - PyObject *ret; - int i; - intp newd[MAX_DIMS]; - char msg[] = "PyArray_FromDimsAndDataAndDescr: use PyArray_NewFromDescr."; - - if (DEPRECATE(msg) < 0) { - return NULL; - } - if (!PyArray_ISNBO(descr->byteorder)) - descr->byteorder = '='; - for (i = 0; i < nd; i++) { - newd[i] = (intp) d[i]; - } - ret = PyArray_NewFromDescr(&PyArray_Type, descr, - nd, newd, - NULL, data, - (data ? CARRAY : 0), NULL); - return ret; -} - -/*NUMPY_API - Construct an empty array from dimensions and typenum -*/ -NPY_NO_EXPORT PyObject * -PyArray_FromDims(int nd, int *d, int type) -{ - PyObject *ret; - char msg[] = "PyArray_FromDims: use PyArray_SimpleNew."; - - if (DEPRECATE(msg) < 0) { - return NULL; - } - ret = PyArray_FromDimsAndDataAndDescr(nd, d, - PyArray_DescrFromType(type), - NULL); - /* - * Old FromDims set memory to zero --- some algorithms - * relied on that. Better keep it the same. If - * Object type, then it's already been set to zero, though. - */ - if (ret && (PyArray_DESCR(ret)->type_num != PyArray_OBJECT)) { - memset(PyArray_DATA(ret), 0, PyArray_NBYTES(ret)); - } - return ret; -} - -/* end old calls */ - - /*NUMPY_API Copy an array. */ @@ -3034,61 +2296,6 @@ array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op) } -/*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 /* Lifted from numarray */ @@ -3499,348 +2706,6 @@ _array_fill_strides(intp *strides, intp *dims, int nd, size_t itemsize, 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) { - 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; - - 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; - } - } - - 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)); - } - 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; - } - 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; - } - - 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) { - self->dimensions = PyDimMem_NEW(2*nd); - if (self->dimensions == NULL) { - PyErr_NoMemory(); - goto fail; - } - self->strides = self->dimensions + nd; - memcpy(self->dimensions, dims, sizeof(intp)*nd); - if (strides == NULL) { /* fill it in */ - sd = _array_fill_strides(self->strides, dims, nd, sd, - flags, &(self->flags)); - } - else { - /* - * 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 = self->strides = NULL; - } - - 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); - } - } - 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; - - /* - * 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; - - 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); - } - return (PyObject *)self; - - fail: - Py_DECREF(self); - return NULL; -} - static void _putzero(char *optr, PyObject *zero, PyArray_Descr *dtype) { @@ -4389,165 +3254,6 @@ NPY_NO_EXPORT PyTypeObject PyArray_Type = { #endif }; -/* - * The rest of this code is to build the right kind of array - * from a python object. - */ - -static int -discover_depth(PyObject *s, int max, int stop_at_string, int stop_at_tuple) -{ - int d = 0; - PyObject *e; - - if(max < 1) { - return -1; - } - if(!PySequence_Check(s) || PyInstance_Check(s) || - PySequence_Length(s) < 0) { - PyErr_Clear(); - return 0; - } - if (PyArray_Check(s)) { - return PyArray_NDIM(s); - } - if (PyArray_IsScalar(s, Generic)) { - return 0; - } - if (PyString_Check(s) || PyBuffer_Check(s) || PyUnicode_Check(s)) { - return stop_at_string ? 0:1; - } - if (stop_at_tuple && PyTuple_Check(s)) { - return 0; - } - if ((e = PyObject_GetAttrString(s, "__array_struct__")) != NULL) { - d = -1; - if (PyCObject_Check(e)) { - PyArrayInterface *inter; - inter = (PyArrayInterface *)PyCObject_AsVoidPtr(e); - if (inter->two == 2) { - d = inter->nd; - } - } - Py_DECREF(e); - if (d > -1) { - return d; - } - } - else { - PyErr_Clear(); - } - if ((e=PyObject_GetAttrString(s, "__array_interface__")) != NULL) { - d = -1; - if (PyDict_Check(e)) { - PyObject *new; - new = PyDict_GetItemString(e, "shape"); - if (new && PyTuple_Check(new)) { - d = PyTuple_GET_SIZE(new); - } - } - Py_DECREF(e); - if (d>-1) { - return d; - } - } - else PyErr_Clear(); - - if (PySequence_Length(s) == 0) { - return 1; - } - if ((e=PySequence_GetItem(s,0)) == NULL) { - return -1; - } - if (e != s) { - d = discover_depth(e, max-1, stop_at_string, stop_at_tuple); - if (d >= 0) { - d++; - } - } - Py_DECREF(e); - return d; -} - -static int -discover_itemsize(PyObject *s, int nd, int *itemsize) -{ - int n, r, i; - PyObject *e; - - if (PyArray_Check(s)) { - *itemsize = MAX(*itemsize, PyArray_ITEMSIZE(s)); - return 0; - } - - n = PyObject_Length(s); - if ((nd == 0) || PyString_Check(s) || - PyUnicode_Check(s) || PyBuffer_Check(s)) { - *itemsize = MAX(*itemsize, n); - return 0; - } - for (i = 0; i < n; i++) { - if ((e = PySequence_GetItem(s,i))==NULL) { - return -1; - } - r = discover_itemsize(e,nd-1,itemsize); - Py_DECREF(e); - if (r == -1) { - return -1; - } - } - return 0; -} - -/* - * Take an arbitrary object known to represent - * an array of ndim nd, and determine the size in each dimension - */ -static int -discover_dimensions(PyObject *s, int nd, intp *d, int check_it) -{ - PyObject *e; - int r, n, i, n_lower; - - - if (PyArray_Check(s)) { - for (i=0; i<nd; i++) { - d[i] = PyArray_DIM(s,i); - } - return 0; - } - n = PyObject_Length(s); - *d = n; - if (*d < 0) { - return -1; - } - if (nd <= 1) { - return 0; - } - n_lower = 0; - for(i = 0; i < n; i++) { - if ((e = PySequence_GetItem(s,i)) == NULL) { - return -1; - } - r = discover_dimensions(e, nd - 1, d + 1, check_it); - Py_DECREF(e); - - if (r == -1) { - return -1; - } - if (check_it && n_lower != 0 && n_lower != d[1]) { - PyErr_SetString(PyExc_ValueError, - "inconsistent shape in sequence"); - return -1; - } - if (d[1] > n_lower) { - n_lower = d[1]; - } - } - d[1] = n_lower; - - return 0; -} /* * new reference @@ -4619,7 +3325,7 @@ _array_small_type(PyArray_Descr *chktype, PyArray_Descr* mintype) return outtype; } -static PyArray_Descr * +NPY_NO_EXPORT PyArray_Descr * _array_find_python_scalar_type(PyObject *op) { if (PyFloat_Check(op)) { @@ -4679,7 +3385,7 @@ _use_default_type(PyObject *op) * max is the maximum number of dimensions -- used for recursive call * to avoid infinite recursion... */ -static PyArray_Descr * +NPY_NO_EXPORT PyArray_Descr * _array_find_type(PyObject *op, PyArray_Descr *minitype, int max) { int l; @@ -4847,307 +3553,6 @@ _array_find_type(PyObject *op, PyArray_Descr *minitype, int max) return outtype; } -/* adapted from Numarray */ -static int -setArrayFromSequence(PyArrayObject *a, PyObject *s, int dim, intp offset) -{ - Py_ssize_t i, slen; - int res = 0; - - /* - * This code is to ensure that the sequence access below will - * return a lower-dimensional sequence. - */ - if (PyArray_Check(s) && !(PyArray_CheckExact(s))) { - /* - * FIXME: This could probably copy the entire subarray at once here using - * a faster algorithm. Right now, just make sure a base-class array is - * used so that the dimensionality reduction assumption is correct. - */ - s = PyArray_EnsureArray(s); - } - - if (dim > a->nd) { - PyErr_Format(PyExc_ValueError, - "setArrayFromSequence: sequence/array dimensions mismatch."); - return -1; - } - - slen = PySequence_Length(s); - if (slen != a->dimensions[dim]) { - PyErr_Format(PyExc_ValueError, - "setArrayFromSequence: sequence/array shape mismatch."); - return -1; - } - - for (i = 0; i < slen; i++) { - PyObject *o = PySequence_GetItem(s, i); - if ((a->nd - dim) > 1) { - res = setArrayFromSequence(a, o, dim+1, offset); - } - else { - res = a->descr->f->setitem(o, (a->data + offset), a); - } - Py_DECREF(o); - if (res < 0) { - return res; - } - offset += a->strides[dim]; - } - return 0; -} - - -static int -Assign_Array(PyArrayObject *self, PyObject *v) -{ - if (!PySequence_Check(v)) { - PyErr_SetString(PyExc_ValueError, - "assignment from non-sequence"); - return -1; - } - if (self->nd == 0) { - PyErr_SetString(PyExc_ValueError, - "assignment to 0-d array"); - return -1; - } - return setArrayFromSequence(self, v, 0, 0); -} - -/* - * "Array Scalars don't call this code" - * steals reference to typecode -- no NULL - */ -static PyObject * -Array_FromPyScalar(PyObject *op, PyArray_Descr *typecode) -{ - PyArrayObject *ret; - int itemsize; - int type; - - itemsize = typecode->elsize; - type = typecode->type_num; - - if (itemsize == 0 && PyTypeNum_ISEXTENDED(type)) { - itemsize = PyObject_Length(op); - if (type == PyArray_UNICODE) { - itemsize *= 4; - } - if (itemsize != typecode->elsize) { - PyArray_DESCR_REPLACE(typecode); - typecode->elsize = itemsize; - } - } - - ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, typecode, - 0, NULL, - NULL, NULL, 0, NULL); - if (ret == NULL) { - return NULL; - } - if (ret->nd > 0) { - PyErr_SetString(PyExc_ValueError, - "shape-mismatch on array construction"); - Py_DECREF(ret); - return NULL; - } - - ret->descr->f->setitem(op, ret->data, ret); - if (PyErr_Occurred()) { - Py_DECREF(ret); - return NULL; - } - else { - return (PyObject *)ret; - } -} - - -/* - * If s is not a list, return 0 - * Otherwise: - * - * run object_depth_and_dimension on all the elements - * and make sure the returned shape and size is the - * same for each element - */ -static int -object_depth_and_dimension(PyObject *s, int max, intp *dims) -{ - intp *newdims, *test_dims; - int nd, test_nd; - int i, islist, istuple; - intp size; - PyObject *obj; - - islist = PyList_Check(s); - istuple = PyTuple_Check(s); - if (!(islist || istuple)) { - return 0; - } - - size = PySequence_Size(s); - if (size == 0) { - return 0; - } - if (max < 1) { - return 0; - } - if (max < 2) { - dims[0] = size; - return 1; - } - - newdims = PyDimMem_NEW(2*(max - 1)); - test_dims = newdims + (max - 1); - if (islist) { - obj = PyList_GET_ITEM(s, 0); - } - else { - obj = PyTuple_GET_ITEM(s, 0); - } - nd = object_depth_and_dimension(obj, max - 1, newdims); - - for (i = 1; i < size; i++) { - if (islist) { - obj = PyList_GET_ITEM(s, i); - } - else { - obj = PyTuple_GET_ITEM(s, i); - } - test_nd = object_depth_and_dimension(obj, max-1, test_dims); - - if ((nd != test_nd) || - (!PyArray_CompareLists(newdims, test_dims, nd))) { - nd = 0; - break; - } - } - - for (i = 1; i <= nd; i++) { - dims[i] = newdims[i-1]; - } - dims[0] = size; - PyDimMem_FREE(newdims); - return nd + 1; -} - -static PyObject * -ObjectArray_FromNestedList(PyObject *s, PyArray_Descr *typecode, int fortran) -{ - int nd; - intp d[MAX_DIMS]; - PyArrayObject *r; - - /* Get the depth and the number of dimensions */ - nd = object_depth_and_dimension(s, MAX_DIMS, d); - if (nd < 0) { - return NULL; - } - if (nd == 0) { - return Array_FromPyScalar(s, typecode); - } - r = (PyArrayObject*)PyArray_NewFromDescr(&PyArray_Type, typecode, - nd, d, - NULL, NULL, - fortran, NULL); - if (!r) { - return NULL; - } - if(Assign_Array(r,s) == -1) { - Py_DECREF(r); - return NULL; - } - return (PyObject*)r; -} - -/* - * isobject means that we are constructing an - * object array on-purpose with a nested list. - * Only a list is interpreted as a sequence with these rules - * steals reference to typecode - */ -static PyObject * -Array_FromSequence(PyObject *s, PyArray_Descr *typecode, int fortran, - int min_depth, int max_depth) -{ - PyArrayObject *r; - int nd; - int err; - intp d[MAX_DIMS]; - int stop_at_string; - int stop_at_tuple; - int check_it; - int type = typecode->type_num; - int itemsize = typecode->elsize; - - check_it = (typecode->type != PyArray_CHARLTR); - stop_at_string = (type != PyArray_STRING) || - (typecode->type == PyArray_STRINGLTR); - stop_at_tuple = (type == PyArray_VOID && (typecode->names - || typecode->subarray)); - - nd = discover_depth(s, MAX_DIMS + 1, stop_at_string, stop_at_tuple); - if (nd == 0) { - return Array_FromPyScalar(s, typecode); - } - else if (nd < 0) { - PyErr_SetString(PyExc_ValueError, - "invalid input sequence"); - goto fail; - } - if (max_depth && PyTypeNum_ISOBJECT(type) && (nd > max_depth)) { - nd = max_depth; - } - if ((max_depth && nd > max_depth) || (min_depth && nd < min_depth)) { - PyErr_SetString(PyExc_ValueError, - "invalid number of dimensions"); - goto fail; - } - - err = discover_dimensions(s, nd, d, check_it); - if (err == -1) { - goto fail; - } - if (typecode->type == PyArray_CHARLTR && nd > 0 && d[nd - 1] == 1) { - nd = nd - 1; - } - - if (itemsize == 0 && PyTypeNum_ISEXTENDED(type)) { - err = discover_itemsize(s, nd, &itemsize); - if (err == -1) { - goto fail; - } - if (type == PyArray_UNICODE) { - itemsize *= 4; - } - } - if (itemsize != typecode->elsize) { - PyArray_DESCR_REPLACE(typecode); - typecode->elsize = itemsize; - } - - r = (PyArrayObject*)PyArray_NewFromDescr(&PyArray_Type, typecode, - nd, d, - NULL, NULL, - fortran, NULL); - if (!r) { - return NULL; - } - - err = Assign_Array(r,s); - if (err == -1) { - Py_DECREF(r); - return NULL; - } - return (PyObject*)r; - - fail: - Py_DECREF(typecode); - return NULL; -} - - /*NUMPY_API * Is the typenum valid? */ @@ -5644,158 +4049,8 @@ PyArray_CastAnyTo(PyArrayObject *out, PyArrayObject *mp) -/*NUMPY_API - * steals reference to newtype --- acc. NULL - */ -NPY_NO_EXPORT PyObject * -PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags) -{ - - PyArrayObject *ret = NULL; - int itemsize; - int copy = 0; - int arrflags; - PyArray_Descr *oldtype; - char *msg = "cannot copy back to a read-only array"; - PyTypeObject *subtype; - - oldtype = PyArray_DESCR(arr); - subtype = arr->ob_type; - if (newtype == NULL) { - newtype = oldtype; Py_INCREF(oldtype); - } - itemsize = newtype->elsize; - if (itemsize == 0) { - PyArray_DESCR_REPLACE(newtype); - if (newtype == NULL) { - return NULL; - } - newtype->elsize = oldtype->elsize; - itemsize = newtype->elsize; - } - - /* - * Can't cast unless ndim-0 array, FORCECAST is specified - * or the cast is safe. - */ - if (!(flags & FORCECAST) && !PyArray_NDIM(arr) == 0 && - !PyArray_CanCastTo(oldtype, newtype)) { - Py_DECREF(newtype); - PyErr_SetString(PyExc_TypeError, - "array cannot be safely cast " \ - "to required type"); - return NULL; - } - - /* Don't copy if sizes are compatible */ - if ((flags & ENSURECOPY) || PyArray_EquivTypes(oldtype, newtype)) { - arrflags = arr->flags; - copy = (flags & ENSURECOPY) || - ((flags & CONTIGUOUS) && (!(arrflags & CONTIGUOUS))) - || ((flags & ALIGNED) && (!(arrflags & ALIGNED))) - || (arr->nd > 1 && - ((flags & FORTRAN) && (!(arrflags & FORTRAN)))) - || ((flags & WRITEABLE) && (!(arrflags & WRITEABLE))); - - if (copy) { - if ((flags & UPDATEIFCOPY) && - (!PyArray_ISWRITEABLE(arr))) { - Py_DECREF(newtype); - PyErr_SetString(PyExc_ValueError, msg); - return NULL; - } - if ((flags & ENSUREARRAY)) { - subtype = &PyArray_Type; - } - ret = (PyArrayObject *) - PyArray_NewFromDescr(subtype, newtype, - arr->nd, - arr->dimensions, - NULL, NULL, - flags & FORTRAN, - (PyObject *)arr); - if (ret == NULL) { - return NULL; - } - if (PyArray_CopyInto(ret, arr) == -1) { - Py_DECREF(ret); - return NULL; - } - if (flags & UPDATEIFCOPY) { - ret->flags |= UPDATEIFCOPY; - ret->base = (PyObject *)arr; - PyArray_FLAGS(ret->base) &= ~WRITEABLE; - Py_INCREF(arr); - } - } - /* - * If no copy then just increase the reference - * count and return the input - */ - else { - Py_DECREF(newtype); - if ((flags & ENSUREARRAY) && - !PyArray_CheckExact(arr)) { - Py_INCREF(arr->descr); - ret = (PyArrayObject *) - PyArray_NewFromDescr(&PyArray_Type, - arr->descr, - arr->nd, - arr->dimensions, - arr->strides, - arr->data, - arr->flags,NULL); - if (ret == NULL) { - return NULL; - } - ret->base = (PyObject *)arr; - } - else { - ret = arr; - } - Py_INCREF(arr); - } - } - - /* - * The desired output type is different than the input - * array type and copy was not specified - */ - else { - if ((flags & UPDATEIFCOPY) && - (!PyArray_ISWRITEABLE(arr))) { - Py_DECREF(newtype); - PyErr_SetString(PyExc_ValueError, msg); - return NULL; - } - if ((flags & ENSUREARRAY)) { - subtype = &PyArray_Type; - } - ret = (PyArrayObject *) - PyArray_NewFromDescr(subtype, newtype, - arr->nd, arr->dimensions, - NULL, NULL, - flags & FORTRAN, - (PyObject *)arr); - if (ret == NULL) { - return NULL; - } - if (PyArray_CastTo(ret, arr) < 0) { - Py_DECREF(ret); - return NULL; - } - if (flags & UPDATEIFCOPY) { - ret->flags |= UPDATEIFCOPY; - ret->base = (PyObject *)arr; - PyArray_FLAGS(ret->base) &= ~WRITEABLE; - Py_INCREF(arr); - } - } - return (PyObject *)ret; -} - /* new reference */ -static PyArray_Descr * +NPY_NO_EXPORT PyArray_Descr * _array_typedescr_fromstr(char *str) { PyArray_Descr *descr; @@ -5944,434 +4199,6 @@ _array_typedescr_fromstr(char *str) return descr; } -/*NUMPY_API */ -NPY_NO_EXPORT PyObject * -PyArray_FromStructInterface(PyObject *input) -{ - PyArray_Descr *thetype = NULL; - char buf[40]; - PyArrayInterface *inter; - PyObject *attr, *r; - char endian = PyArray_NATBYTE; - - attr = PyObject_GetAttrString(input, "__array_struct__"); - if (attr == NULL) { - PyErr_Clear(); - return Py_NotImplemented; - } - if (!PyCObject_Check(attr)) { - goto fail; - } - inter = PyCObject_AsVoidPtr(attr); - if (inter->two != 2) { - goto fail; - } - if ((inter->flags & NOTSWAPPED) != NOTSWAPPED) { - endian = PyArray_OPPBYTE; - inter->flags &= ~NOTSWAPPED; - } - - if (inter->flags & ARR_HAS_DESCR) { - if (PyArray_DescrConverter(inter->descr, &thetype) == PY_FAIL) { - thetype = NULL; - PyErr_Clear(); - } - } - - if (thetype == NULL) { - PyOS_snprintf(buf, sizeof(buf), - "%c%c%d", endian, inter->typekind, inter->itemsize); - if (!(thetype=_array_typedescr_fromstr(buf))) { - Py_DECREF(attr); - return NULL; - } - } - - r = PyArray_NewFromDescr(&PyArray_Type, thetype, - inter->nd, inter->shape, - inter->strides, inter->data, - inter->flags, NULL); - Py_INCREF(input); - PyArray_BASE(r) = input; - Py_DECREF(attr); - PyArray_UpdateFlags((PyArrayObject *)r, UPDATE_ALL); - return r; - - fail: - PyErr_SetString(PyExc_ValueError, "invalid __array_struct__"); - Py_DECREF(attr); - return NULL; -} - -#define PyIntOrLong_Check(obj) (PyInt_Check(obj) || PyLong_Check(obj)) - -/*NUMPY_API*/ -NPY_NO_EXPORT PyObject * -PyArray_FromInterface(PyObject *input) -{ - PyObject *attr = NULL, *item = NULL; - PyObject *tstr = NULL, *shape = NULL; - PyObject *inter = NULL; - PyObject *base = NULL; - PyArrayObject *ret; - PyArray_Descr *type=NULL; - char *data; - Py_ssize_t buffer_len; - int res, i, n; - intp dims[MAX_DIMS], strides[MAX_DIMS]; - int dataflags = BEHAVED; - - /* Get the memory from __array_data__ and __array_offset__ */ - /* Get the shape */ - /* Get the typestring -- ignore array_descr */ - /* Get the strides */ - - inter = PyObject_GetAttrString(input, "__array_interface__"); - if (inter == NULL) { - PyErr_Clear(); - return Py_NotImplemented; - } - if (!PyDict_Check(inter)) { - Py_DECREF(inter); - return Py_NotImplemented; - } - shape = PyDict_GetItemString(inter, "shape"); - if (shape == NULL) { - Py_DECREF(inter); - return Py_NotImplemented; - } - tstr = PyDict_GetItemString(inter, "typestr"); - if (tstr == NULL) { - Py_DECREF(inter); - return Py_NotImplemented; - } - - attr = PyDict_GetItemString(inter, "data"); - base = input; - if ((attr == NULL) || (attr==Py_None) || (!PyTuple_Check(attr))) { - if (attr && (attr != Py_None)) { - item = attr; - } - else { - item = input; - } - res = PyObject_AsWriteBuffer(item, (void **)&data, &buffer_len); - if (res < 0) { - PyErr_Clear(); - res = PyObject_AsReadBuffer( - item, (const void **)&data, &buffer_len); - if (res < 0) { - goto fail; - } - dataflags &= ~WRITEABLE; - } - attr = PyDict_GetItemString(inter, "offset"); - if (attr) { - longlong num = PyLong_AsLongLong(attr); - if (error_converting(num)) { - PyErr_SetString(PyExc_TypeError, - "offset "\ - "must be an integer"); - goto fail; - } - data += num; - } - base = item; - } - else { - PyObject *dataptr; - if (PyTuple_GET_SIZE(attr) != 2) { - PyErr_SetString(PyExc_TypeError, - "data must return " \ - "a 2-tuple with (data pointer "\ - "integer, read-only flag)"); - goto fail; - } - dataptr = PyTuple_GET_ITEM(attr, 0); - if (PyString_Check(dataptr)) { - res = sscanf(PyString_AsString(dataptr), - "%p", (void **)&data); - if (res < 1) { - PyErr_SetString(PyExc_TypeError, - "data string cannot be " \ - "converted"); - goto fail; - } - } - else if (PyIntOrLong_Check(dataptr)) { - data = PyLong_AsVoidPtr(dataptr); - } - else { - PyErr_SetString(PyExc_TypeError, "first element " \ - "of data tuple must be integer" \ - " or string."); - goto fail; - } - if (PyObject_IsTrue(PyTuple_GET_ITEM(attr,1))) { - dataflags &= ~WRITEABLE; - } - } - attr = tstr; - if (!PyString_Check(attr)) { - PyErr_SetString(PyExc_TypeError, "typestr must be a string"); - goto fail; - } - type = _array_typedescr_fromstr(PyString_AS_STRING(attr)); - if (type == NULL) { - goto fail; - } - attr = shape; - if (!PyTuple_Check(attr)) { - PyErr_SetString(PyExc_TypeError, "shape must be a tuple"); - Py_DECREF(type); - goto fail; - } - n = PyTuple_GET_SIZE(attr); - for (i = 0; i < n; i++) { - item = PyTuple_GET_ITEM(attr, i); - dims[i] = PyArray_PyIntAsIntp(item); - if (error_converting(dims[i])) { - break; - } - } - - ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, type, - n, dims, - NULL, data, - dataflags, NULL); - if (ret == NULL) { - return NULL; - } - Py_INCREF(base); - ret->base = base; - - attr = PyDict_GetItemString(inter, "strides"); - if (attr != NULL && attr != Py_None) { - if (!PyTuple_Check(attr)) { - PyErr_SetString(PyExc_TypeError, - "strides must be a tuple"); - Py_DECREF(ret); - return NULL; - } - if (n != PyTuple_GET_SIZE(attr)) { - PyErr_SetString(PyExc_ValueError, - "mismatch in length of "\ - "strides and shape"); - Py_DECREF(ret); - return NULL; - } - for (i = 0; i < n; i++) { - item = PyTuple_GET_ITEM(attr, i); - strides[i] = PyArray_PyIntAsIntp(item); - if (error_converting(strides[i])) { - break; - } - } - if (PyErr_Occurred()) { - PyErr_Clear(); - } - memcpy(ret->strides, strides, n*sizeof(intp)); - } - else PyErr_Clear(); - PyArray_UpdateFlags(ret, UPDATE_ALL); - Py_DECREF(inter); - return (PyObject *)ret; - - fail: - Py_XDECREF(inter); - return NULL; -} - -/*NUMPY_API*/ -NPY_NO_EXPORT PyObject * -PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context) -{ - PyObject *new; - PyObject *array_meth; - - array_meth = PyObject_GetAttrString(op, "__array__"); - if (array_meth == NULL) { - PyErr_Clear(); - return Py_NotImplemented; - } - if (context == NULL) { - if (typecode == NULL) { - new = PyObject_CallFunction(array_meth, NULL); - } - else { - new = PyObject_CallFunction(array_meth, "O", typecode); - } - } - else { - if (typecode == NULL) { - new = PyObject_CallFunction(array_meth, "OO", Py_None, context); - if (new == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_Clear(); - new = PyObject_CallFunction(array_meth, ""); - } - } - else { - new = PyObject_CallFunction(array_meth, "OO", typecode, context); - if (new == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_Clear(); - new = PyObject_CallFunction(array_meth, "O", typecode); - } - } - } - Py_DECREF(array_meth); - if (new == NULL) { - return NULL; - } - if (!PyArray_Check(new)) { - PyErr_SetString(PyExc_ValueError, - "object __array__ method not " \ - "producing an array"); - Py_DECREF(new); - return NULL; - } - return new; -} - -/*NUMPY_API - * Does not check for ENSURECOPY and NOTSWAPPED in flags - * Steals a reference to newtype --- which can be NULL - */ -NPY_NO_EXPORT PyObject * -PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth, - int max_depth, int flags, PyObject *context) -{ - /* - * This is the main code to make a NumPy array from a Python - * Object. It is called from lot's of different places which - * is why there are so many checks. The comments try to - * explain some of the checks. - */ - PyObject *r = NULL; - int seq = FALSE; - - /* - * Is input object already an array? - * This is where the flags are used - */ - if (PyArray_Check(op)) { - r = PyArray_FromArray((PyArrayObject *)op, newtype, flags); - } - else if (PyArray_IsScalar(op, Generic)) { - if (flags & UPDATEIFCOPY) { - goto err; - } - r = PyArray_FromScalar(op, newtype); - } - else if (newtype == NULL && - (newtype = _array_find_python_scalar_type(op))) { - if (flags & UPDATEIFCOPY) { - goto err; - } - r = Array_FromPyScalar(op, newtype); - } - else if (PyArray_HasArrayInterfaceType(op, newtype, context, r)) { - PyObject *new; - if (r == NULL) { - Py_XDECREF(newtype); - return NULL; - } - if (newtype != NULL || flags != 0) { - new = PyArray_FromArray((PyArrayObject *)r, newtype, flags); - Py_DECREF(r); - r = new; - } - } - else { - int isobject = 0; - - if (flags & UPDATEIFCOPY) { - goto err; - } - if (newtype == NULL) { - newtype = _array_find_type(op, NULL, MAX_DIMS); - } - else if (newtype->type_num == PyArray_OBJECT) { - isobject = 1; - } - if (PySequence_Check(op)) { - PyObject *thiserr = NULL; - - /* necessary but not sufficient */ - Py_INCREF(newtype); - r = Array_FromSequence(op, newtype, flags & FORTRAN, - min_depth, max_depth); - if (r == NULL && (thiserr=PyErr_Occurred())) { - if (PyErr_GivenExceptionMatches(thiserr, - PyExc_MemoryError)) { - return NULL; - } - /* - * If object was explicitly requested, - * then try nested list object array creation - */ - PyErr_Clear(); - if (isobject) { - Py_INCREF(newtype); - r = ObjectArray_FromNestedList - (op, newtype, flags & FORTRAN); - seq = TRUE; - Py_DECREF(newtype); - } - } - else { - seq = TRUE; - Py_DECREF(newtype); - } - } - if (!seq) { - r = Array_FromPyScalar(op, newtype); - } - } - - /* If we didn't succeed return NULL */ - if (r == NULL) { - return NULL; - } - - /* Be sure we succeed here */ - if(!PyArray_Check(r)) { - PyErr_SetString(PyExc_RuntimeError, - "internal error: PyArray_FromAny "\ - "not producing an array"); - Py_DECREF(r); - return NULL; - } - - if (min_depth != 0 && ((PyArrayObject *)r)->nd < min_depth) { - PyErr_SetString(PyExc_ValueError, - "object of too small depth for desired array"); - Py_DECREF(r); - return NULL; - } - if (max_depth != 0 && ((PyArrayObject *)r)->nd > max_depth) { - PyErr_SetString(PyExc_ValueError, - "object too deep for desired array"); - Py_DECREF(r); - return NULL; - } - return r; - - err: - Py_XDECREF(newtype); - PyErr_SetString(PyExc_TypeError, - "UPDATEIFCOPY used for non-array input."); - return NULL; -} - -/*NUMPY_API -* new reference -- accepts NULL for mintype -*/ -NPY_NO_EXPORT PyArray_Descr * -PyArray_DescrFromObject(PyObject *op, PyArray_Descr *mintype) -{ - return _array_find_type(op, mintype, MAX_DIMS); -} - /*NUMPY_API * Return the typecode of the array a Python object would be converted to */ @@ -6436,85 +4263,6 @@ PyArray_ObjectType(PyObject *op, int minimum_type) */ /*NUMPY_API - * steals a reference to descr -- accepts NULL - */ -NPY_NO_EXPORT PyObject * -PyArray_CheckFromAny(PyObject *op, PyArray_Descr *descr, int min_depth, - int max_depth, int requires, PyObject *context) -{ - PyObject *obj; - if (requires & NOTSWAPPED) { - if (!descr && PyArray_Check(op) && - !PyArray_ISNBO(PyArray_DESCR(op)->byteorder)) { - descr = PyArray_DescrNew(PyArray_DESCR(op)); - } - else if (descr && !PyArray_ISNBO(descr->byteorder)) { - PyArray_DESCR_REPLACE(descr); - } - if (descr) { - descr->byteorder = PyArray_NATIVE; - } - } - - obj = PyArray_FromAny(op, descr, min_depth, max_depth, requires, context); - if (obj == NULL) { - return NULL; - } - if ((requires & ELEMENTSTRIDES) && - !PyArray_ElementStrides(obj)) { - PyObject *new; - new = PyArray_NewCopy((PyArrayObject *)obj, PyArray_ANYORDER); - Py_DECREF(obj); - obj = new; - } - return obj; -} - -/*NUMPY_API - * This is a quick wrapper around PyArray_FromAny(op, NULL, 0, 0, ENSUREARRAY) - * that special cases Arrays and PyArray_Scalars up front - * It *steals a reference* to the object - * It also guarantees that the result is PyArray_Type - * Because it decrefs op if any conversion needs to take place - * so it can be used like PyArray_EnsureArray(some_function(...)) - */ -NPY_NO_EXPORT PyObject * -PyArray_EnsureArray(PyObject *op) -{ - PyObject *new; - - if (op == NULL) { - return NULL; - } - if (PyArray_CheckExact(op)) { - return op; - } - if (PyArray_Check(op)) { - new = PyArray_View((PyArrayObject *)op, NULL, &PyArray_Type); - Py_DECREF(op); - return new; - } - if (PyArray_IsScalar(op, Generic)) { - new = PyArray_FromScalar(op, NULL); - Py_DECREF(op); - return new; - } - new = PyArray_FromAny(op, NULL, 0, 0, ENSUREARRAY, NULL); - Py_DECREF(op); - return new; -} - -/*NUMPY_API*/ -NPY_NO_EXPORT PyObject * -PyArray_EnsureAnyArray(PyObject *op) -{ - if (op && PyArray_Check(op)) { - return op; - } - return PyArray_EnsureArray(op); -} - -/*NUMPY_API *Check the type coercion rules. */ NPY_NO_EXPORT int diff --git a/numpy/core/src/arrayobject.h b/numpy/core/src/arrayobject.h index f5cb1490b..d3d4b8794 100644 --- a/numpy/core/src/arrayobject.h +++ b/numpy/core/src/arrayobject.h @@ -124,6 +124,15 @@ _IsAligned(PyArrayObject *ap); NPY_NO_EXPORT Bool _IsWriteable(PyArrayObject *ap); +NPY_NO_EXPORT PyArray_Descr * +_array_find_type(PyObject *op, PyArray_Descr *minitype, int max); + +NPY_NO_EXPORT PyArray_Descr * +_array_find_python_scalar_type(PyObject *op); + +NPY_NO_EXPORT PyArray_Descr * +_array_typedescr_fromstr(char *str); + /* FIXME: this is defined in multiarraymodule.c ... */ NPY_NO_EXPORT PyObject * __New_PyArray_Std(PyArrayObject *self, int axis, int rtype, PyArrayObject *out, |