Repository: numpy/numpy
File: numpy/_core/src/multiarray/methods.c (C)

Code before:
}

static PyObject *
array_reduce_ex_picklebuffer(PyArrayObject *self, int protocol)
{
    PyObject *from_buffer_func = NULL;
    PyObject *picklebuf_class = NULL;
    PyObject *buffer = NULL, *transposed_array = NULL;
    PyArray_Descr *descr = NULL;
    PyObject *rev_perm = NULL;  // only used in 'K' order
    char order;

    descr = PyArray_DESCR(self);

    /* we expect protocol 5 to be available in Python 3.8 */
    if (npy_cache_import_runtime("pickle", "PickleBuffer", &picklebuf_class) == -1) {
        return NULL;
    }

    /* Construct a PickleBuffer of the array */
    if (PyArray_IS_C_CONTIGUOUS((PyArrayObject *)self)) {
        order = 'C';
        rev_perm = PyTuple_New(0);
        if (rev_perm == NULL) {
            return NULL;
        }
    }
    else if (PyArray_IS_F_CONTIGUOUS((PyArrayObject *)self)) {
        /* if the array if Fortran-contiguous and not C-contiguous,
         * the PickleBuffer instance will hold a view on the transpose
         * of the initial array, that is C-contiguous. */
        order = 'F';
        transposed_array = PyArray_Transpose((PyArrayObject *)self, NULL);
        if(transposed_array == NULL) {
            return NULL;
        }
        rev_perm = PyTuple_New(0);
        if (rev_perm == NULL) {
            Py_DECREF(transposed_array);
            return NULL;
        }
    }
    else {
        order = 'K';
        const int n = PyArray_NDIM(self);
        npy_stride_sort_item items[NPY_MAXDIMS];
        // sort (strde, perm) as descending = transpose to C
        PyArray_CreateSortedStridePerm(n, PyArray_STRIDES(self), items);
        rev_perm = PyTuple_New(n);
        if (rev_perm == NULL) {
            return NULL;

Review comment (suggestion):
I do have one more ask here, sorry:
```suggestion
```
(Also below for the fortran path.)

I would much prefer if we make sure that for C/F contiguous arrays the pickle format is unchanged.  That way _most_ arrays will load just fine, and if someone complains we can tell them: "please just do `arr.copy()` first and it'll work".

Code after:
        return NULL;
    }

    /* Construct a PickleBuffer of the array */
    if (PyArray_IS_C_CONTIGUOUS((PyArrayObject *)self)) {
        order = 'C';
    }
    else if (PyArray_IS_F_CONTIGUOUS((PyArrayObject *)self)) {
        /* if the array if Fortran-contiguous and not C-contiguous,
         * the PickleBuffer instance will hold a view on the transpose
         * of the initial array, that is C-contiguous. */
        order = 'F';
        transposed_array = PyArray_Transpose((PyArrayObject *)self, NULL);
        if (transposed_array == NULL) {
            return NULL;
        }
    }
    else {
        order = 'K';
        const int n = PyArray_NDIM(self);
        npy_stride_sort_item items[NPY_MAXDIMS];
        // sort (strde, perm) as descending = transpose to C
        PyArray_CreateSortedStridePerm(n, PyArray_STRIDES(self), items);
        rev_perm = PyTuple_New(n);
        if (rev_perm == NULL) {
            return NULL;
        }
        PyArray_Dims perm;
        npy_intp dims[NPY_MAXDIMS];
        for (int i = 0; i < n; i++) {
            dims[i] = items[i].perm;
            PyObject *idx = PyLong_FromLong(i);
            if (idx == NULL) {
                Py_DECREF(rev_perm);
                return NULL;
            }
            PyTuple_SET_ITEM(rev_perm, items[i].perm, idx);
        }
        perm.ptr = dims;
        perm.len = n;
        transposed_array = PyArray_Transpose((PyArrayObject *)self, &perm);
        if (transposed_array == NULL) {
            Py_DECREF(rev_perm);
            return NULL;
        }
        if (!PyArray_IS_C_CONTIGUOUS((PyArrayObject *)transposed_array)) {
            // self is non-contiguous
            Py_DECREF(rev_perm);
            Py_DECREF(transposed_array);
            return array_reduce_ex_regular(self, protocol);
        }