summaryrefslogtreecommitdiff
path: root/numpy/core
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/core')
-rw-r--r--numpy/core/code_generators/numpy_api.py1
-rw-r--r--numpy/core/include/numpy/ndarraytypes.h2
-rw-r--r--numpy/core/src/multiarray/convert.c16
-rw-r--r--numpy/core/src/multiarray/ctors.c142
4 files changed, 138 insertions, 23 deletions
diff --git a/numpy/core/code_generators/numpy_api.py b/numpy/core/code_generators/numpy_api.py
index 86dd4458f..47c292ac8 100644
--- a/numpy/core/code_generators/numpy_api.py
+++ b/numpy/core/code_generators/numpy_api.py
@@ -308,6 +308,7 @@ multiarray_funcs_api = {
'PyArray_CanCastTypeTo': 271,
'PyArray_EinsteinSum': 272,
'PyArray_FillWithZero': 273,
+ 'PyArray_NewLikeArray': 274,
}
ufunc_types_api = {
diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h
index 51b87c5eb..13d5650b5 100644
--- a/numpy/core/include/numpy/ndarraytypes.h
+++ b/numpy/core/include/numpy/ndarraytypes.h
@@ -825,6 +825,8 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);
#define PyArray_ISWRITEABLE(m) PyArray_CHKFLAGS(m, NPY_WRITEABLE)
#define PyArray_ISALIGNED(m) PyArray_CHKFLAGS(m, NPY_ALIGNED)
+#define PyArray_IS_C_CONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_C_CONTIGUOUS)
+#define PyArray_IS_F_CONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_F_CONTIGUOUS)
#if NPY_ALLOW_THREADS
#define NPY_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
diff --git a/numpy/core/src/multiarray/convert.c b/numpy/core/src/multiarray/convert.c
index 5aef72d45..04bcdfc4d 100644
--- a/numpy/core/src/multiarray/convert.c
+++ b/numpy/core/src/multiarray/convert.c
@@ -429,23 +429,13 @@ PyArray_FillWithZero(PyArrayObject *a)
* Copy an array.
*/
NPY_NO_EXPORT PyObject *
-PyArray_NewCopy(PyArrayObject *m1, NPY_ORDER fortran)
+PyArray_NewCopy(PyArrayObject *m1, NPY_ORDER order)
{
- PyArrayObject *ret;
- if (fortran == PyArray_ANYORDER)
- fortran = PyArray_ISFORTRAN(m1);
-
- Py_INCREF(m1->descr);
- ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(m1),
- m1->descr,
- m1->nd,
- m1->dimensions,
- NULL, NULL,
- fortran,
- (PyObject *)m1);
+ PyArrayObject *ret = PyArray_NewLikeArray(m1, order, NULL);
if (ret == NULL) {
return NULL;
}
+
if (PyArray_CopyInto(ret, m1) == -1) {
Py_DECREF(ret);
return NULL;
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c
index f0b12af3d..511672d3f 100644
--- a/numpy/core/src/multiarray/ctors.c
+++ b/numpy/core/src/multiarray/ctors.c
@@ -498,6 +498,8 @@ int _arrays_overlap(PyArrayObject *arr1, PyArrayObject *arr2)
*
* Instead of trying to be fancy, we simply check for overlap and make
* a temporary copy when one exists.
+ *
+ * Returns 0 on success, negative on failure.
*/
NPY_NO_EXPORT int
PyArray_MoveInto(PyArrayObject *dst, PyArrayObject *src)
@@ -522,17 +524,8 @@ PyArray_MoveInto(PyArrayObject *dst, PyArrayObject *src)
/*
* Allocate a temporary copy array.
- * TODO: For efficiency, this should have a memory ordering
- * matching 'dst', even if 'dst' has its axes arbitrarily
- * scrambled. A function to allocate this array needs to
- * be created.
*/
- Py_INCREF(PyArray_DESCR(dst));
- tmp = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type,
- PyArray_DESCR(dst),
- PyArray_NDIM(dst), PyArray_DIMS(dst), NULL,
- NULL, PyArray_ISFORTRAN(dst) ? NPY_F_CONTIGUOUS : 0,
- NULL);
+ tmp = (PyArrayObject *)PyArray_NewLikeArray(dst, NPY_KEEPORDER, NULL);
if (tmp == NULL) {
return -1;
}
@@ -1235,6 +1228,135 @@ PyArray_NewFromDescr(PyTypeObject *subtype, PyArray_Descr *descr, int nd,
return NULL;
}
+typedef struct {
+ npy_intp perm, stride;
+} _npy_stride_sort_item;
+
+/*
+ * Sorts items so stride is descending, because C-order
+ * is the default in the face of ambiguity.
+ */
+int _npy_stride_sort_item_comparator(const void *a, const void *b)
+{
+ npy_intp astride = ((_npy_stride_sort_item *)a)->stride,
+ bstride = ((_npy_stride_sort_item *)b)->stride;
+
+ if (astride > bstride) {
+ return -1;
+ }
+ else if (astride == bstride) {
+ /*
+ * Make the qsort stable by next comparing the perm order.
+ * (Note that two perm entries will never be equal)
+ */
+ npy_intp aperm = ((_npy_stride_sort_item *)a)->perm,
+ bperm = ((_npy_stride_sort_item *)b)->perm;
+ return (aperm < bperm) ? -1 : 1;
+ }
+ else {
+ return 1;
+ }
+}
+
+/*NUMPY_API
+ * Creates a new array with the same shape as the provided one,
+ * with possible memory layout order and data type changes.
+ *
+ * prototype - The array the new one should be like.
+ * order - NPY_CORDER - C-contiguous result.
+ * NPY_FORTRANORDER - Fortran-contiguous result.
+ * NPY_ANYORDER - Fortran if prototype is Fortran, C otherwise.
+ * NPY_KEEPORDER - Keeps the axis ordering of prototype.
+ * dtype - If not NULL, overrides the data type of the result.
+ *
+ * NOTE: If dtype is not NULL, steals the dtype reference.
+ */
+NPY_NO_EXPORT PyObject *
+PyArray_NewLikeArray(PyArrayObject *prototype, NPY_ORDER order,
+ PyArray_Descr *dtype)
+{
+ PyObject *ret = NULL;
+ int ndim = PyArray_NDIM(prototype);
+
+ /* If no override data type, use the one from the prototype */
+ if (dtype == NULL) {
+ dtype = PyArray_DESCR(prototype);
+ Py_INCREF(dtype);
+ }
+
+ /* Handle ANYORDER and simple KEEPORDER cases */
+ switch (order) {
+ case NPY_ANYORDER:
+ order = PyArray_ISFORTRAN(prototype) ?
+ NPY_FORTRANORDER : NPY_CORDER;
+ break;
+ case NPY_KEEPORDER:
+ if (PyArray_IS_C_CONTIGUOUS(prototype) || ndim <= 1) {
+ order = NPY_CORDER;
+ break;
+ }
+ else if (PyArray_IS_F_CONTIGUOUS(prototype)) {
+ order = NPY_FORTRANORDER;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* If it's not KEEPORDER, this is simple */
+ if (order != NPY_KEEPORDER) {
+ ret = PyArray_NewFromDescr(Py_TYPE(prototype),
+ dtype,
+ ndim,
+ PyArray_DIMS(prototype),
+ NULL,
+ NULL,
+ order,
+ (PyObject *)prototype);
+ }
+ /* KEEPORDER needs some analysis of the strides */
+ else {
+ npy_intp strides[NPY_MAXDIMS], stride;
+ npy_intp *shape = PyArray_DIMS(prototype);
+ _npy_stride_sort_item sortstrides[NPY_MAXDIMS];
+ int i, ndim = PyArray_NDIM(prototype);
+
+ /* Set up the permutation and absolute value of strides */
+ for (i = 0; i < ndim; ++i) {
+ sortstrides[i].perm = i;
+ sortstrides[i].stride = PyArray_STRIDE(prototype, i);
+ if (sortstrides[i].stride < 0) {
+ sortstrides[i].stride = -sortstrides[i].stride;
+ }
+ }
+
+ /* Sort them */
+ qsort(sortstrides, ndim, sizeof(_npy_stride_sort_item),
+ &_npy_stride_sort_item_comparator);
+
+ /* Build the new strides */
+ stride = dtype->elsize;
+ for (i = ndim-1; i >= 0; --i) {
+ npy_intp i_perm = sortstrides[i].perm;
+ strides[i_perm] = stride;
+ stride *= shape[i_perm];
+ }
+
+ /* Finally, allocate the array */
+ ret = PyArray_NewFromDescr(Py_TYPE(prototype),
+ dtype,
+ ndim,
+ shape,
+ strides,
+ NULL,
+ 0,
+ (PyObject *)prototype);
+ }
+
+ return ret;
+}
+
/*NUMPY_API
* Generic new array creation routine.
*/