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