17db96d56Sopenharmony_ci/* C Extension module to test all aspects of PEP-3118.
27db96d56Sopenharmony_ci   Written by Stefan Krah. */
37db96d56Sopenharmony_ci
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ci#define PY_SSIZE_T_CLEAN
67db96d56Sopenharmony_ci
77db96d56Sopenharmony_ci#include "Python.h"
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ci/* struct module */
117db96d56Sopenharmony_cistatic PyObject *structmodule = NULL;
127db96d56Sopenharmony_cistatic PyObject *Struct = NULL;
137db96d56Sopenharmony_cistatic PyObject *calcsize = NULL;
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ci/* cache simple format string */
167db96d56Sopenharmony_cistatic const char *simple_fmt = "B";
177db96d56Sopenharmony_cistatic PyObject *simple_format = NULL;
187db96d56Sopenharmony_ci#define SIMPLE_FORMAT(fmt) (fmt == NULL || strcmp(fmt, "B") == 0)
197db96d56Sopenharmony_ci#define FIX_FORMAT(fmt) (fmt == NULL ? "B" : fmt)
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci
227db96d56Sopenharmony_ci/**************************************************************************/
237db96d56Sopenharmony_ci/*                             NDArray Object                             */
247db96d56Sopenharmony_ci/**************************************************************************/
257db96d56Sopenharmony_ci
267db96d56Sopenharmony_cistatic PyTypeObject NDArray_Type;
277db96d56Sopenharmony_ci#define NDArray_Check(v) Py_IS_TYPE(v, &NDArray_Type)
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci#define CHECK_LIST_OR_TUPLE(v) \
307db96d56Sopenharmony_ci    if (!PyList_Check(v) && !PyTuple_Check(v)) { \
317db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,         \
327db96d56Sopenharmony_ci            #v " must be a list or a tuple");    \
337db96d56Sopenharmony_ci        return NULL;                             \
347db96d56Sopenharmony_ci    }                                            \
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_ci#define PyMem_XFree(v) \
377db96d56Sopenharmony_ci    do { if (v) PyMem_Free(v); } while (0)
387db96d56Sopenharmony_ci
397db96d56Sopenharmony_ci/* Maximum number of dimensions. */
407db96d56Sopenharmony_ci#define ND_MAX_NDIM (2 * PyBUF_MAX_NDIM)
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_ci/* Check for the presence of suboffsets in the first dimension. */
437db96d56Sopenharmony_ci#define HAVE_PTR(suboffsets) (suboffsets && suboffsets[0] >= 0)
447db96d56Sopenharmony_ci/* Adjust ptr if suboffsets are present. */
457db96d56Sopenharmony_ci#define ADJUST_PTR(ptr, suboffsets) \
467db96d56Sopenharmony_ci    (HAVE_PTR(suboffsets) ? *((char**)ptr) + suboffsets[0] : ptr)
477db96d56Sopenharmony_ci
487db96d56Sopenharmony_ci/* Default: NumPy style (strides), read-only, no var-export, C-style layout */
497db96d56Sopenharmony_ci#define ND_DEFAULT          0x000
507db96d56Sopenharmony_ci/* User configurable flags for the ndarray */
517db96d56Sopenharmony_ci#define ND_VAREXPORT        0x001   /* change layout while buffers are exported */
527db96d56Sopenharmony_ci/* User configurable flags for each base buffer */
537db96d56Sopenharmony_ci#define ND_WRITABLE         0x002   /* mark base buffer as writable */
547db96d56Sopenharmony_ci#define ND_FORTRAN          0x004   /* Fortran contiguous layout */
557db96d56Sopenharmony_ci#define ND_SCALAR           0x008   /* scalar: ndim = 0 */
567db96d56Sopenharmony_ci#define ND_PIL              0x010   /* convert to PIL-style array (suboffsets) */
577db96d56Sopenharmony_ci#define ND_REDIRECT         0x020   /* redirect buffer requests */
587db96d56Sopenharmony_ci#define ND_GETBUF_FAIL      0x040   /* trigger getbuffer failure */
597db96d56Sopenharmony_ci#define ND_GETBUF_UNDEFINED 0x080   /* undefined view.obj */
607db96d56Sopenharmony_ci/* Internal flags for the base buffer */
617db96d56Sopenharmony_ci#define ND_C                0x100   /* C contiguous layout (default) */
627db96d56Sopenharmony_ci#define ND_OWN_ARRAYS       0x200   /* consumer owns arrays */
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ci/* ndarray properties */
657db96d56Sopenharmony_ci#define ND_IS_CONSUMER(nd) \
667db96d56Sopenharmony_ci    (((NDArrayObject *)nd)->head == &((NDArrayObject *)nd)->staticbuf)
677db96d56Sopenharmony_ci
687db96d56Sopenharmony_ci/* ndbuf->flags properties */
697db96d56Sopenharmony_ci#define ND_C_CONTIGUOUS(flags) (!!(flags&(ND_SCALAR|ND_C)))
707db96d56Sopenharmony_ci#define ND_FORTRAN_CONTIGUOUS(flags) (!!(flags&(ND_SCALAR|ND_FORTRAN)))
717db96d56Sopenharmony_ci#define ND_ANY_CONTIGUOUS(flags) (!!(flags&(ND_SCALAR|ND_C|ND_FORTRAN)))
727db96d56Sopenharmony_ci
737db96d56Sopenharmony_ci/* getbuffer() requests */
747db96d56Sopenharmony_ci#define REQ_INDIRECT(flags) ((flags&PyBUF_INDIRECT) == PyBUF_INDIRECT)
757db96d56Sopenharmony_ci#define REQ_C_CONTIGUOUS(flags) ((flags&PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS)
767db96d56Sopenharmony_ci#define REQ_F_CONTIGUOUS(flags) ((flags&PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS)
777db96d56Sopenharmony_ci#define REQ_ANY_CONTIGUOUS(flags) ((flags&PyBUF_ANY_CONTIGUOUS) == PyBUF_ANY_CONTIGUOUS)
787db96d56Sopenharmony_ci#define REQ_STRIDES(flags) ((flags&PyBUF_STRIDES) == PyBUF_STRIDES)
797db96d56Sopenharmony_ci#define REQ_SHAPE(flags) ((flags&PyBUF_ND) == PyBUF_ND)
807db96d56Sopenharmony_ci#define REQ_WRITABLE(flags) (flags&PyBUF_WRITABLE)
817db96d56Sopenharmony_ci#define REQ_FORMAT(flags) (flags&PyBUF_FORMAT)
827db96d56Sopenharmony_ci
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_ci/* Single node of a list of base buffers. The list is needed to implement
857db96d56Sopenharmony_ci   changes in memory layout while exported buffers are active. */
867db96d56Sopenharmony_cistatic PyTypeObject NDArray_Type;
877db96d56Sopenharmony_ci
887db96d56Sopenharmony_cistruct ndbuf;
897db96d56Sopenharmony_citypedef struct ndbuf {
907db96d56Sopenharmony_ci    struct ndbuf *next;
917db96d56Sopenharmony_ci    struct ndbuf *prev;
927db96d56Sopenharmony_ci    Py_ssize_t len;     /* length of data */
937db96d56Sopenharmony_ci    Py_ssize_t offset;  /* start of the array relative to data */
947db96d56Sopenharmony_ci    char *data;         /* raw data */
957db96d56Sopenharmony_ci    int flags;          /* capabilities of the base buffer */
967db96d56Sopenharmony_ci    Py_ssize_t exports; /* number of exports */
977db96d56Sopenharmony_ci    Py_buffer base;     /* base buffer */
987db96d56Sopenharmony_ci} ndbuf_t;
997db96d56Sopenharmony_ci
1007db96d56Sopenharmony_citypedef struct {
1017db96d56Sopenharmony_ci    PyObject_HEAD
1027db96d56Sopenharmony_ci    int flags;          /* ndarray flags */
1037db96d56Sopenharmony_ci    ndbuf_t staticbuf;  /* static buffer for re-exporting mode */
1047db96d56Sopenharmony_ci    ndbuf_t *head;      /* currently active base buffer */
1057db96d56Sopenharmony_ci} NDArrayObject;
1067db96d56Sopenharmony_ci
1077db96d56Sopenharmony_ci
1087db96d56Sopenharmony_cistatic ndbuf_t *
1097db96d56Sopenharmony_cindbuf_new(Py_ssize_t nitems, Py_ssize_t itemsize, Py_ssize_t offset, int flags)
1107db96d56Sopenharmony_ci{
1117db96d56Sopenharmony_ci    ndbuf_t *ndbuf;
1127db96d56Sopenharmony_ci    Py_buffer *base;
1137db96d56Sopenharmony_ci    Py_ssize_t len;
1147db96d56Sopenharmony_ci
1157db96d56Sopenharmony_ci    len = nitems * itemsize;
1167db96d56Sopenharmony_ci    if (offset % itemsize) {
1177db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
1187db96d56Sopenharmony_ci            "offset must be a multiple of itemsize");
1197db96d56Sopenharmony_ci        return NULL;
1207db96d56Sopenharmony_ci    }
1217db96d56Sopenharmony_ci    if (offset < 0 || offset+itemsize > len) {
1227db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError, "offset out of bounds");
1237db96d56Sopenharmony_ci        return NULL;
1247db96d56Sopenharmony_ci    }
1257db96d56Sopenharmony_ci
1267db96d56Sopenharmony_ci    ndbuf = PyMem_Malloc(sizeof *ndbuf);
1277db96d56Sopenharmony_ci    if (ndbuf == NULL) {
1287db96d56Sopenharmony_ci        PyErr_NoMemory();
1297db96d56Sopenharmony_ci        return NULL;
1307db96d56Sopenharmony_ci    }
1317db96d56Sopenharmony_ci
1327db96d56Sopenharmony_ci    ndbuf->next = NULL;
1337db96d56Sopenharmony_ci    ndbuf->prev = NULL;
1347db96d56Sopenharmony_ci    ndbuf->len = len;
1357db96d56Sopenharmony_ci    ndbuf->offset= offset;
1367db96d56Sopenharmony_ci
1377db96d56Sopenharmony_ci    ndbuf->data = PyMem_Malloc(len);
1387db96d56Sopenharmony_ci    if (ndbuf->data == NULL) {
1397db96d56Sopenharmony_ci        PyErr_NoMemory();
1407db96d56Sopenharmony_ci        PyMem_Free(ndbuf);
1417db96d56Sopenharmony_ci        return NULL;
1427db96d56Sopenharmony_ci    }
1437db96d56Sopenharmony_ci
1447db96d56Sopenharmony_ci    ndbuf->flags = flags;
1457db96d56Sopenharmony_ci    ndbuf->exports = 0;
1467db96d56Sopenharmony_ci
1477db96d56Sopenharmony_ci    base = &ndbuf->base;
1487db96d56Sopenharmony_ci    base->obj = NULL;
1497db96d56Sopenharmony_ci    base->buf = ndbuf->data;
1507db96d56Sopenharmony_ci    base->len = len;
1517db96d56Sopenharmony_ci    base->itemsize = 1;
1527db96d56Sopenharmony_ci    base->readonly = 0;
1537db96d56Sopenharmony_ci    base->format = NULL;
1547db96d56Sopenharmony_ci    base->ndim = 1;
1557db96d56Sopenharmony_ci    base->shape = NULL;
1567db96d56Sopenharmony_ci    base->strides = NULL;
1577db96d56Sopenharmony_ci    base->suboffsets = NULL;
1587db96d56Sopenharmony_ci    base->internal = ndbuf;
1597db96d56Sopenharmony_ci
1607db96d56Sopenharmony_ci    return ndbuf;
1617db96d56Sopenharmony_ci}
1627db96d56Sopenharmony_ci
1637db96d56Sopenharmony_cistatic void
1647db96d56Sopenharmony_cindbuf_free(ndbuf_t *ndbuf)
1657db96d56Sopenharmony_ci{
1667db96d56Sopenharmony_ci    Py_buffer *base = &ndbuf->base;
1677db96d56Sopenharmony_ci
1687db96d56Sopenharmony_ci    PyMem_XFree(ndbuf->data);
1697db96d56Sopenharmony_ci    PyMem_XFree(base->format);
1707db96d56Sopenharmony_ci    PyMem_XFree(base->shape);
1717db96d56Sopenharmony_ci    PyMem_XFree(base->strides);
1727db96d56Sopenharmony_ci    PyMem_XFree(base->suboffsets);
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_ci    PyMem_Free(ndbuf);
1757db96d56Sopenharmony_ci}
1767db96d56Sopenharmony_ci
1777db96d56Sopenharmony_cistatic void
1787db96d56Sopenharmony_cindbuf_push(NDArrayObject *nd, ndbuf_t *elt)
1797db96d56Sopenharmony_ci{
1807db96d56Sopenharmony_ci    elt->next = nd->head;
1817db96d56Sopenharmony_ci    if (nd->head) nd->head->prev = elt;
1827db96d56Sopenharmony_ci    nd->head = elt;
1837db96d56Sopenharmony_ci    elt->prev = NULL;
1847db96d56Sopenharmony_ci}
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_cistatic void
1877db96d56Sopenharmony_cindbuf_delete(NDArrayObject *nd, ndbuf_t *elt)
1887db96d56Sopenharmony_ci{
1897db96d56Sopenharmony_ci    if (elt->prev)
1907db96d56Sopenharmony_ci        elt->prev->next = elt->next;
1917db96d56Sopenharmony_ci    else
1927db96d56Sopenharmony_ci        nd->head = elt->next;
1937db96d56Sopenharmony_ci
1947db96d56Sopenharmony_ci    if (elt->next)
1957db96d56Sopenharmony_ci        elt->next->prev = elt->prev;
1967db96d56Sopenharmony_ci
1977db96d56Sopenharmony_ci    ndbuf_free(elt);
1987db96d56Sopenharmony_ci}
1997db96d56Sopenharmony_ci
2007db96d56Sopenharmony_cistatic void
2017db96d56Sopenharmony_cindbuf_pop(NDArrayObject *nd)
2027db96d56Sopenharmony_ci{
2037db96d56Sopenharmony_ci    ndbuf_delete(nd, nd->head);
2047db96d56Sopenharmony_ci}
2057db96d56Sopenharmony_ci
2067db96d56Sopenharmony_ci
2077db96d56Sopenharmony_cistatic PyObject *
2087db96d56Sopenharmony_cindarray_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
2097db96d56Sopenharmony_ci{
2107db96d56Sopenharmony_ci    NDArrayObject *nd;
2117db96d56Sopenharmony_ci
2127db96d56Sopenharmony_ci    nd = PyObject_New(NDArrayObject, &NDArray_Type);
2137db96d56Sopenharmony_ci    if (nd == NULL)
2147db96d56Sopenharmony_ci        return NULL;
2157db96d56Sopenharmony_ci
2167db96d56Sopenharmony_ci    nd->flags = 0;
2177db96d56Sopenharmony_ci    nd->head = NULL;
2187db96d56Sopenharmony_ci    return (PyObject *)nd;
2197db96d56Sopenharmony_ci}
2207db96d56Sopenharmony_ci
2217db96d56Sopenharmony_cistatic void
2227db96d56Sopenharmony_cindarray_dealloc(NDArrayObject *self)
2237db96d56Sopenharmony_ci{
2247db96d56Sopenharmony_ci    if (self->head) {
2257db96d56Sopenharmony_ci        if (ND_IS_CONSUMER(self)) {
2267db96d56Sopenharmony_ci            Py_buffer *base = &self->head->base;
2277db96d56Sopenharmony_ci            if (self->head->flags & ND_OWN_ARRAYS) {
2287db96d56Sopenharmony_ci                PyMem_XFree(base->shape);
2297db96d56Sopenharmony_ci                PyMem_XFree(base->strides);
2307db96d56Sopenharmony_ci                PyMem_XFree(base->suboffsets);
2317db96d56Sopenharmony_ci            }
2327db96d56Sopenharmony_ci            PyBuffer_Release(base);
2337db96d56Sopenharmony_ci        }
2347db96d56Sopenharmony_ci        else {
2357db96d56Sopenharmony_ci            while (self->head)
2367db96d56Sopenharmony_ci                ndbuf_pop(self);
2377db96d56Sopenharmony_ci        }
2387db96d56Sopenharmony_ci    }
2397db96d56Sopenharmony_ci    PyObject_Free(self);
2407db96d56Sopenharmony_ci}
2417db96d56Sopenharmony_ci
2427db96d56Sopenharmony_cistatic int
2437db96d56Sopenharmony_cindarray_init_staticbuf(PyObject *exporter, NDArrayObject *nd, int flags)
2447db96d56Sopenharmony_ci{
2457db96d56Sopenharmony_ci    Py_buffer *base = &nd->staticbuf.base;
2467db96d56Sopenharmony_ci
2477db96d56Sopenharmony_ci    if (PyObject_GetBuffer(exporter, base, flags) < 0)
2487db96d56Sopenharmony_ci        return -1;
2497db96d56Sopenharmony_ci
2507db96d56Sopenharmony_ci    nd->head = &nd->staticbuf;
2517db96d56Sopenharmony_ci
2527db96d56Sopenharmony_ci    nd->head->next = NULL;
2537db96d56Sopenharmony_ci    nd->head->prev = NULL;
2547db96d56Sopenharmony_ci    nd->head->len = -1;
2557db96d56Sopenharmony_ci    nd->head->offset = -1;
2567db96d56Sopenharmony_ci    nd->head->data = NULL;
2577db96d56Sopenharmony_ci
2587db96d56Sopenharmony_ci    nd->head->flags = base->readonly ? 0 : ND_WRITABLE;
2597db96d56Sopenharmony_ci    nd->head->exports = 0;
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci    return 0;
2627db96d56Sopenharmony_ci}
2637db96d56Sopenharmony_ci
2647db96d56Sopenharmony_cistatic void
2657db96d56Sopenharmony_ciinit_flags(ndbuf_t *ndbuf)
2667db96d56Sopenharmony_ci{
2677db96d56Sopenharmony_ci    if (ndbuf->base.ndim == 0)
2687db96d56Sopenharmony_ci        ndbuf->flags |= ND_SCALAR;
2697db96d56Sopenharmony_ci    if (ndbuf->base.suboffsets)
2707db96d56Sopenharmony_ci        ndbuf->flags |= ND_PIL;
2717db96d56Sopenharmony_ci    if (PyBuffer_IsContiguous(&ndbuf->base, 'C'))
2727db96d56Sopenharmony_ci        ndbuf->flags |= ND_C;
2737db96d56Sopenharmony_ci    if (PyBuffer_IsContiguous(&ndbuf->base, 'F'))
2747db96d56Sopenharmony_ci        ndbuf->flags |= ND_FORTRAN;
2757db96d56Sopenharmony_ci}
2767db96d56Sopenharmony_ci
2777db96d56Sopenharmony_ci
2787db96d56Sopenharmony_ci/****************************************************************************/
2797db96d56Sopenharmony_ci/*                          Buffer/List conversions                         */
2807db96d56Sopenharmony_ci/****************************************************************************/
2817db96d56Sopenharmony_ci
2827db96d56Sopenharmony_cistatic Py_ssize_t *strides_from_shape(const ndbuf_t *, int flags);
2837db96d56Sopenharmony_ci
2847db96d56Sopenharmony_ci/* Get number of members in a struct: see issue #12740 */
2857db96d56Sopenharmony_citypedef struct {
2867db96d56Sopenharmony_ci    PyObject_HEAD
2877db96d56Sopenharmony_ci    Py_ssize_t s_size;
2887db96d56Sopenharmony_ci    Py_ssize_t s_len;
2897db96d56Sopenharmony_ci} PyPartialStructObject;
2907db96d56Sopenharmony_ci
2917db96d56Sopenharmony_cistatic Py_ssize_t
2927db96d56Sopenharmony_ciget_nmemb(PyObject *s)
2937db96d56Sopenharmony_ci{
2947db96d56Sopenharmony_ci    return ((PyPartialStructObject *)s)->s_len;
2957db96d56Sopenharmony_ci}
2967db96d56Sopenharmony_ci
2977db96d56Sopenharmony_ci/* Pack all items into the buffer of 'obj'. The 'format' parameter must be
2987db96d56Sopenharmony_ci   in struct module syntax. For standard C types, a single item is an integer.
2997db96d56Sopenharmony_ci   For compound types, a single item is a tuple of integers. */
3007db96d56Sopenharmony_cistatic int
3017db96d56Sopenharmony_cipack_from_list(PyObject *obj, PyObject *items, PyObject *format,
3027db96d56Sopenharmony_ci               Py_ssize_t itemsize)
3037db96d56Sopenharmony_ci{
3047db96d56Sopenharmony_ci    PyObject *structobj, *pack_into;
3057db96d56Sopenharmony_ci    PyObject *args, *offset;
3067db96d56Sopenharmony_ci    PyObject *item, *tmp;
3077db96d56Sopenharmony_ci    Py_ssize_t nitems; /* number of items */
3087db96d56Sopenharmony_ci    Py_ssize_t nmemb;  /* number of members in a single item */
3097db96d56Sopenharmony_ci    Py_ssize_t i, j;
3107db96d56Sopenharmony_ci    int ret = 0;
3117db96d56Sopenharmony_ci
3127db96d56Sopenharmony_ci    assert(PyObject_CheckBuffer(obj));
3137db96d56Sopenharmony_ci    assert(PyList_Check(items) || PyTuple_Check(items));
3147db96d56Sopenharmony_ci
3157db96d56Sopenharmony_ci    structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL);
3167db96d56Sopenharmony_ci    if (structobj == NULL)
3177db96d56Sopenharmony_ci        return -1;
3187db96d56Sopenharmony_ci
3197db96d56Sopenharmony_ci    nitems = PySequence_Fast_GET_SIZE(items);
3207db96d56Sopenharmony_ci    nmemb = get_nmemb(structobj);
3217db96d56Sopenharmony_ci    assert(nmemb >= 1);
3227db96d56Sopenharmony_ci
3237db96d56Sopenharmony_ci    pack_into = PyObject_GetAttrString(structobj, "pack_into");
3247db96d56Sopenharmony_ci    if (pack_into == NULL) {
3257db96d56Sopenharmony_ci        Py_DECREF(structobj);
3267db96d56Sopenharmony_ci        return -1;
3277db96d56Sopenharmony_ci    }
3287db96d56Sopenharmony_ci
3297db96d56Sopenharmony_ci    /* nmemb >= 1 */
3307db96d56Sopenharmony_ci    args = PyTuple_New(2 + nmemb);
3317db96d56Sopenharmony_ci    if (args == NULL) {
3327db96d56Sopenharmony_ci        Py_DECREF(pack_into);
3337db96d56Sopenharmony_ci        Py_DECREF(structobj);
3347db96d56Sopenharmony_ci        return -1;
3357db96d56Sopenharmony_ci    }
3367db96d56Sopenharmony_ci
3377db96d56Sopenharmony_ci    offset = NULL;
3387db96d56Sopenharmony_ci    for (i = 0; i < nitems; i++) {
3397db96d56Sopenharmony_ci        /* Loop invariant: args[j] are borrowed references or NULL. */
3407db96d56Sopenharmony_ci        PyTuple_SET_ITEM(args, 0, obj);
3417db96d56Sopenharmony_ci        for (j = 1; j < 2+nmemb; j++)
3427db96d56Sopenharmony_ci            PyTuple_SET_ITEM(args, j, NULL);
3437db96d56Sopenharmony_ci
3447db96d56Sopenharmony_ci        Py_XDECREF(offset);
3457db96d56Sopenharmony_ci        offset = PyLong_FromSsize_t(i*itemsize);
3467db96d56Sopenharmony_ci        if (offset == NULL) {
3477db96d56Sopenharmony_ci            ret = -1;
3487db96d56Sopenharmony_ci            break;
3497db96d56Sopenharmony_ci        }
3507db96d56Sopenharmony_ci        PyTuple_SET_ITEM(args, 1, offset);
3517db96d56Sopenharmony_ci
3527db96d56Sopenharmony_ci        item = PySequence_Fast_GET_ITEM(items, i);
3537db96d56Sopenharmony_ci        if ((PyBytes_Check(item) || PyLong_Check(item) ||
3547db96d56Sopenharmony_ci             PyFloat_Check(item)) && nmemb == 1) {
3557db96d56Sopenharmony_ci            PyTuple_SET_ITEM(args, 2, item);
3567db96d56Sopenharmony_ci        }
3577db96d56Sopenharmony_ci        else if ((PyList_Check(item) || PyTuple_Check(item)) &&
3587db96d56Sopenharmony_ci                 PySequence_Length(item) == nmemb) {
3597db96d56Sopenharmony_ci            for (j = 0; j < nmemb; j++) {
3607db96d56Sopenharmony_ci                tmp = PySequence_Fast_GET_ITEM(item, j);
3617db96d56Sopenharmony_ci                PyTuple_SET_ITEM(args, 2+j, tmp);
3627db96d56Sopenharmony_ci            }
3637db96d56Sopenharmony_ci        }
3647db96d56Sopenharmony_ci        else {
3657db96d56Sopenharmony_ci            PyErr_SetString(PyExc_ValueError,
3667db96d56Sopenharmony_ci                "mismatch between initializer element and format string");
3677db96d56Sopenharmony_ci            ret = -1;
3687db96d56Sopenharmony_ci            break;
3697db96d56Sopenharmony_ci        }
3707db96d56Sopenharmony_ci
3717db96d56Sopenharmony_ci        tmp = PyObject_CallObject(pack_into, args);
3727db96d56Sopenharmony_ci        if (tmp == NULL) {
3737db96d56Sopenharmony_ci            ret = -1;
3747db96d56Sopenharmony_ci            break;
3757db96d56Sopenharmony_ci        }
3767db96d56Sopenharmony_ci        Py_DECREF(tmp);
3777db96d56Sopenharmony_ci    }
3787db96d56Sopenharmony_ci
3797db96d56Sopenharmony_ci    Py_INCREF(obj); /* args[0] */
3807db96d56Sopenharmony_ci    /* args[1]: offset is either NULL or should be dealloc'd */
3817db96d56Sopenharmony_ci    for (i = 2; i < 2+nmemb; i++) {
3827db96d56Sopenharmony_ci        tmp = PyTuple_GET_ITEM(args, i);
3837db96d56Sopenharmony_ci        Py_XINCREF(tmp);
3847db96d56Sopenharmony_ci    }
3857db96d56Sopenharmony_ci    Py_DECREF(args);
3867db96d56Sopenharmony_ci
3877db96d56Sopenharmony_ci    Py_DECREF(pack_into);
3887db96d56Sopenharmony_ci    Py_DECREF(structobj);
3897db96d56Sopenharmony_ci    return ret;
3907db96d56Sopenharmony_ci
3917db96d56Sopenharmony_ci}
3927db96d56Sopenharmony_ci
3937db96d56Sopenharmony_ci/* Pack single element */
3947db96d56Sopenharmony_cistatic int
3957db96d56Sopenharmony_cipack_single(char *ptr, PyObject *item, const char *fmt, Py_ssize_t itemsize)
3967db96d56Sopenharmony_ci{
3977db96d56Sopenharmony_ci    PyObject *structobj = NULL, *pack_into = NULL, *args = NULL;
3987db96d56Sopenharmony_ci    PyObject *format = NULL, *mview = NULL, *zero = NULL;
3997db96d56Sopenharmony_ci    Py_ssize_t i, nmemb;
4007db96d56Sopenharmony_ci    int ret = -1;
4017db96d56Sopenharmony_ci    PyObject *x;
4027db96d56Sopenharmony_ci
4037db96d56Sopenharmony_ci    if (fmt == NULL) fmt = "B";
4047db96d56Sopenharmony_ci
4057db96d56Sopenharmony_ci    format = PyUnicode_FromString(fmt);
4067db96d56Sopenharmony_ci    if (format == NULL)
4077db96d56Sopenharmony_ci        goto out;
4087db96d56Sopenharmony_ci
4097db96d56Sopenharmony_ci    structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL);
4107db96d56Sopenharmony_ci    if (structobj == NULL)
4117db96d56Sopenharmony_ci        goto out;
4127db96d56Sopenharmony_ci
4137db96d56Sopenharmony_ci    nmemb = get_nmemb(structobj);
4147db96d56Sopenharmony_ci    assert(nmemb >= 1);
4157db96d56Sopenharmony_ci
4167db96d56Sopenharmony_ci    mview = PyMemoryView_FromMemory(ptr, itemsize, PyBUF_WRITE);
4177db96d56Sopenharmony_ci    if (mview == NULL)
4187db96d56Sopenharmony_ci        goto out;
4197db96d56Sopenharmony_ci
4207db96d56Sopenharmony_ci    zero = PyLong_FromLong(0);
4217db96d56Sopenharmony_ci    if (zero == NULL)
4227db96d56Sopenharmony_ci        goto out;
4237db96d56Sopenharmony_ci
4247db96d56Sopenharmony_ci    pack_into = PyObject_GetAttrString(structobj, "pack_into");
4257db96d56Sopenharmony_ci    if (pack_into == NULL)
4267db96d56Sopenharmony_ci        goto out;
4277db96d56Sopenharmony_ci
4287db96d56Sopenharmony_ci    args = PyTuple_New(2+nmemb);
4297db96d56Sopenharmony_ci    if (args == NULL)
4307db96d56Sopenharmony_ci        goto out;
4317db96d56Sopenharmony_ci
4327db96d56Sopenharmony_ci    PyTuple_SET_ITEM(args, 0, mview);
4337db96d56Sopenharmony_ci    PyTuple_SET_ITEM(args, 1, zero);
4347db96d56Sopenharmony_ci
4357db96d56Sopenharmony_ci    if ((PyBytes_Check(item) || PyLong_Check(item) ||
4367db96d56Sopenharmony_ci         PyFloat_Check(item)) && nmemb == 1) {
4377db96d56Sopenharmony_ci         PyTuple_SET_ITEM(args, 2, item);
4387db96d56Sopenharmony_ci    }
4397db96d56Sopenharmony_ci    else if ((PyList_Check(item) || PyTuple_Check(item)) &&
4407db96d56Sopenharmony_ci             PySequence_Length(item) == nmemb) {
4417db96d56Sopenharmony_ci        for (i = 0; i < nmemb; i++) {
4427db96d56Sopenharmony_ci            x = PySequence_Fast_GET_ITEM(item, i);
4437db96d56Sopenharmony_ci            PyTuple_SET_ITEM(args, 2+i, x);
4447db96d56Sopenharmony_ci        }
4457db96d56Sopenharmony_ci    }
4467db96d56Sopenharmony_ci    else {
4477db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
4487db96d56Sopenharmony_ci            "mismatch between initializer element and format string");
4497db96d56Sopenharmony_ci        goto args_out;
4507db96d56Sopenharmony_ci    }
4517db96d56Sopenharmony_ci
4527db96d56Sopenharmony_ci    x = PyObject_CallObject(pack_into, args);
4537db96d56Sopenharmony_ci    if (x != NULL) {
4547db96d56Sopenharmony_ci        Py_DECREF(x);
4557db96d56Sopenharmony_ci        ret = 0;
4567db96d56Sopenharmony_ci    }
4577db96d56Sopenharmony_ci
4587db96d56Sopenharmony_ci
4597db96d56Sopenharmony_ciargs_out:
4607db96d56Sopenharmony_ci    for (i = 0; i < 2+nmemb; i++)
4617db96d56Sopenharmony_ci        Py_XINCREF(PyTuple_GET_ITEM(args, i));
4627db96d56Sopenharmony_ci    Py_XDECREF(args);
4637db96d56Sopenharmony_ciout:
4647db96d56Sopenharmony_ci    Py_XDECREF(pack_into);
4657db96d56Sopenharmony_ci    Py_XDECREF(zero);
4667db96d56Sopenharmony_ci    Py_XDECREF(mview);
4677db96d56Sopenharmony_ci    Py_XDECREF(structobj);
4687db96d56Sopenharmony_ci    Py_XDECREF(format);
4697db96d56Sopenharmony_ci    return ret;
4707db96d56Sopenharmony_ci}
4717db96d56Sopenharmony_ci
4727db96d56Sopenharmony_cistatic void
4737db96d56Sopenharmony_cicopy_rec(const Py_ssize_t *shape, Py_ssize_t ndim, Py_ssize_t itemsize,
4747db96d56Sopenharmony_ci         char *dptr, const Py_ssize_t *dstrides, const Py_ssize_t *dsuboffsets,
4757db96d56Sopenharmony_ci         char *sptr, const Py_ssize_t *sstrides, const Py_ssize_t *ssuboffsets,
4767db96d56Sopenharmony_ci         char *mem)
4777db96d56Sopenharmony_ci{
4787db96d56Sopenharmony_ci    Py_ssize_t i;
4797db96d56Sopenharmony_ci
4807db96d56Sopenharmony_ci    assert(ndim >= 1);
4817db96d56Sopenharmony_ci
4827db96d56Sopenharmony_ci    if (ndim == 1) {
4837db96d56Sopenharmony_ci        if (!HAVE_PTR(dsuboffsets) && !HAVE_PTR(ssuboffsets) &&
4847db96d56Sopenharmony_ci            dstrides[0] == itemsize && sstrides[0] == itemsize) {
4857db96d56Sopenharmony_ci            memmove(dptr, sptr, shape[0] * itemsize);
4867db96d56Sopenharmony_ci        }
4877db96d56Sopenharmony_ci        else {
4887db96d56Sopenharmony_ci            char *p;
4897db96d56Sopenharmony_ci            assert(mem != NULL);
4907db96d56Sopenharmony_ci            for (i=0, p=mem; i<shape[0]; p+=itemsize, sptr+=sstrides[0], i++) {
4917db96d56Sopenharmony_ci                char *xsptr = ADJUST_PTR(sptr, ssuboffsets);
4927db96d56Sopenharmony_ci                memcpy(p, xsptr, itemsize);
4937db96d56Sopenharmony_ci            }
4947db96d56Sopenharmony_ci            for (i=0, p=mem; i<shape[0]; p+=itemsize, dptr+=dstrides[0], i++) {
4957db96d56Sopenharmony_ci                char *xdptr = ADJUST_PTR(dptr, dsuboffsets);
4967db96d56Sopenharmony_ci                memcpy(xdptr, p, itemsize);
4977db96d56Sopenharmony_ci            }
4987db96d56Sopenharmony_ci        }
4997db96d56Sopenharmony_ci        return;
5007db96d56Sopenharmony_ci    }
5017db96d56Sopenharmony_ci
5027db96d56Sopenharmony_ci    for (i = 0; i < shape[0]; dptr+=dstrides[0], sptr+=sstrides[0], i++) {
5037db96d56Sopenharmony_ci        char *xdptr = ADJUST_PTR(dptr, dsuboffsets);
5047db96d56Sopenharmony_ci        char *xsptr = ADJUST_PTR(sptr, ssuboffsets);
5057db96d56Sopenharmony_ci
5067db96d56Sopenharmony_ci        copy_rec(shape+1, ndim-1, itemsize,
5077db96d56Sopenharmony_ci                 xdptr, dstrides+1, dsuboffsets ? dsuboffsets+1 : NULL,
5087db96d56Sopenharmony_ci                 xsptr, sstrides+1, ssuboffsets ? ssuboffsets+1 : NULL,
5097db96d56Sopenharmony_ci                 mem);
5107db96d56Sopenharmony_ci    }
5117db96d56Sopenharmony_ci}
5127db96d56Sopenharmony_ci
5137db96d56Sopenharmony_cistatic int
5147db96d56Sopenharmony_cicmp_structure(Py_buffer *dest, Py_buffer *src)
5157db96d56Sopenharmony_ci{
5167db96d56Sopenharmony_ci    Py_ssize_t i;
5177db96d56Sopenharmony_ci
5187db96d56Sopenharmony_ci    if (strcmp(FIX_FORMAT(dest->format), FIX_FORMAT(src->format)) != 0 ||
5197db96d56Sopenharmony_ci        dest->itemsize != src->itemsize ||
5207db96d56Sopenharmony_ci        dest->ndim != src->ndim)
5217db96d56Sopenharmony_ci        return -1;
5227db96d56Sopenharmony_ci
5237db96d56Sopenharmony_ci    for (i = 0; i < dest->ndim; i++) {
5247db96d56Sopenharmony_ci        if (dest->shape[i] != src->shape[i])
5257db96d56Sopenharmony_ci            return -1;
5267db96d56Sopenharmony_ci        if (dest->shape[i] == 0)
5277db96d56Sopenharmony_ci            break;
5287db96d56Sopenharmony_ci    }
5297db96d56Sopenharmony_ci
5307db96d56Sopenharmony_ci    return 0;
5317db96d56Sopenharmony_ci}
5327db96d56Sopenharmony_ci
5337db96d56Sopenharmony_ci/* Copy src to dest. Both buffers must have the same format, itemsize,
5347db96d56Sopenharmony_ci   ndim and shape. Copying is atomic, the function never fails with
5357db96d56Sopenharmony_ci   a partial copy. */
5367db96d56Sopenharmony_cistatic int
5377db96d56Sopenharmony_cicopy_buffer(Py_buffer *dest, Py_buffer *src)
5387db96d56Sopenharmony_ci{
5397db96d56Sopenharmony_ci    char *mem = NULL;
5407db96d56Sopenharmony_ci
5417db96d56Sopenharmony_ci    assert(dest->ndim > 0);
5427db96d56Sopenharmony_ci
5437db96d56Sopenharmony_ci    if (cmp_structure(dest, src) < 0) {
5447db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
5457db96d56Sopenharmony_ci            "ndarray assignment: lvalue and rvalue have different structures");
5467db96d56Sopenharmony_ci        return -1;
5477db96d56Sopenharmony_ci    }
5487db96d56Sopenharmony_ci
5497db96d56Sopenharmony_ci    if ((dest->suboffsets && dest->suboffsets[dest->ndim-1] >= 0) ||
5507db96d56Sopenharmony_ci        (src->suboffsets && src->suboffsets[src->ndim-1] >= 0) ||
5517db96d56Sopenharmony_ci        dest->strides[dest->ndim-1] != dest->itemsize ||
5527db96d56Sopenharmony_ci        src->strides[src->ndim-1] != src->itemsize) {
5537db96d56Sopenharmony_ci        mem = PyMem_Malloc(dest->shape[dest->ndim-1] * dest->itemsize);
5547db96d56Sopenharmony_ci        if (mem == NULL) {
5557db96d56Sopenharmony_ci            PyErr_NoMemory();
5567db96d56Sopenharmony_ci            return -1;
5577db96d56Sopenharmony_ci        }
5587db96d56Sopenharmony_ci    }
5597db96d56Sopenharmony_ci
5607db96d56Sopenharmony_ci    copy_rec(dest->shape, dest->ndim, dest->itemsize,
5617db96d56Sopenharmony_ci             dest->buf, dest->strides, dest->suboffsets,
5627db96d56Sopenharmony_ci             src->buf, src->strides, src->suboffsets,
5637db96d56Sopenharmony_ci             mem);
5647db96d56Sopenharmony_ci
5657db96d56Sopenharmony_ci    PyMem_XFree(mem);
5667db96d56Sopenharmony_ci    return 0;
5677db96d56Sopenharmony_ci}
5687db96d56Sopenharmony_ci
5697db96d56Sopenharmony_ci
5707db96d56Sopenharmony_ci/* Unpack single element */
5717db96d56Sopenharmony_cistatic PyObject *
5727db96d56Sopenharmony_ciunpack_single(char *ptr, const char *fmt, Py_ssize_t itemsize)
5737db96d56Sopenharmony_ci{
5747db96d56Sopenharmony_ci    PyObject *x, *unpack_from, *mview;
5757db96d56Sopenharmony_ci
5767db96d56Sopenharmony_ci    if (fmt == NULL) {
5777db96d56Sopenharmony_ci        fmt = "B";
5787db96d56Sopenharmony_ci        itemsize = 1;
5797db96d56Sopenharmony_ci    }
5807db96d56Sopenharmony_ci
5817db96d56Sopenharmony_ci    unpack_from = PyObject_GetAttrString(structmodule, "unpack_from");
5827db96d56Sopenharmony_ci    if (unpack_from == NULL)
5837db96d56Sopenharmony_ci        return NULL;
5847db96d56Sopenharmony_ci
5857db96d56Sopenharmony_ci    mview = PyMemoryView_FromMemory(ptr, itemsize, PyBUF_READ);
5867db96d56Sopenharmony_ci    if (mview == NULL) {
5877db96d56Sopenharmony_ci        Py_DECREF(unpack_from);
5887db96d56Sopenharmony_ci        return NULL;
5897db96d56Sopenharmony_ci    }
5907db96d56Sopenharmony_ci
5917db96d56Sopenharmony_ci    x = PyObject_CallFunction(unpack_from, "sO", fmt, mview);
5927db96d56Sopenharmony_ci    Py_DECREF(unpack_from);
5937db96d56Sopenharmony_ci    Py_DECREF(mview);
5947db96d56Sopenharmony_ci    if (x == NULL)
5957db96d56Sopenharmony_ci        return NULL;
5967db96d56Sopenharmony_ci
5977db96d56Sopenharmony_ci    if (PyTuple_GET_SIZE(x) == 1) {
5987db96d56Sopenharmony_ci        PyObject *tmp = PyTuple_GET_ITEM(x, 0);
5997db96d56Sopenharmony_ci        Py_INCREF(tmp);
6007db96d56Sopenharmony_ci        Py_DECREF(x);
6017db96d56Sopenharmony_ci        return tmp;
6027db96d56Sopenharmony_ci    }
6037db96d56Sopenharmony_ci
6047db96d56Sopenharmony_ci    return x;
6057db96d56Sopenharmony_ci}
6067db96d56Sopenharmony_ci
6077db96d56Sopenharmony_ci/* Unpack a multi-dimensional matrix into a nested list. Return a scalar
6087db96d56Sopenharmony_ci   for ndim = 0. */
6097db96d56Sopenharmony_cistatic PyObject *
6107db96d56Sopenharmony_ciunpack_rec(PyObject *unpack_from, char *ptr, PyObject *mview, char *item,
6117db96d56Sopenharmony_ci           const Py_ssize_t *shape, const Py_ssize_t *strides,
6127db96d56Sopenharmony_ci           const Py_ssize_t *suboffsets, Py_ssize_t ndim, Py_ssize_t itemsize)
6137db96d56Sopenharmony_ci{
6147db96d56Sopenharmony_ci    PyObject *lst, *x;
6157db96d56Sopenharmony_ci    Py_ssize_t i;
6167db96d56Sopenharmony_ci
6177db96d56Sopenharmony_ci    assert(ndim >= 0);
6187db96d56Sopenharmony_ci    assert(shape != NULL);
6197db96d56Sopenharmony_ci    assert(strides != NULL);
6207db96d56Sopenharmony_ci
6217db96d56Sopenharmony_ci    if (ndim == 0) {
6227db96d56Sopenharmony_ci        memcpy(item, ptr, itemsize);
6237db96d56Sopenharmony_ci        x = PyObject_CallFunctionObjArgs(unpack_from, mview, NULL);
6247db96d56Sopenharmony_ci        if (x == NULL)
6257db96d56Sopenharmony_ci            return NULL;
6267db96d56Sopenharmony_ci        if (PyTuple_GET_SIZE(x) == 1) {
6277db96d56Sopenharmony_ci            PyObject *tmp = PyTuple_GET_ITEM(x, 0);
6287db96d56Sopenharmony_ci            Py_INCREF(tmp);
6297db96d56Sopenharmony_ci            Py_DECREF(x);
6307db96d56Sopenharmony_ci            return tmp;
6317db96d56Sopenharmony_ci        }
6327db96d56Sopenharmony_ci        return x;
6337db96d56Sopenharmony_ci    }
6347db96d56Sopenharmony_ci
6357db96d56Sopenharmony_ci    lst = PyList_New(shape[0]);
6367db96d56Sopenharmony_ci    if (lst == NULL)
6377db96d56Sopenharmony_ci        return NULL;
6387db96d56Sopenharmony_ci
6397db96d56Sopenharmony_ci    for (i = 0; i < shape[0]; ptr+=strides[0], i++) {
6407db96d56Sopenharmony_ci        char *nextptr = ADJUST_PTR(ptr, suboffsets);
6417db96d56Sopenharmony_ci
6427db96d56Sopenharmony_ci        x = unpack_rec(unpack_from, nextptr, mview, item,
6437db96d56Sopenharmony_ci                       shape+1, strides+1, suboffsets ? suboffsets+1 : NULL,
6447db96d56Sopenharmony_ci                       ndim-1, itemsize);
6457db96d56Sopenharmony_ci        if (x == NULL) {
6467db96d56Sopenharmony_ci            Py_DECREF(lst);
6477db96d56Sopenharmony_ci            return NULL;
6487db96d56Sopenharmony_ci        }
6497db96d56Sopenharmony_ci
6507db96d56Sopenharmony_ci        PyList_SET_ITEM(lst, i, x);
6517db96d56Sopenharmony_ci    }
6527db96d56Sopenharmony_ci
6537db96d56Sopenharmony_ci    return lst;
6547db96d56Sopenharmony_ci}
6557db96d56Sopenharmony_ci
6567db96d56Sopenharmony_ci
6577db96d56Sopenharmony_cistatic PyObject *
6587db96d56Sopenharmony_cindarray_as_list(NDArrayObject *nd)
6597db96d56Sopenharmony_ci{
6607db96d56Sopenharmony_ci    PyObject *structobj = NULL, *unpack_from = NULL;
6617db96d56Sopenharmony_ci    PyObject *lst = NULL, *mview = NULL;
6627db96d56Sopenharmony_ci    Py_buffer *base = &nd->head->base;
6637db96d56Sopenharmony_ci    Py_ssize_t *shape = base->shape;
6647db96d56Sopenharmony_ci    Py_ssize_t *strides = base->strides;
6657db96d56Sopenharmony_ci    Py_ssize_t simple_shape[1];
6667db96d56Sopenharmony_ci    Py_ssize_t simple_strides[1];
6677db96d56Sopenharmony_ci    char *item = NULL;
6687db96d56Sopenharmony_ci    PyObject *format;
6697db96d56Sopenharmony_ci    char *fmt = base->format;
6707db96d56Sopenharmony_ci
6717db96d56Sopenharmony_ci    base = &nd->head->base;
6727db96d56Sopenharmony_ci
6737db96d56Sopenharmony_ci    if (fmt == NULL) {
6747db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
6757db96d56Sopenharmony_ci            "ndarray: tolist() does not support format=NULL, use "
6767db96d56Sopenharmony_ci            "tobytes()");
6777db96d56Sopenharmony_ci        return NULL;
6787db96d56Sopenharmony_ci    }
6797db96d56Sopenharmony_ci    if (shape == NULL) {
6807db96d56Sopenharmony_ci        assert(ND_C_CONTIGUOUS(nd->head->flags));
6817db96d56Sopenharmony_ci        assert(base->strides == NULL);
6827db96d56Sopenharmony_ci        assert(base->ndim <= 1);
6837db96d56Sopenharmony_ci        shape = simple_shape;
6847db96d56Sopenharmony_ci        shape[0] = base->len;
6857db96d56Sopenharmony_ci        strides = simple_strides;
6867db96d56Sopenharmony_ci        strides[0] = base->itemsize;
6877db96d56Sopenharmony_ci    }
6887db96d56Sopenharmony_ci    else if (strides == NULL) {
6897db96d56Sopenharmony_ci        assert(ND_C_CONTIGUOUS(nd->head->flags));
6907db96d56Sopenharmony_ci        strides = strides_from_shape(nd->head, 0);
6917db96d56Sopenharmony_ci        if (strides == NULL)
6927db96d56Sopenharmony_ci            return NULL;
6937db96d56Sopenharmony_ci    }
6947db96d56Sopenharmony_ci
6957db96d56Sopenharmony_ci    format = PyUnicode_FromString(fmt);
6967db96d56Sopenharmony_ci    if (format == NULL)
6977db96d56Sopenharmony_ci        goto out;
6987db96d56Sopenharmony_ci
6997db96d56Sopenharmony_ci    structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL);
7007db96d56Sopenharmony_ci    Py_DECREF(format);
7017db96d56Sopenharmony_ci    if (structobj == NULL)
7027db96d56Sopenharmony_ci        goto out;
7037db96d56Sopenharmony_ci
7047db96d56Sopenharmony_ci    unpack_from = PyObject_GetAttrString(structobj, "unpack_from");
7057db96d56Sopenharmony_ci    if (unpack_from == NULL)
7067db96d56Sopenharmony_ci        goto out;
7077db96d56Sopenharmony_ci
7087db96d56Sopenharmony_ci    item = PyMem_Malloc(base->itemsize);
7097db96d56Sopenharmony_ci    if (item == NULL) {
7107db96d56Sopenharmony_ci        PyErr_NoMemory();
7117db96d56Sopenharmony_ci        goto out;
7127db96d56Sopenharmony_ci    }
7137db96d56Sopenharmony_ci
7147db96d56Sopenharmony_ci    mview = PyMemoryView_FromMemory(item, base->itemsize, PyBUF_WRITE);
7157db96d56Sopenharmony_ci    if (mview == NULL)
7167db96d56Sopenharmony_ci        goto out;
7177db96d56Sopenharmony_ci
7187db96d56Sopenharmony_ci    lst = unpack_rec(unpack_from, base->buf, mview, item,
7197db96d56Sopenharmony_ci                     shape, strides, base->suboffsets,
7207db96d56Sopenharmony_ci                     base->ndim, base->itemsize);
7217db96d56Sopenharmony_ci
7227db96d56Sopenharmony_ciout:
7237db96d56Sopenharmony_ci    Py_XDECREF(mview);
7247db96d56Sopenharmony_ci    PyMem_XFree(item);
7257db96d56Sopenharmony_ci    Py_XDECREF(unpack_from);
7267db96d56Sopenharmony_ci    Py_XDECREF(structobj);
7277db96d56Sopenharmony_ci    if (strides != base->strides && strides != simple_strides)
7287db96d56Sopenharmony_ci        PyMem_XFree(strides);
7297db96d56Sopenharmony_ci
7307db96d56Sopenharmony_ci    return lst;
7317db96d56Sopenharmony_ci}
7327db96d56Sopenharmony_ci
7337db96d56Sopenharmony_ci
7347db96d56Sopenharmony_ci/****************************************************************************/
7357db96d56Sopenharmony_ci/*                            Initialize ndbuf                              */
7367db96d56Sopenharmony_ci/****************************************************************************/
7377db96d56Sopenharmony_ci
7387db96d56Sopenharmony_ci/*
7397db96d56Sopenharmony_ci   State of a new ndbuf during initialization. 'OK' means that initialization
7407db96d56Sopenharmony_ci   is complete. 'PTR' means that a pointer has been initialized, but the
7417db96d56Sopenharmony_ci   state of the memory is still undefined and ndbuf->offset is disregarded.
7427db96d56Sopenharmony_ci
7437db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7447db96d56Sopenharmony_ci  |                 | ndbuf_new | init_simple | init_structure |
7457db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7467db96d56Sopenharmony_ci  | next            | OK (NULL) |     OK      |       OK       |
7477db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7487db96d56Sopenharmony_ci  | prev            | OK (NULL) |     OK      |       OK       |
7497db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7507db96d56Sopenharmony_ci  | len             |    OK     |     OK      |       OK       |
7517db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7527db96d56Sopenharmony_ci  | offset          |    OK     |     OK      |       OK       |
7537db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7547db96d56Sopenharmony_ci  | data            |    PTR    |     OK      |       OK       |
7557db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7567db96d56Sopenharmony_ci  | flags           |    user   |    user     |       OK       |
7577db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7587db96d56Sopenharmony_ci  | exports         |   OK (0)  |     OK      |       OK       |
7597db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7607db96d56Sopenharmony_ci  | base.obj        | OK (NULL) |     OK      |       OK       |
7617db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7627db96d56Sopenharmony_ci  | base.buf        |    PTR    |     PTR     |       OK       |
7637db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7647db96d56Sopenharmony_ci  | base.len        | len(data) |  len(data)  |       OK       |
7657db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7667db96d56Sopenharmony_ci  | base.itemsize   |     1     |     OK      |       OK       |
7677db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7687db96d56Sopenharmony_ci  | base.readonly   |     0     |     OK      |       OK       |
7697db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7707db96d56Sopenharmony_ci  | base.format     |    NULL   |     OK      |       OK       |
7717db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7727db96d56Sopenharmony_ci  | base.ndim       |     1     |      1      |       OK       |
7737db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7747db96d56Sopenharmony_ci  | base.shape      |    NULL   |    NULL     |       OK       |
7757db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7767db96d56Sopenharmony_ci  | base.strides    |    NULL   |    NULL     |       OK       |
7777db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7787db96d56Sopenharmony_ci  | base.suboffsets |    NULL   |    NULL     |       OK       |
7797db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7807db96d56Sopenharmony_ci  | base.internal   |    OK     |    OK       |       OK       |
7817db96d56Sopenharmony_ci  +-----------------+-----------+-------------+----------------+
7827db96d56Sopenharmony_ci
7837db96d56Sopenharmony_ci*/
7847db96d56Sopenharmony_ci
7857db96d56Sopenharmony_cistatic Py_ssize_t
7867db96d56Sopenharmony_ciget_itemsize(PyObject *format)
7877db96d56Sopenharmony_ci{
7887db96d56Sopenharmony_ci    PyObject *tmp;
7897db96d56Sopenharmony_ci    Py_ssize_t itemsize;
7907db96d56Sopenharmony_ci
7917db96d56Sopenharmony_ci    tmp = PyObject_CallFunctionObjArgs(calcsize, format, NULL);
7927db96d56Sopenharmony_ci    if (tmp == NULL)
7937db96d56Sopenharmony_ci        return -1;
7947db96d56Sopenharmony_ci    itemsize = PyLong_AsSsize_t(tmp);
7957db96d56Sopenharmony_ci    Py_DECREF(tmp);
7967db96d56Sopenharmony_ci
7977db96d56Sopenharmony_ci    return itemsize;
7987db96d56Sopenharmony_ci}
7997db96d56Sopenharmony_ci
8007db96d56Sopenharmony_cistatic char *
8017db96d56Sopenharmony_ciget_format(PyObject *format)
8027db96d56Sopenharmony_ci{
8037db96d56Sopenharmony_ci    PyObject *tmp;
8047db96d56Sopenharmony_ci    char *fmt;
8057db96d56Sopenharmony_ci
8067db96d56Sopenharmony_ci    tmp = PyUnicode_AsASCIIString(format);
8077db96d56Sopenharmony_ci    if (tmp == NULL)
8087db96d56Sopenharmony_ci        return NULL;
8097db96d56Sopenharmony_ci    fmt = PyMem_Malloc(PyBytes_GET_SIZE(tmp)+1);
8107db96d56Sopenharmony_ci    if (fmt == NULL) {
8117db96d56Sopenharmony_ci        PyErr_NoMemory();
8127db96d56Sopenharmony_ci        Py_DECREF(tmp);
8137db96d56Sopenharmony_ci        return NULL;
8147db96d56Sopenharmony_ci    }
8157db96d56Sopenharmony_ci    strcpy(fmt, PyBytes_AS_STRING(tmp));
8167db96d56Sopenharmony_ci    Py_DECREF(tmp);
8177db96d56Sopenharmony_ci
8187db96d56Sopenharmony_ci    return fmt;
8197db96d56Sopenharmony_ci}
8207db96d56Sopenharmony_ci
8217db96d56Sopenharmony_cistatic int
8227db96d56Sopenharmony_ciinit_simple(ndbuf_t *ndbuf, PyObject *items, PyObject *format,
8237db96d56Sopenharmony_ci            Py_ssize_t itemsize)
8247db96d56Sopenharmony_ci{
8257db96d56Sopenharmony_ci    PyObject *mview;
8267db96d56Sopenharmony_ci    Py_buffer *base = &ndbuf->base;
8277db96d56Sopenharmony_ci    int ret;
8287db96d56Sopenharmony_ci
8297db96d56Sopenharmony_ci    mview = PyMemoryView_FromBuffer(base);
8307db96d56Sopenharmony_ci    if (mview == NULL)
8317db96d56Sopenharmony_ci        return -1;
8327db96d56Sopenharmony_ci
8337db96d56Sopenharmony_ci    ret = pack_from_list(mview, items, format, itemsize);
8347db96d56Sopenharmony_ci    Py_DECREF(mview);
8357db96d56Sopenharmony_ci    if (ret < 0)
8367db96d56Sopenharmony_ci        return -1;
8377db96d56Sopenharmony_ci
8387db96d56Sopenharmony_ci    base->readonly = !(ndbuf->flags & ND_WRITABLE);
8397db96d56Sopenharmony_ci    base->itemsize = itemsize;
8407db96d56Sopenharmony_ci    base->format = get_format(format);
8417db96d56Sopenharmony_ci    if (base->format == NULL)
8427db96d56Sopenharmony_ci        return -1;
8437db96d56Sopenharmony_ci
8447db96d56Sopenharmony_ci    return 0;
8457db96d56Sopenharmony_ci}
8467db96d56Sopenharmony_ci
8477db96d56Sopenharmony_cistatic Py_ssize_t *
8487db96d56Sopenharmony_ciseq_as_ssize_array(PyObject *seq, Py_ssize_t len, int is_shape)
8497db96d56Sopenharmony_ci{
8507db96d56Sopenharmony_ci    Py_ssize_t *dest;
8517db96d56Sopenharmony_ci    Py_ssize_t x, i;
8527db96d56Sopenharmony_ci
8537db96d56Sopenharmony_ci    /* ndim = len <= ND_MAX_NDIM, so PyMem_New() is actually not needed. */
8547db96d56Sopenharmony_ci    dest = PyMem_New(Py_ssize_t, len);
8557db96d56Sopenharmony_ci    if (dest == NULL) {
8567db96d56Sopenharmony_ci        PyErr_NoMemory();
8577db96d56Sopenharmony_ci        return NULL;
8587db96d56Sopenharmony_ci    }
8597db96d56Sopenharmony_ci
8607db96d56Sopenharmony_ci    for (i = 0; i < len; i++) {
8617db96d56Sopenharmony_ci        PyObject *tmp = PySequence_Fast_GET_ITEM(seq, i);
8627db96d56Sopenharmony_ci        if (!PyLong_Check(tmp)) {
8637db96d56Sopenharmony_ci            PyErr_Format(PyExc_ValueError,
8647db96d56Sopenharmony_ci                "elements of %s must be integers",
8657db96d56Sopenharmony_ci                is_shape ? "shape" : "strides");
8667db96d56Sopenharmony_ci            PyMem_Free(dest);
8677db96d56Sopenharmony_ci            return NULL;
8687db96d56Sopenharmony_ci        }
8697db96d56Sopenharmony_ci        x = PyLong_AsSsize_t(tmp);
8707db96d56Sopenharmony_ci        if (PyErr_Occurred()) {
8717db96d56Sopenharmony_ci            PyMem_Free(dest);
8727db96d56Sopenharmony_ci            return NULL;
8737db96d56Sopenharmony_ci        }
8747db96d56Sopenharmony_ci        if (is_shape && x < 0) {
8757db96d56Sopenharmony_ci            PyErr_Format(PyExc_ValueError,
8767db96d56Sopenharmony_ci                "elements of shape must be integers >= 0");
8777db96d56Sopenharmony_ci            PyMem_Free(dest);
8787db96d56Sopenharmony_ci            return NULL;
8797db96d56Sopenharmony_ci        }
8807db96d56Sopenharmony_ci        dest[i] = x;
8817db96d56Sopenharmony_ci    }
8827db96d56Sopenharmony_ci
8837db96d56Sopenharmony_ci    return dest;
8847db96d56Sopenharmony_ci}
8857db96d56Sopenharmony_ci
8867db96d56Sopenharmony_cistatic Py_ssize_t *
8877db96d56Sopenharmony_cistrides_from_shape(const ndbuf_t *ndbuf, int flags)
8887db96d56Sopenharmony_ci{
8897db96d56Sopenharmony_ci    const Py_buffer *base = &ndbuf->base;
8907db96d56Sopenharmony_ci    Py_ssize_t *s, i;
8917db96d56Sopenharmony_ci
8927db96d56Sopenharmony_ci    s = PyMem_Malloc(base->ndim * (sizeof *s));
8937db96d56Sopenharmony_ci    if (s == NULL) {
8947db96d56Sopenharmony_ci        PyErr_NoMemory();
8957db96d56Sopenharmony_ci        return NULL;
8967db96d56Sopenharmony_ci    }
8977db96d56Sopenharmony_ci
8987db96d56Sopenharmony_ci    if (flags & ND_FORTRAN) {
8997db96d56Sopenharmony_ci        s[0] = base->itemsize;
9007db96d56Sopenharmony_ci        for (i = 1; i < base->ndim; i++)
9017db96d56Sopenharmony_ci            s[i] = s[i-1] * base->shape[i-1];
9027db96d56Sopenharmony_ci    }
9037db96d56Sopenharmony_ci    else {
9047db96d56Sopenharmony_ci        s[base->ndim-1] = base->itemsize;
9057db96d56Sopenharmony_ci        for (i = base->ndim-2; i >= 0; i--)
9067db96d56Sopenharmony_ci            s[i] = s[i+1] * base->shape[i+1];
9077db96d56Sopenharmony_ci    }
9087db96d56Sopenharmony_ci
9097db96d56Sopenharmony_ci    return s;
9107db96d56Sopenharmony_ci}
9117db96d56Sopenharmony_ci
9127db96d56Sopenharmony_ci/* Bounds check:
9137db96d56Sopenharmony_ci
9147db96d56Sopenharmony_ci     len := complete length of allocated memory
9157db96d56Sopenharmony_ci     offset := start of the array
9167db96d56Sopenharmony_ci
9177db96d56Sopenharmony_ci     A single array element is indexed by:
9187db96d56Sopenharmony_ci
9197db96d56Sopenharmony_ci       i = indices[0] * strides[0] + indices[1] * strides[1] + ...
9207db96d56Sopenharmony_ci
9217db96d56Sopenharmony_ci     imin is reached when all indices[n] combined with positive strides are 0
9227db96d56Sopenharmony_ci     and all indices combined with negative strides are shape[n]-1, which is
9237db96d56Sopenharmony_ci     the maximum index for the nth dimension.
9247db96d56Sopenharmony_ci
9257db96d56Sopenharmony_ci     imax is reached when all indices[n] combined with negative strides are 0
9267db96d56Sopenharmony_ci     and all indices combined with positive strides are shape[n]-1.
9277db96d56Sopenharmony_ci*/
9287db96d56Sopenharmony_cistatic int
9297db96d56Sopenharmony_civerify_structure(Py_ssize_t len, Py_ssize_t itemsize, Py_ssize_t offset,
9307db96d56Sopenharmony_ci                 const Py_ssize_t *shape, const Py_ssize_t *strides,
9317db96d56Sopenharmony_ci                 Py_ssize_t ndim)
9327db96d56Sopenharmony_ci{
9337db96d56Sopenharmony_ci    Py_ssize_t imin, imax;
9347db96d56Sopenharmony_ci    Py_ssize_t n;
9357db96d56Sopenharmony_ci
9367db96d56Sopenharmony_ci    assert(ndim >= 0);
9377db96d56Sopenharmony_ci
9387db96d56Sopenharmony_ci    if (ndim == 0 && (offset < 0 || offset+itemsize > len))
9397db96d56Sopenharmony_ci        goto invalid_combination;
9407db96d56Sopenharmony_ci
9417db96d56Sopenharmony_ci    for (n = 0; n < ndim; n++)
9427db96d56Sopenharmony_ci        if (strides[n] % itemsize) {
9437db96d56Sopenharmony_ci            PyErr_SetString(PyExc_ValueError,
9447db96d56Sopenharmony_ci            "strides must be a multiple of itemsize");
9457db96d56Sopenharmony_ci            return -1;
9467db96d56Sopenharmony_ci        }
9477db96d56Sopenharmony_ci
9487db96d56Sopenharmony_ci    for (n = 0; n < ndim; n++)
9497db96d56Sopenharmony_ci        if (shape[n] == 0)
9507db96d56Sopenharmony_ci            return 0;
9517db96d56Sopenharmony_ci
9527db96d56Sopenharmony_ci    imin = imax = 0;
9537db96d56Sopenharmony_ci    for (n = 0; n < ndim; n++)
9547db96d56Sopenharmony_ci        if (strides[n] <= 0)
9557db96d56Sopenharmony_ci            imin += (shape[n]-1) * strides[n];
9567db96d56Sopenharmony_ci        else
9577db96d56Sopenharmony_ci            imax += (shape[n]-1) * strides[n];
9587db96d56Sopenharmony_ci
9597db96d56Sopenharmony_ci    if (imin + offset < 0 || imax + offset + itemsize > len)
9607db96d56Sopenharmony_ci        goto invalid_combination;
9617db96d56Sopenharmony_ci
9627db96d56Sopenharmony_ci    return 0;
9637db96d56Sopenharmony_ci
9647db96d56Sopenharmony_ci
9657db96d56Sopenharmony_ciinvalid_combination:
9667db96d56Sopenharmony_ci    PyErr_SetString(PyExc_ValueError,
9677db96d56Sopenharmony_ci        "invalid combination of buffer, shape and strides");
9687db96d56Sopenharmony_ci    return -1;
9697db96d56Sopenharmony_ci}
9707db96d56Sopenharmony_ci
9717db96d56Sopenharmony_ci/*
9727db96d56Sopenharmony_ci   Convert a NumPy-style array to an array using suboffsets to stride in
9737db96d56Sopenharmony_ci   the first dimension. Requirements: ndim > 0.
9747db96d56Sopenharmony_ci
9757db96d56Sopenharmony_ci   Contiguous example
9767db96d56Sopenharmony_ci   ==================
9777db96d56Sopenharmony_ci
9787db96d56Sopenharmony_ci     Input:
9797db96d56Sopenharmony_ci     ------
9807db96d56Sopenharmony_ci       shape      = {2, 2, 3};
9817db96d56Sopenharmony_ci       strides    = {6, 3, 1};
9827db96d56Sopenharmony_ci       suboffsets = NULL;
9837db96d56Sopenharmony_ci       data       = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
9847db96d56Sopenharmony_ci       buf        = &data[0]
9857db96d56Sopenharmony_ci
9867db96d56Sopenharmony_ci     Output:
9877db96d56Sopenharmony_ci     -------
9887db96d56Sopenharmony_ci       shape      = {2, 2, 3};
9897db96d56Sopenharmony_ci       strides    = {sizeof(char *), 3, 1};
9907db96d56Sopenharmony_ci       suboffsets = {0, -1, -1};
9917db96d56Sopenharmony_ci       data       = {p1, p2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
9927db96d56Sopenharmony_ci                     |   |   ^                 ^
9937db96d56Sopenharmony_ci                     `---'---'                 |
9947db96d56Sopenharmony_ci                         |                     |
9957db96d56Sopenharmony_ci                         `---------------------'
9967db96d56Sopenharmony_ci       buf        = &data[0]
9977db96d56Sopenharmony_ci
9987db96d56Sopenharmony_ci     So, in the example the input resembles the three-dimensional array
9997db96d56Sopenharmony_ci     char v[2][2][3], while the output resembles an array of two pointers
10007db96d56Sopenharmony_ci     to two-dimensional arrays: char (*v[2])[2][3].
10017db96d56Sopenharmony_ci
10027db96d56Sopenharmony_ci
10037db96d56Sopenharmony_ci   Non-contiguous example:
10047db96d56Sopenharmony_ci   =======================
10057db96d56Sopenharmony_ci
10067db96d56Sopenharmony_ci     Input (with offset and negative strides):
10077db96d56Sopenharmony_ci     -----------------------------------------
10087db96d56Sopenharmony_ci       shape      = {2, 2, 3};
10097db96d56Sopenharmony_ci       strides    = {-6, 3, -1};
10107db96d56Sopenharmony_ci       offset     = 8
10117db96d56Sopenharmony_ci       suboffsets = NULL;
10127db96d56Sopenharmony_ci       data       = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
10137db96d56Sopenharmony_ci
10147db96d56Sopenharmony_ci     Output:
10157db96d56Sopenharmony_ci     -------
10167db96d56Sopenharmony_ci       shape      = {2, 2, 3};
10177db96d56Sopenharmony_ci       strides    = {-sizeof(char *), 3, -1};
10187db96d56Sopenharmony_ci       suboffsets = {2, -1, -1};
10197db96d56Sopenharmony_ci       newdata    = {p1, p2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
10207db96d56Sopenharmony_ci                     |   |   ^     ^           ^     ^
10217db96d56Sopenharmony_ci                     `---'---'     |           |     `- p2+suboffsets[0]
10227db96d56Sopenharmony_ci                         |         `-----------|--- p1+suboffsets[0]
10237db96d56Sopenharmony_ci                         `---------------------'
10247db96d56Sopenharmony_ci       buf        = &newdata[1]  # striding backwards over the pointers.
10257db96d56Sopenharmony_ci
10267db96d56Sopenharmony_ci     suboffsets[0] is the same as the offset that one would specify if
10277db96d56Sopenharmony_ci     the two {2, 3} subarrays were created directly, hence the name.
10287db96d56Sopenharmony_ci*/
10297db96d56Sopenharmony_cistatic int
10307db96d56Sopenharmony_ciinit_suboffsets(ndbuf_t *ndbuf)
10317db96d56Sopenharmony_ci{
10327db96d56Sopenharmony_ci    Py_buffer *base = &ndbuf->base;
10337db96d56Sopenharmony_ci    Py_ssize_t start, step;
10347db96d56Sopenharmony_ci    Py_ssize_t imin, suboffset0;
10357db96d56Sopenharmony_ci    Py_ssize_t addsize;
10367db96d56Sopenharmony_ci    Py_ssize_t n;
10377db96d56Sopenharmony_ci    char *data;
10387db96d56Sopenharmony_ci
10397db96d56Sopenharmony_ci    assert(base->ndim > 0);
10407db96d56Sopenharmony_ci    assert(base->suboffsets == NULL);
10417db96d56Sopenharmony_ci
10427db96d56Sopenharmony_ci    /* Allocate new data with additional space for shape[0] pointers. */
10437db96d56Sopenharmony_ci    addsize = base->shape[0] * (sizeof (char *));
10447db96d56Sopenharmony_ci
10457db96d56Sopenharmony_ci    /* Align array start to a multiple of 8. */
10467db96d56Sopenharmony_ci    addsize = 8 * ((addsize + 7) / 8);
10477db96d56Sopenharmony_ci
10487db96d56Sopenharmony_ci    data = PyMem_Malloc(ndbuf->len + addsize);
10497db96d56Sopenharmony_ci    if (data == NULL) {
10507db96d56Sopenharmony_ci        PyErr_NoMemory();
10517db96d56Sopenharmony_ci        return -1;
10527db96d56Sopenharmony_ci    }
10537db96d56Sopenharmony_ci
10547db96d56Sopenharmony_ci    memcpy(data + addsize, ndbuf->data, ndbuf->len);
10557db96d56Sopenharmony_ci
10567db96d56Sopenharmony_ci    PyMem_Free(ndbuf->data);
10577db96d56Sopenharmony_ci    ndbuf->data = data;
10587db96d56Sopenharmony_ci    ndbuf->len += addsize;
10597db96d56Sopenharmony_ci    base->buf = ndbuf->data;
10607db96d56Sopenharmony_ci
10617db96d56Sopenharmony_ci    /* imin: minimum index of the input array relative to ndbuf->offset.
10627db96d56Sopenharmony_ci       suboffset0: offset for each sub-array of the output. This is the
10637db96d56Sopenharmony_ci                   same as calculating -imin' for a sub-array of ndim-1. */
10647db96d56Sopenharmony_ci    imin = suboffset0 = 0;
10657db96d56Sopenharmony_ci    for (n = 0; n < base->ndim; n++) {
10667db96d56Sopenharmony_ci        if (base->shape[n] == 0)
10677db96d56Sopenharmony_ci            break;
10687db96d56Sopenharmony_ci        if (base->strides[n] <= 0) {
10697db96d56Sopenharmony_ci            Py_ssize_t x = (base->shape[n]-1) * base->strides[n];
10707db96d56Sopenharmony_ci            imin += x;
10717db96d56Sopenharmony_ci            suboffset0 += (n >= 1) ? -x : 0;
10727db96d56Sopenharmony_ci        }
10737db96d56Sopenharmony_ci    }
10747db96d56Sopenharmony_ci
10757db96d56Sopenharmony_ci    /* Initialize the array of pointers to the sub-arrays. */
10767db96d56Sopenharmony_ci    start = addsize + ndbuf->offset + imin;
10777db96d56Sopenharmony_ci    step = base->strides[0] < 0 ? -base->strides[0] : base->strides[0];
10787db96d56Sopenharmony_ci
10797db96d56Sopenharmony_ci    for (n = 0; n < base->shape[0]; n++)
10807db96d56Sopenharmony_ci        ((char **)base->buf)[n] = (char *)base->buf + start + n*step;
10817db96d56Sopenharmony_ci
10827db96d56Sopenharmony_ci    /* Initialize suboffsets. */
10837db96d56Sopenharmony_ci    base->suboffsets = PyMem_Malloc(base->ndim * (sizeof *base->suboffsets));
10847db96d56Sopenharmony_ci    if (base->suboffsets == NULL) {
10857db96d56Sopenharmony_ci        PyErr_NoMemory();
10867db96d56Sopenharmony_ci        return -1;
10877db96d56Sopenharmony_ci    }
10887db96d56Sopenharmony_ci    base->suboffsets[0] = suboffset0;
10897db96d56Sopenharmony_ci    for (n = 1; n < base->ndim; n++)
10907db96d56Sopenharmony_ci        base->suboffsets[n] = -1;
10917db96d56Sopenharmony_ci
10927db96d56Sopenharmony_ci    /* Adjust strides for the first (zeroth) dimension. */
10937db96d56Sopenharmony_ci    if (base->strides[0] >= 0) {
10947db96d56Sopenharmony_ci        base->strides[0] = sizeof(char *);
10957db96d56Sopenharmony_ci    }
10967db96d56Sopenharmony_ci    else {
10977db96d56Sopenharmony_ci        /* Striding backwards. */
10987db96d56Sopenharmony_ci        base->strides[0] = -(Py_ssize_t)sizeof(char *);
10997db96d56Sopenharmony_ci        if (base->shape[0] > 0)
11007db96d56Sopenharmony_ci            base->buf = (char *)base->buf + (base->shape[0]-1) * sizeof(char *);
11017db96d56Sopenharmony_ci    }
11027db96d56Sopenharmony_ci
11037db96d56Sopenharmony_ci    ndbuf->flags &= ~(ND_C|ND_FORTRAN);
11047db96d56Sopenharmony_ci    ndbuf->offset = 0;
11057db96d56Sopenharmony_ci    return 0;
11067db96d56Sopenharmony_ci}
11077db96d56Sopenharmony_ci
11087db96d56Sopenharmony_cistatic void
11097db96d56Sopenharmony_ciinit_len(Py_buffer *base)
11107db96d56Sopenharmony_ci{
11117db96d56Sopenharmony_ci    Py_ssize_t i;
11127db96d56Sopenharmony_ci
11137db96d56Sopenharmony_ci    base->len = 1;
11147db96d56Sopenharmony_ci    for (i = 0; i < base->ndim; i++)
11157db96d56Sopenharmony_ci        base->len *= base->shape[i];
11167db96d56Sopenharmony_ci    base->len *= base->itemsize;
11177db96d56Sopenharmony_ci}
11187db96d56Sopenharmony_ci
11197db96d56Sopenharmony_cistatic int
11207db96d56Sopenharmony_ciinit_structure(ndbuf_t *ndbuf, PyObject *shape, PyObject *strides,
11217db96d56Sopenharmony_ci               Py_ssize_t ndim)
11227db96d56Sopenharmony_ci{
11237db96d56Sopenharmony_ci    Py_buffer *base = &ndbuf->base;
11247db96d56Sopenharmony_ci
11257db96d56Sopenharmony_ci    base->ndim = (int)ndim;
11267db96d56Sopenharmony_ci    if (ndim == 0) {
11277db96d56Sopenharmony_ci        if (ndbuf->flags & ND_PIL) {
11287db96d56Sopenharmony_ci            PyErr_SetString(PyExc_TypeError,
11297db96d56Sopenharmony_ci                "ndim = 0 cannot be used in conjunction with ND_PIL");
11307db96d56Sopenharmony_ci            return -1;
11317db96d56Sopenharmony_ci        }
11327db96d56Sopenharmony_ci        ndbuf->flags |= (ND_SCALAR|ND_C|ND_FORTRAN);
11337db96d56Sopenharmony_ci        return 0;
11347db96d56Sopenharmony_ci    }
11357db96d56Sopenharmony_ci
11367db96d56Sopenharmony_ci    /* shape */
11377db96d56Sopenharmony_ci    base->shape = seq_as_ssize_array(shape, ndim, 1);
11387db96d56Sopenharmony_ci    if (base->shape == NULL)
11397db96d56Sopenharmony_ci        return -1;
11407db96d56Sopenharmony_ci
11417db96d56Sopenharmony_ci    /* strides */
11427db96d56Sopenharmony_ci    if (strides) {
11437db96d56Sopenharmony_ci        base->strides = seq_as_ssize_array(strides, ndim, 0);
11447db96d56Sopenharmony_ci    }
11457db96d56Sopenharmony_ci    else {
11467db96d56Sopenharmony_ci        base->strides = strides_from_shape(ndbuf, ndbuf->flags);
11477db96d56Sopenharmony_ci    }
11487db96d56Sopenharmony_ci    if (base->strides == NULL)
11497db96d56Sopenharmony_ci        return -1;
11507db96d56Sopenharmony_ci    if (verify_structure(base->len, base->itemsize, ndbuf->offset,
11517db96d56Sopenharmony_ci                         base->shape, base->strides, ndim) < 0)
11527db96d56Sopenharmony_ci        return -1;
11537db96d56Sopenharmony_ci
11547db96d56Sopenharmony_ci    /* buf */
11557db96d56Sopenharmony_ci    base->buf = ndbuf->data + ndbuf->offset;
11567db96d56Sopenharmony_ci
11577db96d56Sopenharmony_ci    /* len */
11587db96d56Sopenharmony_ci    init_len(base);
11597db96d56Sopenharmony_ci
11607db96d56Sopenharmony_ci    /* ndbuf->flags */
11617db96d56Sopenharmony_ci    if (PyBuffer_IsContiguous(base, 'C'))
11627db96d56Sopenharmony_ci        ndbuf->flags |= ND_C;
11637db96d56Sopenharmony_ci    if (PyBuffer_IsContiguous(base, 'F'))
11647db96d56Sopenharmony_ci        ndbuf->flags |= ND_FORTRAN;
11657db96d56Sopenharmony_ci
11667db96d56Sopenharmony_ci
11677db96d56Sopenharmony_ci    /* convert numpy array to suboffset representation */
11687db96d56Sopenharmony_ci    if (ndbuf->flags & ND_PIL) {
11697db96d56Sopenharmony_ci        /* modifies base->buf, base->strides and base->suboffsets **/
11707db96d56Sopenharmony_ci        return init_suboffsets(ndbuf);
11717db96d56Sopenharmony_ci    }
11727db96d56Sopenharmony_ci
11737db96d56Sopenharmony_ci    return 0;
11747db96d56Sopenharmony_ci}
11757db96d56Sopenharmony_ci
11767db96d56Sopenharmony_cistatic ndbuf_t *
11777db96d56Sopenharmony_ciinit_ndbuf(PyObject *items, PyObject *shape, PyObject *strides,
11787db96d56Sopenharmony_ci           Py_ssize_t offset, PyObject *format, int flags)
11797db96d56Sopenharmony_ci{
11807db96d56Sopenharmony_ci    ndbuf_t *ndbuf;
11817db96d56Sopenharmony_ci    Py_ssize_t ndim;
11827db96d56Sopenharmony_ci    Py_ssize_t nitems;
11837db96d56Sopenharmony_ci    Py_ssize_t itemsize;
11847db96d56Sopenharmony_ci
11857db96d56Sopenharmony_ci    /* ndim = len(shape) */
11867db96d56Sopenharmony_ci    CHECK_LIST_OR_TUPLE(shape)
11877db96d56Sopenharmony_ci    ndim = PySequence_Fast_GET_SIZE(shape);
11887db96d56Sopenharmony_ci    if (ndim > ND_MAX_NDIM) {
11897db96d56Sopenharmony_ci        PyErr_Format(PyExc_ValueError,
11907db96d56Sopenharmony_ci            "ndim must not exceed %d", ND_MAX_NDIM);
11917db96d56Sopenharmony_ci        return NULL;
11927db96d56Sopenharmony_ci    }
11937db96d56Sopenharmony_ci
11947db96d56Sopenharmony_ci    /* len(strides) = len(shape) */
11957db96d56Sopenharmony_ci    if (strides) {
11967db96d56Sopenharmony_ci        CHECK_LIST_OR_TUPLE(strides)
11977db96d56Sopenharmony_ci        if (PySequence_Fast_GET_SIZE(strides) == 0)
11987db96d56Sopenharmony_ci            strides = NULL;
11997db96d56Sopenharmony_ci        else if (flags & ND_FORTRAN) {
12007db96d56Sopenharmony_ci            PyErr_SetString(PyExc_TypeError,
12017db96d56Sopenharmony_ci                "ND_FORTRAN cannot be used together with strides");
12027db96d56Sopenharmony_ci            return NULL;
12037db96d56Sopenharmony_ci        }
12047db96d56Sopenharmony_ci        else if (PySequence_Fast_GET_SIZE(strides) != ndim) {
12057db96d56Sopenharmony_ci            PyErr_SetString(PyExc_ValueError,
12067db96d56Sopenharmony_ci                "len(shape) != len(strides)");
12077db96d56Sopenharmony_ci            return NULL;
12087db96d56Sopenharmony_ci        }
12097db96d56Sopenharmony_ci    }
12107db96d56Sopenharmony_ci
12117db96d56Sopenharmony_ci    /* itemsize */
12127db96d56Sopenharmony_ci    itemsize = get_itemsize(format);
12137db96d56Sopenharmony_ci    if (itemsize <= 0) {
12147db96d56Sopenharmony_ci        if (itemsize == 0) {
12157db96d56Sopenharmony_ci            PyErr_SetString(PyExc_ValueError,
12167db96d56Sopenharmony_ci                "itemsize must not be zero");
12177db96d56Sopenharmony_ci        }
12187db96d56Sopenharmony_ci        return NULL;
12197db96d56Sopenharmony_ci    }
12207db96d56Sopenharmony_ci
12217db96d56Sopenharmony_ci    /* convert scalar to list */
12227db96d56Sopenharmony_ci    if (ndim == 0) {
12237db96d56Sopenharmony_ci        items = Py_BuildValue("(O)", items);
12247db96d56Sopenharmony_ci        if (items == NULL)
12257db96d56Sopenharmony_ci            return NULL;
12267db96d56Sopenharmony_ci    }
12277db96d56Sopenharmony_ci    else {
12287db96d56Sopenharmony_ci        CHECK_LIST_OR_TUPLE(items)
12297db96d56Sopenharmony_ci        Py_INCREF(items);
12307db96d56Sopenharmony_ci    }
12317db96d56Sopenharmony_ci
12327db96d56Sopenharmony_ci    /* number of items */
12337db96d56Sopenharmony_ci    nitems = PySequence_Fast_GET_SIZE(items);
12347db96d56Sopenharmony_ci    if (nitems == 0) {
12357db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
12367db96d56Sopenharmony_ci            "initializer list or tuple must not be empty");
12377db96d56Sopenharmony_ci        Py_DECREF(items);
12387db96d56Sopenharmony_ci        return NULL;
12397db96d56Sopenharmony_ci    }
12407db96d56Sopenharmony_ci
12417db96d56Sopenharmony_ci    ndbuf = ndbuf_new(nitems, itemsize, offset, flags);
12427db96d56Sopenharmony_ci    if (ndbuf == NULL) {
12437db96d56Sopenharmony_ci        Py_DECREF(items);
12447db96d56Sopenharmony_ci        return NULL;
12457db96d56Sopenharmony_ci    }
12467db96d56Sopenharmony_ci
12477db96d56Sopenharmony_ci
12487db96d56Sopenharmony_ci    if (init_simple(ndbuf, items, format, itemsize) < 0)
12497db96d56Sopenharmony_ci        goto error;
12507db96d56Sopenharmony_ci    if (init_structure(ndbuf, shape, strides, ndim) < 0)
12517db96d56Sopenharmony_ci        goto error;
12527db96d56Sopenharmony_ci
12537db96d56Sopenharmony_ci    Py_DECREF(items);
12547db96d56Sopenharmony_ci    return ndbuf;
12557db96d56Sopenharmony_ci
12567db96d56Sopenharmony_cierror:
12577db96d56Sopenharmony_ci    Py_DECREF(items);
12587db96d56Sopenharmony_ci    ndbuf_free(ndbuf);
12597db96d56Sopenharmony_ci    return NULL;
12607db96d56Sopenharmony_ci}
12617db96d56Sopenharmony_ci
12627db96d56Sopenharmony_ci/* initialize and push a new base onto the linked list */
12637db96d56Sopenharmony_cistatic int
12647db96d56Sopenharmony_cindarray_push_base(NDArrayObject *nd, PyObject *items,
12657db96d56Sopenharmony_ci                  PyObject *shape, PyObject *strides,
12667db96d56Sopenharmony_ci                  Py_ssize_t offset, PyObject *format, int flags)
12677db96d56Sopenharmony_ci{
12687db96d56Sopenharmony_ci    ndbuf_t *ndbuf;
12697db96d56Sopenharmony_ci
12707db96d56Sopenharmony_ci    ndbuf = init_ndbuf(items, shape, strides, offset, format, flags);
12717db96d56Sopenharmony_ci    if (ndbuf == NULL)
12727db96d56Sopenharmony_ci        return -1;
12737db96d56Sopenharmony_ci
12747db96d56Sopenharmony_ci    ndbuf_push(nd, ndbuf);
12757db96d56Sopenharmony_ci    return 0;
12767db96d56Sopenharmony_ci}
12777db96d56Sopenharmony_ci
12787db96d56Sopenharmony_ci#define PyBUF_UNUSED 0x10000
12797db96d56Sopenharmony_cistatic int
12807db96d56Sopenharmony_cindarray_init(PyObject *self, PyObject *args, PyObject *kwds)
12817db96d56Sopenharmony_ci{
12827db96d56Sopenharmony_ci    NDArrayObject *nd = (NDArrayObject *)self;
12837db96d56Sopenharmony_ci    static char *kwlist[] = {
12847db96d56Sopenharmony_ci        "obj", "shape", "strides", "offset", "format", "flags", "getbuf", NULL
12857db96d56Sopenharmony_ci    };
12867db96d56Sopenharmony_ci    PyObject *v = NULL;  /* initializer: scalar, list, tuple or base object */
12877db96d56Sopenharmony_ci    PyObject *shape = NULL;   /* size of each dimension */
12887db96d56Sopenharmony_ci    PyObject *strides = NULL; /* number of bytes to the next elt in each dim */
12897db96d56Sopenharmony_ci    Py_ssize_t offset = 0;            /* buffer offset */
12907db96d56Sopenharmony_ci    PyObject *format = simple_format; /* struct module specifier: "B" */
12917db96d56Sopenharmony_ci    int flags = ND_DEFAULT;           /* base buffer and ndarray flags */
12927db96d56Sopenharmony_ci
12937db96d56Sopenharmony_ci    int getbuf = PyBUF_UNUSED; /* re-exporter: getbuffer request flags */
12947db96d56Sopenharmony_ci
12957db96d56Sopenharmony_ci
12967db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOnOii", kwlist,
12977db96d56Sopenharmony_ci            &v, &shape, &strides, &offset, &format, &flags, &getbuf))
12987db96d56Sopenharmony_ci        return -1;
12997db96d56Sopenharmony_ci
13007db96d56Sopenharmony_ci    /* NDArrayObject is re-exporter */
13017db96d56Sopenharmony_ci    if (PyObject_CheckBuffer(v) && shape == NULL) {
13027db96d56Sopenharmony_ci        if (strides || offset || format != simple_format ||
13037db96d56Sopenharmony_ci            !(flags == ND_DEFAULT || flags == ND_REDIRECT)) {
13047db96d56Sopenharmony_ci            PyErr_SetString(PyExc_TypeError,
13057db96d56Sopenharmony_ci               "construction from exporter object only takes 'obj', 'getbuf' "
13067db96d56Sopenharmony_ci               "and 'flags' arguments");
13077db96d56Sopenharmony_ci            return -1;
13087db96d56Sopenharmony_ci        }
13097db96d56Sopenharmony_ci
13107db96d56Sopenharmony_ci        getbuf = (getbuf == PyBUF_UNUSED) ? PyBUF_FULL_RO : getbuf;
13117db96d56Sopenharmony_ci
13127db96d56Sopenharmony_ci        if (ndarray_init_staticbuf(v, nd, getbuf) < 0)
13137db96d56Sopenharmony_ci            return -1;
13147db96d56Sopenharmony_ci
13157db96d56Sopenharmony_ci        init_flags(nd->head);
13167db96d56Sopenharmony_ci        nd->head->flags |= flags;
13177db96d56Sopenharmony_ci
13187db96d56Sopenharmony_ci        return 0;
13197db96d56Sopenharmony_ci    }
13207db96d56Sopenharmony_ci
13217db96d56Sopenharmony_ci    /* NDArrayObject is the original base object. */
13227db96d56Sopenharmony_ci    if (getbuf != PyBUF_UNUSED) {
13237db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
13247db96d56Sopenharmony_ci            "getbuf argument only valid for construction from exporter "
13257db96d56Sopenharmony_ci            "object");
13267db96d56Sopenharmony_ci        return -1;
13277db96d56Sopenharmony_ci    }
13287db96d56Sopenharmony_ci    if (shape == NULL) {
13297db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
13307db96d56Sopenharmony_ci            "shape is a required argument when constructing from "
13317db96d56Sopenharmony_ci            "list, tuple or scalar");
13327db96d56Sopenharmony_ci        return -1;
13337db96d56Sopenharmony_ci    }
13347db96d56Sopenharmony_ci
13357db96d56Sopenharmony_ci    if (flags & ND_VAREXPORT) {
13367db96d56Sopenharmony_ci        nd->flags |= ND_VAREXPORT;
13377db96d56Sopenharmony_ci        flags &= ~ND_VAREXPORT;
13387db96d56Sopenharmony_ci    }
13397db96d56Sopenharmony_ci
13407db96d56Sopenharmony_ci    /* Initialize and push the first base buffer onto the linked list. */
13417db96d56Sopenharmony_ci    return ndarray_push_base(nd, v, shape, strides, offset, format, flags);
13427db96d56Sopenharmony_ci}
13437db96d56Sopenharmony_ci
13447db96d56Sopenharmony_ci/* Push an additional base onto the linked list. */
13457db96d56Sopenharmony_cistatic PyObject *
13467db96d56Sopenharmony_cindarray_push(PyObject *self, PyObject *args, PyObject *kwds)
13477db96d56Sopenharmony_ci{
13487db96d56Sopenharmony_ci    NDArrayObject *nd = (NDArrayObject *)self;
13497db96d56Sopenharmony_ci    static char *kwlist[] = {
13507db96d56Sopenharmony_ci        "items", "shape", "strides", "offset", "format", "flags", NULL
13517db96d56Sopenharmony_ci    };
13527db96d56Sopenharmony_ci    PyObject *items = NULL;   /* initializer: scalar, list or tuple */
13537db96d56Sopenharmony_ci    PyObject *shape = NULL;   /* size of each dimension */
13547db96d56Sopenharmony_ci    PyObject *strides = NULL; /* number of bytes to the next elt in each dim */
13557db96d56Sopenharmony_ci    PyObject *format = simple_format;  /* struct module specifier: "B" */
13567db96d56Sopenharmony_ci    Py_ssize_t offset = 0;             /* buffer offset */
13577db96d56Sopenharmony_ci    int flags = ND_DEFAULT;            /* base buffer flags */
13587db96d56Sopenharmony_ci
13597db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OnOi", kwlist,
13607db96d56Sopenharmony_ci            &items, &shape, &strides, &offset, &format, &flags))
13617db96d56Sopenharmony_ci        return NULL;
13627db96d56Sopenharmony_ci
13637db96d56Sopenharmony_ci    if (flags & ND_VAREXPORT) {
13647db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
13657db96d56Sopenharmony_ci            "ND_VAREXPORT flag can only be used during object creation");
13667db96d56Sopenharmony_ci        return NULL;
13677db96d56Sopenharmony_ci    }
13687db96d56Sopenharmony_ci    if (ND_IS_CONSUMER(nd)) {
13697db96d56Sopenharmony_ci        PyErr_SetString(PyExc_BufferError,
13707db96d56Sopenharmony_ci            "structure of re-exporting object is immutable");
13717db96d56Sopenharmony_ci        return NULL;
13727db96d56Sopenharmony_ci    }
13737db96d56Sopenharmony_ci    if (!(nd->flags&ND_VAREXPORT) && nd->head->exports > 0) {
13747db96d56Sopenharmony_ci        PyErr_Format(PyExc_BufferError,
13757db96d56Sopenharmony_ci            "cannot change structure: %zd exported buffer%s",
13767db96d56Sopenharmony_ci            nd->head->exports, nd->head->exports==1 ? "" : "s");
13777db96d56Sopenharmony_ci        return NULL;
13787db96d56Sopenharmony_ci    }
13797db96d56Sopenharmony_ci
13807db96d56Sopenharmony_ci    if (ndarray_push_base(nd, items, shape, strides,
13817db96d56Sopenharmony_ci                          offset, format, flags) < 0)
13827db96d56Sopenharmony_ci        return NULL;
13837db96d56Sopenharmony_ci    Py_RETURN_NONE;
13847db96d56Sopenharmony_ci}
13857db96d56Sopenharmony_ci
13867db96d56Sopenharmony_ci/* Pop a base from the linked list (if possible). */
13877db96d56Sopenharmony_cistatic PyObject *
13887db96d56Sopenharmony_cindarray_pop(PyObject *self, PyObject *dummy)
13897db96d56Sopenharmony_ci{
13907db96d56Sopenharmony_ci    NDArrayObject *nd = (NDArrayObject *)self;
13917db96d56Sopenharmony_ci    if (ND_IS_CONSUMER(nd)) {
13927db96d56Sopenharmony_ci        PyErr_SetString(PyExc_BufferError,
13937db96d56Sopenharmony_ci            "structure of re-exporting object is immutable");
13947db96d56Sopenharmony_ci        return NULL;
13957db96d56Sopenharmony_ci    }
13967db96d56Sopenharmony_ci    if (nd->head->exports > 0) {
13977db96d56Sopenharmony_ci        PyErr_Format(PyExc_BufferError,
13987db96d56Sopenharmony_ci            "cannot change structure: %zd exported buffer%s",
13997db96d56Sopenharmony_ci            nd->head->exports, nd->head->exports==1 ? "" : "s");
14007db96d56Sopenharmony_ci        return NULL;
14017db96d56Sopenharmony_ci    }
14027db96d56Sopenharmony_ci    if (nd->head->next == NULL) {
14037db96d56Sopenharmony_ci        PyErr_SetString(PyExc_BufferError,
14047db96d56Sopenharmony_ci            "list only has a single base");
14057db96d56Sopenharmony_ci        return NULL;
14067db96d56Sopenharmony_ci    }
14077db96d56Sopenharmony_ci
14087db96d56Sopenharmony_ci    ndbuf_pop(nd);
14097db96d56Sopenharmony_ci    Py_RETURN_NONE;
14107db96d56Sopenharmony_ci}
14117db96d56Sopenharmony_ci
14127db96d56Sopenharmony_ci/**************************************************************************/
14137db96d56Sopenharmony_ci/*                               getbuffer                                */
14147db96d56Sopenharmony_ci/**************************************************************************/
14157db96d56Sopenharmony_ci
14167db96d56Sopenharmony_cistatic int
14177db96d56Sopenharmony_cindarray_getbuf(NDArrayObject *self, Py_buffer *view, int flags)
14187db96d56Sopenharmony_ci{
14197db96d56Sopenharmony_ci    ndbuf_t *ndbuf = self->head;
14207db96d56Sopenharmony_ci    Py_buffer *base = &ndbuf->base;
14217db96d56Sopenharmony_ci    int baseflags = ndbuf->flags;
14227db96d56Sopenharmony_ci
14237db96d56Sopenharmony_ci    /* redirect mode */
14247db96d56Sopenharmony_ci    if (base->obj != NULL && (baseflags&ND_REDIRECT)) {
14257db96d56Sopenharmony_ci        return PyObject_GetBuffer(base->obj, view, flags);
14267db96d56Sopenharmony_ci    }
14277db96d56Sopenharmony_ci
14287db96d56Sopenharmony_ci    /* start with complete information */
14297db96d56Sopenharmony_ci    *view = *base;
14307db96d56Sopenharmony_ci    view->obj = NULL;
14317db96d56Sopenharmony_ci
14327db96d56Sopenharmony_ci    /* reconstruct format */
14337db96d56Sopenharmony_ci    if (view->format == NULL)
14347db96d56Sopenharmony_ci        view->format = "B";
14357db96d56Sopenharmony_ci
14367db96d56Sopenharmony_ci    if (base->ndim != 0 &&
14377db96d56Sopenharmony_ci        ((REQ_SHAPE(flags) && base->shape == NULL) ||
14387db96d56Sopenharmony_ci         (REQ_STRIDES(flags) && base->strides == NULL))) {
14397db96d56Sopenharmony_ci        /* The ndarray is a re-exporter that has been created without full
14407db96d56Sopenharmony_ci           information for testing purposes. In this particular case the
14417db96d56Sopenharmony_ci           ndarray is not a PEP-3118 compliant buffer provider. */
14427db96d56Sopenharmony_ci        PyErr_SetString(PyExc_BufferError,
14437db96d56Sopenharmony_ci            "re-exporter does not provide format, shape or strides");
14447db96d56Sopenharmony_ci        return -1;
14457db96d56Sopenharmony_ci    }
14467db96d56Sopenharmony_ci
14477db96d56Sopenharmony_ci    if (baseflags & ND_GETBUF_FAIL) {
14487db96d56Sopenharmony_ci        PyErr_SetString(PyExc_BufferError,
14497db96d56Sopenharmony_ci            "ND_GETBUF_FAIL: forced test exception");
14507db96d56Sopenharmony_ci        if (baseflags & ND_GETBUF_UNDEFINED)
14517db96d56Sopenharmony_ci            view->obj = (PyObject *)0x1; /* wrong but permitted in <= 3.2 */
14527db96d56Sopenharmony_ci        return -1;
14537db96d56Sopenharmony_ci    }
14547db96d56Sopenharmony_ci
14557db96d56Sopenharmony_ci    if (REQ_WRITABLE(flags) && base->readonly) {
14567db96d56Sopenharmony_ci        PyErr_SetString(PyExc_BufferError,
14577db96d56Sopenharmony_ci            "ndarray is not writable");
14587db96d56Sopenharmony_ci        return -1;
14597db96d56Sopenharmony_ci    }
14607db96d56Sopenharmony_ci    if (!REQ_FORMAT(flags)) {
14617db96d56Sopenharmony_ci        /* NULL indicates that the buffer's data type has been cast to 'B'.
14627db96d56Sopenharmony_ci           view->itemsize is the _previous_ itemsize. If shape is present,
14637db96d56Sopenharmony_ci           the equality product(shape) * itemsize = len still holds at this
14647db96d56Sopenharmony_ci           point. The equality calcsize(format) = itemsize does _not_ hold
14657db96d56Sopenharmony_ci           from here on! */
14667db96d56Sopenharmony_ci        view->format = NULL;
14677db96d56Sopenharmony_ci    }
14687db96d56Sopenharmony_ci
14697db96d56Sopenharmony_ci    if (REQ_C_CONTIGUOUS(flags) && !ND_C_CONTIGUOUS(baseflags)) {
14707db96d56Sopenharmony_ci        PyErr_SetString(PyExc_BufferError,
14717db96d56Sopenharmony_ci            "ndarray is not C-contiguous");
14727db96d56Sopenharmony_ci        return -1;
14737db96d56Sopenharmony_ci    }
14747db96d56Sopenharmony_ci    if (REQ_F_CONTIGUOUS(flags) && !ND_FORTRAN_CONTIGUOUS(baseflags)) {
14757db96d56Sopenharmony_ci        PyErr_SetString(PyExc_BufferError,
14767db96d56Sopenharmony_ci            "ndarray is not Fortran contiguous");
14777db96d56Sopenharmony_ci        return -1;
14787db96d56Sopenharmony_ci    }
14797db96d56Sopenharmony_ci    if (REQ_ANY_CONTIGUOUS(flags) && !ND_ANY_CONTIGUOUS(baseflags)) {
14807db96d56Sopenharmony_ci        PyErr_SetString(PyExc_BufferError,
14817db96d56Sopenharmony_ci            "ndarray is not contiguous");
14827db96d56Sopenharmony_ci        return -1;
14837db96d56Sopenharmony_ci    }
14847db96d56Sopenharmony_ci    if (!REQ_INDIRECT(flags) && (baseflags & ND_PIL)) {
14857db96d56Sopenharmony_ci        PyErr_SetString(PyExc_BufferError,
14867db96d56Sopenharmony_ci            "ndarray cannot be represented without suboffsets");
14877db96d56Sopenharmony_ci        return -1;
14887db96d56Sopenharmony_ci    }
14897db96d56Sopenharmony_ci    if (!REQ_STRIDES(flags)) {
14907db96d56Sopenharmony_ci        if (!ND_C_CONTIGUOUS(baseflags)) {
14917db96d56Sopenharmony_ci            PyErr_SetString(PyExc_BufferError,
14927db96d56Sopenharmony_ci                "ndarray is not C-contiguous");
14937db96d56Sopenharmony_ci            return -1;
14947db96d56Sopenharmony_ci        }
14957db96d56Sopenharmony_ci        view->strides = NULL;
14967db96d56Sopenharmony_ci    }
14977db96d56Sopenharmony_ci    if (!REQ_SHAPE(flags)) {
14987db96d56Sopenharmony_ci        /* PyBUF_SIMPLE or PyBUF_WRITABLE: at this point buf is C-contiguous,
14997db96d56Sopenharmony_ci           so base->buf = ndbuf->data. */
15007db96d56Sopenharmony_ci        if (view->format != NULL) {
15017db96d56Sopenharmony_ci            /* PyBUF_SIMPLE|PyBUF_FORMAT and PyBUF_WRITABLE|PyBUF_FORMAT do
15027db96d56Sopenharmony_ci               not make sense. */
15037db96d56Sopenharmony_ci            PyErr_Format(PyExc_BufferError,
15047db96d56Sopenharmony_ci                "ndarray: cannot cast to unsigned bytes if the format flag "
15057db96d56Sopenharmony_ci                "is present");
15067db96d56Sopenharmony_ci            return -1;
15077db96d56Sopenharmony_ci        }
15087db96d56Sopenharmony_ci        /* product(shape) * itemsize = len and calcsize(format) = itemsize
15097db96d56Sopenharmony_ci           do _not_ hold from here on! */
15107db96d56Sopenharmony_ci        view->ndim = 1;
15117db96d56Sopenharmony_ci        view->shape = NULL;
15127db96d56Sopenharmony_ci    }
15137db96d56Sopenharmony_ci
15147db96d56Sopenharmony_ci    /* Ascertain that the new buffer has the same contiguity as the exporter */
15157db96d56Sopenharmony_ci    if (ND_C_CONTIGUOUS(baseflags) != PyBuffer_IsContiguous(view, 'C') ||
15167db96d56Sopenharmony_ci        /* skip cast to 1-d */
15177db96d56Sopenharmony_ci        (view->format != NULL && view->shape != NULL &&
15187db96d56Sopenharmony_ci         ND_FORTRAN_CONTIGUOUS(baseflags) != PyBuffer_IsContiguous(view, 'F')) ||
15197db96d56Sopenharmony_ci        /* cast to 1-d */
15207db96d56Sopenharmony_ci        (view->format == NULL && view->shape == NULL &&
15217db96d56Sopenharmony_ci         !PyBuffer_IsContiguous(view, 'F'))) {
15227db96d56Sopenharmony_ci        PyErr_SetString(PyExc_BufferError,
15237db96d56Sopenharmony_ci            "ndarray: contiguity mismatch in getbuf()");
15247db96d56Sopenharmony_ci            return -1;
15257db96d56Sopenharmony_ci    }
15267db96d56Sopenharmony_ci
15277db96d56Sopenharmony_ci    view->obj = (PyObject *)self;
15287db96d56Sopenharmony_ci    Py_INCREF(view->obj);
15297db96d56Sopenharmony_ci    self->head->exports++;
15307db96d56Sopenharmony_ci
15317db96d56Sopenharmony_ci    return 0;
15327db96d56Sopenharmony_ci}
15337db96d56Sopenharmony_ci
15347db96d56Sopenharmony_cistatic void
15357db96d56Sopenharmony_cindarray_releasebuf(NDArrayObject *self, Py_buffer *view)
15367db96d56Sopenharmony_ci{
15377db96d56Sopenharmony_ci    if (!ND_IS_CONSUMER(self)) {
15387db96d56Sopenharmony_ci        ndbuf_t *ndbuf = view->internal;
15397db96d56Sopenharmony_ci        if (--ndbuf->exports == 0 && ndbuf != self->head)
15407db96d56Sopenharmony_ci            ndbuf_delete(self, ndbuf);
15417db96d56Sopenharmony_ci    }
15427db96d56Sopenharmony_ci}
15437db96d56Sopenharmony_ci
15447db96d56Sopenharmony_cistatic PyBufferProcs ndarray_as_buffer = {
15457db96d56Sopenharmony_ci    (getbufferproc)ndarray_getbuf,        /* bf_getbuffer */
15467db96d56Sopenharmony_ci    (releasebufferproc)ndarray_releasebuf /* bf_releasebuffer */
15477db96d56Sopenharmony_ci};
15487db96d56Sopenharmony_ci
15497db96d56Sopenharmony_ci
15507db96d56Sopenharmony_ci/**************************************************************************/
15517db96d56Sopenharmony_ci/*                           indexing/slicing                             */
15527db96d56Sopenharmony_ci/**************************************************************************/
15537db96d56Sopenharmony_ci
15547db96d56Sopenharmony_cistatic char *
15557db96d56Sopenharmony_ciptr_from_index(Py_buffer *base, Py_ssize_t index)
15567db96d56Sopenharmony_ci{
15577db96d56Sopenharmony_ci    char *ptr;
15587db96d56Sopenharmony_ci    Py_ssize_t nitems; /* items in the first dimension */
15597db96d56Sopenharmony_ci
15607db96d56Sopenharmony_ci    if (base->shape)
15617db96d56Sopenharmony_ci        nitems = base->shape[0];
15627db96d56Sopenharmony_ci    else {
15637db96d56Sopenharmony_ci        assert(base->ndim == 1 && SIMPLE_FORMAT(base->format));
15647db96d56Sopenharmony_ci        nitems = base->len;
15657db96d56Sopenharmony_ci    }
15667db96d56Sopenharmony_ci
15677db96d56Sopenharmony_ci    if (index < 0) {
15687db96d56Sopenharmony_ci        index += nitems;
15697db96d56Sopenharmony_ci    }
15707db96d56Sopenharmony_ci    if (index < 0 || index >= nitems) {
15717db96d56Sopenharmony_ci        PyErr_SetString(PyExc_IndexError, "index out of bounds");
15727db96d56Sopenharmony_ci        return NULL;
15737db96d56Sopenharmony_ci    }
15747db96d56Sopenharmony_ci
15757db96d56Sopenharmony_ci    ptr = (char *)base->buf;
15767db96d56Sopenharmony_ci
15777db96d56Sopenharmony_ci    if (base->strides == NULL)
15787db96d56Sopenharmony_ci         ptr += base->itemsize * index;
15797db96d56Sopenharmony_ci    else
15807db96d56Sopenharmony_ci         ptr += base->strides[0] * index;
15817db96d56Sopenharmony_ci
15827db96d56Sopenharmony_ci    ptr = ADJUST_PTR(ptr, base->suboffsets);
15837db96d56Sopenharmony_ci
15847db96d56Sopenharmony_ci    return ptr;
15857db96d56Sopenharmony_ci}
15867db96d56Sopenharmony_ci
15877db96d56Sopenharmony_cistatic PyObject *
15887db96d56Sopenharmony_cindarray_item(NDArrayObject *self, Py_ssize_t index)
15897db96d56Sopenharmony_ci{
15907db96d56Sopenharmony_ci    ndbuf_t *ndbuf = self->head;
15917db96d56Sopenharmony_ci    Py_buffer *base = &ndbuf->base;
15927db96d56Sopenharmony_ci    char *ptr;
15937db96d56Sopenharmony_ci
15947db96d56Sopenharmony_ci    if (base->ndim == 0) {
15957db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError, "invalid indexing of scalar");
15967db96d56Sopenharmony_ci        return NULL;
15977db96d56Sopenharmony_ci    }
15987db96d56Sopenharmony_ci
15997db96d56Sopenharmony_ci    ptr = ptr_from_index(base, index);
16007db96d56Sopenharmony_ci    if (ptr == NULL)
16017db96d56Sopenharmony_ci        return NULL;
16027db96d56Sopenharmony_ci
16037db96d56Sopenharmony_ci    if (base->ndim == 1) {
16047db96d56Sopenharmony_ci        return unpack_single(ptr, base->format, base->itemsize);
16057db96d56Sopenharmony_ci    }
16067db96d56Sopenharmony_ci    else {
16077db96d56Sopenharmony_ci        NDArrayObject *nd;
16087db96d56Sopenharmony_ci        Py_buffer *subview;
16097db96d56Sopenharmony_ci
16107db96d56Sopenharmony_ci        nd = (NDArrayObject *)ndarray_new(&NDArray_Type, NULL, NULL);
16117db96d56Sopenharmony_ci        if (nd == NULL)
16127db96d56Sopenharmony_ci            return NULL;
16137db96d56Sopenharmony_ci
16147db96d56Sopenharmony_ci        if (ndarray_init_staticbuf((PyObject *)self, nd, PyBUF_FULL_RO) < 0) {
16157db96d56Sopenharmony_ci            Py_DECREF(nd);
16167db96d56Sopenharmony_ci            return NULL;
16177db96d56Sopenharmony_ci        }
16187db96d56Sopenharmony_ci
16197db96d56Sopenharmony_ci        subview = &nd->staticbuf.base;
16207db96d56Sopenharmony_ci
16217db96d56Sopenharmony_ci        subview->buf = ptr;
16227db96d56Sopenharmony_ci        subview->len /= subview->shape[0];
16237db96d56Sopenharmony_ci
16247db96d56Sopenharmony_ci        subview->ndim--;
16257db96d56Sopenharmony_ci        subview->shape++;
16267db96d56Sopenharmony_ci        if (subview->strides) subview->strides++;
16277db96d56Sopenharmony_ci        if (subview->suboffsets) subview->suboffsets++;
16287db96d56Sopenharmony_ci
16297db96d56Sopenharmony_ci        init_flags(&nd->staticbuf);
16307db96d56Sopenharmony_ci
16317db96d56Sopenharmony_ci        return (PyObject *)nd;
16327db96d56Sopenharmony_ci    }
16337db96d56Sopenharmony_ci}
16347db96d56Sopenharmony_ci
16357db96d56Sopenharmony_ci/*
16367db96d56Sopenharmony_ci  For each dimension, we get valid (start, stop, step, slicelength) quadruples
16377db96d56Sopenharmony_ci  from PySlice_GetIndicesEx().
16387db96d56Sopenharmony_ci
16397db96d56Sopenharmony_ci  Slicing NumPy arrays
16407db96d56Sopenharmony_ci  ====================
16417db96d56Sopenharmony_ci
16427db96d56Sopenharmony_ci    A pointer to an element in a NumPy array is defined by:
16437db96d56Sopenharmony_ci
16447db96d56Sopenharmony_ci      ptr = (char *)buf + indices[0] * strides[0] +
16457db96d56Sopenharmony_ci                          ... +
16467db96d56Sopenharmony_ci                          indices[ndim-1] * strides[ndim-1]
16477db96d56Sopenharmony_ci
16487db96d56Sopenharmony_ci    Adjust buf:
16497db96d56Sopenharmony_ci    -----------
16507db96d56Sopenharmony_ci      Adding start[n] for each dimension effectively adds the constant:
16517db96d56Sopenharmony_ci
16527db96d56Sopenharmony_ci        c = start[0] * strides[0] + ... + start[ndim-1] * strides[ndim-1]
16537db96d56Sopenharmony_ci
16547db96d56Sopenharmony_ci      Therefore init_slice() adds all start[n] directly to buf.
16557db96d56Sopenharmony_ci
16567db96d56Sopenharmony_ci    Adjust shape:
16577db96d56Sopenharmony_ci    -------------
16587db96d56Sopenharmony_ci      Obviously shape[n] = slicelength[n]
16597db96d56Sopenharmony_ci
16607db96d56Sopenharmony_ci    Adjust strides:
16617db96d56Sopenharmony_ci    ---------------
16627db96d56Sopenharmony_ci      In the original array, the next element in a dimension is reached
16637db96d56Sopenharmony_ci      by adding strides[n] to the pointer. In the sliced array, elements
16647db96d56Sopenharmony_ci      may be skipped, so the next element is reached by adding:
16657db96d56Sopenharmony_ci
16667db96d56Sopenharmony_ci        strides[n] * step[n]
16677db96d56Sopenharmony_ci
16687db96d56Sopenharmony_ci  Slicing PIL arrays
16697db96d56Sopenharmony_ci  ==================
16707db96d56Sopenharmony_ci
16717db96d56Sopenharmony_ci    Layout:
16727db96d56Sopenharmony_ci    -------
16737db96d56Sopenharmony_ci      In the first (zeroth) dimension, PIL arrays have an array of pointers
16747db96d56Sopenharmony_ci      to sub-arrays of ndim-1. Striding in the first dimension is done by
16757db96d56Sopenharmony_ci      getting the index of the nth pointer, dereference it and then add a
16767db96d56Sopenharmony_ci      suboffset to it. The arrays pointed to can best be seen a regular
16777db96d56Sopenharmony_ci      NumPy arrays.
16787db96d56Sopenharmony_ci
16797db96d56Sopenharmony_ci    Adjust buf:
16807db96d56Sopenharmony_ci    -----------
16817db96d56Sopenharmony_ci      In the original array, buf points to a location (usually the start)
16827db96d56Sopenharmony_ci      in the array of pointers. For the sliced array, start[0] can be
16837db96d56Sopenharmony_ci      added to buf in the same manner as for NumPy arrays.
16847db96d56Sopenharmony_ci
16857db96d56Sopenharmony_ci    Adjust suboffsets:
16867db96d56Sopenharmony_ci    ------------------
16877db96d56Sopenharmony_ci      Due to the dereferencing step in the addressing scheme, it is not
16887db96d56Sopenharmony_ci      possible to adjust buf for higher dimensions. Recall that the
16897db96d56Sopenharmony_ci      sub-arrays pointed to are regular NumPy arrays, so for each of
16907db96d56Sopenharmony_ci      those arrays adding start[n] effectively adds the constant:
16917db96d56Sopenharmony_ci
16927db96d56Sopenharmony_ci        c = start[1] * strides[1] + ... + start[ndim-1] * strides[ndim-1]
16937db96d56Sopenharmony_ci
16947db96d56Sopenharmony_ci      This constant is added to suboffsets[0]. suboffsets[0] in turn is
16957db96d56Sopenharmony_ci      added to each pointer right after dereferencing.
16967db96d56Sopenharmony_ci
16977db96d56Sopenharmony_ci    Adjust shape and strides:
16987db96d56Sopenharmony_ci    -------------------------
16997db96d56Sopenharmony_ci      Shape and strides are not influenced by the dereferencing step, so
17007db96d56Sopenharmony_ci      they are adjusted in the same manner as for NumPy arrays.
17017db96d56Sopenharmony_ci
17027db96d56Sopenharmony_ci  Multiple levels of suboffsets
17037db96d56Sopenharmony_ci  =============================
17047db96d56Sopenharmony_ci
17057db96d56Sopenharmony_ci      For a construct like an array of pointers to array of pointers to
17067db96d56Sopenharmony_ci      sub-arrays of ndim-2:
17077db96d56Sopenharmony_ci
17087db96d56Sopenharmony_ci        suboffsets[0] = start[1] * strides[1]
17097db96d56Sopenharmony_ci        suboffsets[1] = start[2] * strides[2] + ...
17107db96d56Sopenharmony_ci*/
17117db96d56Sopenharmony_cistatic int
17127db96d56Sopenharmony_ciinit_slice(Py_buffer *base, PyObject *key, int dim)
17137db96d56Sopenharmony_ci{
17147db96d56Sopenharmony_ci    Py_ssize_t start, stop, step, slicelength;
17157db96d56Sopenharmony_ci
17167db96d56Sopenharmony_ci    if (PySlice_Unpack(key, &start, &stop, &step) < 0) {
17177db96d56Sopenharmony_ci        return -1;
17187db96d56Sopenharmony_ci    }
17197db96d56Sopenharmony_ci    slicelength = PySlice_AdjustIndices(base->shape[dim], &start, &stop, step);
17207db96d56Sopenharmony_ci
17217db96d56Sopenharmony_ci
17227db96d56Sopenharmony_ci    if (base->suboffsets == NULL || dim == 0) {
17237db96d56Sopenharmony_ci    adjust_buf:
17247db96d56Sopenharmony_ci        base->buf = (char *)base->buf + base->strides[dim] * start;
17257db96d56Sopenharmony_ci    }
17267db96d56Sopenharmony_ci    else {
17277db96d56Sopenharmony_ci        Py_ssize_t n = dim-1;
17287db96d56Sopenharmony_ci        while (n >= 0 && base->suboffsets[n] < 0)
17297db96d56Sopenharmony_ci            n--;
17307db96d56Sopenharmony_ci        if (n < 0)
17317db96d56Sopenharmony_ci            goto adjust_buf; /* all suboffsets are negative */
17327db96d56Sopenharmony_ci        base->suboffsets[n] = base->suboffsets[n] + base->strides[dim] * start;
17337db96d56Sopenharmony_ci    }
17347db96d56Sopenharmony_ci    base->shape[dim] = slicelength;
17357db96d56Sopenharmony_ci    base->strides[dim] = base->strides[dim] * step;
17367db96d56Sopenharmony_ci
17377db96d56Sopenharmony_ci    return 0;
17387db96d56Sopenharmony_ci}
17397db96d56Sopenharmony_ci
17407db96d56Sopenharmony_cistatic int
17417db96d56Sopenharmony_cicopy_structure(Py_buffer *base)
17427db96d56Sopenharmony_ci{
17437db96d56Sopenharmony_ci    Py_ssize_t *shape = NULL, *strides = NULL, *suboffsets = NULL;
17447db96d56Sopenharmony_ci    Py_ssize_t i;
17457db96d56Sopenharmony_ci
17467db96d56Sopenharmony_ci    shape = PyMem_Malloc(base->ndim * (sizeof *shape));
17477db96d56Sopenharmony_ci    strides = PyMem_Malloc(base->ndim * (sizeof *strides));
17487db96d56Sopenharmony_ci    if (shape == NULL || strides == NULL)
17497db96d56Sopenharmony_ci        goto err_nomem;
17507db96d56Sopenharmony_ci
17517db96d56Sopenharmony_ci    suboffsets = NULL;
17527db96d56Sopenharmony_ci    if (base->suboffsets) {
17537db96d56Sopenharmony_ci        suboffsets = PyMem_Malloc(base->ndim * (sizeof *suboffsets));
17547db96d56Sopenharmony_ci        if (suboffsets == NULL)
17557db96d56Sopenharmony_ci            goto err_nomem;
17567db96d56Sopenharmony_ci    }
17577db96d56Sopenharmony_ci
17587db96d56Sopenharmony_ci    for (i = 0; i < base->ndim; i++) {
17597db96d56Sopenharmony_ci        shape[i] = base->shape[i];
17607db96d56Sopenharmony_ci        strides[i] = base->strides[i];
17617db96d56Sopenharmony_ci        if (suboffsets)
17627db96d56Sopenharmony_ci            suboffsets[i] = base->suboffsets[i];
17637db96d56Sopenharmony_ci    }
17647db96d56Sopenharmony_ci
17657db96d56Sopenharmony_ci    base->shape = shape;
17667db96d56Sopenharmony_ci    base->strides = strides;
17677db96d56Sopenharmony_ci    base->suboffsets = suboffsets;
17687db96d56Sopenharmony_ci
17697db96d56Sopenharmony_ci    return 0;
17707db96d56Sopenharmony_ci
17717db96d56Sopenharmony_cierr_nomem:
17727db96d56Sopenharmony_ci    PyErr_NoMemory();
17737db96d56Sopenharmony_ci    PyMem_XFree(shape);
17747db96d56Sopenharmony_ci    PyMem_XFree(strides);
17757db96d56Sopenharmony_ci    PyMem_XFree(suboffsets);
17767db96d56Sopenharmony_ci    return -1;
17777db96d56Sopenharmony_ci}
17787db96d56Sopenharmony_ci
17797db96d56Sopenharmony_cistatic PyObject *
17807db96d56Sopenharmony_cindarray_subscript(NDArrayObject *self, PyObject *key)
17817db96d56Sopenharmony_ci{
17827db96d56Sopenharmony_ci    NDArrayObject *nd;
17837db96d56Sopenharmony_ci    ndbuf_t *ndbuf;
17847db96d56Sopenharmony_ci    Py_buffer *base = &self->head->base;
17857db96d56Sopenharmony_ci
17867db96d56Sopenharmony_ci    if (base->ndim == 0) {
17877db96d56Sopenharmony_ci        if (PyTuple_Check(key) && PyTuple_GET_SIZE(key) == 0) {
17887db96d56Sopenharmony_ci            return unpack_single(base->buf, base->format, base->itemsize);
17897db96d56Sopenharmony_ci        }
17907db96d56Sopenharmony_ci        else if (key == Py_Ellipsis) {
17917db96d56Sopenharmony_ci            Py_INCREF(self);
17927db96d56Sopenharmony_ci            return (PyObject *)self;
17937db96d56Sopenharmony_ci        }
17947db96d56Sopenharmony_ci        else {
17957db96d56Sopenharmony_ci            PyErr_SetString(PyExc_TypeError, "invalid indexing of scalar");
17967db96d56Sopenharmony_ci            return NULL;
17977db96d56Sopenharmony_ci        }
17987db96d56Sopenharmony_ci    }
17997db96d56Sopenharmony_ci    if (PyIndex_Check(key)) {
18007db96d56Sopenharmony_ci        Py_ssize_t index = PyLong_AsSsize_t(key);
18017db96d56Sopenharmony_ci        if (index == -1 && PyErr_Occurred())
18027db96d56Sopenharmony_ci            return NULL;
18037db96d56Sopenharmony_ci        return ndarray_item(self, index);
18047db96d56Sopenharmony_ci    }
18057db96d56Sopenharmony_ci
18067db96d56Sopenharmony_ci    nd = (NDArrayObject *)ndarray_new(&NDArray_Type, NULL, NULL);
18077db96d56Sopenharmony_ci    if (nd == NULL)
18087db96d56Sopenharmony_ci        return NULL;
18097db96d56Sopenharmony_ci
18107db96d56Sopenharmony_ci    /* new ndarray is a consumer */
18117db96d56Sopenharmony_ci    if (ndarray_init_staticbuf((PyObject *)self, nd, PyBUF_FULL_RO) < 0) {
18127db96d56Sopenharmony_ci        Py_DECREF(nd);
18137db96d56Sopenharmony_ci        return NULL;
18147db96d56Sopenharmony_ci    }
18157db96d56Sopenharmony_ci
18167db96d56Sopenharmony_ci    /* copy shape, strides and suboffsets */
18177db96d56Sopenharmony_ci    ndbuf = nd->head;
18187db96d56Sopenharmony_ci    base = &ndbuf->base;
18197db96d56Sopenharmony_ci    if (copy_structure(base) < 0) {
18207db96d56Sopenharmony_ci        Py_DECREF(nd);
18217db96d56Sopenharmony_ci        return NULL;
18227db96d56Sopenharmony_ci    }
18237db96d56Sopenharmony_ci    ndbuf->flags |= ND_OWN_ARRAYS;
18247db96d56Sopenharmony_ci
18257db96d56Sopenharmony_ci    if (PySlice_Check(key)) {
18267db96d56Sopenharmony_ci        /* one-dimensional slice */
18277db96d56Sopenharmony_ci        if (init_slice(base, key, 0) < 0)
18287db96d56Sopenharmony_ci            goto err_occurred;
18297db96d56Sopenharmony_ci    }
18307db96d56Sopenharmony_ci    else if (PyTuple_Check(key)) {
18317db96d56Sopenharmony_ci        /* multi-dimensional slice */
18327db96d56Sopenharmony_ci        PyObject *tuple = key;
18337db96d56Sopenharmony_ci        Py_ssize_t i, n;
18347db96d56Sopenharmony_ci
18357db96d56Sopenharmony_ci        n = PyTuple_GET_SIZE(tuple);
18367db96d56Sopenharmony_ci        for (i = 0; i < n; i++) {
18377db96d56Sopenharmony_ci            key = PyTuple_GET_ITEM(tuple, i);
18387db96d56Sopenharmony_ci            if (!PySlice_Check(key))
18397db96d56Sopenharmony_ci                goto type_error;
18407db96d56Sopenharmony_ci            if (init_slice(base, key, (int)i) < 0)
18417db96d56Sopenharmony_ci                goto err_occurred;
18427db96d56Sopenharmony_ci        }
18437db96d56Sopenharmony_ci    }
18447db96d56Sopenharmony_ci    else {
18457db96d56Sopenharmony_ci        goto type_error;
18467db96d56Sopenharmony_ci    }
18477db96d56Sopenharmony_ci
18487db96d56Sopenharmony_ci    init_len(base);
18497db96d56Sopenharmony_ci    init_flags(ndbuf);
18507db96d56Sopenharmony_ci
18517db96d56Sopenharmony_ci    return (PyObject *)nd;
18527db96d56Sopenharmony_ci
18537db96d56Sopenharmony_ci
18547db96d56Sopenharmony_citype_error:
18557db96d56Sopenharmony_ci    PyErr_Format(PyExc_TypeError,
18567db96d56Sopenharmony_ci        "cannot index memory using \"%.200s\"",
18577db96d56Sopenharmony_ci        Py_TYPE(key)->tp_name);
18587db96d56Sopenharmony_cierr_occurred:
18597db96d56Sopenharmony_ci    Py_DECREF(nd);
18607db96d56Sopenharmony_ci    return NULL;
18617db96d56Sopenharmony_ci}
18627db96d56Sopenharmony_ci
18637db96d56Sopenharmony_ci
18647db96d56Sopenharmony_cistatic int
18657db96d56Sopenharmony_cindarray_ass_subscript(NDArrayObject *self, PyObject *key, PyObject *value)
18667db96d56Sopenharmony_ci{
18677db96d56Sopenharmony_ci    NDArrayObject *nd;
18687db96d56Sopenharmony_ci    Py_buffer *dest = &self->head->base;
18697db96d56Sopenharmony_ci    Py_buffer src;
18707db96d56Sopenharmony_ci    char *ptr;
18717db96d56Sopenharmony_ci    Py_ssize_t index;
18727db96d56Sopenharmony_ci    int ret = -1;
18737db96d56Sopenharmony_ci
18747db96d56Sopenharmony_ci    if (dest->readonly) {
18757db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError, "ndarray is not writable");
18767db96d56Sopenharmony_ci        return -1;
18777db96d56Sopenharmony_ci    }
18787db96d56Sopenharmony_ci    if (value == NULL) {
18797db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError, "ndarray data cannot be deleted");
18807db96d56Sopenharmony_ci        return -1;
18817db96d56Sopenharmony_ci    }
18827db96d56Sopenharmony_ci    if (dest->ndim == 0) {
18837db96d56Sopenharmony_ci        if (key == Py_Ellipsis ||
18847db96d56Sopenharmony_ci            (PyTuple_Check(key) && PyTuple_GET_SIZE(key) == 0)) {
18857db96d56Sopenharmony_ci            ptr = (char *)dest->buf;
18867db96d56Sopenharmony_ci            return pack_single(ptr, value, dest->format, dest->itemsize);
18877db96d56Sopenharmony_ci        }
18887db96d56Sopenharmony_ci        else {
18897db96d56Sopenharmony_ci            PyErr_SetString(PyExc_TypeError, "invalid indexing of scalar");
18907db96d56Sopenharmony_ci            return -1;
18917db96d56Sopenharmony_ci        }
18927db96d56Sopenharmony_ci    }
18937db96d56Sopenharmony_ci    if (dest->ndim == 1 && PyIndex_Check(key)) {
18947db96d56Sopenharmony_ci        /* rvalue must be a single item */
18957db96d56Sopenharmony_ci        index = PyLong_AsSsize_t(key);
18967db96d56Sopenharmony_ci        if (index == -1 && PyErr_Occurred())
18977db96d56Sopenharmony_ci            return -1;
18987db96d56Sopenharmony_ci        else {
18997db96d56Sopenharmony_ci            ptr = ptr_from_index(dest, index);
19007db96d56Sopenharmony_ci            if (ptr == NULL)
19017db96d56Sopenharmony_ci                return -1;
19027db96d56Sopenharmony_ci        }
19037db96d56Sopenharmony_ci        return pack_single(ptr, value, dest->format, dest->itemsize);
19047db96d56Sopenharmony_ci    }
19057db96d56Sopenharmony_ci
19067db96d56Sopenharmony_ci    /* rvalue must be an exporter */
19077db96d56Sopenharmony_ci    if (PyObject_GetBuffer(value, &src, PyBUF_FULL_RO) == -1)
19087db96d56Sopenharmony_ci        return -1;
19097db96d56Sopenharmony_ci
19107db96d56Sopenharmony_ci    nd = (NDArrayObject *)ndarray_subscript(self, key);
19117db96d56Sopenharmony_ci    if (nd != NULL) {
19127db96d56Sopenharmony_ci        dest = &nd->head->base;
19137db96d56Sopenharmony_ci        ret = copy_buffer(dest, &src);
19147db96d56Sopenharmony_ci        Py_DECREF(nd);
19157db96d56Sopenharmony_ci    }
19167db96d56Sopenharmony_ci
19177db96d56Sopenharmony_ci    PyBuffer_Release(&src);
19187db96d56Sopenharmony_ci    return ret;
19197db96d56Sopenharmony_ci}
19207db96d56Sopenharmony_ci
19217db96d56Sopenharmony_cistatic PyObject *
19227db96d56Sopenharmony_cislice_indices(PyObject *self, PyObject *args)
19237db96d56Sopenharmony_ci{
19247db96d56Sopenharmony_ci    PyObject *ret, *key, *tmp;
19257db96d56Sopenharmony_ci    Py_ssize_t s[4]; /* start, stop, step, slicelength */
19267db96d56Sopenharmony_ci    Py_ssize_t i, len;
19277db96d56Sopenharmony_ci
19287db96d56Sopenharmony_ci    if (!PyArg_ParseTuple(args, "On", &key, &len)) {
19297db96d56Sopenharmony_ci        return NULL;
19307db96d56Sopenharmony_ci    }
19317db96d56Sopenharmony_ci    if (!PySlice_Check(key)) {
19327db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
19337db96d56Sopenharmony_ci            "first argument must be a slice object");
19347db96d56Sopenharmony_ci        return NULL;
19357db96d56Sopenharmony_ci    }
19367db96d56Sopenharmony_ci    if (PySlice_Unpack(key, &s[0], &s[1], &s[2]) < 0) {
19377db96d56Sopenharmony_ci        return NULL;
19387db96d56Sopenharmony_ci    }
19397db96d56Sopenharmony_ci    s[3] = PySlice_AdjustIndices(len, &s[0], &s[1], s[2]);
19407db96d56Sopenharmony_ci
19417db96d56Sopenharmony_ci    ret = PyTuple_New(4);
19427db96d56Sopenharmony_ci    if (ret == NULL)
19437db96d56Sopenharmony_ci        return NULL;
19447db96d56Sopenharmony_ci
19457db96d56Sopenharmony_ci    for (i = 0; i < 4; i++) {
19467db96d56Sopenharmony_ci        tmp = PyLong_FromSsize_t(s[i]);
19477db96d56Sopenharmony_ci        if (tmp == NULL)
19487db96d56Sopenharmony_ci            goto error;
19497db96d56Sopenharmony_ci        PyTuple_SET_ITEM(ret, i, tmp);
19507db96d56Sopenharmony_ci    }
19517db96d56Sopenharmony_ci
19527db96d56Sopenharmony_ci    return ret;
19537db96d56Sopenharmony_ci
19547db96d56Sopenharmony_cierror:
19557db96d56Sopenharmony_ci    Py_DECREF(ret);
19567db96d56Sopenharmony_ci    return NULL;
19577db96d56Sopenharmony_ci}
19587db96d56Sopenharmony_ci
19597db96d56Sopenharmony_ci
19607db96d56Sopenharmony_cistatic PyMappingMethods ndarray_as_mapping = {
19617db96d56Sopenharmony_ci    NULL,                                 /* mp_length */
19627db96d56Sopenharmony_ci    (binaryfunc)ndarray_subscript,        /* mp_subscript */
19637db96d56Sopenharmony_ci    (objobjargproc)ndarray_ass_subscript  /* mp_ass_subscript */
19647db96d56Sopenharmony_ci};
19657db96d56Sopenharmony_ci
19667db96d56Sopenharmony_cistatic PySequenceMethods ndarray_as_sequence = {
19677db96d56Sopenharmony_ci        0,                                /* sq_length */
19687db96d56Sopenharmony_ci        0,                                /* sq_concat */
19697db96d56Sopenharmony_ci        0,                                /* sq_repeat */
19707db96d56Sopenharmony_ci        (ssizeargfunc)ndarray_item,       /* sq_item */
19717db96d56Sopenharmony_ci};
19727db96d56Sopenharmony_ci
19737db96d56Sopenharmony_ci
19747db96d56Sopenharmony_ci/**************************************************************************/
19757db96d56Sopenharmony_ci/*                                 getters                                */
19767db96d56Sopenharmony_ci/**************************************************************************/
19777db96d56Sopenharmony_ci
19787db96d56Sopenharmony_cistatic PyObject *
19797db96d56Sopenharmony_cissize_array_as_tuple(Py_ssize_t *array, Py_ssize_t len)
19807db96d56Sopenharmony_ci{
19817db96d56Sopenharmony_ci    PyObject *tuple, *x;
19827db96d56Sopenharmony_ci    Py_ssize_t i;
19837db96d56Sopenharmony_ci
19847db96d56Sopenharmony_ci    if (array == NULL)
19857db96d56Sopenharmony_ci        return PyTuple_New(0);
19867db96d56Sopenharmony_ci
19877db96d56Sopenharmony_ci    tuple = PyTuple_New(len);
19887db96d56Sopenharmony_ci    if (tuple == NULL)
19897db96d56Sopenharmony_ci        return NULL;
19907db96d56Sopenharmony_ci
19917db96d56Sopenharmony_ci    for (i = 0; i < len; i++) {
19927db96d56Sopenharmony_ci        x = PyLong_FromSsize_t(array[i]);
19937db96d56Sopenharmony_ci        if (x == NULL) {
19947db96d56Sopenharmony_ci            Py_DECREF(tuple);
19957db96d56Sopenharmony_ci            return NULL;
19967db96d56Sopenharmony_ci        }
19977db96d56Sopenharmony_ci        PyTuple_SET_ITEM(tuple, i, x);
19987db96d56Sopenharmony_ci    }
19997db96d56Sopenharmony_ci
20007db96d56Sopenharmony_ci    return tuple;
20017db96d56Sopenharmony_ci}
20027db96d56Sopenharmony_ci
20037db96d56Sopenharmony_cistatic PyObject *
20047db96d56Sopenharmony_cindarray_get_flags(NDArrayObject *self, void *closure)
20057db96d56Sopenharmony_ci{
20067db96d56Sopenharmony_ci    return PyLong_FromLong(self->head->flags);
20077db96d56Sopenharmony_ci}
20087db96d56Sopenharmony_ci
20097db96d56Sopenharmony_cistatic PyObject *
20107db96d56Sopenharmony_cindarray_get_offset(NDArrayObject *self, void *closure)
20117db96d56Sopenharmony_ci{
20127db96d56Sopenharmony_ci    ndbuf_t *ndbuf = self->head;
20137db96d56Sopenharmony_ci    return PyLong_FromSsize_t(ndbuf->offset);
20147db96d56Sopenharmony_ci}
20157db96d56Sopenharmony_ci
20167db96d56Sopenharmony_cistatic PyObject *
20177db96d56Sopenharmony_cindarray_get_obj(NDArrayObject *self, void *closure)
20187db96d56Sopenharmony_ci{
20197db96d56Sopenharmony_ci    Py_buffer *base = &self->head->base;
20207db96d56Sopenharmony_ci
20217db96d56Sopenharmony_ci    if (base->obj == NULL) {
20227db96d56Sopenharmony_ci        Py_RETURN_NONE;
20237db96d56Sopenharmony_ci    }
20247db96d56Sopenharmony_ci    Py_INCREF(base->obj);
20257db96d56Sopenharmony_ci    return base->obj;
20267db96d56Sopenharmony_ci}
20277db96d56Sopenharmony_ci
20287db96d56Sopenharmony_cistatic PyObject *
20297db96d56Sopenharmony_cindarray_get_nbytes(NDArrayObject *self, void *closure)
20307db96d56Sopenharmony_ci{
20317db96d56Sopenharmony_ci    Py_buffer *base = &self->head->base;
20327db96d56Sopenharmony_ci    return PyLong_FromSsize_t(base->len);
20337db96d56Sopenharmony_ci}
20347db96d56Sopenharmony_ci
20357db96d56Sopenharmony_cistatic PyObject *
20367db96d56Sopenharmony_cindarray_get_readonly(NDArrayObject *self, void *closure)
20377db96d56Sopenharmony_ci{
20387db96d56Sopenharmony_ci    Py_buffer *base = &self->head->base;
20397db96d56Sopenharmony_ci    return PyBool_FromLong(base->readonly);
20407db96d56Sopenharmony_ci}
20417db96d56Sopenharmony_ci
20427db96d56Sopenharmony_cistatic PyObject *
20437db96d56Sopenharmony_cindarray_get_itemsize(NDArrayObject *self, void *closure)
20447db96d56Sopenharmony_ci{
20457db96d56Sopenharmony_ci    Py_buffer *base = &self->head->base;
20467db96d56Sopenharmony_ci    return PyLong_FromSsize_t(base->itemsize);
20477db96d56Sopenharmony_ci}
20487db96d56Sopenharmony_ci
20497db96d56Sopenharmony_cistatic PyObject *
20507db96d56Sopenharmony_cindarray_get_format(NDArrayObject *self, void *closure)
20517db96d56Sopenharmony_ci{
20527db96d56Sopenharmony_ci    Py_buffer *base = &self->head->base;
20537db96d56Sopenharmony_ci    const char *fmt = base->format ? base->format : "";
20547db96d56Sopenharmony_ci    return PyUnicode_FromString(fmt);
20557db96d56Sopenharmony_ci}
20567db96d56Sopenharmony_ci
20577db96d56Sopenharmony_cistatic PyObject *
20587db96d56Sopenharmony_cindarray_get_ndim(NDArrayObject *self, void *closure)
20597db96d56Sopenharmony_ci{
20607db96d56Sopenharmony_ci    Py_buffer *base = &self->head->base;
20617db96d56Sopenharmony_ci    return PyLong_FromSsize_t(base->ndim);
20627db96d56Sopenharmony_ci}
20637db96d56Sopenharmony_ci
20647db96d56Sopenharmony_cistatic PyObject *
20657db96d56Sopenharmony_cindarray_get_shape(NDArrayObject *self, void *closure)
20667db96d56Sopenharmony_ci{
20677db96d56Sopenharmony_ci    Py_buffer *base = &self->head->base;
20687db96d56Sopenharmony_ci    return ssize_array_as_tuple(base->shape, base->ndim);
20697db96d56Sopenharmony_ci}
20707db96d56Sopenharmony_ci
20717db96d56Sopenharmony_cistatic PyObject *
20727db96d56Sopenharmony_cindarray_get_strides(NDArrayObject *self, void *closure)
20737db96d56Sopenharmony_ci{
20747db96d56Sopenharmony_ci    Py_buffer *base = &self->head->base;
20757db96d56Sopenharmony_ci    return ssize_array_as_tuple(base->strides, base->ndim);
20767db96d56Sopenharmony_ci}
20777db96d56Sopenharmony_ci
20787db96d56Sopenharmony_cistatic PyObject *
20797db96d56Sopenharmony_cindarray_get_suboffsets(NDArrayObject *self, void *closure)
20807db96d56Sopenharmony_ci{
20817db96d56Sopenharmony_ci    Py_buffer *base = &self->head->base;
20827db96d56Sopenharmony_ci    return ssize_array_as_tuple(base->suboffsets, base->ndim);
20837db96d56Sopenharmony_ci}
20847db96d56Sopenharmony_ci
20857db96d56Sopenharmony_cistatic PyObject *
20867db96d56Sopenharmony_cindarray_c_contig(PyObject *self, PyObject *dummy)
20877db96d56Sopenharmony_ci{
20887db96d56Sopenharmony_ci    NDArrayObject *nd = (NDArrayObject *)self;
20897db96d56Sopenharmony_ci    int ret = PyBuffer_IsContiguous(&nd->head->base, 'C');
20907db96d56Sopenharmony_ci
20917db96d56Sopenharmony_ci    if (ret != ND_C_CONTIGUOUS(nd->head->flags)) {
20927db96d56Sopenharmony_ci        PyErr_SetString(PyExc_RuntimeError,
20937db96d56Sopenharmony_ci            "results from PyBuffer_IsContiguous() and flags differ");
20947db96d56Sopenharmony_ci        return NULL;
20957db96d56Sopenharmony_ci    }
20967db96d56Sopenharmony_ci    return PyBool_FromLong(ret);
20977db96d56Sopenharmony_ci}
20987db96d56Sopenharmony_ci
20997db96d56Sopenharmony_cistatic PyObject *
21007db96d56Sopenharmony_cindarray_fortran_contig(PyObject *self, PyObject *dummy)
21017db96d56Sopenharmony_ci{
21027db96d56Sopenharmony_ci    NDArrayObject *nd = (NDArrayObject *)self;
21037db96d56Sopenharmony_ci    int ret = PyBuffer_IsContiguous(&nd->head->base, 'F');
21047db96d56Sopenharmony_ci
21057db96d56Sopenharmony_ci    if (ret != ND_FORTRAN_CONTIGUOUS(nd->head->flags)) {
21067db96d56Sopenharmony_ci        PyErr_SetString(PyExc_RuntimeError,
21077db96d56Sopenharmony_ci            "results from PyBuffer_IsContiguous() and flags differ");
21087db96d56Sopenharmony_ci        return NULL;
21097db96d56Sopenharmony_ci    }
21107db96d56Sopenharmony_ci    return PyBool_FromLong(ret);
21117db96d56Sopenharmony_ci}
21127db96d56Sopenharmony_ci
21137db96d56Sopenharmony_cistatic PyObject *
21147db96d56Sopenharmony_cindarray_contig(PyObject *self, PyObject *dummy)
21157db96d56Sopenharmony_ci{
21167db96d56Sopenharmony_ci    NDArrayObject *nd = (NDArrayObject *)self;
21177db96d56Sopenharmony_ci    int ret = PyBuffer_IsContiguous(&nd->head->base, 'A');
21187db96d56Sopenharmony_ci
21197db96d56Sopenharmony_ci    if (ret != ND_ANY_CONTIGUOUS(nd->head->flags)) {
21207db96d56Sopenharmony_ci        PyErr_SetString(PyExc_RuntimeError,
21217db96d56Sopenharmony_ci            "results from PyBuffer_IsContiguous() and flags differ");
21227db96d56Sopenharmony_ci        return NULL;
21237db96d56Sopenharmony_ci    }
21247db96d56Sopenharmony_ci    return PyBool_FromLong(ret);
21257db96d56Sopenharmony_ci}
21267db96d56Sopenharmony_ci
21277db96d56Sopenharmony_ci
21287db96d56Sopenharmony_cistatic PyGetSetDef ndarray_getset [] =
21297db96d56Sopenharmony_ci{
21307db96d56Sopenharmony_ci  /* ndbuf */
21317db96d56Sopenharmony_ci  { "flags",        (getter)ndarray_get_flags,      NULL, NULL, NULL},
21327db96d56Sopenharmony_ci  { "offset",       (getter)ndarray_get_offset,     NULL, NULL, NULL},
21337db96d56Sopenharmony_ci  /* ndbuf.base */
21347db96d56Sopenharmony_ci  { "obj",          (getter)ndarray_get_obj,        NULL, NULL, NULL},
21357db96d56Sopenharmony_ci  { "nbytes",       (getter)ndarray_get_nbytes,     NULL, NULL, NULL},
21367db96d56Sopenharmony_ci  { "readonly",     (getter)ndarray_get_readonly,   NULL, NULL, NULL},
21377db96d56Sopenharmony_ci  { "itemsize",     (getter)ndarray_get_itemsize,   NULL, NULL, NULL},
21387db96d56Sopenharmony_ci  { "format",       (getter)ndarray_get_format,     NULL, NULL, NULL},
21397db96d56Sopenharmony_ci  { "ndim",         (getter)ndarray_get_ndim,       NULL, NULL, NULL},
21407db96d56Sopenharmony_ci  { "shape",        (getter)ndarray_get_shape,      NULL, NULL, NULL},
21417db96d56Sopenharmony_ci  { "strides",      (getter)ndarray_get_strides,    NULL, NULL, NULL},
21427db96d56Sopenharmony_ci  { "suboffsets",   (getter)ndarray_get_suboffsets, NULL, NULL, NULL},
21437db96d56Sopenharmony_ci  { "c_contiguous", (getter)ndarray_c_contig,       NULL, NULL, NULL},
21447db96d56Sopenharmony_ci  { "f_contiguous", (getter)ndarray_fortran_contig, NULL, NULL, NULL},
21457db96d56Sopenharmony_ci  { "contiguous",   (getter)ndarray_contig,         NULL, NULL, NULL},
21467db96d56Sopenharmony_ci  {NULL}
21477db96d56Sopenharmony_ci};
21487db96d56Sopenharmony_ci
21497db96d56Sopenharmony_cistatic PyObject *
21507db96d56Sopenharmony_cindarray_tolist(PyObject *self, PyObject *dummy)
21517db96d56Sopenharmony_ci{
21527db96d56Sopenharmony_ci    return ndarray_as_list((NDArrayObject *)self);
21537db96d56Sopenharmony_ci}
21547db96d56Sopenharmony_ci
21557db96d56Sopenharmony_cistatic PyObject *
21567db96d56Sopenharmony_cindarray_tobytes(PyObject *self, PyObject *dummy)
21577db96d56Sopenharmony_ci{
21587db96d56Sopenharmony_ci    ndbuf_t *ndbuf = ((NDArrayObject *)self)->head;
21597db96d56Sopenharmony_ci    Py_buffer *src = &ndbuf->base;
21607db96d56Sopenharmony_ci    Py_buffer dest;
21617db96d56Sopenharmony_ci    PyObject *ret = NULL;
21627db96d56Sopenharmony_ci    char *mem;
21637db96d56Sopenharmony_ci
21647db96d56Sopenharmony_ci    if (ND_C_CONTIGUOUS(ndbuf->flags))
21657db96d56Sopenharmony_ci        return PyBytes_FromStringAndSize(src->buf, src->len);
21667db96d56Sopenharmony_ci
21677db96d56Sopenharmony_ci    assert(src->shape != NULL);
21687db96d56Sopenharmony_ci    assert(src->strides != NULL);
21697db96d56Sopenharmony_ci    assert(src->ndim > 0);
21707db96d56Sopenharmony_ci
21717db96d56Sopenharmony_ci    mem = PyMem_Malloc(src->len);
21727db96d56Sopenharmony_ci    if (mem == NULL) {
21737db96d56Sopenharmony_ci        PyErr_NoMemory();
21747db96d56Sopenharmony_ci        return NULL;
21757db96d56Sopenharmony_ci    }
21767db96d56Sopenharmony_ci
21777db96d56Sopenharmony_ci    dest = *src;
21787db96d56Sopenharmony_ci    dest.buf = mem;
21797db96d56Sopenharmony_ci    dest.suboffsets = NULL;
21807db96d56Sopenharmony_ci    dest.strides = strides_from_shape(ndbuf, 0);
21817db96d56Sopenharmony_ci    if (dest.strides == NULL)
21827db96d56Sopenharmony_ci        goto out;
21837db96d56Sopenharmony_ci    if (copy_buffer(&dest, src) < 0)
21847db96d56Sopenharmony_ci        goto out;
21857db96d56Sopenharmony_ci
21867db96d56Sopenharmony_ci    ret = PyBytes_FromStringAndSize(mem, src->len);
21877db96d56Sopenharmony_ci
21887db96d56Sopenharmony_ciout:
21897db96d56Sopenharmony_ci    PyMem_XFree(dest.strides);
21907db96d56Sopenharmony_ci    PyMem_Free(mem);
21917db96d56Sopenharmony_ci    return ret;
21927db96d56Sopenharmony_ci}
21937db96d56Sopenharmony_ci
21947db96d56Sopenharmony_ci/* add redundant (negative) suboffsets for testing */
21957db96d56Sopenharmony_cistatic PyObject *
21967db96d56Sopenharmony_cindarray_add_suboffsets(PyObject *self, PyObject *dummy)
21977db96d56Sopenharmony_ci{
21987db96d56Sopenharmony_ci    NDArrayObject *nd = (NDArrayObject *)self;
21997db96d56Sopenharmony_ci    Py_buffer *base = &nd->head->base;
22007db96d56Sopenharmony_ci    Py_ssize_t i;
22017db96d56Sopenharmony_ci
22027db96d56Sopenharmony_ci    if (base->suboffsets != NULL) {
22037db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
22047db96d56Sopenharmony_ci            "cannot add suboffsets to PIL-style array");
22057db96d56Sopenharmony_ci            return NULL;
22067db96d56Sopenharmony_ci    }
22077db96d56Sopenharmony_ci    if (base->strides == NULL) {
22087db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
22097db96d56Sopenharmony_ci            "cannot add suboffsets to array without strides");
22107db96d56Sopenharmony_ci            return NULL;
22117db96d56Sopenharmony_ci    }
22127db96d56Sopenharmony_ci
22137db96d56Sopenharmony_ci    base->suboffsets = PyMem_Malloc(base->ndim * (sizeof *base->suboffsets));
22147db96d56Sopenharmony_ci    if (base->suboffsets == NULL) {
22157db96d56Sopenharmony_ci        PyErr_NoMemory();
22167db96d56Sopenharmony_ci        return NULL;
22177db96d56Sopenharmony_ci    }
22187db96d56Sopenharmony_ci
22197db96d56Sopenharmony_ci    for (i = 0; i < base->ndim; i++)
22207db96d56Sopenharmony_ci        base->suboffsets[i] = -1;
22217db96d56Sopenharmony_ci
22227db96d56Sopenharmony_ci    nd->head->flags &= ~(ND_C|ND_FORTRAN);
22237db96d56Sopenharmony_ci
22247db96d56Sopenharmony_ci    Py_RETURN_NONE;
22257db96d56Sopenharmony_ci}
22267db96d56Sopenharmony_ci
22277db96d56Sopenharmony_ci/* Test PyMemoryView_FromBuffer(): return a memoryview from a static buffer.
22287db96d56Sopenharmony_ci   Obviously this is fragile and only one such view may be active at any
22297db96d56Sopenharmony_ci   time. Never use anything like this in real code! */
22307db96d56Sopenharmony_cistatic char *infobuf = NULL;
22317db96d56Sopenharmony_cistatic PyObject *
22327db96d56Sopenharmony_cindarray_memoryview_from_buffer(PyObject *self, PyObject *dummy)
22337db96d56Sopenharmony_ci{
22347db96d56Sopenharmony_ci    const NDArrayObject *nd = (NDArrayObject *)self;
22357db96d56Sopenharmony_ci    const Py_buffer *view = &nd->head->base;
22367db96d56Sopenharmony_ci    const ndbuf_t *ndbuf;
22377db96d56Sopenharmony_ci    static char format[ND_MAX_NDIM+1];
22387db96d56Sopenharmony_ci    static Py_ssize_t shape[ND_MAX_NDIM];
22397db96d56Sopenharmony_ci    static Py_ssize_t strides[ND_MAX_NDIM];
22407db96d56Sopenharmony_ci    static Py_ssize_t suboffsets[ND_MAX_NDIM];
22417db96d56Sopenharmony_ci    static Py_buffer info;
22427db96d56Sopenharmony_ci    char *p;
22437db96d56Sopenharmony_ci
22447db96d56Sopenharmony_ci    if (!ND_IS_CONSUMER(nd))
22457db96d56Sopenharmony_ci        ndbuf = nd->head; /* self is ndarray/original exporter */
22467db96d56Sopenharmony_ci    else if (NDArray_Check(view->obj) && !ND_IS_CONSUMER(view->obj))
22477db96d56Sopenharmony_ci        /* self is ndarray and consumer from ndarray/original exporter */
22487db96d56Sopenharmony_ci        ndbuf = ((NDArrayObject *)view->obj)->head;
22497db96d56Sopenharmony_ci    else {
22507db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
22517db96d56Sopenharmony_ci        "memoryview_from_buffer(): ndarray must be original exporter or "
22527db96d56Sopenharmony_ci        "consumer from ndarray/original exporter");
22537db96d56Sopenharmony_ci         return NULL;
22547db96d56Sopenharmony_ci    }
22557db96d56Sopenharmony_ci
22567db96d56Sopenharmony_ci    info = *view;
22577db96d56Sopenharmony_ci    p = PyMem_Realloc(infobuf, ndbuf->len);
22587db96d56Sopenharmony_ci    if (p == NULL) {
22597db96d56Sopenharmony_ci        PyMem_Free(infobuf);
22607db96d56Sopenharmony_ci        PyErr_NoMemory();
22617db96d56Sopenharmony_ci        infobuf = NULL;
22627db96d56Sopenharmony_ci        return NULL;
22637db96d56Sopenharmony_ci    }
22647db96d56Sopenharmony_ci    else {
22657db96d56Sopenharmony_ci        infobuf = p;
22667db96d56Sopenharmony_ci    }
22677db96d56Sopenharmony_ci    /* copy the complete raw data */
22687db96d56Sopenharmony_ci    memcpy(infobuf, ndbuf->data, ndbuf->len);
22697db96d56Sopenharmony_ci    info.buf = infobuf + ((char *)view->buf - ndbuf->data);
22707db96d56Sopenharmony_ci
22717db96d56Sopenharmony_ci    if (view->format) {
22727db96d56Sopenharmony_ci        if (strlen(view->format) > ND_MAX_NDIM) {
22737db96d56Sopenharmony_ci            PyErr_Format(PyExc_TypeError,
22747db96d56Sopenharmony_ci                "memoryview_from_buffer: format is limited to %d characters",
22757db96d56Sopenharmony_ci                ND_MAX_NDIM);
22767db96d56Sopenharmony_ci                return NULL;
22777db96d56Sopenharmony_ci        }
22787db96d56Sopenharmony_ci        strcpy(format, view->format);
22797db96d56Sopenharmony_ci        info.format = format;
22807db96d56Sopenharmony_ci    }
22817db96d56Sopenharmony_ci    if (view->ndim > ND_MAX_NDIM) {
22827db96d56Sopenharmony_ci        PyErr_Format(PyExc_TypeError,
22837db96d56Sopenharmony_ci            "memoryview_from_buffer: ndim is limited to %d", ND_MAX_NDIM);
22847db96d56Sopenharmony_ci            return NULL;
22857db96d56Sopenharmony_ci    }
22867db96d56Sopenharmony_ci    if (view->shape) {
22877db96d56Sopenharmony_ci        memcpy(shape, view->shape, view->ndim * sizeof(Py_ssize_t));
22887db96d56Sopenharmony_ci        info.shape = shape;
22897db96d56Sopenharmony_ci    }
22907db96d56Sopenharmony_ci    if (view->strides) {
22917db96d56Sopenharmony_ci        memcpy(strides, view->strides, view->ndim * sizeof(Py_ssize_t));
22927db96d56Sopenharmony_ci        info.strides = strides;
22937db96d56Sopenharmony_ci    }
22947db96d56Sopenharmony_ci    if (view->suboffsets) {
22957db96d56Sopenharmony_ci        memcpy(suboffsets, view->suboffsets, view->ndim * sizeof(Py_ssize_t));
22967db96d56Sopenharmony_ci        info.suboffsets = suboffsets;
22977db96d56Sopenharmony_ci    }
22987db96d56Sopenharmony_ci
22997db96d56Sopenharmony_ci    return PyMemoryView_FromBuffer(&info);
23007db96d56Sopenharmony_ci}
23017db96d56Sopenharmony_ci
23027db96d56Sopenharmony_ci/* Get a single item from bufobj at the location specified by seq.
23037db96d56Sopenharmony_ci   seq is a list or tuple of indices. The purpose of this function
23047db96d56Sopenharmony_ci   is to check other functions against PyBuffer_GetPointer(). */
23057db96d56Sopenharmony_cistatic PyObject *
23067db96d56Sopenharmony_ciget_pointer(PyObject *self, PyObject *args)
23077db96d56Sopenharmony_ci{
23087db96d56Sopenharmony_ci    PyObject *ret = NULL, *bufobj, *seq;
23097db96d56Sopenharmony_ci    Py_buffer view;
23107db96d56Sopenharmony_ci    Py_ssize_t indices[ND_MAX_NDIM];
23117db96d56Sopenharmony_ci    Py_ssize_t i;
23127db96d56Sopenharmony_ci    void *ptr;
23137db96d56Sopenharmony_ci
23147db96d56Sopenharmony_ci    if (!PyArg_ParseTuple(args, "OO", &bufobj, &seq)) {
23157db96d56Sopenharmony_ci        return NULL;
23167db96d56Sopenharmony_ci    }
23177db96d56Sopenharmony_ci
23187db96d56Sopenharmony_ci    CHECK_LIST_OR_TUPLE(seq);
23197db96d56Sopenharmony_ci    if (PyObject_GetBuffer(bufobj, &view, PyBUF_FULL_RO) < 0)
23207db96d56Sopenharmony_ci        return NULL;
23217db96d56Sopenharmony_ci
23227db96d56Sopenharmony_ci    if (view.ndim > ND_MAX_NDIM) {
23237db96d56Sopenharmony_ci        PyErr_Format(PyExc_ValueError,
23247db96d56Sopenharmony_ci            "get_pointer(): ndim > %d", ND_MAX_NDIM);
23257db96d56Sopenharmony_ci        goto out;
23267db96d56Sopenharmony_ci    }
23277db96d56Sopenharmony_ci    if (PySequence_Fast_GET_SIZE(seq) != view.ndim) {
23287db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
23297db96d56Sopenharmony_ci            "get_pointer(): len(indices) != ndim");
23307db96d56Sopenharmony_ci        goto out;
23317db96d56Sopenharmony_ci    }
23327db96d56Sopenharmony_ci
23337db96d56Sopenharmony_ci    for (i = 0; i < view.ndim; i++) {
23347db96d56Sopenharmony_ci        PyObject *x = PySequence_Fast_GET_ITEM(seq, i);
23357db96d56Sopenharmony_ci        indices[i] = PyLong_AsSsize_t(x);
23367db96d56Sopenharmony_ci        if (PyErr_Occurred())
23377db96d56Sopenharmony_ci            goto out;
23387db96d56Sopenharmony_ci        if (indices[i] < 0 || indices[i] >= view.shape[i]) {
23397db96d56Sopenharmony_ci            PyErr_Format(PyExc_ValueError,
23407db96d56Sopenharmony_ci                "get_pointer(): invalid index %zd at position %zd",
23417db96d56Sopenharmony_ci                indices[i], i);
23427db96d56Sopenharmony_ci            goto out;
23437db96d56Sopenharmony_ci        }
23447db96d56Sopenharmony_ci    }
23457db96d56Sopenharmony_ci
23467db96d56Sopenharmony_ci    ptr = PyBuffer_GetPointer(&view, indices);
23477db96d56Sopenharmony_ci    ret = unpack_single(ptr, view.format, view.itemsize);
23487db96d56Sopenharmony_ci
23497db96d56Sopenharmony_ciout:
23507db96d56Sopenharmony_ci    PyBuffer_Release(&view);
23517db96d56Sopenharmony_ci    return ret;
23527db96d56Sopenharmony_ci}
23537db96d56Sopenharmony_ci
23547db96d56Sopenharmony_cistatic PyObject *
23557db96d56Sopenharmony_ciget_sizeof_void_p(PyObject *self, PyObject *Py_UNUSED(ignored))
23567db96d56Sopenharmony_ci{
23577db96d56Sopenharmony_ci    return PyLong_FromSize_t(sizeof(void *));
23587db96d56Sopenharmony_ci}
23597db96d56Sopenharmony_ci
23607db96d56Sopenharmony_cistatic char
23617db96d56Sopenharmony_ciget_ascii_order(PyObject *order)
23627db96d56Sopenharmony_ci{
23637db96d56Sopenharmony_ci    PyObject *ascii_order;
23647db96d56Sopenharmony_ci    char ord;
23657db96d56Sopenharmony_ci
23667db96d56Sopenharmony_ci    if (!PyUnicode_Check(order)) {
23677db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
23687db96d56Sopenharmony_ci            "order must be a string");
23697db96d56Sopenharmony_ci        return CHAR_MAX;
23707db96d56Sopenharmony_ci    }
23717db96d56Sopenharmony_ci
23727db96d56Sopenharmony_ci    ascii_order = PyUnicode_AsASCIIString(order);
23737db96d56Sopenharmony_ci    if (ascii_order == NULL) {
23747db96d56Sopenharmony_ci        return CHAR_MAX;
23757db96d56Sopenharmony_ci    }
23767db96d56Sopenharmony_ci
23777db96d56Sopenharmony_ci    ord = PyBytes_AS_STRING(ascii_order)[0];
23787db96d56Sopenharmony_ci    Py_DECREF(ascii_order);
23797db96d56Sopenharmony_ci
23807db96d56Sopenharmony_ci    if (ord != 'C' && ord != 'F' && ord != 'A') {
23817db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
23827db96d56Sopenharmony_ci            "invalid order, must be C, F or A");
23837db96d56Sopenharmony_ci        return CHAR_MAX;
23847db96d56Sopenharmony_ci    }
23857db96d56Sopenharmony_ci
23867db96d56Sopenharmony_ci    return ord;
23877db96d56Sopenharmony_ci}
23887db96d56Sopenharmony_ci
23897db96d56Sopenharmony_ci/* Get a contiguous memoryview. */
23907db96d56Sopenharmony_cistatic PyObject *
23917db96d56Sopenharmony_ciget_contiguous(PyObject *self, PyObject *args)
23927db96d56Sopenharmony_ci{
23937db96d56Sopenharmony_ci    PyObject *obj;
23947db96d56Sopenharmony_ci    PyObject *buffertype;
23957db96d56Sopenharmony_ci    PyObject *order;
23967db96d56Sopenharmony_ci    long type;
23977db96d56Sopenharmony_ci    char ord;
23987db96d56Sopenharmony_ci
23997db96d56Sopenharmony_ci    if (!PyArg_ParseTuple(args, "OOO", &obj, &buffertype, &order)) {
24007db96d56Sopenharmony_ci        return NULL;
24017db96d56Sopenharmony_ci    }
24027db96d56Sopenharmony_ci
24037db96d56Sopenharmony_ci    if (!PyLong_Check(buffertype)) {
24047db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
24057db96d56Sopenharmony_ci            "buffertype must be PyBUF_READ or PyBUF_WRITE");
24067db96d56Sopenharmony_ci        return NULL;
24077db96d56Sopenharmony_ci    }
24087db96d56Sopenharmony_ci
24097db96d56Sopenharmony_ci    type = PyLong_AsLong(buffertype);
24107db96d56Sopenharmony_ci    if (type == -1 && PyErr_Occurred()) {
24117db96d56Sopenharmony_ci        return NULL;
24127db96d56Sopenharmony_ci    }
24137db96d56Sopenharmony_ci    if (type != PyBUF_READ && type != PyBUF_WRITE) {
24147db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
24157db96d56Sopenharmony_ci            "invalid buffer type");
24167db96d56Sopenharmony_ci        return NULL;
24177db96d56Sopenharmony_ci    }
24187db96d56Sopenharmony_ci
24197db96d56Sopenharmony_ci    ord = get_ascii_order(order);
24207db96d56Sopenharmony_ci    if (ord == CHAR_MAX)
24217db96d56Sopenharmony_ci        return NULL;
24227db96d56Sopenharmony_ci
24237db96d56Sopenharmony_ci    return PyMemoryView_GetContiguous(obj, (int)type, ord);
24247db96d56Sopenharmony_ci}
24257db96d56Sopenharmony_ci
24267db96d56Sopenharmony_ci/* PyBuffer_ToContiguous() */
24277db96d56Sopenharmony_cistatic PyObject *
24287db96d56Sopenharmony_cipy_buffer_to_contiguous(PyObject *self, PyObject *args)
24297db96d56Sopenharmony_ci{
24307db96d56Sopenharmony_ci    PyObject *obj;
24317db96d56Sopenharmony_ci    PyObject *order;
24327db96d56Sopenharmony_ci    PyObject *ret = NULL;
24337db96d56Sopenharmony_ci    int flags;
24347db96d56Sopenharmony_ci    char ord;
24357db96d56Sopenharmony_ci    Py_buffer view;
24367db96d56Sopenharmony_ci    char *buf = NULL;
24377db96d56Sopenharmony_ci
24387db96d56Sopenharmony_ci    if (!PyArg_ParseTuple(args, "OOi", &obj, &order, &flags)) {
24397db96d56Sopenharmony_ci        return NULL;
24407db96d56Sopenharmony_ci    }
24417db96d56Sopenharmony_ci
24427db96d56Sopenharmony_ci    if (PyObject_GetBuffer(obj, &view, flags) < 0) {
24437db96d56Sopenharmony_ci        return NULL;
24447db96d56Sopenharmony_ci    }
24457db96d56Sopenharmony_ci
24467db96d56Sopenharmony_ci    ord = get_ascii_order(order);
24477db96d56Sopenharmony_ci    if (ord == CHAR_MAX) {
24487db96d56Sopenharmony_ci        goto out;
24497db96d56Sopenharmony_ci    }
24507db96d56Sopenharmony_ci
24517db96d56Sopenharmony_ci    buf = PyMem_Malloc(view.len);
24527db96d56Sopenharmony_ci    if (buf == NULL) {
24537db96d56Sopenharmony_ci        PyErr_NoMemory();
24547db96d56Sopenharmony_ci        goto out;
24557db96d56Sopenharmony_ci    }
24567db96d56Sopenharmony_ci
24577db96d56Sopenharmony_ci    if (PyBuffer_ToContiguous(buf, &view, view.len, ord) < 0) {
24587db96d56Sopenharmony_ci        goto out;
24597db96d56Sopenharmony_ci    }
24607db96d56Sopenharmony_ci
24617db96d56Sopenharmony_ci    ret = PyBytes_FromStringAndSize(buf, view.len);
24627db96d56Sopenharmony_ci
24637db96d56Sopenharmony_ciout:
24647db96d56Sopenharmony_ci    PyBuffer_Release(&view);
24657db96d56Sopenharmony_ci    PyMem_XFree(buf);
24667db96d56Sopenharmony_ci    return ret;
24677db96d56Sopenharmony_ci}
24687db96d56Sopenharmony_ci
24697db96d56Sopenharmony_cistatic int
24707db96d56Sopenharmony_cifmtcmp(const char *fmt1, const char *fmt2)
24717db96d56Sopenharmony_ci{
24727db96d56Sopenharmony_ci    if (fmt1 == NULL) {
24737db96d56Sopenharmony_ci        return fmt2 == NULL || strcmp(fmt2, "B") == 0;
24747db96d56Sopenharmony_ci    }
24757db96d56Sopenharmony_ci    if (fmt2 == NULL) {
24767db96d56Sopenharmony_ci        return fmt1 == NULL || strcmp(fmt1, "B") == 0;
24777db96d56Sopenharmony_ci    }
24787db96d56Sopenharmony_ci    return strcmp(fmt1, fmt2) == 0;
24797db96d56Sopenharmony_ci}
24807db96d56Sopenharmony_ci
24817db96d56Sopenharmony_cistatic int
24827db96d56Sopenharmony_ciarraycmp(const Py_ssize_t *a1, const Py_ssize_t *a2, const Py_ssize_t *shape,
24837db96d56Sopenharmony_ci         Py_ssize_t ndim)
24847db96d56Sopenharmony_ci{
24857db96d56Sopenharmony_ci    Py_ssize_t i;
24867db96d56Sopenharmony_ci
24877db96d56Sopenharmony_ci
24887db96d56Sopenharmony_ci    for (i = 0; i < ndim; i++) {
24897db96d56Sopenharmony_ci        if (shape && shape[i] <= 1) {
24907db96d56Sopenharmony_ci            /* strides can differ if the dimension is less than 2 */
24917db96d56Sopenharmony_ci            continue;
24927db96d56Sopenharmony_ci        }
24937db96d56Sopenharmony_ci        if (a1[i] != a2[i]) {
24947db96d56Sopenharmony_ci            return 0;
24957db96d56Sopenharmony_ci        }
24967db96d56Sopenharmony_ci    }
24977db96d56Sopenharmony_ci
24987db96d56Sopenharmony_ci    return 1;
24997db96d56Sopenharmony_ci}
25007db96d56Sopenharmony_ci
25017db96d56Sopenharmony_ci/* Compare two contiguous buffers for physical equality. */
25027db96d56Sopenharmony_cistatic PyObject *
25037db96d56Sopenharmony_cicmp_contig(PyObject *self, PyObject *args)
25047db96d56Sopenharmony_ci{
25057db96d56Sopenharmony_ci    PyObject *b1, *b2; /* buffer objects */
25067db96d56Sopenharmony_ci    Py_buffer v1, v2;
25077db96d56Sopenharmony_ci    PyObject *ret;
25087db96d56Sopenharmony_ci    int equal = 0;
25097db96d56Sopenharmony_ci
25107db96d56Sopenharmony_ci    if (!PyArg_ParseTuple(args, "OO", &b1, &b2)) {
25117db96d56Sopenharmony_ci        return NULL;
25127db96d56Sopenharmony_ci    }
25137db96d56Sopenharmony_ci
25147db96d56Sopenharmony_ci    if (PyObject_GetBuffer(b1, &v1, PyBUF_FULL_RO) < 0) {
25157db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
25167db96d56Sopenharmony_ci            "cmp_contig: first argument does not implement the buffer "
25177db96d56Sopenharmony_ci            "protocol");
25187db96d56Sopenharmony_ci        return NULL;
25197db96d56Sopenharmony_ci    }
25207db96d56Sopenharmony_ci    if (PyObject_GetBuffer(b2, &v2, PyBUF_FULL_RO) < 0) {
25217db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
25227db96d56Sopenharmony_ci            "cmp_contig: second argument does not implement the buffer "
25237db96d56Sopenharmony_ci            "protocol");
25247db96d56Sopenharmony_ci        PyBuffer_Release(&v1);
25257db96d56Sopenharmony_ci        return NULL;
25267db96d56Sopenharmony_ci    }
25277db96d56Sopenharmony_ci
25287db96d56Sopenharmony_ci    if (!(PyBuffer_IsContiguous(&v1, 'C')&&PyBuffer_IsContiguous(&v2, 'C')) &&
25297db96d56Sopenharmony_ci        !(PyBuffer_IsContiguous(&v1, 'F')&&PyBuffer_IsContiguous(&v2, 'F'))) {
25307db96d56Sopenharmony_ci        goto result;
25317db96d56Sopenharmony_ci    }
25327db96d56Sopenharmony_ci
25337db96d56Sopenharmony_ci    /* readonly may differ if created from non-contiguous */
25347db96d56Sopenharmony_ci    if (v1.len != v2.len ||
25357db96d56Sopenharmony_ci        v1.itemsize != v2.itemsize ||
25367db96d56Sopenharmony_ci        v1.ndim != v2.ndim ||
25377db96d56Sopenharmony_ci        !fmtcmp(v1.format, v2.format) ||
25387db96d56Sopenharmony_ci        !!v1.shape != !!v2.shape ||
25397db96d56Sopenharmony_ci        !!v1.strides != !!v2.strides ||
25407db96d56Sopenharmony_ci        !!v1.suboffsets != !!v2.suboffsets) {
25417db96d56Sopenharmony_ci        goto result;
25427db96d56Sopenharmony_ci    }
25437db96d56Sopenharmony_ci
25447db96d56Sopenharmony_ci    if ((v1.shape && !arraycmp(v1.shape, v2.shape, NULL, v1.ndim)) ||
25457db96d56Sopenharmony_ci        (v1.strides && !arraycmp(v1.strides, v2.strides, v1.shape, v1.ndim)) ||
25467db96d56Sopenharmony_ci        (v1.suboffsets && !arraycmp(v1.suboffsets, v2.suboffsets, NULL,
25477db96d56Sopenharmony_ci                                    v1.ndim))) {
25487db96d56Sopenharmony_ci        goto result;
25497db96d56Sopenharmony_ci    }
25507db96d56Sopenharmony_ci
25517db96d56Sopenharmony_ci    if (memcmp((char *)v1.buf, (char *)v2.buf, v1.len) != 0) {
25527db96d56Sopenharmony_ci        goto result;
25537db96d56Sopenharmony_ci    }
25547db96d56Sopenharmony_ci
25557db96d56Sopenharmony_ci    equal = 1;
25567db96d56Sopenharmony_ci
25577db96d56Sopenharmony_ciresult:
25587db96d56Sopenharmony_ci    PyBuffer_Release(&v1);
25597db96d56Sopenharmony_ci    PyBuffer_Release(&v2);
25607db96d56Sopenharmony_ci
25617db96d56Sopenharmony_ci    ret = equal ? Py_True : Py_False;
25627db96d56Sopenharmony_ci    Py_INCREF(ret);
25637db96d56Sopenharmony_ci    return ret;
25647db96d56Sopenharmony_ci}
25657db96d56Sopenharmony_ci
25667db96d56Sopenharmony_cistatic PyObject *
25677db96d56Sopenharmony_ciis_contiguous(PyObject *self, PyObject *args)
25687db96d56Sopenharmony_ci{
25697db96d56Sopenharmony_ci    PyObject *obj;
25707db96d56Sopenharmony_ci    PyObject *order;
25717db96d56Sopenharmony_ci    PyObject *ret = NULL;
25727db96d56Sopenharmony_ci    Py_buffer view, *base;
25737db96d56Sopenharmony_ci    char ord;
25747db96d56Sopenharmony_ci
25757db96d56Sopenharmony_ci    if (!PyArg_ParseTuple(args, "OO", &obj, &order)) {
25767db96d56Sopenharmony_ci        return NULL;
25777db96d56Sopenharmony_ci    }
25787db96d56Sopenharmony_ci
25797db96d56Sopenharmony_ci    ord = get_ascii_order(order);
25807db96d56Sopenharmony_ci    if (ord == CHAR_MAX) {
25817db96d56Sopenharmony_ci        return NULL;
25827db96d56Sopenharmony_ci    }
25837db96d56Sopenharmony_ci
25847db96d56Sopenharmony_ci    if (NDArray_Check(obj)) {
25857db96d56Sopenharmony_ci        /* Skip the buffer protocol to check simple etc. buffers directly. */
25867db96d56Sopenharmony_ci        base = &((NDArrayObject *)obj)->head->base;
25877db96d56Sopenharmony_ci        ret = PyBuffer_IsContiguous(base, ord) ? Py_True : Py_False;
25887db96d56Sopenharmony_ci    }
25897db96d56Sopenharmony_ci    else {
25907db96d56Sopenharmony_ci        if (PyObject_GetBuffer(obj, &view, PyBUF_FULL_RO) < 0) {
25917db96d56Sopenharmony_ci            PyErr_SetString(PyExc_TypeError,
25927db96d56Sopenharmony_ci                "is_contiguous: object does not implement the buffer "
25937db96d56Sopenharmony_ci                "protocol");
25947db96d56Sopenharmony_ci            return NULL;
25957db96d56Sopenharmony_ci        }
25967db96d56Sopenharmony_ci        ret = PyBuffer_IsContiguous(&view, ord) ? Py_True : Py_False;
25977db96d56Sopenharmony_ci        PyBuffer_Release(&view);
25987db96d56Sopenharmony_ci    }
25997db96d56Sopenharmony_ci
26007db96d56Sopenharmony_ci    Py_INCREF(ret);
26017db96d56Sopenharmony_ci    return ret;
26027db96d56Sopenharmony_ci}
26037db96d56Sopenharmony_ci
26047db96d56Sopenharmony_cistatic Py_hash_t
26057db96d56Sopenharmony_cindarray_hash(PyObject *self)
26067db96d56Sopenharmony_ci{
26077db96d56Sopenharmony_ci    const NDArrayObject *nd = (NDArrayObject *)self;
26087db96d56Sopenharmony_ci    const Py_buffer *view = &nd->head->base;
26097db96d56Sopenharmony_ci    PyObject *bytes;
26107db96d56Sopenharmony_ci    Py_hash_t hash;
26117db96d56Sopenharmony_ci
26127db96d56Sopenharmony_ci    if (!view->readonly) {
26137db96d56Sopenharmony_ci         PyErr_SetString(PyExc_ValueError,
26147db96d56Sopenharmony_ci             "cannot hash writable ndarray object");
26157db96d56Sopenharmony_ci         return -1;
26167db96d56Sopenharmony_ci    }
26177db96d56Sopenharmony_ci    if (view->obj != NULL && PyObject_Hash(view->obj) == -1) {
26187db96d56Sopenharmony_ci         return -1;
26197db96d56Sopenharmony_ci    }
26207db96d56Sopenharmony_ci
26217db96d56Sopenharmony_ci    bytes = ndarray_tobytes(self, NULL);
26227db96d56Sopenharmony_ci    if (bytes == NULL) {
26237db96d56Sopenharmony_ci        return -1;
26247db96d56Sopenharmony_ci    }
26257db96d56Sopenharmony_ci
26267db96d56Sopenharmony_ci    hash = PyObject_Hash(bytes);
26277db96d56Sopenharmony_ci    Py_DECREF(bytes);
26287db96d56Sopenharmony_ci    return hash;
26297db96d56Sopenharmony_ci}
26307db96d56Sopenharmony_ci
26317db96d56Sopenharmony_ci
26327db96d56Sopenharmony_cistatic PyMethodDef ndarray_methods [] =
26337db96d56Sopenharmony_ci{
26347db96d56Sopenharmony_ci    { "tolist", ndarray_tolist, METH_NOARGS, NULL },
26357db96d56Sopenharmony_ci    { "tobytes", ndarray_tobytes, METH_NOARGS, NULL },
26367db96d56Sopenharmony_ci    { "push", _PyCFunction_CAST(ndarray_push), METH_VARARGS|METH_KEYWORDS, NULL },
26377db96d56Sopenharmony_ci    { "pop", ndarray_pop, METH_NOARGS, NULL },
26387db96d56Sopenharmony_ci    { "add_suboffsets", ndarray_add_suboffsets, METH_NOARGS, NULL },
26397db96d56Sopenharmony_ci    { "memoryview_from_buffer", ndarray_memoryview_from_buffer, METH_NOARGS, NULL },
26407db96d56Sopenharmony_ci    {NULL}
26417db96d56Sopenharmony_ci};
26427db96d56Sopenharmony_ci
26437db96d56Sopenharmony_cistatic PyTypeObject NDArray_Type = {
26447db96d56Sopenharmony_ci    PyVarObject_HEAD_INIT(NULL, 0)
26457db96d56Sopenharmony_ci    "ndarray",                   /* Name of this type */
26467db96d56Sopenharmony_ci    sizeof(NDArrayObject),       /* Basic object size */
26477db96d56Sopenharmony_ci    0,                           /* Item size for varobject */
26487db96d56Sopenharmony_ci    (destructor)ndarray_dealloc, /* tp_dealloc */
26497db96d56Sopenharmony_ci    0,                           /* tp_vectorcall_offset */
26507db96d56Sopenharmony_ci    0,                           /* tp_getattr */
26517db96d56Sopenharmony_ci    0,                           /* tp_setattr */
26527db96d56Sopenharmony_ci    0,                           /* tp_as_async */
26537db96d56Sopenharmony_ci    0,                           /* tp_repr */
26547db96d56Sopenharmony_ci    0,                           /* tp_as_number */
26557db96d56Sopenharmony_ci    &ndarray_as_sequence,        /* tp_as_sequence */
26567db96d56Sopenharmony_ci    &ndarray_as_mapping,         /* tp_as_mapping */
26577db96d56Sopenharmony_ci    (hashfunc)ndarray_hash,      /* tp_hash */
26587db96d56Sopenharmony_ci    0,                           /* tp_call */
26597db96d56Sopenharmony_ci    0,                           /* tp_str */
26607db96d56Sopenharmony_ci    PyObject_GenericGetAttr,     /* tp_getattro */
26617db96d56Sopenharmony_ci    0,                           /* tp_setattro */
26627db96d56Sopenharmony_ci    &ndarray_as_buffer,          /* tp_as_buffer */
26637db96d56Sopenharmony_ci    Py_TPFLAGS_DEFAULT,          /* tp_flags */
26647db96d56Sopenharmony_ci    0,                           /* tp_doc */
26657db96d56Sopenharmony_ci    0,                           /* tp_traverse */
26667db96d56Sopenharmony_ci    0,                           /* tp_clear */
26677db96d56Sopenharmony_ci    0,                           /* tp_richcompare */
26687db96d56Sopenharmony_ci    0,                           /* tp_weaklistoffset */
26697db96d56Sopenharmony_ci    0,                           /* tp_iter */
26707db96d56Sopenharmony_ci    0,                           /* tp_iternext */
26717db96d56Sopenharmony_ci    ndarray_methods,             /* tp_methods */
26727db96d56Sopenharmony_ci    0,                           /* tp_members */
26737db96d56Sopenharmony_ci    ndarray_getset,              /* tp_getset */
26747db96d56Sopenharmony_ci    0,                           /* tp_base */
26757db96d56Sopenharmony_ci    0,                           /* tp_dict */
26767db96d56Sopenharmony_ci    0,                           /* tp_descr_get */
26777db96d56Sopenharmony_ci    0,                           /* tp_descr_set */
26787db96d56Sopenharmony_ci    0,                           /* tp_dictoffset */
26797db96d56Sopenharmony_ci    ndarray_init,                /* tp_init */
26807db96d56Sopenharmony_ci    0,                           /* tp_alloc */
26817db96d56Sopenharmony_ci    ndarray_new,                 /* tp_new */
26827db96d56Sopenharmony_ci};
26837db96d56Sopenharmony_ci
26847db96d56Sopenharmony_ci/**************************************************************************/
26857db96d56Sopenharmony_ci/*                          StaticArray Object                            */
26867db96d56Sopenharmony_ci/**************************************************************************/
26877db96d56Sopenharmony_ci
26887db96d56Sopenharmony_cistatic PyTypeObject StaticArray_Type;
26897db96d56Sopenharmony_ci
26907db96d56Sopenharmony_citypedef struct {
26917db96d56Sopenharmony_ci    PyObject_HEAD
26927db96d56Sopenharmony_ci    int legacy_mode; /* if true, use the view.obj==NULL hack */
26937db96d56Sopenharmony_ci} StaticArrayObject;
26947db96d56Sopenharmony_ci
26957db96d56Sopenharmony_cistatic char static_mem[12] = {0,1,2,3,4,5,6,7,8,9,10,11};
26967db96d56Sopenharmony_cistatic Py_ssize_t static_shape[1] = {12};
26977db96d56Sopenharmony_cistatic Py_ssize_t static_strides[1] = {1};
26987db96d56Sopenharmony_cistatic Py_buffer static_buffer = {
26997db96d56Sopenharmony_ci    static_mem,     /* buf */
27007db96d56Sopenharmony_ci    NULL,           /* obj */
27017db96d56Sopenharmony_ci    12,             /* len */
27027db96d56Sopenharmony_ci    1,              /* itemsize */
27037db96d56Sopenharmony_ci    1,              /* readonly */
27047db96d56Sopenharmony_ci    1,              /* ndim */
27057db96d56Sopenharmony_ci    "B",            /* format */
27067db96d56Sopenharmony_ci    static_shape,   /* shape */
27077db96d56Sopenharmony_ci    static_strides, /* strides */
27087db96d56Sopenharmony_ci    NULL,           /* suboffsets */
27097db96d56Sopenharmony_ci    NULL            /* internal */
27107db96d56Sopenharmony_ci};
27117db96d56Sopenharmony_ci
27127db96d56Sopenharmony_cistatic PyObject *
27137db96d56Sopenharmony_cistaticarray_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
27147db96d56Sopenharmony_ci{
27157db96d56Sopenharmony_ci    return (PyObject *)PyObject_New(StaticArrayObject, &StaticArray_Type);
27167db96d56Sopenharmony_ci}
27177db96d56Sopenharmony_ci
27187db96d56Sopenharmony_cistatic int
27197db96d56Sopenharmony_cistaticarray_init(PyObject *self, PyObject *args, PyObject *kwds)
27207db96d56Sopenharmony_ci{
27217db96d56Sopenharmony_ci    StaticArrayObject *a = (StaticArrayObject *)self;
27227db96d56Sopenharmony_ci    static char *kwlist[] = {
27237db96d56Sopenharmony_ci        "legacy_mode", NULL
27247db96d56Sopenharmony_ci    };
27257db96d56Sopenharmony_ci    PyObject *legacy_mode = Py_False;
27267db96d56Sopenharmony_ci
27277db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &legacy_mode))
27287db96d56Sopenharmony_ci        return -1;
27297db96d56Sopenharmony_ci
27307db96d56Sopenharmony_ci    a->legacy_mode = (legacy_mode != Py_False);
27317db96d56Sopenharmony_ci    return 0;
27327db96d56Sopenharmony_ci}
27337db96d56Sopenharmony_ci
27347db96d56Sopenharmony_cistatic void
27357db96d56Sopenharmony_cistaticarray_dealloc(StaticArrayObject *self)
27367db96d56Sopenharmony_ci{
27377db96d56Sopenharmony_ci    PyObject_Free(self);
27387db96d56Sopenharmony_ci}
27397db96d56Sopenharmony_ci
27407db96d56Sopenharmony_ci/* Return a buffer for a PyBUF_FULL_RO request. Flags are not checked,
27417db96d56Sopenharmony_ci   which makes this object a non-compliant exporter! */
27427db96d56Sopenharmony_cistatic int
27437db96d56Sopenharmony_cistaticarray_getbuf(StaticArrayObject *self, Py_buffer *view, int flags)
27447db96d56Sopenharmony_ci{
27457db96d56Sopenharmony_ci    *view = static_buffer;
27467db96d56Sopenharmony_ci
27477db96d56Sopenharmony_ci    if (self->legacy_mode) {
27487db96d56Sopenharmony_ci        view->obj = NULL; /* Don't use this in new code. */
27497db96d56Sopenharmony_ci    }
27507db96d56Sopenharmony_ci    else {
27517db96d56Sopenharmony_ci        view->obj = (PyObject *)self;
27527db96d56Sopenharmony_ci        Py_INCREF(view->obj);
27537db96d56Sopenharmony_ci    }
27547db96d56Sopenharmony_ci
27557db96d56Sopenharmony_ci    return 0;
27567db96d56Sopenharmony_ci}
27577db96d56Sopenharmony_ci
27587db96d56Sopenharmony_cistatic PyBufferProcs staticarray_as_buffer = {
27597db96d56Sopenharmony_ci    (getbufferproc)staticarray_getbuf, /* bf_getbuffer */
27607db96d56Sopenharmony_ci    NULL,                              /* bf_releasebuffer */
27617db96d56Sopenharmony_ci};
27627db96d56Sopenharmony_ci
27637db96d56Sopenharmony_cistatic PyTypeObject StaticArray_Type = {
27647db96d56Sopenharmony_ci    PyVarObject_HEAD_INIT(NULL, 0)
27657db96d56Sopenharmony_ci    "staticarray",                   /* Name of this type */
27667db96d56Sopenharmony_ci    sizeof(StaticArrayObject),       /* Basic object size */
27677db96d56Sopenharmony_ci    0,                               /* Item size for varobject */
27687db96d56Sopenharmony_ci    (destructor)staticarray_dealloc, /* tp_dealloc */
27697db96d56Sopenharmony_ci    0,                               /* tp_vectorcall_offset */
27707db96d56Sopenharmony_ci    0,                               /* tp_getattr */
27717db96d56Sopenharmony_ci    0,                               /* tp_setattr */
27727db96d56Sopenharmony_ci    0,                               /* tp_as_async */
27737db96d56Sopenharmony_ci    0,                               /* tp_repr */
27747db96d56Sopenharmony_ci    0,                               /* tp_as_number */
27757db96d56Sopenharmony_ci    0,                               /* tp_as_sequence */
27767db96d56Sopenharmony_ci    0,                               /* tp_as_mapping */
27777db96d56Sopenharmony_ci    0,                               /* tp_hash */
27787db96d56Sopenharmony_ci    0,                               /* tp_call */
27797db96d56Sopenharmony_ci    0,                               /* tp_str */
27807db96d56Sopenharmony_ci    0,                               /* tp_getattro */
27817db96d56Sopenharmony_ci    0,                               /* tp_setattro */
27827db96d56Sopenharmony_ci    &staticarray_as_buffer,          /* tp_as_buffer */
27837db96d56Sopenharmony_ci    Py_TPFLAGS_DEFAULT,              /* tp_flags */
27847db96d56Sopenharmony_ci    0,                               /* tp_doc */
27857db96d56Sopenharmony_ci    0,                               /* tp_traverse */
27867db96d56Sopenharmony_ci    0,                               /* tp_clear */
27877db96d56Sopenharmony_ci    0,                               /* tp_richcompare */
27887db96d56Sopenharmony_ci    0,                               /* tp_weaklistoffset */
27897db96d56Sopenharmony_ci    0,                               /* tp_iter */
27907db96d56Sopenharmony_ci    0,                               /* tp_iternext */
27917db96d56Sopenharmony_ci    0,                               /* tp_methods */
27927db96d56Sopenharmony_ci    0,                               /* tp_members */
27937db96d56Sopenharmony_ci    0,                               /* tp_getset */
27947db96d56Sopenharmony_ci    0,                               /* tp_base */
27957db96d56Sopenharmony_ci    0,                               /* tp_dict */
27967db96d56Sopenharmony_ci    0,                               /* tp_descr_get */
27977db96d56Sopenharmony_ci    0,                               /* tp_descr_set */
27987db96d56Sopenharmony_ci    0,                               /* tp_dictoffset */
27997db96d56Sopenharmony_ci    staticarray_init,                /* tp_init */
28007db96d56Sopenharmony_ci    0,                               /* tp_alloc */
28017db96d56Sopenharmony_ci    staticarray_new,                 /* tp_new */
28027db96d56Sopenharmony_ci};
28037db96d56Sopenharmony_ci
28047db96d56Sopenharmony_ci
28057db96d56Sopenharmony_cistatic struct PyMethodDef _testbuffer_functions[] = {
28067db96d56Sopenharmony_ci    {"slice_indices", slice_indices, METH_VARARGS, NULL},
28077db96d56Sopenharmony_ci    {"get_pointer", get_pointer, METH_VARARGS, NULL},
28087db96d56Sopenharmony_ci    {"get_sizeof_void_p", get_sizeof_void_p, METH_NOARGS, NULL},
28097db96d56Sopenharmony_ci    {"get_contiguous", get_contiguous, METH_VARARGS, NULL},
28107db96d56Sopenharmony_ci    {"py_buffer_to_contiguous", py_buffer_to_contiguous, METH_VARARGS, NULL},
28117db96d56Sopenharmony_ci    {"is_contiguous", is_contiguous, METH_VARARGS, NULL},
28127db96d56Sopenharmony_ci    {"cmp_contig", cmp_contig, METH_VARARGS, NULL},
28137db96d56Sopenharmony_ci    {NULL, NULL}
28147db96d56Sopenharmony_ci};
28157db96d56Sopenharmony_ci
28167db96d56Sopenharmony_cistatic struct PyModuleDef _testbuffermodule = {
28177db96d56Sopenharmony_ci    PyModuleDef_HEAD_INIT,
28187db96d56Sopenharmony_ci    "_testbuffer",
28197db96d56Sopenharmony_ci    NULL,
28207db96d56Sopenharmony_ci    -1,
28217db96d56Sopenharmony_ci    _testbuffer_functions,
28227db96d56Sopenharmony_ci    NULL,
28237db96d56Sopenharmony_ci    NULL,
28247db96d56Sopenharmony_ci    NULL,
28257db96d56Sopenharmony_ci    NULL
28267db96d56Sopenharmony_ci};
28277db96d56Sopenharmony_ci
28287db96d56Sopenharmony_ci
28297db96d56Sopenharmony_ciPyMODINIT_FUNC
28307db96d56Sopenharmony_ciPyInit__testbuffer(void)
28317db96d56Sopenharmony_ci{
28327db96d56Sopenharmony_ci    PyObject *m;
28337db96d56Sopenharmony_ci
28347db96d56Sopenharmony_ci    m = PyModule_Create(&_testbuffermodule);
28357db96d56Sopenharmony_ci    if (m == NULL)
28367db96d56Sopenharmony_ci        return NULL;
28377db96d56Sopenharmony_ci
28387db96d56Sopenharmony_ci    Py_SET_TYPE(&NDArray_Type, &PyType_Type);
28397db96d56Sopenharmony_ci    Py_INCREF(&NDArray_Type);
28407db96d56Sopenharmony_ci    PyModule_AddObject(m, "ndarray", (PyObject *)&NDArray_Type);
28417db96d56Sopenharmony_ci
28427db96d56Sopenharmony_ci    Py_SET_TYPE(&StaticArray_Type, &PyType_Type);
28437db96d56Sopenharmony_ci    Py_INCREF(&StaticArray_Type);
28447db96d56Sopenharmony_ci    PyModule_AddObject(m, "staticarray", (PyObject *)&StaticArray_Type);
28457db96d56Sopenharmony_ci
28467db96d56Sopenharmony_ci    structmodule = PyImport_ImportModule("struct");
28477db96d56Sopenharmony_ci    if (structmodule == NULL)
28487db96d56Sopenharmony_ci        return NULL;
28497db96d56Sopenharmony_ci
28507db96d56Sopenharmony_ci    Struct = PyObject_GetAttrString(structmodule, "Struct");
28517db96d56Sopenharmony_ci    calcsize = PyObject_GetAttrString(structmodule, "calcsize");
28527db96d56Sopenharmony_ci    if (Struct == NULL || calcsize == NULL)
28537db96d56Sopenharmony_ci        return NULL;
28547db96d56Sopenharmony_ci
28557db96d56Sopenharmony_ci    simple_format = PyUnicode_FromString(simple_fmt);
28567db96d56Sopenharmony_ci    if (simple_format == NULL)
28577db96d56Sopenharmony_ci        return NULL;
28587db96d56Sopenharmony_ci
28597db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, ND_MAX_NDIM);
28607db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, ND_VAREXPORT);
28617db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, ND_WRITABLE);
28627db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, ND_FORTRAN);
28637db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, ND_SCALAR);
28647db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, ND_PIL);
28657db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, ND_GETBUF_FAIL);
28667db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, ND_GETBUF_UNDEFINED);
28677db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, ND_REDIRECT);
28687db96d56Sopenharmony_ci
28697db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_SIMPLE);
28707db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_WRITABLE);
28717db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_FORMAT);
28727db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_ND);
28737db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_STRIDES);
28747db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_INDIRECT);
28757db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_C_CONTIGUOUS);
28767db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_F_CONTIGUOUS);
28777db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_ANY_CONTIGUOUS);
28787db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_FULL);
28797db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_FULL_RO);
28807db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_RECORDS);
28817db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_RECORDS_RO);
28827db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_STRIDED);
28837db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_STRIDED_RO);
28847db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_CONTIG);
28857db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_CONTIG_RO);
28867db96d56Sopenharmony_ci
28877db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_READ);
28887db96d56Sopenharmony_ci    PyModule_AddIntMacro(m, PyBUF_WRITE);
28897db96d56Sopenharmony_ci
28907db96d56Sopenharmony_ci    return m;
28917db96d56Sopenharmony_ci}
28927db96d56Sopenharmony_ci
28937db96d56Sopenharmony_ci
28947db96d56Sopenharmony_ci
2895