You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2820 lines
81 KiB

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