_testbuffer.c revision 009b811d678f36cf63be4fe26f3fbaa38aa0078e
1/* C Extension module to test all aspects of PEP-3118.
2   Written by Stefan Krah. */
3
4
5#define PY_SSIZE_T_CLEAN
6
7#include "Python.h"
8
9
10/* struct module */
11PyObject *structmodule = NULL;
12PyObject *Struct = NULL;
13PyObject *calcsize = NULL;
14
15/* cache simple format string */
16static const char *simple_fmt = "B";
17PyObject *simple_format = NULL;
18#define SIMPLE_FORMAT(fmt) (fmt == NULL || strcmp(fmt, "B") == 0)
19#define FIX_FORMAT(fmt) (fmt == NULL ? "B" : fmt)
20
21
22/**************************************************************************/
23/*                             NDArray Object                             */
24/**************************************************************************/
25
26static PyTypeObject NDArray_Type;
27#define NDArray_Check(v) (Py_TYPE(v) == &NDArray_Type)
28
29#define CHECK_LIST_OR_TUPLE(v) \
30    if (!PyList_Check(v) && !PyTuple_Check(v)) { \
31        PyErr_SetString(PyExc_TypeError,         \
32            #v " must be a list or a tuple");    \
33        return NULL;                             \
34    }                                            \
35
36#define PyMem_XFree(v) \
37    do { if (v) PyMem_Free(v); } while (0)
38
39/* Maximum number of dimensions. */
40#define ND_MAX_NDIM (2 * PyBUF_MAX_NDIM)
41
42/* Check for the presence of suboffsets in the first dimension. */
43#define HAVE_PTR(suboffsets) (suboffsets && suboffsets[0] >= 0)
44/* Adjust ptr if suboffsets are present. */
45#define ADJUST_PTR(ptr, suboffsets) \
46    (HAVE_PTR(suboffsets) ? *((char**)ptr) + suboffsets[0] : ptr)
47
48/* Default: NumPy style (strides), read-only, no var-export, C-style layout */
49#define ND_DEFAULT          0x000
50/* User configurable flags for the ndarray */
51#define ND_VAREXPORT        0x001   /* change layout while buffers are exported */
52/* User configurable flags for each base buffer */
53#define ND_WRITABLE         0x002   /* mark base buffer as writable */
54#define ND_FORTRAN          0x004   /* Fortran contiguous layout */
55#define ND_SCALAR           0x008   /* scalar: ndim = 0 */
56#define ND_PIL              0x010   /* convert to PIL-style array (suboffsets) */
57#define ND_REDIRECT         0x020   /* redirect buffer requests */
58#define ND_GETBUF_FAIL      0x040   /* trigger getbuffer failure */
59#define ND_GETBUF_UNDEFINED 0x080   /* undefined view.obj */
60/* Internal flags for the base buffer */
61#define ND_C                0x100   /* C contiguous layout (default) */
62#define ND_OWN_ARRAYS       0x200   /* consumer owns arrays */
63
64/* ndarray properties */
65#define ND_IS_CONSUMER(nd) \
66    (((NDArrayObject *)nd)->head == &((NDArrayObject *)nd)->staticbuf)
67
68/* ndbuf->flags properties */
69#define ND_C_CONTIGUOUS(flags) (!!(flags&(ND_SCALAR|ND_C)))
70#define ND_FORTRAN_CONTIGUOUS(flags) (!!(flags&(ND_SCALAR|ND_FORTRAN)))
71#define ND_ANY_CONTIGUOUS(flags) (!!(flags&(ND_SCALAR|ND_C|ND_FORTRAN)))
72
73/* getbuffer() requests */
74#define REQ_INDIRECT(flags) ((flags&PyBUF_INDIRECT) == PyBUF_INDIRECT)
75#define REQ_C_CONTIGUOUS(flags) ((flags&PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS)
76#define REQ_F_CONTIGUOUS(flags) ((flags&PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS)
77#define REQ_ANY_CONTIGUOUS(flags) ((flags&PyBUF_ANY_CONTIGUOUS) == PyBUF_ANY_CONTIGUOUS)
78#define REQ_STRIDES(flags) ((flags&PyBUF_STRIDES) == PyBUF_STRIDES)
79#define REQ_SHAPE(flags) ((flags&PyBUF_ND) == PyBUF_ND)
80#define REQ_WRITABLE(flags) (flags&PyBUF_WRITABLE)
81#define REQ_FORMAT(flags) (flags&PyBUF_FORMAT)
82
83
84/* Single node of a list of base buffers. The list is needed to implement
85   changes in memory layout while exported buffers are active. */
86static PyTypeObject NDArray_Type;
87
88struct ndbuf;
89typedef struct ndbuf {
90    struct ndbuf *next;
91    struct ndbuf *prev;
92    Py_ssize_t len;     /* length of data */
93    Py_ssize_t offset;  /* start of the array relative to data */
94    char *data;         /* raw data */
95    int flags;          /* capabilities of the base buffer */
96    Py_ssize_t exports; /* number of exports */
97    Py_buffer base;     /* base buffer */
98} ndbuf_t;
99
100typedef struct {
101    PyObject_HEAD
102    int flags;          /* ndarray flags */
103    ndbuf_t staticbuf;  /* static buffer for re-exporting mode */
104    ndbuf_t *head;      /* currently active base buffer */
105} NDArrayObject;
106
107
108static ndbuf_t *
109ndbuf_new(Py_ssize_t nitems, Py_ssize_t itemsize, Py_ssize_t offset, int flags)
110{
111    ndbuf_t *ndbuf;
112    Py_buffer *base;
113    Py_ssize_t len;
114
115    len = nitems * itemsize;
116    if (offset % itemsize) {
117        PyErr_SetString(PyExc_ValueError,
118            "offset must be a multiple of itemsize");
119        return NULL;
120    }
121    if (offset < 0 || offset+itemsize > len) {
122        PyErr_SetString(PyExc_ValueError, "offset out of bounds");
123        return NULL;
124    }
125
126    ndbuf = PyMem_Malloc(sizeof *ndbuf);
127    if (ndbuf == NULL) {
128        PyErr_NoMemory();
129        return NULL;
130    }
131
132    ndbuf->next = NULL;
133    ndbuf->prev = NULL;
134    ndbuf->len = len;
135    ndbuf->offset= offset;
136
137    ndbuf->data = PyMem_Malloc(len);
138    if (ndbuf->data == NULL) {
139        PyErr_NoMemory();
140        PyMem_Free(ndbuf);
141        return NULL;
142    }
143
144    ndbuf->flags = flags;
145    ndbuf->exports = 0;
146
147    base = &ndbuf->base;
148    base->obj = NULL;
149    base->buf = ndbuf->data;
150    base->len = len;
151    base->itemsize = 1;
152    base->readonly = 0;
153    base->format = NULL;
154    base->ndim = 1;
155    base->shape = NULL;
156    base->strides = NULL;
157    base->suboffsets = NULL;
158    base->internal = ndbuf;
159
160    return ndbuf;
161}
162
163static void
164ndbuf_free(ndbuf_t *ndbuf)
165{
166    Py_buffer *base = &ndbuf->base;
167
168    PyMem_XFree(ndbuf->data);
169    PyMem_XFree(base->format);
170    PyMem_XFree(base->shape);
171    PyMem_XFree(base->strides);
172    PyMem_XFree(base->suboffsets);
173
174    PyMem_Free(ndbuf);
175}
176
177static void
178ndbuf_push(NDArrayObject *nd, ndbuf_t *elt)
179{
180    elt->next = nd->head;
181    if (nd->head) nd->head->prev = elt;
182    nd->head = elt;
183    elt->prev = NULL;
184}
185
186static void
187ndbuf_delete(NDArrayObject *nd, ndbuf_t *elt)
188{
189    if (elt->prev)
190        elt->prev->next = elt->next;
191    else
192        nd->head = elt->next;
193
194    if (elt->next)
195        elt->next->prev = elt->prev;
196
197    ndbuf_free(elt);
198}
199
200static void
201ndbuf_pop(NDArrayObject *nd)
202{
203    ndbuf_delete(nd, nd->head);
204}
205
206
207static PyObject *
208ndarray_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
209{
210    NDArrayObject *nd;
211
212    nd = PyObject_New(NDArrayObject, &NDArray_Type);
213    if (nd == NULL)
214        return NULL;
215
216    nd->flags = 0;
217    nd->head = NULL;
218    return (PyObject *)nd;
219}
220
221static void
222ndarray_dealloc(NDArrayObject *self)
223{
224    if (self->head) {
225        if (ND_IS_CONSUMER(self)) {
226            Py_buffer *base = &self->head->base;
227            if (self->head->flags & ND_OWN_ARRAYS) {
228                PyMem_XFree(base->shape);
229                PyMem_XFree(base->strides);
230                PyMem_XFree(base->suboffsets);
231            }
232            PyBuffer_Release(base);
233        }
234        else {
235            while (self->head)
236                ndbuf_pop(self);
237        }
238    }
239    PyObject_Del(self);
240}
241
242static int
243ndarray_init_staticbuf(PyObject *exporter, NDArrayObject *nd, int flags)
244{
245    Py_buffer *base = &nd->staticbuf.base;
246
247    if (PyObject_GetBuffer(exporter, base, flags) < 0)
248        return -1;
249
250    nd->head = &nd->staticbuf;
251
252    nd->head->next = NULL;
253    nd->head->prev = NULL;
254    nd->head->len = -1;
255    nd->head->offset = -1;
256    nd->head->data = NULL;
257
258    nd->head->flags = base->readonly ? 0 : ND_WRITABLE;
259    nd->head->exports = 0;
260
261    return 0;
262}
263
264static void
265init_flags(ndbuf_t *ndbuf)
266{
267    if (ndbuf->base.ndim == 0)
268        ndbuf->flags |= ND_SCALAR;
269    if (ndbuf->base.suboffsets)
270        ndbuf->flags |= ND_PIL;
271    if (PyBuffer_IsContiguous(&ndbuf->base, 'C'))
272        ndbuf->flags |= ND_C;
273    if (PyBuffer_IsContiguous(&ndbuf->base, 'F'))
274        ndbuf->flags |= ND_FORTRAN;
275}
276
277
278/****************************************************************************/
279/*                          Buffer/List conversions                         */
280/****************************************************************************/
281
282static Py_ssize_t *strides_from_shape(const ndbuf_t *, int flags);
283
284/* Get number of members in a struct: see issue #12740 */
285typedef struct {
286    PyObject_HEAD
287    Py_ssize_t s_size;
288    Py_ssize_t s_len;
289} PyPartialStructObject;
290
291static Py_ssize_t
292get_nmemb(PyObject *s)
293{
294    return ((PyPartialStructObject *)s)->s_len;
295}
296
297/* Pack all items into the buffer of 'obj'. The 'format' parameter must be
298   in struct module syntax. For standard C types, a single item is an integer.
299   For compound types, a single item is a tuple of integers. */
300static int
301pack_from_list(PyObject *obj, PyObject *items, PyObject *format,
302               Py_ssize_t itemsize)
303{
304    PyObject *structobj, *pack_into;
305    PyObject *args, *offset;
306    PyObject *item, *tmp;
307    Py_ssize_t nitems; /* number of items */
308    Py_ssize_t nmemb;  /* number of members in a single item */
309    Py_ssize_t i, j;
310    int ret = 0;
311
312    assert(PyObject_CheckBuffer(obj));
313    assert(PyList_Check(items) || PyTuple_Check(items));
314
315    structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL);
316    if (structobj == NULL)
317        return -1;
318
319    nitems = PySequence_Fast_GET_SIZE(items);
320    nmemb = get_nmemb(structobj);
321    assert(nmemb >= 1);
322
323    pack_into = PyObject_GetAttrString(structobj, "pack_into");
324    if (pack_into == NULL) {
325        Py_DECREF(structobj);
326        return -1;
327    }
328
329    /* nmemb >= 1 */
330    args = PyTuple_New(2 + nmemb);
331    if (args == NULL) {
332        Py_DECREF(pack_into);
333        Py_DECREF(structobj);
334        return -1;
335    }
336
337    offset = NULL;
338    for (i = 0; i < nitems; i++) {
339        /* Loop invariant: args[j] are borrowed references or NULL. */
340        PyTuple_SET_ITEM(args, 0, obj);
341        for (j = 1; j < 2+nmemb; j++)
342            PyTuple_SET_ITEM(args, j, NULL);
343
344        Py_XDECREF(offset);
345        offset = PyLong_FromSsize_t(i*itemsize);
346        if (offset == NULL) {
347            ret = -1;
348            break;
349        }
350        PyTuple_SET_ITEM(args, 1, offset);
351
352        item = PySequence_Fast_GET_ITEM(items, i);
353        if ((PyBytes_Check(item) || PyLong_Check(item) ||
354             PyFloat_Check(item)) && nmemb == 1) {
355            PyTuple_SET_ITEM(args, 2, item);
356        }
357        else if ((PyList_Check(item) || PyTuple_Check(item)) &&
358                 PySequence_Length(item) == nmemb) {
359            for (j = 0; j < nmemb; j++) {
360                tmp = PySequence_Fast_GET_ITEM(item, j);
361                PyTuple_SET_ITEM(args, 2+j, tmp);
362            }
363        }
364        else {
365            PyErr_SetString(PyExc_ValueError,
366                "mismatch between initializer element and format string");
367            ret = -1;
368            break;
369        }
370
371        tmp = PyObject_CallObject(pack_into, args);
372        if (tmp == NULL) {
373            ret = -1;
374            break;
375        }
376        Py_DECREF(tmp);
377    }
378
379    Py_INCREF(obj); /* args[0] */
380    /* args[1]: offset is either NULL or should be dealloc'd */
381    for (i = 2; i < 2+nmemb; i++) {
382        tmp = PyTuple_GET_ITEM(args, i);
383        Py_XINCREF(tmp);
384    }
385    Py_DECREF(args);
386
387    Py_DECREF(pack_into);
388    Py_DECREF(structobj);
389    return ret;
390
391}
392
393/* Pack single element */
394static int
395pack_single(char *ptr, PyObject *item, const char *fmt, Py_ssize_t itemsize)
396{
397    PyObject *structobj = NULL, *pack_into = NULL, *args = NULL;
398    PyObject *format = NULL, *mview = NULL, *zero = NULL;
399    Py_ssize_t i, nmemb;
400    int ret = -1;
401    PyObject *x;
402
403    if (fmt == NULL) fmt = "B";
404
405    format = PyUnicode_FromString(fmt);
406    if (format == NULL)
407        goto out;
408
409    structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL);
410    if (structobj == NULL)
411        goto out;
412
413    nmemb = get_nmemb(structobj);
414    assert(nmemb >= 1);
415
416    mview = PyMemoryView_FromMemory(ptr, itemsize, PyBUF_WRITE);
417    if (mview == NULL)
418        goto out;
419
420    zero = PyLong_FromLong(0);
421    if (zero == NULL)
422        goto out;
423
424    pack_into = PyObject_GetAttrString(structobj, "pack_into");
425    if (pack_into == NULL)
426        goto out;
427
428    args = PyTuple_New(2+nmemb);
429    if (args == NULL)
430        goto out;
431
432    PyTuple_SET_ITEM(args, 0, mview);
433    PyTuple_SET_ITEM(args, 1, zero);
434
435    if ((PyBytes_Check(item) || PyLong_Check(item) ||
436         PyFloat_Check(item)) && nmemb == 1) {
437         PyTuple_SET_ITEM(args, 2, item);
438    }
439    else if ((PyList_Check(item) || PyTuple_Check(item)) &&
440             PySequence_Length(item) == nmemb) {
441        for (i = 0; i < nmemb; i++) {
442            x = PySequence_Fast_GET_ITEM(item, i);
443            PyTuple_SET_ITEM(args, 2+i, x);
444        }
445    }
446    else {
447        PyErr_SetString(PyExc_ValueError,
448            "mismatch between initializer element and format string");
449        goto args_out;
450    }
451
452    x = PyObject_CallObject(pack_into, args);
453    if (x != NULL) {
454        Py_DECREF(x);
455        ret = 0;
456    }
457
458
459args_out:
460    for (i = 0; i < 2+nmemb; i++)
461        Py_XINCREF(PyTuple_GET_ITEM(args, i));
462    Py_XDECREF(args);
463out:
464    Py_XDECREF(pack_into);
465    Py_XDECREF(zero);
466    Py_XDECREF(mview);
467    Py_XDECREF(structobj);
468    Py_XDECREF(format);
469    return ret;
470}
471
472static void
473copy_rec(const Py_ssize_t *shape, Py_ssize_t ndim, Py_ssize_t itemsize,
474         char *dptr, const Py_ssize_t *dstrides, const Py_ssize_t *dsuboffsets,
475         char *sptr, const Py_ssize_t *sstrides, const Py_ssize_t *ssuboffsets,
476         char *mem)
477{
478    Py_ssize_t i;
479
480    assert(ndim >= 1);
481
482    if (ndim == 1) {
483        if (!HAVE_PTR(dsuboffsets) && !HAVE_PTR(ssuboffsets) &&
484            dstrides[0] == itemsize && sstrides[0] == itemsize) {
485            memmove(dptr, sptr, shape[0] * itemsize);
486        }
487        else {
488            char *p;
489            assert(mem != NULL);
490            for (i=0, p=mem; i<shape[0]; p+=itemsize, sptr+=sstrides[0], i++) {
491                char *xsptr = ADJUST_PTR(sptr, ssuboffsets);
492                memcpy(p, xsptr, itemsize);
493            }
494            for (i=0, p=mem; i<shape[0]; p+=itemsize, dptr+=dstrides[0], i++) {
495                char *xdptr = ADJUST_PTR(dptr, dsuboffsets);
496                memcpy(xdptr, p, itemsize);
497            }
498        }
499        return;
500    }
501
502    for (i = 0; i < shape[0]; dptr+=dstrides[0], sptr+=sstrides[0], i++) {
503        char *xdptr = ADJUST_PTR(dptr, dsuboffsets);
504        char *xsptr = ADJUST_PTR(sptr, ssuboffsets);
505
506        copy_rec(shape+1, ndim-1, itemsize,
507                 xdptr, dstrides+1, dsuboffsets ? dsuboffsets+1 : NULL,
508                 xsptr, sstrides+1, ssuboffsets ? ssuboffsets+1 : NULL,
509                 mem);
510    }
511}
512
513static int
514cmp_structure(Py_buffer *dest, Py_buffer *src)
515{
516    Py_ssize_t i;
517
518    if (strcmp(FIX_FORMAT(dest->format), FIX_FORMAT(src->format)) != 0 ||
519        dest->itemsize != src->itemsize ||
520        dest->ndim != src->ndim)
521        return -1;
522
523    for (i = 0; i < dest->ndim; i++) {
524        if (dest->shape[i] != src->shape[i])
525            return -1;
526        if (dest->shape[i] == 0)
527            break;
528    }
529
530    return 0;
531}
532
533/* Copy src to dest. Both buffers must have the same format, itemsize,
534   ndim and shape. Copying is atomic, the function never fails with
535   a partial copy. */
536static int
537copy_buffer(Py_buffer *dest, Py_buffer *src)
538{
539    char *mem = NULL;
540
541    assert(dest->ndim > 0);
542
543    if (cmp_structure(dest, src) < 0) {
544        PyErr_SetString(PyExc_ValueError,
545            "ndarray assignment: lvalue and rvalue have different structures");
546        return -1;
547    }
548
549    if ((dest->suboffsets && dest->suboffsets[dest->ndim-1] >= 0) ||
550        (src->suboffsets && src->suboffsets[src->ndim-1] >= 0) ||
551        dest->strides[dest->ndim-1] != dest->itemsize ||
552        src->strides[src->ndim-1] != src->itemsize) {
553        mem = PyMem_Malloc(dest->shape[dest->ndim-1] * dest->itemsize);
554        if (mem == NULL) {
555            PyErr_NoMemory();
556            return -1;
557        }
558    }
559
560    copy_rec(dest->shape, dest->ndim, dest->itemsize,
561             dest->buf, dest->strides, dest->suboffsets,
562             src->buf, src->strides, src->suboffsets,
563             mem);
564
565    PyMem_XFree(mem);
566    return 0;
567}
568
569
570/* Unpack single element */
571static PyObject *
572unpack_single(char *ptr, const char *fmt, Py_ssize_t itemsize)
573{
574    PyObject *x, *unpack_from, *mview;
575
576    if (fmt == NULL) {
577        fmt = "B";
578        itemsize = 1;
579    }
580
581    unpack_from = PyObject_GetAttrString(structmodule, "unpack_from");
582    if (unpack_from == NULL)
583        return NULL;
584
585    mview = PyMemoryView_FromMemory(ptr, itemsize, PyBUF_READ);
586    if (mview == NULL) {
587        Py_DECREF(unpack_from);
588        return NULL;
589    }
590
591    x = PyObject_CallFunction(unpack_from, "sO", fmt, mview);
592    Py_DECREF(unpack_from);
593    Py_DECREF(mview);
594    if (x == NULL)
595        return NULL;
596
597    if (PyTuple_GET_SIZE(x) == 1) {
598        PyObject *tmp = PyTuple_GET_ITEM(x, 0);
599        Py_INCREF(tmp);
600        Py_DECREF(x);
601        return tmp;
602    }
603
604    return x;
605}
606
607/* Unpack a multi-dimensional matrix into a nested list. Return a scalar
608   for ndim = 0. */
609static PyObject *
610unpack_rec(PyObject *unpack_from, char *ptr, PyObject *mview, char *item,
611           const Py_ssize_t *shape, const Py_ssize_t *strides,
612           const Py_ssize_t *suboffsets, Py_ssize_t ndim, Py_ssize_t itemsize)
613{
614    PyObject *lst, *x;
615    Py_ssize_t i;
616
617    assert(ndim >= 0);
618    assert(shape != NULL);
619    assert(strides != NULL);
620
621    if (ndim == 0) {
622        memcpy(item, ptr, itemsize);
623        x = PyObject_CallFunctionObjArgs(unpack_from, mview, NULL);
624        if (x == NULL)
625            return NULL;
626        if (PyTuple_GET_SIZE(x) == 1) {
627            PyObject *tmp = PyTuple_GET_ITEM(x, 0);
628            Py_INCREF(tmp);
629            Py_DECREF(x);
630            return tmp;
631        }
632        return x;
633    }
634
635    lst = PyList_New(shape[0]);
636    if (lst == NULL)
637        return NULL;
638
639    for (i = 0; i < shape[0]; ptr+=strides[0], i++) {
640        char *nextptr = ADJUST_PTR(ptr, suboffsets);
641
642        x = unpack_rec(unpack_from, nextptr, mview, item,
643                       shape+1, strides+1, suboffsets ? suboffsets+1 : NULL,
644                       ndim-1, itemsize);
645        if (x == NULL) {
646            Py_DECREF(lst);
647            return NULL;
648        }
649
650        PyList_SET_ITEM(lst, i, x);
651    }
652
653    return lst;
654}
655
656
657static PyObject *
658ndarray_as_list(NDArrayObject *nd)
659{
660    PyObject *structobj = NULL, *unpack_from = NULL;
661    PyObject *lst = NULL, *mview = NULL;
662    Py_buffer *base = &nd->head->base;
663    Py_ssize_t *shape = base->shape;
664    Py_ssize_t *strides = base->strides;
665    Py_ssize_t simple_shape[1];
666    Py_ssize_t simple_strides[1];
667    char *item = NULL;
668    PyObject *format;
669    char *fmt = base->format;
670
671    base = &nd->head->base;
672
673    if (fmt == NULL) {
674        PyErr_SetString(PyExc_ValueError,
675            "ndarray: tolist() does not support format=NULL, use "
676            "tobytes()");
677        return NULL;
678    }
679    if (shape == NULL) {
680        assert(ND_C_CONTIGUOUS(nd->head->flags));
681        assert(base->strides == NULL);
682        assert(base->ndim <= 1);
683        shape = simple_shape;
684        shape[0] = base->len;
685        strides = simple_strides;
686        strides[0] = base->itemsize;
687    }
688    else if (strides == NULL) {
689        assert(ND_C_CONTIGUOUS(nd->head->flags));
690        strides = strides_from_shape(nd->head, 0);
691        if (strides == NULL)
692            return NULL;
693    }
694
695    format = PyUnicode_FromString(fmt);
696    if (format == NULL)
697        goto out;
698
699    structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL);
700    Py_DECREF(format);
701    if (structobj == NULL)
702        goto out;
703
704    unpack_from = PyObject_GetAttrString(structobj, "unpack_from");
705    if (unpack_from == NULL)
706        goto out;
707
708    item = PyMem_Malloc(base->itemsize);
709    if (item == NULL) {
710        PyErr_NoMemory();
711        goto out;
712    }
713
714    mview = PyMemoryView_FromMemory(item, base->itemsize, PyBUF_WRITE);
715    if (mview == NULL)
716        goto out;
717
718    lst = unpack_rec(unpack_from, base->buf, mview, item,
719                     shape, strides, base->suboffsets,
720                     base->ndim, base->itemsize);
721
722out:
723    Py_XDECREF(mview);
724    PyMem_XFree(item);
725    Py_XDECREF(unpack_from);
726    Py_XDECREF(structobj);
727    if (strides != base->strides && strides != simple_strides)
728        PyMem_XFree(strides);
729
730    return lst;
731}
732
733
734/****************************************************************************/
735/*                            Initialize ndbuf                              */
736/****************************************************************************/
737
738/*
739   State of a new ndbuf during initialization. 'OK' means that initialization
740   is complete. 'PTR' means that a pointer has been initialized, but the
741   state of the memory is still undefined and ndbuf->offset is disregarded.
742
743  +-----------------+-----------+-------------+----------------+
744  |                 | ndbuf_new | init_simple | init_structure |
745  +-----------------+-----------+-------------+----------------+
746  | next            | OK (NULL) |     OK      |       OK       |
747  +-----------------+-----------+-------------+----------------+
748  | prev            | OK (NULL) |     OK      |       OK       |
749  +-----------------+-----------+-------------+----------------+
750  | len             |    OK     |     OK      |       OK       |
751  +-----------------+-----------+-------------+----------------+
752  | offset          |    OK     |     OK      |       OK       |
753  +-----------------+-----------+-------------+----------------+
754  | data            |    PTR    |     OK      |       OK       |
755  +-----------------+-----------+-------------+----------------+
756  | flags           |    user   |    user     |       OK       |
757  +-----------------+-----------+-------------+----------------+
758  | exports         |   OK (0)  |     OK      |       OK       |
759  +-----------------+-----------+-------------+----------------+
760  | base.obj        | OK (NULL) |     OK      |       OK       |
761  +-----------------+-----------+-------------+----------------+
762  | base.buf        |    PTR    |     PTR     |       OK       |
763  +-----------------+-----------+-------------+----------------+
764  | base.len        | len(data) |  len(data)  |       OK       |
765  +-----------------+-----------+-------------+----------------+
766  | base.itemsize   |     1     |     OK      |       OK       |
767  +-----------------+-----------+-------------+----------------+
768  | base.readonly   |     0     |     OK      |       OK       |
769  +-----------------+-----------+-------------+----------------+
770  | base.format     |    NULL   |     OK      |       OK       |
771  +-----------------+-----------+-------------+----------------+
772  | base.ndim       |     1     |      1      |       OK       |
773  +-----------------+-----------+-------------+----------------+
774  | base.shape      |    NULL   |    NULL     |       OK       |
775  +-----------------+-----------+-------------+----------------+
776  | base.strides    |    NULL   |    NULL     |       OK       |
777  +-----------------+-----------+-------------+----------------+
778  | base.suboffsets |    NULL   |    NULL     |       OK       |
779  +-----------------+-----------+-------------+----------------+
780  | base.internal   |    OK     |    OK       |       OK       |
781  +-----------------+-----------+-------------+----------------+
782
783*/
784
785static Py_ssize_t
786get_itemsize(PyObject *format)
787{
788    PyObject *tmp;
789    Py_ssize_t itemsize;
790
791    tmp = PyObject_CallFunctionObjArgs(calcsize, format, NULL);
792    if (tmp == NULL)
793        return -1;
794    itemsize = PyLong_AsSsize_t(tmp);
795    Py_DECREF(tmp);
796
797    return itemsize;
798}
799
800static char *
801get_format(PyObject *format)
802{
803    PyObject *tmp;
804    char *fmt;
805
806    tmp = PyUnicode_AsASCIIString(format);
807    if (tmp == NULL)
808        return NULL;
809    fmt = PyMem_Malloc(PyBytes_GET_SIZE(tmp)+1);
810    if (fmt == NULL) {
811        PyErr_NoMemory();
812        Py_DECREF(tmp);
813        return NULL;
814    }
815    strcpy(fmt, PyBytes_AS_STRING(tmp));
816    Py_DECREF(tmp);
817
818    return fmt;
819}
820
821static int
822init_simple(ndbuf_t *ndbuf, PyObject *items, PyObject *format,
823            Py_ssize_t itemsize)
824{
825    PyObject *mview;
826    Py_buffer *base = &ndbuf->base;
827    int ret;
828
829    mview = PyMemoryView_FromBuffer(base);
830    if (mview == NULL)
831        return -1;
832
833    ret = pack_from_list(mview, items, format, itemsize);
834    Py_DECREF(mview);
835    if (ret < 0)
836        return -1;
837
838    base->readonly = !(ndbuf->flags & ND_WRITABLE);
839    base->itemsize = itemsize;
840    base->format = get_format(format);
841    if (base->format == NULL)
842        return -1;
843
844    return 0;
845}
846
847static Py_ssize_t *
848seq_as_ssize_array(PyObject *seq, Py_ssize_t len, int is_shape)
849{
850    Py_ssize_t *dest;
851    Py_ssize_t x, i;
852
853    dest = PyMem_New(Py_ssize_t, len);
854    if (dest == NULL) {
855        PyErr_NoMemory();
856        return NULL;
857    }
858
859    for (i = 0; i < len; i++) {
860        PyObject *tmp = PySequence_Fast_GET_ITEM(seq, i);
861        if (!PyLong_Check(tmp)) {
862            PyErr_Format(PyExc_ValueError,
863                "elements of %s must be integers",
864                is_shape ? "shape" : "strides");
865            PyMem_Free(dest);
866            return NULL;
867        }
868        x = PyLong_AsSsize_t(tmp);
869        if (PyErr_Occurred()) {
870            PyMem_Free(dest);
871            return NULL;
872        }
873        if (is_shape && x < 0) {
874            PyErr_Format(PyExc_ValueError,
875                "elements of shape must be integers >= 0");
876            PyMem_Free(dest);
877            return NULL;
878        }
879        dest[i] = x;
880    }
881
882    return dest;
883}
884
885static Py_ssize_t *
886strides_from_shape(const ndbuf_t *ndbuf, int flags)
887{
888    const Py_buffer *base = &ndbuf->base;
889    Py_ssize_t *s, i;
890
891    s = PyMem_Malloc(base->ndim * (sizeof *s));
892    if (s == NULL) {
893        PyErr_NoMemory();
894        return NULL;
895    }
896
897    if (flags & ND_FORTRAN) {
898        s[0] = base->itemsize;
899        for (i = 1; i < base->ndim; i++)
900            s[i] = s[i-1] * base->shape[i-1];
901    }
902    else {
903        s[base->ndim-1] = base->itemsize;
904        for (i = base->ndim-2; i >= 0; i--)
905            s[i] = s[i+1] * base->shape[i+1];
906    }
907
908    return s;
909}
910
911/* Bounds check:
912
913     len := complete length of allocated memory
914     offset := start of the array
915
916     A single array element is indexed by:
917
918       i = indices[0] * strides[0] + indices[1] * strides[1] + ...
919
920     imin is reached when all indices[n] combined with positive strides are 0
921     and all indices combined with negative strides are shape[n]-1, which is
922     the maximum index for the nth dimension.
923
924     imax is reached when all indices[n] combined with negative strides are 0
925     and all indices combined with positive strides are shape[n]-1.
926*/
927static int
928verify_structure(Py_ssize_t len, Py_ssize_t itemsize, Py_ssize_t offset,
929                 const Py_ssize_t *shape, const Py_ssize_t *strides,
930                 Py_ssize_t ndim)
931{
932    Py_ssize_t imin, imax;
933    Py_ssize_t n;
934
935    assert(ndim >= 0);
936
937    if (ndim == 0 && (offset < 0 || offset+itemsize > len))
938        goto invalid_combination;
939
940    for (n = 0; n < ndim; n++)
941        if (strides[n] % itemsize) {
942            PyErr_SetString(PyExc_ValueError,
943            "strides must be a multiple of itemsize");
944            return -1;
945        }
946
947    for (n = 0; n < ndim; n++)
948        if (shape[n] == 0)
949            return 0;
950
951    imin = imax = 0;
952    for (n = 0; n < ndim; n++)
953        if (strides[n] <= 0)
954            imin += (shape[n]-1) * strides[n];
955        else
956            imax += (shape[n]-1) * strides[n];
957
958    if (imin + offset < 0 || imax + offset + itemsize > len)
959        goto invalid_combination;
960
961    return 0;
962
963
964invalid_combination:
965    PyErr_SetString(PyExc_ValueError,
966        "invalid combination of buffer, shape and strides");
967    return -1;
968}
969
970/*
971   Convert a NumPy-style array to an array using suboffsets to stride in
972   the first dimension. Requirements: ndim > 0.
973
974   Contiguous example
975   ==================
976
977     Input:
978     ------
979       shape      = {2, 2, 3};
980       strides    = {6, 3, 1};
981       suboffsets = NULL;
982       data       = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
983       buf        = &data[0]
984
985     Output:
986     -------
987       shape      = {2, 2, 3};
988       strides    = {sizeof(char *), 3, 1};
989       suboffsets = {0, -1, -1};
990       data       = {p1, p2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
991                     |   |   ^                 ^
992                     `---'---'                 |
993                         |                     |
994                         `---------------------'
995       buf        = &data[0]
996
997     So, in the example the input resembles the three-dimensional array
998     char v[2][2][3], while the output resembles an array of two pointers
999     to two-dimensional arrays: char (*v[2])[2][3].
1000
1001
1002   Non-contiguous example:
1003   =======================
1004
1005     Input (with offset and negative strides):
1006     -----------------------------------------
1007       shape      = {2, 2, 3};
1008       strides    = {-6, 3, -1};
1009       offset     = 8
1010       suboffsets = NULL;
1011       data       = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
1012
1013     Output:
1014     -------
1015       shape      = {2, 2, 3};
1016       strides    = {-sizeof(char *), 3, -1};
1017       suboffsets = {2, -1, -1};
1018       newdata    = {p1, p2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
1019                     |   |   ^     ^           ^     ^
1020                     `---'---'     |           |     `- p2+suboffsets[0]
1021                         |         `-----------|--- p1+suboffsets[0]
1022                         `---------------------'
1023       buf        = &newdata[1]  # striding backwards over the pointers.
1024
1025     suboffsets[0] is the same as the offset that one would specify if
1026     the two {2, 3} subarrays were created directly, hence the name.
1027*/
1028static int
1029init_suboffsets(ndbuf_t *ndbuf)
1030{
1031    Py_buffer *base = &ndbuf->base;
1032    Py_ssize_t start, step;
1033    Py_ssize_t imin, suboffset0;
1034    Py_ssize_t addsize;
1035    Py_ssize_t n;
1036    char *data;
1037
1038    assert(base->ndim > 0);
1039    assert(base->suboffsets == NULL);
1040
1041    /* Allocate new data with additional space for shape[0] pointers. */
1042    addsize = base->shape[0] * (sizeof (char *));
1043
1044    /* Align array start to a multiple of 8. */
1045    addsize = 8 * ((addsize + 7) / 8);
1046
1047    data = PyMem_Malloc(ndbuf->len + addsize);
1048    if (data == NULL) {
1049        PyErr_NoMemory();
1050        return -1;
1051    }
1052
1053    memcpy(data + addsize, ndbuf->data, ndbuf->len);
1054
1055    PyMem_Free(ndbuf->data);
1056    ndbuf->data = data;
1057    ndbuf->len += addsize;
1058    base->buf = ndbuf->data;
1059
1060    /* imin: minimum index of the input array relative to ndbuf->offset.
1061       suboffset0: offset for each sub-array of the output. This is the
1062                   same as calculating -imin' for a sub-array of ndim-1. */
1063    imin = suboffset0 = 0;
1064    for (n = 0; n < base->ndim; n++) {
1065        if (base->shape[n] == 0)
1066            break;
1067        if (base->strides[n] <= 0) {
1068            Py_ssize_t x = (base->shape[n]-1) * base->strides[n];
1069            imin += x;
1070            suboffset0 += (n >= 1) ? -x : 0;
1071        }
1072    }
1073
1074    /* Initialize the array of pointers to the sub-arrays. */
1075    start = addsize + ndbuf->offset + imin;
1076    step = base->strides[0] < 0 ? -base->strides[0] : base->strides[0];
1077
1078    for (n = 0; n < base->shape[0]; n++)
1079        ((char **)base->buf)[n] = (char *)base->buf + start + n*step;
1080
1081    /* Initialize suboffsets. */
1082    base->suboffsets = PyMem_Malloc(base->ndim * (sizeof *base->suboffsets));
1083    if (base->suboffsets == NULL) {
1084        PyErr_NoMemory();
1085        return -1;
1086    }
1087    base->suboffsets[0] = suboffset0;
1088    for (n = 1; n < base->ndim; n++)
1089        base->suboffsets[n] = -1;
1090
1091    /* Adjust strides for the first (zeroth) dimension. */
1092    if (base->strides[0] >= 0) {
1093        base->strides[0] = sizeof(char *);
1094    }
1095    else {
1096        /* Striding backwards. */
1097        base->strides[0] = -(Py_ssize_t)sizeof(char *);
1098        if (base->shape[0] > 0)
1099            base->buf = (char *)base->buf + (base->shape[0]-1) * sizeof(char *);
1100    }
1101
1102    ndbuf->flags &= ~(ND_C|ND_FORTRAN);
1103    ndbuf->offset = 0;
1104    return 0;
1105}
1106
1107static void
1108init_len(Py_buffer *base)
1109{
1110    Py_ssize_t i;
1111
1112    base->len = 1;
1113    for (i = 0; i < base->ndim; i++)
1114        base->len *= base->shape[i];
1115    base->len *= base->itemsize;
1116}
1117
1118static int
1119init_structure(ndbuf_t *ndbuf, PyObject *shape, PyObject *strides,
1120               Py_ssize_t ndim)
1121{
1122    Py_buffer *base = &ndbuf->base;
1123
1124    base->ndim = (int)ndim;
1125    if (ndim == 0) {
1126        if (ndbuf->flags & ND_PIL) {
1127            PyErr_SetString(PyExc_TypeError,
1128                "ndim = 0 cannot be used in conjunction with ND_PIL");
1129            return -1;
1130        }
1131        ndbuf->flags |= (ND_SCALAR|ND_C|ND_FORTRAN);
1132        return 0;
1133    }
1134
1135    /* shape */
1136    base->shape = seq_as_ssize_array(shape, ndim, 1);
1137    if (base->shape == NULL)
1138        return -1;
1139
1140    /* strides */
1141    if (strides) {
1142        base->strides = seq_as_ssize_array(strides, ndim, 0);
1143    }
1144    else {
1145        base->strides = strides_from_shape(ndbuf, ndbuf->flags);
1146    }
1147    if (base->strides == NULL)
1148        return -1;
1149    if (verify_structure(base->len, base->itemsize, ndbuf->offset,
1150                         base->shape, base->strides, ndim) < 0)
1151        return -1;
1152
1153    /* buf */
1154    base->buf = ndbuf->data + ndbuf->offset;
1155
1156    /* len */
1157    init_len(base);
1158
1159    /* ndbuf->flags */
1160    if (PyBuffer_IsContiguous(base, 'C'))
1161        ndbuf->flags |= ND_C;
1162    if (PyBuffer_IsContiguous(base, 'F'))
1163        ndbuf->flags |= ND_FORTRAN;
1164
1165
1166    /* convert numpy array to suboffset representation */
1167    if (ndbuf->flags & ND_PIL) {
1168        /* modifies base->buf, base->strides and base->suboffsets **/
1169        return init_suboffsets(ndbuf);
1170    }
1171
1172    return 0;
1173}
1174
1175static ndbuf_t *
1176init_ndbuf(PyObject *items, PyObject *shape, PyObject *strides,
1177           Py_ssize_t offset, PyObject *format, int flags)
1178{
1179    ndbuf_t *ndbuf;
1180    Py_ssize_t ndim;
1181    Py_ssize_t nitems;
1182    Py_ssize_t itemsize;
1183
1184    /* ndim = len(shape) */
1185    CHECK_LIST_OR_TUPLE(shape)
1186    ndim = PySequence_Fast_GET_SIZE(shape);
1187    if (ndim > ND_MAX_NDIM) {
1188        PyErr_Format(PyExc_ValueError,
1189            "ndim must not exceed %d", ND_MAX_NDIM);
1190        return NULL;
1191    }
1192
1193    /* len(strides) = len(shape) */
1194    if (strides) {
1195        CHECK_LIST_OR_TUPLE(strides)
1196        if (PySequence_Fast_GET_SIZE(strides) == 0)
1197            strides = NULL;
1198        else if (flags & ND_FORTRAN) {
1199            PyErr_SetString(PyExc_TypeError,
1200                "ND_FORTRAN cannot be used together with strides");
1201            return NULL;
1202        }
1203        else if (PySequence_Fast_GET_SIZE(strides) != ndim) {
1204            PyErr_SetString(PyExc_ValueError,
1205                "len(shape) != len(strides)");
1206            return NULL;
1207        }
1208    }
1209
1210    /* itemsize */
1211    itemsize = get_itemsize(format);
1212    if (itemsize <= 0) {
1213        if (itemsize == 0) {
1214            PyErr_SetString(PyExc_ValueError,
1215                "itemsize must not be zero");
1216        }
1217        return NULL;
1218    }
1219
1220    /* convert scalar to list */
1221    if (ndim == 0) {
1222        items = Py_BuildValue("(O)", items);
1223        if (items == NULL)
1224            return NULL;
1225    }
1226    else {
1227        CHECK_LIST_OR_TUPLE(items)
1228        Py_INCREF(items);
1229    }
1230
1231    /* number of items */
1232    nitems = PySequence_Fast_GET_SIZE(items);
1233    if (nitems == 0) {
1234        PyErr_SetString(PyExc_ValueError,
1235            "initializer list or tuple must not be empty");
1236        Py_DECREF(items);
1237        return NULL;
1238    }
1239
1240    ndbuf = ndbuf_new(nitems, itemsize, offset, flags);
1241    if (ndbuf == NULL) {
1242        Py_DECREF(items);
1243        return NULL;
1244    }
1245
1246
1247    if (init_simple(ndbuf, items, format, itemsize) < 0)
1248        goto error;
1249    if (init_structure(ndbuf, shape, strides, ndim) < 0)
1250        goto error;
1251
1252    Py_DECREF(items);
1253    return ndbuf;
1254
1255error:
1256    Py_DECREF(items);
1257    ndbuf_free(ndbuf);
1258    return NULL;
1259}
1260
1261/* initialize and push a new base onto the linked list */
1262static int
1263ndarray_push_base(NDArrayObject *nd, PyObject *items,
1264                  PyObject *shape, PyObject *strides,
1265                  Py_ssize_t offset, PyObject *format, int flags)
1266{
1267    ndbuf_t *ndbuf;
1268
1269    ndbuf = init_ndbuf(items, shape, strides, offset, format, flags);
1270    if (ndbuf == NULL)
1271        return -1;
1272
1273    ndbuf_push(nd, ndbuf);
1274    return 0;
1275}
1276
1277#define PyBUF_UNUSED 0x10000
1278static int
1279ndarray_init(PyObject *self, PyObject *args, PyObject *kwds)
1280{
1281    NDArrayObject *nd = (NDArrayObject *)self;
1282    static char *kwlist[] = {
1283        "obj", "shape", "strides", "offset", "format", "flags", "getbuf", NULL
1284    };
1285    PyObject *v = NULL;  /* initializer: scalar, list, tuple or base object */
1286    PyObject *shape = NULL;   /* size of each dimension */
1287    PyObject *strides = NULL; /* number of bytes to the next elt in each dim */
1288    Py_ssize_t offset = 0;            /* buffer offset */
1289    PyObject *format = simple_format; /* struct module specifier: "B" */
1290    int flags = ND_DEFAULT;           /* base buffer and ndarray flags */
1291
1292    int getbuf = PyBUF_UNUSED; /* re-exporter: getbuffer request flags */
1293
1294
1295    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOnOii", kwlist,
1296            &v, &shape, &strides, &offset, &format, &flags, &getbuf))
1297        return -1;
1298
1299    /* NDArrayObject is re-exporter */
1300    if (PyObject_CheckBuffer(v) && shape == NULL) {
1301        if (strides || offset || format != simple_format ||
1302            !(flags == ND_DEFAULT || flags == ND_REDIRECT)) {
1303            PyErr_SetString(PyExc_TypeError,
1304               "construction from exporter object only takes 'obj', 'getbuf' "
1305               "and 'flags' arguments");
1306            return -1;
1307        }
1308
1309        getbuf = (getbuf == PyBUF_UNUSED) ? PyBUF_FULL_RO : getbuf;
1310
1311        if (ndarray_init_staticbuf(v, nd, getbuf) < 0)
1312            return -1;
1313
1314        init_flags(nd->head);
1315        nd->head->flags |= flags;
1316
1317        return 0;
1318    }
1319
1320    /* NDArrayObject is the original base object. */
1321    if (getbuf != PyBUF_UNUSED) {
1322        PyErr_SetString(PyExc_TypeError,
1323            "getbuf argument only valid for construction from exporter "
1324            "object");
1325        return -1;
1326    }
1327    if (shape == NULL) {
1328        PyErr_SetString(PyExc_TypeError,
1329            "shape is a required argument when constructing from "
1330            "list, tuple or scalar");
1331        return -1;
1332    }
1333
1334    if (flags & ND_VAREXPORT) {
1335        nd->flags |= ND_VAREXPORT;
1336        flags &= ~ND_VAREXPORT;
1337    }
1338
1339    /* Initialize and push the first base buffer onto the linked list. */
1340    return ndarray_push_base(nd, v, shape, strides, offset, format, flags);
1341}
1342
1343/* Push an additional base onto the linked list. */
1344static PyObject *
1345ndarray_push(PyObject *self, PyObject *args, PyObject *kwds)
1346{
1347    NDArrayObject *nd = (NDArrayObject *)self;
1348    static char *kwlist[] = {
1349        "items", "shape", "strides", "offset", "format", "flags", NULL
1350    };
1351    PyObject *items = NULL;   /* initializer: scalar, list or tuple */
1352    PyObject *shape = NULL;   /* size of each dimension */
1353    PyObject *strides = NULL; /* number of bytes to the next elt in each dim */
1354    PyObject *format = simple_format;  /* struct module specifier: "B" */
1355    Py_ssize_t offset = 0;             /* buffer offset */
1356    int flags = ND_DEFAULT;            /* base buffer flags */
1357
1358    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OnOi", kwlist,
1359            &items, &shape, &strides, &offset, &format, &flags))
1360        return NULL;
1361
1362    if (flags & ND_VAREXPORT) {
1363        PyErr_SetString(PyExc_ValueError,
1364            "ND_VAREXPORT flag can only be used during object creation");
1365        return NULL;
1366    }
1367    if (ND_IS_CONSUMER(nd)) {
1368        PyErr_SetString(PyExc_BufferError,
1369            "structure of re-exporting object is immutable");
1370        return NULL;
1371    }
1372    if (!(nd->flags&ND_VAREXPORT) && nd->head->exports > 0) {
1373        PyErr_Format(PyExc_BufferError,
1374            "cannot change structure: %zd exported buffer%s",
1375            nd->head->exports, nd->head->exports==1 ? "" : "s");
1376        return NULL;
1377    }
1378
1379    if (ndarray_push_base(nd, items, shape, strides,
1380                          offset, format, flags) < 0)
1381        return NULL;
1382    Py_RETURN_NONE;
1383}
1384
1385/* Pop a base from the linked list (if possible). */
1386static PyObject *
1387ndarray_pop(PyObject *self, PyObject *dummy)
1388{
1389    NDArrayObject *nd = (NDArrayObject *)self;
1390    if (ND_IS_CONSUMER(nd)) {
1391        PyErr_SetString(PyExc_BufferError,
1392            "structure of re-exporting object is immutable");
1393        return NULL;
1394    }
1395    if (nd->head->exports > 0) {
1396        PyErr_Format(PyExc_BufferError,
1397            "cannot change structure: %zd exported buffer%s",
1398            nd->head->exports, nd->head->exports==1 ? "" : "s");
1399        return NULL;
1400    }
1401    if (nd->head->next == NULL) {
1402        PyErr_SetString(PyExc_BufferError,
1403            "list only has a single base");
1404        return NULL;
1405    }
1406
1407    ndbuf_pop(nd);
1408    Py_RETURN_NONE;
1409}
1410
1411/**************************************************************************/
1412/*                               getbuffer                                */
1413/**************************************************************************/
1414
1415static int
1416ndarray_getbuf(NDArrayObject *self, Py_buffer *view, int flags)
1417{
1418    ndbuf_t *ndbuf = self->head;
1419    Py_buffer *base = &ndbuf->base;
1420    int baseflags = ndbuf->flags;
1421
1422    /* redirect mode */
1423    if (base->obj != NULL && (baseflags&ND_REDIRECT)) {
1424        return PyObject_GetBuffer(base->obj, view, flags);
1425    }
1426
1427    /* start with complete information */
1428    *view = *base;
1429    view->obj = NULL;
1430
1431    /* reconstruct format */
1432    if (view->format == NULL)
1433        view->format = "B";
1434
1435    if (base->ndim != 0 &&
1436        ((REQ_SHAPE(flags) && base->shape == NULL) ||
1437         (REQ_STRIDES(flags) && base->strides == NULL))) {
1438        /* The ndarray is a re-exporter that has been created without full
1439           information for testing purposes. In this particular case the
1440           ndarray is not a PEP-3118 compliant buffer provider. */
1441        PyErr_SetString(PyExc_BufferError,
1442            "re-exporter does not provide format, shape or strides");
1443        return -1;
1444    }
1445
1446    if (baseflags & ND_GETBUF_FAIL) {
1447        PyErr_SetString(PyExc_BufferError,
1448            "ND_GETBUF_FAIL: forced test exception");
1449        if (baseflags & ND_GETBUF_UNDEFINED)
1450            view->obj = (PyObject *)0x1; /* wrong but permitted in <= 3.2 */
1451        return -1;
1452    }
1453
1454    if (REQ_WRITABLE(flags) && base->readonly) {
1455        PyErr_SetString(PyExc_BufferError,
1456            "ndarray is not writable");
1457        return -1;
1458    }
1459    if (!REQ_FORMAT(flags)) {
1460        /* NULL indicates that the buffer's data type has been cast to 'B'.
1461           view->itemsize is the _previous_ itemsize. If shape is present,
1462           the equality product(shape) * itemsize = len still holds at this
1463           point. The equality calcsize(format) = itemsize does _not_ hold
1464           from here on! */
1465        view->format = NULL;
1466    }
1467
1468    if (REQ_C_CONTIGUOUS(flags) && !ND_C_CONTIGUOUS(baseflags)) {
1469        PyErr_SetString(PyExc_BufferError,
1470            "ndarray is not C-contiguous");
1471        return -1;
1472    }
1473    if (REQ_F_CONTIGUOUS(flags) && !ND_FORTRAN_CONTIGUOUS(baseflags)) {
1474        PyErr_SetString(PyExc_BufferError,
1475            "ndarray is not Fortran contiguous");
1476        return -1;
1477    }
1478    if (REQ_ANY_CONTIGUOUS(flags) && !ND_ANY_CONTIGUOUS(baseflags)) {
1479        PyErr_SetString(PyExc_BufferError,
1480            "ndarray is not contiguous");
1481        return -1;
1482    }
1483    if (!REQ_INDIRECT(flags) && (baseflags & ND_PIL)) {
1484        PyErr_SetString(PyExc_BufferError,
1485            "ndarray cannot be represented without suboffsets");
1486        return -1;
1487    }
1488    if (!REQ_STRIDES(flags)) {
1489        if (!ND_C_CONTIGUOUS(baseflags)) {
1490            PyErr_SetString(PyExc_BufferError,
1491                "ndarray is not C-contiguous");
1492            return -1;
1493        }
1494        view->strides = NULL;
1495    }
1496    if (!REQ_SHAPE(flags)) {
1497        /* PyBUF_SIMPLE or PyBUF_WRITABLE: at this point buf is C-contiguous,
1498           so base->buf = ndbuf->data. */
1499        if (view->format != NULL) {
1500            /* PyBUF_SIMPLE|PyBUF_FORMAT and PyBUF_WRITABLE|PyBUF_FORMAT do
1501               not make sense. */
1502            PyErr_Format(PyExc_BufferError,
1503                "ndarray: cannot cast to unsigned bytes if the format flag "
1504                "is present");
1505            return -1;
1506        }
1507        /* product(shape) * itemsize = len and calcsize(format) = itemsize
1508           do _not_ hold from here on! */
1509        view->ndim = 1;
1510        view->shape = NULL;
1511    }
1512
1513    /* Ascertain that the new buffer has the same contiguity as the exporter */
1514    if (ND_C_CONTIGUOUS(baseflags) != PyBuffer_IsContiguous(view, 'C') ||
1515        /* skip cast to 1-d */
1516        (view->format != NULL && view->shape != NULL &&
1517         ND_FORTRAN_CONTIGUOUS(baseflags) != PyBuffer_IsContiguous(view, 'F')) ||
1518        /* cast to 1-d */
1519        (view->format == NULL && view->shape == NULL &&
1520         !PyBuffer_IsContiguous(view, 'F'))) {
1521        PyErr_SetString(PyExc_BufferError,
1522            "ndarray: contiguity mismatch in getbuf()");
1523            return -1;
1524    }
1525
1526    view->obj = (PyObject *)self;
1527    Py_INCREF(view->obj);
1528    self->head->exports++;
1529
1530    return 0;
1531}
1532
1533static int
1534ndarray_releasebuf(NDArrayObject *self, Py_buffer *view)
1535{
1536    if (!ND_IS_CONSUMER(self)) {
1537        ndbuf_t *ndbuf = view->internal;
1538        if (--ndbuf->exports == 0 && ndbuf != self->head)
1539            ndbuf_delete(self, ndbuf);
1540    }
1541
1542    return 0;
1543}
1544
1545static PyBufferProcs ndarray_as_buffer = {
1546    (getbufferproc)ndarray_getbuf,        /* bf_getbuffer */
1547    (releasebufferproc)ndarray_releasebuf /* bf_releasebuffer */
1548};
1549
1550
1551/**************************************************************************/
1552/*                           indexing/slicing                             */
1553/**************************************************************************/
1554
1555static char *
1556ptr_from_index(Py_buffer *base, Py_ssize_t index)
1557{
1558    char *ptr;
1559    Py_ssize_t nitems; /* items in the first dimension */
1560
1561    if (base->shape)
1562        nitems = base->shape[0];
1563    else {
1564        assert(base->ndim == 1 && SIMPLE_FORMAT(base->format));
1565        nitems = base->len;
1566    }
1567
1568    if (index < 0) {
1569        index += nitems;
1570    }
1571    if (index < 0 || index >= nitems) {
1572        PyErr_SetString(PyExc_IndexError, "index out of bounds");
1573        return NULL;
1574    }
1575
1576    ptr = (char *)base->buf;
1577
1578    if (base->strides == NULL)
1579         ptr += base->itemsize * index;
1580    else
1581         ptr += base->strides[0] * index;
1582
1583    ptr = ADJUST_PTR(ptr, base->suboffsets);
1584
1585    return ptr;
1586}
1587
1588static PyObject *
1589ndarray_item(NDArrayObject *self, Py_ssize_t index)
1590{
1591    ndbuf_t *ndbuf = self->head;
1592    Py_buffer *base = &ndbuf->base;
1593    char *ptr;
1594
1595    if (base->ndim == 0) {
1596        PyErr_SetString(PyExc_TypeError, "invalid indexing of scalar");
1597        return NULL;
1598    }
1599
1600    ptr = ptr_from_index(base, index);
1601    if (ptr == NULL)
1602        return NULL;
1603
1604    if (base->ndim == 1) {
1605        return unpack_single(ptr, base->format, base->itemsize);
1606    }
1607    else {
1608        NDArrayObject *nd;
1609        Py_buffer *subview;
1610
1611        nd = (NDArrayObject *)ndarray_new(&NDArray_Type, NULL, NULL);
1612        if (nd == NULL)
1613            return NULL;
1614
1615        if (ndarray_init_staticbuf((PyObject *)self, nd, PyBUF_FULL_RO) < 0) {
1616            Py_DECREF(nd);
1617            return NULL;
1618        }
1619
1620        subview = &nd->staticbuf.base;
1621
1622        subview->buf = ptr;
1623        subview->len /= subview->shape[0];
1624
1625        subview->ndim--;
1626        subview->shape++;
1627        if (subview->strides) subview->strides++;
1628        if (subview->suboffsets) subview->suboffsets++;
1629
1630        init_flags(&nd->staticbuf);
1631
1632        return (PyObject *)nd;
1633    }
1634}
1635
1636/*
1637  For each dimension, we get valid (start, stop, step, slicelength) quadruples
1638  from PySlice_GetIndicesEx().
1639
1640  Slicing NumPy arrays
1641  ====================
1642
1643    A pointer to an element in a NumPy array is defined by:
1644
1645      ptr = (char *)buf + indices[0] * strides[0] +
1646                          ... +
1647                          indices[ndim-1] * strides[ndim-1]
1648
1649    Adjust buf:
1650    -----------
1651      Adding start[n] for each dimension effectively adds the constant:
1652
1653        c = start[0] * strides[0] + ... + start[ndim-1] * strides[ndim-1]
1654
1655      Therefore init_slice() adds all start[n] directly to buf.
1656
1657    Adjust shape:
1658    -------------
1659      Obviously shape[n] = slicelength[n]
1660
1661    Adjust strides:
1662    ---------------
1663      In the original array, the next element in a dimension is reached
1664      by adding strides[n] to the pointer. In the sliced array, elements
1665      may be skipped, so the next element is reached by adding:
1666
1667        strides[n] * step[n]
1668
1669  Slicing PIL arrays
1670  ==================
1671
1672    Layout:
1673    -------
1674      In the first (zeroth) dimension, PIL arrays have an array of pointers
1675      to sub-arrays of ndim-1. Striding in the first dimension is done by
1676      getting the index of the nth pointer, dereference it and then add a
1677      suboffset to it. The arrays pointed to can best be seen a regular
1678      NumPy arrays.
1679
1680    Adjust buf:
1681    -----------
1682      In the original array, buf points to a location (usually the start)
1683      in the array of pointers. For the sliced array, start[0] can be
1684      added to buf in the same manner as for NumPy arrays.
1685
1686    Adjust suboffsets:
1687    ------------------
1688      Due to the dereferencing step in the addressing scheme, it is not
1689      possible to adjust buf for higher dimensions. Recall that the
1690      sub-arrays pointed to are regular NumPy arrays, so for each of
1691      those arrays adding start[n] effectively adds the constant:
1692
1693        c = start[1] * strides[1] + ... + start[ndim-1] * strides[ndim-1]
1694
1695      This constant is added to suboffsets[0]. suboffsets[0] in turn is
1696      added to each pointer right after dereferencing.
1697
1698    Adjust shape and strides:
1699    -------------------------
1700      Shape and strides are not influenced by the dereferencing step, so
1701      they are adjusted in the same manner as for NumPy arrays.
1702
1703  Multiple levels of suboffsets
1704  =============================
1705
1706      For a construct like an array of pointers to array of pointers to
1707      sub-arrays of ndim-2:
1708
1709        suboffsets[0] = start[1] * strides[1]
1710        suboffsets[1] = start[2] * strides[2] + ...
1711*/
1712static int
1713init_slice(Py_buffer *base, PyObject *key, int dim)
1714{
1715    Py_ssize_t start, stop, step, slicelength;
1716
1717    if (PySlice_GetIndicesEx(key, base->shape[dim],
1718                             &start, &stop, &step, &slicelength) < 0) {
1719        return -1;
1720    }
1721
1722
1723    if (base->suboffsets == NULL || dim == 0) {
1724    adjust_buf:
1725        base->buf = (char *)base->buf + base->strides[dim] * start;
1726    }
1727    else {
1728        Py_ssize_t n = dim-1;
1729        while (n >= 0 && base->suboffsets[n] < 0)
1730            n--;
1731        if (n < 0)
1732            goto adjust_buf; /* all suboffsets are negative */
1733        base->suboffsets[n] = base->suboffsets[n] + base->strides[dim] * start;
1734    }
1735    base->shape[dim] = slicelength;
1736    base->strides[dim] = base->strides[dim] * step;
1737
1738    return 0;
1739}
1740
1741static int
1742copy_structure(Py_buffer *base)
1743{
1744    Py_ssize_t *shape = NULL, *strides = NULL, *suboffsets = NULL;
1745    Py_ssize_t i;
1746
1747    shape = PyMem_Malloc(base->ndim * (sizeof *shape));
1748    strides = PyMem_Malloc(base->ndim * (sizeof *strides));
1749    if (shape == NULL || strides == NULL)
1750        goto err_nomem;
1751
1752    suboffsets = NULL;
1753    if (base->suboffsets) {
1754        suboffsets = PyMem_Malloc(base->ndim * (sizeof *suboffsets));
1755        if (suboffsets == NULL)
1756            goto err_nomem;
1757    }
1758
1759    for (i = 0; i < base->ndim; i++) {
1760        shape[i] = base->shape[i];
1761        strides[i] = base->strides[i];
1762        if (suboffsets)
1763            suboffsets[i] = base->suboffsets[i];
1764    }
1765
1766    base->shape = shape;
1767    base->strides = strides;
1768    base->suboffsets = suboffsets;
1769
1770    return 0;
1771
1772err_nomem:
1773    PyErr_NoMemory();
1774    PyMem_XFree(shape);
1775    PyMem_XFree(strides);
1776    PyMem_XFree(suboffsets);
1777    return -1;
1778}
1779
1780static PyObject *
1781ndarray_subscript(NDArrayObject *self, PyObject *key)
1782{
1783    NDArrayObject *nd;
1784    ndbuf_t *ndbuf;
1785    Py_buffer *base = &self->head->base;
1786
1787    if (base->ndim == 0) {
1788        if (PyTuple_Check(key) && PyTuple_GET_SIZE(key) == 0) {
1789            return unpack_single(base->buf, base->format, base->itemsize);
1790        }
1791        else if (key == Py_Ellipsis) {
1792            Py_INCREF(self);
1793            return (PyObject *)self;
1794        }
1795        else {
1796            PyErr_SetString(PyExc_TypeError, "invalid indexing of scalar");
1797            return NULL;
1798        }
1799    }
1800    if (PyIndex_Check(key)) {
1801        Py_ssize_t index = PyLong_AsSsize_t(key);
1802        if (index == -1 && PyErr_Occurred())
1803            return NULL;
1804        return ndarray_item(self, index);
1805    }
1806
1807    nd = (NDArrayObject *)ndarray_new(&NDArray_Type, NULL, NULL);
1808    if (nd == NULL)
1809        return NULL;
1810
1811    /* new ndarray is a consumer */
1812    if (ndarray_init_staticbuf((PyObject *)self, nd, PyBUF_FULL_RO) < 0) {
1813        Py_DECREF(nd);
1814        return NULL;
1815    }
1816
1817    /* copy shape, strides and suboffsets */
1818    ndbuf = nd->head;
1819    base = &ndbuf->base;
1820    if (copy_structure(base) < 0) {
1821        Py_DECREF(nd);
1822        return NULL;
1823    }
1824    ndbuf->flags |= ND_OWN_ARRAYS;
1825
1826    if (PySlice_Check(key)) {
1827        /* one-dimensional slice */
1828        if (init_slice(base, key, 0) < 0)
1829            goto err_occurred;
1830    }
1831    else if (PyTuple_Check(key)) {
1832        /* multi-dimensional slice */
1833        PyObject *tuple = key;
1834        Py_ssize_t i, n;
1835
1836        n = PyTuple_GET_SIZE(tuple);
1837        for (i = 0; i < n; i++) {
1838            key = PyTuple_GET_ITEM(tuple, i);
1839            if (!PySlice_Check(key))
1840                goto type_error;
1841            if (init_slice(base, key, (int)i) < 0)
1842                goto err_occurred;
1843        }
1844    }
1845    else {
1846        goto type_error;
1847    }
1848
1849    init_len(base);
1850    init_flags(ndbuf);
1851
1852    return (PyObject *)nd;
1853
1854
1855type_error:
1856    PyErr_Format(PyExc_TypeError,
1857        "cannot index memory using \"%.200s\"",
1858        key->ob_type->tp_name);
1859err_occurred:
1860    Py_DECREF(nd);
1861    return NULL;
1862}
1863
1864
1865static int
1866ndarray_ass_subscript(NDArrayObject *self, PyObject *key, PyObject *value)
1867{
1868    NDArrayObject *nd;
1869    Py_buffer *dest = &self->head->base;
1870    Py_buffer src;
1871    char *ptr;
1872    Py_ssize_t index;
1873    int ret = -1;
1874
1875    if (dest->readonly) {
1876        PyErr_SetString(PyExc_TypeError, "ndarray is not writable");
1877        return -1;
1878    }
1879    if (value == NULL) {
1880        PyErr_SetString(PyExc_TypeError, "ndarray data cannot be deleted");
1881        return -1;
1882    }
1883    if (dest->ndim == 0) {
1884        if (key == Py_Ellipsis ||
1885            (PyTuple_Check(key) && PyTuple_GET_SIZE(key) == 0)) {
1886            ptr = (char *)dest->buf;
1887            return pack_single(ptr, value, dest->format, dest->itemsize);
1888        }
1889        else {
1890            PyErr_SetString(PyExc_TypeError, "invalid indexing of scalar");
1891            return -1;
1892        }
1893    }
1894    if (dest->ndim == 1 && PyIndex_Check(key)) {
1895        /* rvalue must be a single item */
1896        index = PyLong_AsSsize_t(key);
1897        if (index == -1 && PyErr_Occurred())
1898            return -1;
1899        else {
1900            ptr = ptr_from_index(dest, index);
1901            if (ptr == NULL)
1902                return -1;
1903        }
1904        return pack_single(ptr, value, dest->format, dest->itemsize);
1905    }
1906
1907    /* rvalue must be an exporter */
1908    if (PyObject_GetBuffer(value, &src, PyBUF_FULL_RO) == -1)
1909        return -1;
1910
1911    nd = (NDArrayObject *)ndarray_subscript(self, key);
1912    if (nd != NULL) {
1913        dest = &nd->head->base;
1914        ret = copy_buffer(dest, &src);
1915        Py_DECREF(nd);
1916    }
1917
1918    PyBuffer_Release(&src);
1919    return ret;
1920}
1921
1922static PyObject *
1923slice_indices(PyObject *self, PyObject *args)
1924{
1925    PyObject *ret, *key, *tmp;
1926    Py_ssize_t s[4]; /* start, stop, step, slicelength */
1927    Py_ssize_t i, len;
1928
1929    if (!PyArg_ParseTuple(args, "On", &key, &len)) {
1930        return NULL;
1931    }
1932    if (!PySlice_Check(key)) {
1933        PyErr_SetString(PyExc_TypeError,
1934            "first argument must be a slice object");
1935        return NULL;
1936    }
1937    if (PySlice_GetIndicesEx(key, len, &s[0], &s[1], &s[2], &s[3]) < 0) {
1938        return NULL;
1939    }
1940
1941    ret = PyTuple_New(4);
1942    if (ret == NULL)
1943        return NULL;
1944
1945    for (i = 0; i < 4; i++) {
1946        tmp = PyLong_FromSsize_t(s[i]);
1947        if (tmp == NULL)
1948            goto error;
1949        PyTuple_SET_ITEM(ret, i, tmp);
1950    }
1951
1952    return ret;
1953
1954error:
1955    Py_DECREF(ret);
1956    return NULL;
1957}
1958
1959
1960static PyMappingMethods ndarray_as_mapping = {
1961    NULL,                                 /* mp_length */
1962    (binaryfunc)ndarray_subscript,        /* mp_subscript */
1963    (objobjargproc)ndarray_ass_subscript  /* mp_ass_subscript */
1964};
1965
1966static PySequenceMethods ndarray_as_sequence = {
1967        0,                                /* sq_length */
1968        0,                                /* sq_concat */
1969        0,                                /* sq_repeat */
1970        (ssizeargfunc)ndarray_item,       /* sq_item */
1971};
1972
1973
1974/**************************************************************************/
1975/*                                 getters                                */
1976/**************************************************************************/
1977
1978static PyObject *
1979ssize_array_as_tuple(Py_ssize_t *array, Py_ssize_t len)
1980{
1981    PyObject *tuple, *x;
1982    Py_ssize_t i;
1983
1984    if (array == NULL)
1985        return PyTuple_New(0);
1986
1987    tuple = PyTuple_New(len);
1988    if (tuple == NULL)
1989        return NULL;
1990
1991    for (i = 0; i < len; i++) {
1992        x = PyLong_FromSsize_t(array[i]);
1993        if (x == NULL) {
1994            Py_DECREF(tuple);
1995            return NULL;
1996        }
1997        PyTuple_SET_ITEM(tuple, i, x);
1998    }
1999
2000    return tuple;
2001}
2002
2003static PyObject *
2004ndarray_get_flags(NDArrayObject *self, void *closure)
2005{
2006    return PyLong_FromLong(self->head->flags);
2007}
2008
2009static PyObject *
2010ndarray_get_offset(NDArrayObject *self, void *closure)
2011{
2012    ndbuf_t *ndbuf = self->head;
2013    return PyLong_FromSsize_t(ndbuf->offset);
2014}
2015
2016static PyObject *
2017ndarray_get_obj(NDArrayObject *self, void *closure)
2018{
2019    Py_buffer *base = &self->head->base;
2020
2021    if (base->obj == NULL) {
2022        Py_RETURN_NONE;
2023    }
2024    Py_INCREF(base->obj);
2025    return base->obj;
2026}
2027
2028static PyObject *
2029ndarray_get_nbytes(NDArrayObject *self, void *closure)
2030{
2031    Py_buffer *base = &self->head->base;
2032    return PyLong_FromSsize_t(base->len);
2033}
2034
2035static PyObject *
2036ndarray_get_readonly(NDArrayObject *self, void *closure)
2037{
2038    Py_buffer *base = &self->head->base;
2039    return PyLong_FromLong(base->readonly);
2040}
2041
2042static PyObject *
2043ndarray_get_itemsize(NDArrayObject *self, void *closure)
2044{
2045    Py_buffer *base = &self->head->base;
2046    return PyLong_FromSsize_t(base->itemsize);
2047}
2048
2049static PyObject *
2050ndarray_get_format(NDArrayObject *self, void *closure)
2051{
2052    Py_buffer *base = &self->head->base;
2053    char *fmt = base->format ? base->format : "";
2054    return PyUnicode_FromString(fmt);
2055}
2056
2057static PyObject *
2058ndarray_get_ndim(NDArrayObject *self, void *closure)
2059{
2060    Py_buffer *base = &self->head->base;
2061    return PyLong_FromSsize_t(base->ndim);
2062}
2063
2064static PyObject *
2065ndarray_get_shape(NDArrayObject *self, void *closure)
2066{
2067    Py_buffer *base = &self->head->base;
2068    return ssize_array_as_tuple(base->shape, base->ndim);
2069}
2070
2071static PyObject *
2072ndarray_get_strides(NDArrayObject *self, void *closure)
2073{
2074    Py_buffer *base = &self->head->base;
2075    return ssize_array_as_tuple(base->strides, base->ndim);
2076}
2077
2078static PyObject *
2079ndarray_get_suboffsets(NDArrayObject *self, void *closure)
2080{
2081    Py_buffer *base = &self->head->base;
2082    return ssize_array_as_tuple(base->suboffsets, base->ndim);
2083}
2084
2085static PyObject *
2086ndarray_c_contig(PyObject *self, PyObject *dummy)
2087{
2088    NDArrayObject *nd = (NDArrayObject *)self;
2089    int ret = PyBuffer_IsContiguous(&nd->head->base, 'C');
2090
2091    if (ret != ND_C_CONTIGUOUS(nd->head->flags)) {
2092        PyErr_SetString(PyExc_RuntimeError,
2093            "results from PyBuffer_IsContiguous() and flags differ");
2094        return NULL;
2095    }
2096    return PyBool_FromLong(ret);
2097}
2098
2099static PyObject *
2100ndarray_fortran_contig(PyObject *self, PyObject *dummy)
2101{
2102    NDArrayObject *nd = (NDArrayObject *)self;
2103    int ret = PyBuffer_IsContiguous(&nd->head->base, 'F');
2104
2105    if (ret != ND_FORTRAN_CONTIGUOUS(nd->head->flags)) {
2106        PyErr_SetString(PyExc_RuntimeError,
2107            "results from PyBuffer_IsContiguous() and flags differ");
2108        return NULL;
2109    }
2110    return PyBool_FromLong(ret);
2111}
2112
2113static PyObject *
2114ndarray_contig(PyObject *self, PyObject *dummy)
2115{
2116    NDArrayObject *nd = (NDArrayObject *)self;
2117    int ret = PyBuffer_IsContiguous(&nd->head->base, 'A');
2118
2119    if (ret != ND_ANY_CONTIGUOUS(nd->head->flags)) {
2120        PyErr_SetString(PyExc_RuntimeError,
2121            "results from PyBuffer_IsContiguous() and flags differ");
2122        return NULL;
2123    }
2124    return PyBool_FromLong(ret);
2125}
2126
2127
2128static PyGetSetDef ndarray_getset [] =
2129{
2130  /* ndbuf */
2131  { "flags",        (getter)ndarray_get_flags,      NULL, NULL, NULL},
2132  { "offset",       (getter)ndarray_get_offset,     NULL, NULL, NULL},
2133  /* ndbuf.base */
2134  { "obj",          (getter)ndarray_get_obj,        NULL, NULL, NULL},
2135  { "nbytes",       (getter)ndarray_get_nbytes,     NULL, NULL, NULL},
2136  { "readonly",     (getter)ndarray_get_readonly,   NULL, NULL, NULL},
2137  { "itemsize",     (getter)ndarray_get_itemsize,   NULL, NULL, NULL},
2138  { "format",       (getter)ndarray_get_format,     NULL, NULL, NULL},
2139  { "ndim",         (getter)ndarray_get_ndim,       NULL, NULL, NULL},
2140  { "shape",        (getter)ndarray_get_shape,      NULL, NULL, NULL},
2141  { "strides",      (getter)ndarray_get_strides,    NULL, NULL, NULL},
2142  { "suboffsets",   (getter)ndarray_get_suboffsets, NULL, NULL, NULL},
2143  { "c_contiguous", (getter)ndarray_c_contig,       NULL, NULL, NULL},
2144  { "f_contiguous", (getter)ndarray_fortran_contig, NULL, NULL, NULL},
2145  { "contiguous",   (getter)ndarray_contig,         NULL, NULL, NULL},
2146  {NULL}
2147};
2148
2149static PyObject *
2150ndarray_tolist(PyObject *self, PyObject *dummy)
2151{
2152    return ndarray_as_list((NDArrayObject *)self);
2153}
2154
2155static PyObject *
2156ndarray_tobytes(PyObject *self, PyObject *dummy)
2157{
2158    ndbuf_t *ndbuf = ((NDArrayObject *)self)->head;
2159    Py_buffer *src = &ndbuf->base;
2160    Py_buffer dest;
2161    PyObject *ret = NULL;
2162    char *mem;
2163
2164    if (ND_C_CONTIGUOUS(ndbuf->flags))
2165        return PyBytes_FromStringAndSize(src->buf, src->len);
2166
2167    assert(src->shape != NULL);
2168    assert(src->strides != NULL);
2169    assert(src->ndim > 0);
2170
2171    mem = PyMem_Malloc(src->len);
2172    if (mem == NULL) {
2173        PyErr_NoMemory();
2174        return NULL;
2175    }
2176
2177    dest = *src;
2178    dest.buf = mem;
2179    dest.suboffsets = NULL;
2180    dest.strides = strides_from_shape(ndbuf, 0);
2181    if (dest.strides == NULL)
2182        goto out;
2183    if (copy_buffer(&dest, src) < 0)
2184        goto out;
2185
2186    ret = PyBytes_FromStringAndSize(mem, src->len);
2187
2188out:
2189    PyMem_XFree(dest.strides);
2190    PyMem_Free(mem);
2191    return ret;
2192}
2193
2194/* add redundant (negative) suboffsets for testing */
2195static PyObject *
2196ndarray_add_suboffsets(PyObject *self, PyObject *dummy)
2197{
2198    NDArrayObject *nd = (NDArrayObject *)self;
2199    Py_buffer *base = &nd->head->base;
2200    Py_ssize_t i;
2201
2202    if (base->suboffsets != NULL) {
2203        PyErr_SetString(PyExc_TypeError,
2204            "cannot add suboffsets to PIL-style array");
2205            return NULL;
2206    }
2207    if (base->strides == NULL) {
2208        PyErr_SetString(PyExc_TypeError,
2209            "cannot add suboffsets to array without strides");
2210            return NULL;
2211    }
2212
2213    base->suboffsets = PyMem_Malloc(base->ndim * (sizeof *base->suboffsets));
2214    if (base->suboffsets == NULL) {
2215        PyErr_NoMemory();
2216        return NULL;
2217    }
2218
2219    for (i = 0; i < base->ndim; i++)
2220        base->suboffsets[i] = -1;
2221
2222    nd->head->flags &= ~(ND_C|ND_FORTRAN);
2223
2224    Py_RETURN_NONE;
2225}
2226
2227/* Test PyMemoryView_FromBuffer(): return a memoryview from a static buffer.
2228   Obviously this is fragile and only one such view may be active at any
2229   time. Never use anything like this in real code! */
2230static char *infobuf = NULL;
2231static PyObject *
2232ndarray_memoryview_from_buffer(PyObject *self, PyObject *dummy)
2233{
2234    const NDArrayObject *nd = (NDArrayObject *)self;
2235    const Py_buffer *view = &nd->head->base;
2236    const ndbuf_t *ndbuf;
2237    static char format[ND_MAX_NDIM+1];
2238    static Py_ssize_t shape[ND_MAX_NDIM];
2239    static Py_ssize_t strides[ND_MAX_NDIM];
2240    static Py_ssize_t suboffsets[ND_MAX_NDIM];
2241    static Py_buffer info;
2242    char *p;
2243
2244    if (!ND_IS_CONSUMER(nd))
2245        ndbuf = nd->head; /* self is ndarray/original exporter */
2246    else if (NDArray_Check(view->obj) && !ND_IS_CONSUMER(view->obj))
2247        /* self is ndarray and consumer from ndarray/original exporter */
2248        ndbuf = ((NDArrayObject *)view->obj)->head;
2249    else {
2250        PyErr_SetString(PyExc_TypeError,
2251        "memoryview_from_buffer(): ndarray must be original exporter or "
2252        "consumer from ndarray/original exporter");
2253         return NULL;
2254    }
2255
2256    info = *view;
2257    p = PyMem_Realloc(infobuf, ndbuf->len);
2258    if (p == NULL) {
2259        PyMem_Free(infobuf);
2260        PyErr_NoMemory();
2261        infobuf = NULL;
2262        return NULL;
2263    }
2264    else {
2265        infobuf = p;
2266    }
2267    /* copy the complete raw data */
2268    memcpy(infobuf, ndbuf->data, ndbuf->len);
2269    info.buf = infobuf + ((char *)view->buf - ndbuf->data);
2270
2271    if (view->format) {
2272        if (strlen(view->format) > ND_MAX_NDIM) {
2273            PyErr_Format(PyExc_TypeError,
2274                "memoryview_from_buffer: format is limited to %d characters",
2275                ND_MAX_NDIM);
2276                return NULL;
2277        }
2278        strcpy(format, view->format);
2279        info.format = format;
2280    }
2281    if (view->ndim > ND_MAX_NDIM) {
2282        PyErr_Format(PyExc_TypeError,
2283            "memoryview_from_buffer: ndim is limited to %d", ND_MAX_NDIM);
2284            return NULL;
2285    }
2286    if (view->shape) {
2287        memcpy(shape, view->shape, view->ndim * sizeof(Py_ssize_t));
2288        info.shape = shape;
2289    }
2290    if (view->strides) {
2291        memcpy(strides, view->strides, view->ndim * sizeof(Py_ssize_t));
2292        info.strides = strides;
2293    }
2294    if (view->suboffsets) {
2295        memcpy(suboffsets, view->suboffsets, view->ndim * sizeof(Py_ssize_t));
2296        info.suboffsets = suboffsets;
2297    }
2298
2299    return PyMemoryView_FromBuffer(&info);
2300}
2301
2302/* Get a single item from bufobj at the location specified by seq.
2303   seq is a list or tuple of indices. The purpose of this function
2304   is to check other functions against PyBuffer_GetPointer(). */
2305static PyObject *
2306get_pointer(PyObject *self, PyObject *args)
2307{
2308    PyObject *ret = NULL, *bufobj, *seq;
2309    Py_buffer view;
2310    Py_ssize_t indices[ND_MAX_NDIM];
2311    Py_ssize_t i;
2312    void *ptr;
2313
2314    if (!PyArg_ParseTuple(args, "OO", &bufobj, &seq)) {
2315        return NULL;
2316    }
2317
2318    CHECK_LIST_OR_TUPLE(seq);
2319    if (PyObject_GetBuffer(bufobj, &view, PyBUF_FULL_RO) < 0)
2320        return NULL;
2321
2322    if (view.ndim > ND_MAX_NDIM) {
2323        PyErr_Format(PyExc_ValueError,
2324            "get_pointer(): ndim > %d", ND_MAX_NDIM);
2325        goto out;
2326    }
2327    if (PySequence_Fast_GET_SIZE(seq) != view.ndim) {
2328        PyErr_SetString(PyExc_ValueError,
2329            "get_pointer(): len(indices) != ndim");
2330        goto out;
2331    }
2332
2333    for (i = 0; i < view.ndim; i++) {
2334        PyObject *x = PySequence_Fast_GET_ITEM(seq, i);
2335        indices[i] = PyLong_AsSsize_t(x);
2336        if (PyErr_Occurred())
2337            goto out;
2338        if (indices[i] < 0 || indices[i] >= view.shape[i]) {
2339            PyErr_Format(PyExc_ValueError,
2340                "get_pointer(): invalid index %zd at position %zd",
2341                indices[i], i);
2342            goto out;
2343        }
2344    }
2345
2346    ptr = PyBuffer_GetPointer(&view, indices);
2347    ret = unpack_single(ptr, view.format, view.itemsize);
2348
2349out:
2350    PyBuffer_Release(&view);
2351    return ret;
2352}
2353
2354static PyObject *
2355get_sizeof_void_p(PyObject *self)
2356{
2357    return PyLong_FromSize_t(sizeof(void *));
2358}
2359
2360static char
2361get_ascii_order(PyObject *order)
2362{
2363    PyObject *ascii_order;
2364    char ord;
2365
2366    if (!PyUnicode_Check(order)) {
2367        PyErr_SetString(PyExc_TypeError,
2368            "order must be a string");
2369        return CHAR_MAX;
2370    }
2371
2372    ascii_order = PyUnicode_AsASCIIString(order);
2373    if (ascii_order == NULL) {
2374        return CHAR_MAX;
2375    }
2376
2377    ord = PyBytes_AS_STRING(ascii_order)[0];
2378    Py_DECREF(ascii_order);
2379
2380    if (ord != 'C' && ord != 'F' && ord != 'A') {
2381        PyErr_SetString(PyExc_ValueError,
2382            "invalid order, must be C, F or A");
2383        return CHAR_MAX;
2384    }
2385
2386    return ord;
2387}
2388
2389/* Get a contiguous memoryview. */
2390static PyObject *
2391get_contiguous(PyObject *self, PyObject *args)
2392{
2393    PyObject *obj;
2394    PyObject *buffertype;
2395    PyObject *order;
2396    long type;
2397    char ord;
2398
2399    if (!PyArg_ParseTuple(args, "OOO", &obj, &buffertype, &order)) {
2400        return NULL;
2401    }
2402
2403    if (!PyLong_Check(buffertype)) {
2404        PyErr_SetString(PyExc_TypeError,
2405            "buffertype must be PyBUF_READ or PyBUF_WRITE");
2406        return NULL;
2407    }
2408
2409    type = PyLong_AsLong(buffertype);
2410    if (type == -1 && PyErr_Occurred()) {
2411        return NULL;
2412    }
2413    if (type != PyBUF_READ && type != PyBUF_WRITE) {
2414        PyErr_SetString(PyExc_ValueError,
2415            "invalid buffer type");
2416        return NULL;
2417    }
2418
2419    ord = get_ascii_order(order);
2420    if (ord == CHAR_MAX)
2421        return NULL;
2422
2423    return PyMemoryView_GetContiguous(obj, (int)type, ord);
2424}
2425
2426/* PyBuffer_ToContiguous() */
2427static PyObject *
2428py_buffer_to_contiguous(PyObject *self, PyObject *args)
2429{
2430    PyObject *obj;
2431    PyObject *order;
2432    PyObject *ret = NULL;
2433    int flags;
2434    char ord;
2435    Py_buffer view;
2436    char *buf = NULL;
2437
2438    if (!PyArg_ParseTuple(args, "OOi", &obj, &order, &flags)) {
2439        return NULL;
2440    }
2441
2442    if (PyObject_GetBuffer(obj, &view, flags) < 0) {
2443        return NULL;
2444    }
2445
2446    ord = get_ascii_order(order);
2447    if (ord == CHAR_MAX) {
2448        goto out;
2449    }
2450
2451    buf = PyMem_Malloc(view.len);
2452    if (buf == NULL) {
2453        PyErr_NoMemory();
2454        goto out;
2455    }
2456
2457    if (PyBuffer_ToContiguous(buf, &view, view.len, ord) < 0) {
2458        goto out;
2459    }
2460
2461    ret = PyBytes_FromStringAndSize(buf, view.len);
2462
2463out:
2464    PyBuffer_Release(&view);
2465    PyMem_XFree(buf);
2466    return ret;
2467}
2468
2469static int
2470fmtcmp(const char *fmt1, const char *fmt2)
2471{
2472    if (fmt1 == NULL) {
2473        return fmt2 == NULL || strcmp(fmt2, "B") == 0;
2474    }
2475    if (fmt2 == NULL) {
2476        return fmt1 == NULL || strcmp(fmt1, "B") == 0;
2477    }
2478    return strcmp(fmt1, fmt2) == 0;
2479}
2480
2481static int
2482arraycmp(const Py_ssize_t *a1, const Py_ssize_t *a2, const Py_ssize_t *shape,
2483         Py_ssize_t ndim)
2484{
2485    Py_ssize_t i;
2486
2487
2488    for (i = 0; i < ndim; i++) {
2489        if (shape && shape[i] <= 1) {
2490            /* strides can differ if the dimension is less than 2 */
2491            continue;
2492        }
2493        if (a1[i] != a2[i]) {
2494            return 0;
2495        }
2496    }
2497
2498    return 1;
2499}
2500
2501/* Compare two contiguous buffers for physical equality. */
2502static PyObject *
2503cmp_contig(PyObject *self, PyObject *args)
2504{
2505    PyObject *b1, *b2; /* buffer objects */
2506    Py_buffer v1, v2;
2507    PyObject *ret;
2508    int equal = 0;
2509
2510    if (!PyArg_ParseTuple(args, "OO", &b1, &b2)) {
2511        return NULL;
2512    }
2513
2514    if (PyObject_GetBuffer(b1, &v1, PyBUF_FULL_RO) < 0) {
2515        PyErr_SetString(PyExc_TypeError,
2516            "cmp_contig: first argument does not implement the buffer "
2517            "protocol");
2518        return NULL;
2519    }
2520    if (PyObject_GetBuffer(b2, &v2, PyBUF_FULL_RO) < 0) {
2521        PyErr_SetString(PyExc_TypeError,
2522            "cmp_contig: second argument does not implement the buffer "
2523            "protocol");
2524        PyBuffer_Release(&v1);
2525        return NULL;
2526    }
2527
2528    if (!(PyBuffer_IsContiguous(&v1, 'C')&&PyBuffer_IsContiguous(&v2, 'C')) &&
2529        !(PyBuffer_IsContiguous(&v1, 'F')&&PyBuffer_IsContiguous(&v2, 'F'))) {
2530        goto result;
2531    }
2532
2533    /* readonly may differ if created from non-contiguous */
2534    if (v1.len != v2.len ||
2535        v1.itemsize != v2.itemsize ||
2536        v1.ndim != v2.ndim ||
2537        !fmtcmp(v1.format, v2.format) ||
2538        !!v1.shape != !!v2.shape ||
2539        !!v1.strides != !!v2.strides ||
2540        !!v1.suboffsets != !!v2.suboffsets) {
2541        goto result;
2542    }
2543
2544    if ((v1.shape && !arraycmp(v1.shape, v2.shape, NULL, v1.ndim)) ||
2545        (v1.strides && !arraycmp(v1.strides, v2.strides, v1.shape, v1.ndim)) ||
2546        (v1.suboffsets && !arraycmp(v1.suboffsets, v2.suboffsets, NULL,
2547                                    v1.ndim))) {
2548        goto result;
2549    }
2550
2551    if (memcmp((char *)v1.buf, (char *)v2.buf, v1.len) != 0) {
2552        goto result;
2553    }
2554
2555    equal = 1;
2556
2557result:
2558    PyBuffer_Release(&v1);
2559    PyBuffer_Release(&v2);
2560
2561    ret = equal ? Py_True : Py_False;
2562    Py_INCREF(ret);
2563    return ret;
2564}
2565
2566static PyObject *
2567is_contiguous(PyObject *self, PyObject *args)
2568{
2569    PyObject *obj;
2570    PyObject *order;
2571    PyObject *ret = NULL;
2572    Py_buffer view, *base;
2573    char ord;
2574
2575    if (!PyArg_ParseTuple(args, "OO", &obj, &order)) {
2576        return NULL;
2577    }
2578
2579    ord = get_ascii_order(order);
2580    if (ord == CHAR_MAX) {
2581        return NULL;
2582    }
2583
2584    if (NDArray_Check(obj)) {
2585        /* Skip the buffer protocol to check simple etc. buffers directly. */
2586        base = &((NDArrayObject *)obj)->head->base;
2587        ret = PyBuffer_IsContiguous(base, ord) ? Py_True : Py_False;
2588    }
2589    else {
2590        if (PyObject_GetBuffer(obj, &view, PyBUF_FULL_RO) < 0) {
2591            PyErr_SetString(PyExc_TypeError,
2592                "is_contiguous: object does not implement the buffer "
2593                "protocol");
2594            return NULL;
2595        }
2596        ret = PyBuffer_IsContiguous(&view, ord) ? Py_True : Py_False;
2597        PyBuffer_Release(&view);
2598    }
2599
2600    Py_INCREF(ret);
2601    return ret;
2602}
2603
2604static Py_hash_t
2605ndarray_hash(PyObject *self)
2606{
2607    const NDArrayObject *nd = (NDArrayObject *)self;
2608    const Py_buffer *view = &nd->head->base;
2609    PyObject *bytes;
2610    Py_hash_t hash;
2611
2612    if (!view->readonly) {
2613         PyErr_SetString(PyExc_ValueError,
2614             "cannot hash writable ndarray object");
2615         return -1;
2616    }
2617    if (view->obj != NULL && PyObject_Hash(view->obj) == -1) {
2618         return -1;
2619    }
2620
2621    bytes = ndarray_tobytes(self, NULL);
2622    if (bytes == NULL) {
2623        return -1;
2624    }
2625
2626    hash = PyObject_Hash(bytes);
2627    Py_DECREF(bytes);
2628    return hash;
2629}
2630
2631
2632static PyMethodDef ndarray_methods [] =
2633{
2634    { "tolist", ndarray_tolist, METH_NOARGS, NULL },
2635    { "tobytes", ndarray_tobytes, METH_NOARGS, NULL },
2636    { "push", (PyCFunction)ndarray_push, METH_VARARGS|METH_KEYWORDS, NULL },
2637    { "pop", ndarray_pop, METH_NOARGS, NULL },
2638    { "add_suboffsets", ndarray_add_suboffsets, METH_NOARGS, NULL },
2639    { "memoryview_from_buffer", ndarray_memoryview_from_buffer, METH_NOARGS, NULL },
2640    {NULL}
2641};
2642
2643static PyTypeObject NDArray_Type = {
2644    PyVarObject_HEAD_INIT(NULL, 0)
2645    "ndarray",                   /* Name of this type */
2646    sizeof(NDArrayObject),       /* Basic object size */
2647    0,                           /* Item size for varobject */
2648    (destructor)ndarray_dealloc, /* tp_dealloc */
2649    0,                           /* tp_print */
2650    0,                           /* tp_getattr */
2651    0,                           /* tp_setattr */
2652    0,                           /* tp_compare */
2653    0,                           /* tp_repr */
2654    0,                           /* tp_as_number */
2655    &ndarray_as_sequence,        /* tp_as_sequence */
2656    &ndarray_as_mapping,         /* tp_as_mapping */
2657    (hashfunc)ndarray_hash,      /* tp_hash */
2658    0,                           /* tp_call */
2659    0,                           /* tp_str */
2660    PyObject_GenericGetAttr,     /* tp_getattro */
2661    0,                           /* tp_setattro */
2662    &ndarray_as_buffer,          /* tp_as_buffer */
2663    Py_TPFLAGS_DEFAULT,          /* tp_flags */
2664    0,                           /* tp_doc */
2665    0,                           /* tp_traverse */
2666    0,                           /* tp_clear */
2667    0,                           /* tp_richcompare */
2668    0,                           /* tp_weaklistoffset */
2669    0,                           /* tp_iter */
2670    0,                           /* tp_iternext */
2671    ndarray_methods,             /* tp_methods */
2672    0,                           /* tp_members */
2673    ndarray_getset,              /* tp_getset */
2674    0,                           /* tp_base */
2675    0,                           /* tp_dict */
2676    0,                           /* tp_descr_get */
2677    0,                           /* tp_descr_set */
2678    0,                           /* tp_dictoffset */
2679    ndarray_init,                /* tp_init */
2680    0,                           /* tp_alloc */
2681    ndarray_new,                 /* tp_new */
2682};
2683
2684/**************************************************************************/
2685/*                          StaticArray Object                            */
2686/**************************************************************************/
2687
2688static PyTypeObject StaticArray_Type;
2689
2690typedef struct {
2691    PyObject_HEAD
2692    int legacy_mode; /* if true, use the view.obj==NULL hack */
2693} StaticArrayObject;
2694
2695static char static_mem[12] = {0,1,2,3,4,5,6,7,8,9,10,11};
2696static Py_ssize_t static_shape[1] = {12};
2697static Py_ssize_t static_strides[1] = {1};
2698static Py_buffer static_buffer = {
2699    static_mem,     /* buf */
2700    NULL,           /* obj */
2701    12,             /* len */
2702    1,              /* itemsize */
2703    1,              /* readonly */
2704    1,              /* ndim */
2705    "B",            /* format */
2706    static_shape,   /* shape */
2707    static_strides, /* strides */
2708    NULL,           /* suboffsets */
2709    NULL            /* internal */
2710};
2711
2712static PyObject *
2713staticarray_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
2714{
2715    return (PyObject *)PyObject_New(StaticArrayObject, &StaticArray_Type);
2716}
2717
2718static int
2719staticarray_init(PyObject *self, PyObject *args, PyObject *kwds)
2720{
2721    StaticArrayObject *a = (StaticArrayObject *)self;
2722    static char *kwlist[] = {
2723        "legacy_mode", NULL
2724    };
2725    PyObject *legacy_mode = Py_False;
2726
2727    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &legacy_mode))
2728        return -1;
2729
2730    a->legacy_mode = (legacy_mode != Py_False);
2731    return 0;
2732}
2733
2734static void
2735staticarray_dealloc(StaticArrayObject *self)
2736{
2737    PyObject_Del(self);
2738}
2739
2740/* Return a buffer for a PyBUF_FULL_RO request. Flags are not checked,
2741   which makes this object a non-compliant exporter! */
2742static int
2743staticarray_getbuf(StaticArrayObject *self, Py_buffer *view, int flags)
2744{
2745    *view = static_buffer;
2746
2747    if (self->legacy_mode) {
2748        view->obj = NULL; /* Don't use this in new code. */
2749    }
2750    else {
2751        view->obj = (PyObject *)self;
2752        Py_INCREF(view->obj);
2753    }
2754
2755    return 0;
2756}
2757
2758static PyBufferProcs staticarray_as_buffer = {
2759    (getbufferproc)staticarray_getbuf, /* bf_getbuffer */
2760    NULL,                              /* bf_releasebuffer */
2761};
2762
2763static PyTypeObject StaticArray_Type = {
2764    PyVarObject_HEAD_INIT(NULL, 0)
2765    "staticarray",                   /* Name of this type */
2766    sizeof(StaticArrayObject),       /* Basic object size */
2767    0,                               /* Item size for varobject */
2768    (destructor)staticarray_dealloc, /* tp_dealloc */
2769    0,                               /* tp_print */
2770    0,                               /* tp_getattr */
2771    0,                               /* tp_setattr */
2772    0,                               /* tp_compare */
2773    0,                               /* tp_repr */
2774    0,                               /* tp_as_number */
2775    0,                               /* tp_as_sequence */
2776    0,                               /* tp_as_mapping */
2777    0,                               /* tp_hash */
2778    0,                               /* tp_call */
2779    0,                               /* tp_str */
2780    0,                               /* tp_getattro */
2781    0,                               /* tp_setattro */
2782    &staticarray_as_buffer,          /* tp_as_buffer */
2783    Py_TPFLAGS_DEFAULT,              /* tp_flags */
2784    0,                               /* tp_doc */
2785    0,                               /* tp_traverse */
2786    0,                               /* tp_clear */
2787    0,                               /* tp_richcompare */
2788    0,                               /* tp_weaklistoffset */
2789    0,                               /* tp_iter */
2790    0,                               /* tp_iternext */
2791    0,                               /* tp_methods */
2792    0,                               /* tp_members */
2793    0,                               /* tp_getset */
2794    0,                               /* tp_base */
2795    0,                               /* tp_dict */
2796    0,                               /* tp_descr_get */
2797    0,                               /* tp_descr_set */
2798    0,                               /* tp_dictoffset */
2799    staticarray_init,                /* tp_init */
2800    0,                               /* tp_alloc */
2801    staticarray_new,                 /* tp_new */
2802};
2803
2804
2805static struct PyMethodDef _testbuffer_functions[] = {
2806    {"slice_indices", slice_indices, METH_VARARGS, NULL},
2807    {"get_pointer", get_pointer, METH_VARARGS, NULL},
2808    {"get_sizeof_void_p", (PyCFunction)get_sizeof_void_p, METH_NOARGS, NULL},
2809    {"get_contiguous", get_contiguous, METH_VARARGS, NULL},
2810    {"py_buffer_to_contiguous", py_buffer_to_contiguous, METH_VARARGS, NULL},
2811    {"is_contiguous", is_contiguous, METH_VARARGS, NULL},
2812    {"cmp_contig", cmp_contig, METH_VARARGS, NULL},
2813    {NULL, NULL}
2814};
2815
2816static struct PyModuleDef _testbuffermodule = {
2817    PyModuleDef_HEAD_INIT,
2818    "_testbuffer",
2819    NULL,
2820    -1,
2821    _testbuffer_functions,
2822    NULL,
2823    NULL,
2824    NULL,
2825    NULL
2826};
2827
2828
2829PyMODINIT_FUNC
2830PyInit__testbuffer(void)
2831{
2832    PyObject *m;
2833
2834    m = PyModule_Create(&_testbuffermodule);
2835    if (m == NULL)
2836        return NULL;
2837
2838    Py_TYPE(&NDArray_Type) = &PyType_Type;
2839    Py_INCREF(&NDArray_Type);
2840    PyModule_AddObject(m, "ndarray", (PyObject *)&NDArray_Type);
2841
2842    Py_TYPE(&StaticArray_Type) = &PyType_Type;
2843    Py_INCREF(&StaticArray_Type);
2844    PyModule_AddObject(m, "staticarray", (PyObject *)&StaticArray_Type);
2845
2846    structmodule = PyImport_ImportModule("struct");
2847    if (structmodule == NULL)
2848        return NULL;
2849
2850    Struct = PyObject_GetAttrString(structmodule, "Struct");
2851    calcsize = PyObject_GetAttrString(structmodule, "calcsize");
2852    if (Struct == NULL || calcsize == NULL)
2853        return NULL;
2854
2855    simple_format = PyUnicode_FromString(simple_fmt);
2856    if (simple_format == NULL)
2857        return NULL;
2858
2859    PyModule_AddIntMacro(m, ND_MAX_NDIM);
2860    PyModule_AddIntMacro(m, ND_VAREXPORT);
2861    PyModule_AddIntMacro(m, ND_WRITABLE);
2862    PyModule_AddIntMacro(m, ND_FORTRAN);
2863    PyModule_AddIntMacro(m, ND_SCALAR);
2864    PyModule_AddIntMacro(m, ND_PIL);
2865    PyModule_AddIntMacro(m, ND_GETBUF_FAIL);
2866    PyModule_AddIntMacro(m, ND_GETBUF_UNDEFINED);
2867    PyModule_AddIntMacro(m, ND_REDIRECT);
2868
2869    PyModule_AddIntMacro(m, PyBUF_SIMPLE);
2870    PyModule_AddIntMacro(m, PyBUF_WRITABLE);
2871    PyModule_AddIntMacro(m, PyBUF_FORMAT);
2872    PyModule_AddIntMacro(m, PyBUF_ND);
2873    PyModule_AddIntMacro(m, PyBUF_STRIDES);
2874    PyModule_AddIntMacro(m, PyBUF_INDIRECT);
2875    PyModule_AddIntMacro(m, PyBUF_C_CONTIGUOUS);
2876    PyModule_AddIntMacro(m, PyBUF_F_CONTIGUOUS);
2877    PyModule_AddIntMacro(m, PyBUF_ANY_CONTIGUOUS);
2878    PyModule_AddIntMacro(m, PyBUF_FULL);
2879    PyModule_AddIntMacro(m, PyBUF_FULL_RO);
2880    PyModule_AddIntMacro(m, PyBUF_RECORDS);
2881    PyModule_AddIntMacro(m, PyBUF_RECORDS_RO);
2882    PyModule_AddIntMacro(m, PyBUF_STRIDED);
2883    PyModule_AddIntMacro(m, PyBUF_STRIDED_RO);
2884    PyModule_AddIntMacro(m, PyBUF_CONTIG);
2885    PyModule_AddIntMacro(m, PyBUF_CONTIG_RO);
2886
2887    PyModule_AddIntMacro(m, PyBUF_READ);
2888    PyModule_AddIntMacro(m, PyBUF_WRITE);
2889
2890    return m;
2891}
2892
2893
2894
2895