Branch data Line data Source code
1 : : /*
2 : : * Memoryview object implementation
3 : : * --------------------------------
4 : : *
5 : : * This implementation is a complete rewrite contributed by Stefan Krah in
6 : : * Python 3.3. Substantial credit goes to Antoine Pitrou (who had already
7 : : * fortified and rewritten the previous implementation) and Nick Coghlan
8 : : * (who came up with the idea of the ManagedBuffer) for analyzing the complex
9 : : * ownership rules.
10 : : *
11 : : */
12 : :
13 : : #include "Python.h"
14 : : #include "pycore_abstract.h" // _PyIndex_Check()
15 : : #include "pycore_object.h" // _PyObject_GC_UNTRACK()
16 : : #include "pycore_strhex.h" // _Py_strhex_with_sep()
17 : : #include <stddef.h> // offsetof()
18 : :
19 : : /*[clinic input]
20 : : class memoryview "PyMemoryViewObject *" "&PyMemoryView_Type"
21 : : [clinic start generated code]*/
22 : : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=e2e49d2192835219]*/
23 : :
24 : : #include "clinic/memoryobject.c.h"
25 : :
26 : : /****************************************************************************/
27 : : /* ManagedBuffer Object */
28 : : /****************************************************************************/
29 : :
30 : : /*
31 : : ManagedBuffer Object:
32 : : ---------------------
33 : :
34 : : The purpose of this object is to facilitate the handling of chained
35 : : memoryviews that have the same underlying exporting object. PEP-3118
36 : : allows the underlying object to change while a view is exported. This
37 : : could lead to unexpected results when constructing a new memoryview
38 : : from an existing memoryview.
39 : :
40 : : Rather than repeatedly redirecting buffer requests to the original base
41 : : object, all chained memoryviews use a single buffer snapshot. This
42 : : snapshot is generated by the constructor _PyManagedBuffer_FromObject().
43 : :
44 : : Ownership rules:
45 : : ----------------
46 : :
47 : : The master buffer inside a managed buffer is filled in by the original
48 : : base object. shape, strides, suboffsets and format are read-only for
49 : : all consumers.
50 : :
51 : : A memoryview's buffer is a private copy of the exporter's buffer. shape,
52 : : strides and suboffsets belong to the memoryview and are thus writable.
53 : :
54 : : If a memoryview itself exports several buffers via memory_getbuf(), all
55 : : buffer copies share shape, strides and suboffsets. In this case, the
56 : : arrays are NOT writable.
57 : :
58 : : Reference count assumptions:
59 : : ----------------------------
60 : :
61 : : The 'obj' member of a Py_buffer must either be NULL or refer to the
62 : : exporting base object. In the Python codebase, all getbufferprocs
63 : : return a new reference to view.obj (example: bytes_buffer_getbuffer()).
64 : :
65 : : PyBuffer_Release() decrements view.obj (if non-NULL), so the
66 : : releasebufferprocs must NOT decrement view.obj.
67 : : */
68 : :
69 : :
70 : : static inline _PyManagedBufferObject *
71 : 1927208 : mbuf_alloc(void)
72 : : {
73 : : _PyManagedBufferObject *mbuf;
74 : :
75 : : mbuf = (_PyManagedBufferObject *)
76 : 1927208 : PyObject_GC_New(_PyManagedBufferObject, &_PyManagedBuffer_Type);
77 [ - + ]: 1927208 : if (mbuf == NULL)
78 : 0 : return NULL;
79 : 1927208 : mbuf->flags = 0;
80 : 1927208 : mbuf->exports = 0;
81 : 1927208 : mbuf->master.obj = NULL;
82 : 1927208 : _PyObject_GC_TRACK(mbuf);
83 : :
84 : 1927208 : return mbuf;
85 : : }
86 : :
87 : : static PyObject *
88 : 705328 : _PyManagedBuffer_FromObject(PyObject *base)
89 : : {
90 : : _PyManagedBufferObject *mbuf;
91 : :
92 : 705328 : mbuf = mbuf_alloc();
93 [ - + ]: 705328 : if (mbuf == NULL)
94 : 0 : return NULL;
95 : :
96 [ + + ]: 705328 : if (PyObject_GetBuffer(base, &mbuf->master, PyBUF_FULL_RO) < 0) {
97 : 517 : mbuf->master.obj = NULL;
98 : 517 : Py_DECREF(mbuf);
99 : 517 : return NULL;
100 : : }
101 : :
102 : 704811 : return (PyObject *)mbuf;
103 : : }
104 : :
105 : : static void
106 : 3853807 : mbuf_release(_PyManagedBufferObject *self)
107 : : {
108 [ + + ]: 3853807 : if (self->flags&_Py_MANAGED_BUFFER_RELEASED)
109 : 1926643 : return;
110 : :
111 : : /* NOTE: at this point self->exports can still be > 0 if this function
112 : : is called from mbuf_clear() to break up a reference cycle. */
113 : 1927164 : self->flags |= _Py_MANAGED_BUFFER_RELEASED;
114 : :
115 : : /* PyBuffer_Release() decrements master->obj and sets it to NULL. */
116 : 1927164 : _PyObject_GC_UNTRACK(self);
117 : 1927164 : PyBuffer_Release(&self->master);
118 : : }
119 : :
120 : : static void
121 : 1927164 : mbuf_dealloc(_PyManagedBufferObject *self)
122 : : {
123 : : assert(self->exports == 0);
124 : 1927164 : mbuf_release(self);
125 [ + + ]: 1927164 : if (self->flags&_Py_MANAGED_BUFFER_FREE_FORMAT)
126 : 22620 : PyMem_Free(self->master.format);
127 : 1927164 : PyObject_GC_Del(self);
128 : 1927164 : }
129 : :
130 : : static int
131 : 36468 : mbuf_traverse(_PyManagedBufferObject *self, visitproc visit, void *arg)
132 : : {
133 [ + + - + ]: 36468 : Py_VISIT(self->master.obj);
134 : 36468 : return 0;
135 : : }
136 : :
137 : : static int
138 : 2 : mbuf_clear(_PyManagedBufferObject *self)
139 : : {
140 : : assert(self->exports >= 0);
141 : 2 : mbuf_release(self);
142 : 2 : return 0;
143 : : }
144 : :
145 : : PyTypeObject _PyManagedBuffer_Type = {
146 : : PyVarObject_HEAD_INIT(&PyType_Type, 0)
147 : : "managedbuffer",
148 : : sizeof(_PyManagedBufferObject),
149 : : 0,
150 : : (destructor)mbuf_dealloc, /* tp_dealloc */
151 : : 0, /* tp_vectorcall_offset */
152 : : 0, /* tp_getattr */
153 : : 0, /* tp_setattr */
154 : : 0, /* tp_as_async */
155 : : 0, /* tp_repr */
156 : : 0, /* tp_as_number */
157 : : 0, /* tp_as_sequence */
158 : : 0, /* tp_as_mapping */
159 : : 0, /* tp_hash */
160 : : 0, /* tp_call */
161 : : 0, /* tp_str */
162 : : PyObject_GenericGetAttr, /* tp_getattro */
163 : : 0, /* tp_setattro */
164 : : 0, /* tp_as_buffer */
165 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
166 : : 0, /* tp_doc */
167 : : (traverseproc)mbuf_traverse, /* tp_traverse */
168 : : (inquiry)mbuf_clear /* tp_clear */
169 : : };
170 : :
171 : :
172 : : /****************************************************************************/
173 : : /* MemoryView Object */
174 : : /****************************************************************************/
175 : :
176 : : /* In the process of breaking reference cycles mbuf_release() can be
177 : : called before memory_release(). */
178 : : #define BASE_INACCESSIBLE(mv) \
179 : : (((PyMemoryViewObject *)mv)->flags&_Py_MEMORYVIEW_RELEASED || \
180 : : ((PyMemoryViewObject *)mv)->mbuf->flags&_Py_MANAGED_BUFFER_RELEASED)
181 : :
182 : : #define CHECK_RELEASED(mv) \
183 : : if (BASE_INACCESSIBLE(mv)) { \
184 : : PyErr_SetString(PyExc_ValueError, \
185 : : "operation forbidden on released memoryview object"); \
186 : : return NULL; \
187 : : }
188 : :
189 : : #define CHECK_RELEASED_INT(mv) \
190 : : if (BASE_INACCESSIBLE(mv)) { \
191 : : PyErr_SetString(PyExc_ValueError, \
192 : : "operation forbidden on released memoryview object"); \
193 : : return -1; \
194 : : }
195 : :
196 : : /* See gh-92888. These macros signal that we need to check the memoryview
197 : : again due to possible read after frees. */
198 : : #define CHECK_RELEASED_AGAIN(mv) CHECK_RELEASED(mv)
199 : : #define CHECK_RELEASED_INT_AGAIN(mv) CHECK_RELEASED_INT(mv)
200 : :
201 : : #define CHECK_LIST_OR_TUPLE(v) \
202 : : if (!PyList_Check(v) && !PyTuple_Check(v)) { \
203 : : PyErr_SetString(PyExc_TypeError, \
204 : : #v " must be a list or a tuple"); \
205 : : return NULL; \
206 : : }
207 : :
208 : : #define VIEW_ADDR(mv) (&((PyMemoryViewObject *)mv)->view)
209 : :
210 : : /* Check for the presence of suboffsets in the first dimension. */
211 : : #define HAVE_PTR(suboffsets, dim) (suboffsets && suboffsets[dim] >= 0)
212 : : /* Adjust ptr if suboffsets are present. */
213 : : #define ADJUST_PTR(ptr, suboffsets, dim) \
214 : : (HAVE_PTR(suboffsets, dim) ? *((char**)ptr) + suboffsets[dim] : ptr)
215 : :
216 : : /* Memoryview buffer properties */
217 : : #define MV_C_CONTIGUOUS(flags) (flags&(_Py_MEMORYVIEW_SCALAR|_Py_MEMORYVIEW_C))
218 : : #define MV_F_CONTIGUOUS(flags) \
219 : : (flags&(_Py_MEMORYVIEW_SCALAR|_Py_MEMORYVIEW_FORTRAN))
220 : : #define MV_ANY_CONTIGUOUS(flags) \
221 : : (flags&(_Py_MEMORYVIEW_SCALAR|_Py_MEMORYVIEW_C|_Py_MEMORYVIEW_FORTRAN))
222 : :
223 : : /* Fast contiguity test. Caller must ensure suboffsets==NULL and ndim==1. */
224 : : #define MV_CONTIGUOUS_NDIM1(view) \
225 : : ((view)->shape[0] == 1 || (view)->strides[0] == (view)->itemsize)
226 : :
227 : : /* getbuffer() requests */
228 : : #define REQ_INDIRECT(flags) ((flags&PyBUF_INDIRECT) == PyBUF_INDIRECT)
229 : : #define REQ_C_CONTIGUOUS(flags) ((flags&PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS)
230 : : #define REQ_F_CONTIGUOUS(flags) ((flags&PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS)
231 : : #define REQ_ANY_CONTIGUOUS(flags) ((flags&PyBUF_ANY_CONTIGUOUS) == PyBUF_ANY_CONTIGUOUS)
232 : : #define REQ_STRIDES(flags) ((flags&PyBUF_STRIDES) == PyBUF_STRIDES)
233 : : #define REQ_SHAPE(flags) ((flags&PyBUF_ND) == PyBUF_ND)
234 : : #define REQ_WRITABLE(flags) (flags&PyBUF_WRITABLE)
235 : : #define REQ_FORMAT(flags) (flags&PyBUF_FORMAT)
236 : :
237 : :
238 : : /**************************************************************************/
239 : : /* Copy memoryview buffers */
240 : : /**************************************************************************/
241 : :
242 : : /* The functions in this section take a source and a destination buffer
243 : : with the same logical structure: format, itemsize, ndim and shape
244 : : are identical, with ndim > 0.
245 : :
246 : : NOTE: All buffers are assumed to have PyBUF_FULL information, which
247 : : is the case for memoryviews! */
248 : :
249 : :
250 : : /* Assumptions: ndim >= 1. The macro tests for a corner case that should
251 : : perhaps be explicitly forbidden in the PEP. */
252 : : #define HAVE_SUBOFFSETS_IN_LAST_DIM(view) \
253 : : (view->suboffsets && view->suboffsets[dest->ndim-1] >= 0)
254 : :
255 : : static inline int
256 : 225981 : last_dim_is_contiguous(const Py_buffer *dest, const Py_buffer *src)
257 : : {
258 : : assert(dest->ndim > 0 && src->ndim > 0);
259 [ - + ]: 61 : return (!HAVE_SUBOFFSETS_IN_LAST_DIM(dest) &&
260 [ + + + + ]: 225920 : !HAVE_SUBOFFSETS_IN_LAST_DIM(src) &&
261 [ + + + + ]: 606787 : dest->strides[dest->ndim-1] == dest->itemsize &&
262 [ + + ]: 154825 : src->strides[src->ndim-1] == src->itemsize);
263 : : }
264 : :
265 : : /* This is not a general function for determining format equivalence.
266 : : It is used in copy_single() and copy_buffer() to weed out non-matching
267 : : formats. Skipping the '@' character is specifically used in slice
268 : : assignments, where the lvalue is already known to have a single character
269 : : format. This is a performance hack that could be rewritten (if properly
270 : : benchmarked). */
271 : : static inline int
272 : 226924 : equiv_format(const Py_buffer *dest, const Py_buffer *src)
273 : : {
274 : : const char *dfmt, *sfmt;
275 : :
276 : : assert(dest->format && src->format);
277 [ + + ]: 226924 : dfmt = dest->format[0] == '@' ? dest->format+1 : dest->format;
278 [ + + ]: 226924 : sfmt = src->format[0] == '@' ? src->format+1 : src->format;
279 : :
280 [ + + ]: 226924 : if (strcmp(dfmt, sfmt) != 0 ||
281 [ - + ]: 226922 : dest->itemsize != src->itemsize) {
282 : 2 : return 0;
283 : : }
284 : :
285 : 226922 : return 1;
286 : : }
287 : :
288 : : /* Two shapes are equivalent if they are either equal or identical up
289 : : to a zero element at the same position. For example, in NumPy arrays
290 : : the shapes [1, 0, 5] and [1, 0, 7] are equivalent. */
291 : : static inline int
292 : 389985 : equiv_shape(const Py_buffer *dest, const Py_buffer *src)
293 : : {
294 : : int i;
295 : :
296 [ + + ]: 389985 : if (dest->ndim != src->ndim)
297 : 12 : return 0;
298 : :
299 [ + + ]: 959473 : for (i = 0; i < dest->ndim; i++) {
300 [ + + ]: 570855 : if (dest->shape[i] != src->shape[i])
301 : 1001 : return 0;
302 [ + + ]: 569854 : if (dest->shape[i] == 0)
303 : 354 : break;
304 : : }
305 : :
306 : 388972 : return 1;
307 : : }
308 : :
309 : : /* Check that the logical structure of the destination and source buffers
310 : : is identical. */
311 : : static int
312 : 226924 : equiv_structure(const Py_buffer *dest, const Py_buffer *src)
313 : : {
314 [ + + + + ]: 453846 : if (!equiv_format(dest, src) ||
315 : 226922 : !equiv_shape(dest, src)) {
316 : 943 : PyErr_SetString(PyExc_ValueError,
317 : : "memoryview assignment: lvalue and rvalue have different "
318 : : "structures");
319 : 943 : return 0;
320 : : }
321 : :
322 : 225981 : return 1;
323 : : }
324 : :
325 : : /* Base case for recursive multi-dimensional copying. Contiguous arrays are
326 : : copied with very little overhead. Assumptions: ndim == 1, mem == NULL or
327 : : sizeof(mem) == shape[0] * itemsize. */
328 : : static void
329 : 361846 : copy_base(const Py_ssize_t *shape, Py_ssize_t itemsize,
330 : : char *dptr, const Py_ssize_t *dstrides, const Py_ssize_t *dsuboffsets,
331 : : char *sptr, const Py_ssize_t *sstrides, const Py_ssize_t *ssuboffsets,
332 : : char *mem)
333 : : {
334 [ + + ]: 361846 : if (mem == NULL) { /* contiguous */
335 : 66636 : Py_ssize_t size = shape[0] * itemsize;
336 [ + + + + ]: 66636 : if (dptr + size < sptr || sptr + size < dptr)
337 : 66159 : memcpy(dptr, sptr, size); /* no overlapping */
338 : : else
339 : 477 : memmove(dptr, sptr, size);
340 : : }
341 : : else {
342 : : char *p;
343 : : Py_ssize_t i;
344 [ + + ]: 2146657 : for (i=0, p=mem; i < shape[0]; p+=itemsize, sptr+=sstrides[0], i++) {
345 [ + + + + ]: 1851447 : char *xsptr = ADJUST_PTR(sptr, ssuboffsets, 0);
346 : 1851447 : memcpy(p, xsptr, itemsize);
347 : : }
348 [ + + ]: 2146657 : for (i=0, p=mem; i < shape[0]; p+=itemsize, dptr+=dstrides[0], i++) {
349 [ + + + - ]: 1851447 : char *xdptr = ADJUST_PTR(dptr, dsuboffsets, 0);
350 : 1851447 : memcpy(xdptr, p, itemsize);
351 : : }
352 : : }
353 : :
354 : 361846 : }
355 : :
356 : : /* Recursively copy a source buffer to a destination buffer. The two buffers
357 : : have the same ndim, shape and itemsize. */
358 : : static void
359 : 458209 : copy_rec(const Py_ssize_t *shape, Py_ssize_t ndim, Py_ssize_t itemsize,
360 : : char *dptr, const Py_ssize_t *dstrides, const Py_ssize_t *dsuboffsets,
361 : : char *sptr, const Py_ssize_t *sstrides, const Py_ssize_t *ssuboffsets,
362 : : char *mem)
363 : : {
364 : : Py_ssize_t i;
365 : :
366 : : assert(ndim >= 1);
367 : :
368 [ + + ]: 458209 : if (ndim == 1) {
369 : 356928 : copy_base(shape, itemsize,
370 : : dptr, dstrides, dsuboffsets,
371 : : sptr, sstrides, ssuboffsets,
372 : : mem);
373 : 356928 : return;
374 : : }
375 : :
376 [ + + ]: 338427 : for (i = 0; i < shape[0]; dptr+=dstrides[0], sptr+=sstrides[0], i++) {
377 [ - + - - ]: 237146 : char *xdptr = ADJUST_PTR(dptr, dsuboffsets, 0);
378 [ + + + + ]: 237146 : char *xsptr = ADJUST_PTR(sptr, ssuboffsets, 0);
379 : :
380 [ + + - + ]: 237146 : copy_rec(shape+1, ndim-1, itemsize,
381 : : xdptr, dstrides+1, dsuboffsets ? dsuboffsets+1 : NULL,
382 : : xsptr, sstrides+1, ssuboffsets ? ssuboffsets+1 : NULL,
383 : : mem);
384 : : }
385 : : }
386 : :
387 : : /* Faster copying of one-dimensional arrays. */
388 : : static int
389 : 5863 : copy_single(PyMemoryViewObject *self, const Py_buffer *dest, const Py_buffer *src)
390 : : {
391 [ + + - + ]: 5863 : CHECK_RELEASED_INT_AGAIN(self);
392 : 5861 : char *mem = NULL;
393 : :
394 : : assert(dest->ndim == 1);
395 : :
396 [ + + ]: 5861 : if (!equiv_structure(dest, src))
397 : 943 : return -1;
398 : :
399 [ + + ]: 4918 : if (!last_dim_is_contiguous(dest, src)) {
400 : 158 : mem = PyMem_Malloc(dest->shape[0] * dest->itemsize);
401 [ - + ]: 158 : if (mem == NULL) {
402 : : PyErr_NoMemory();
403 : 0 : return -1;
404 : : }
405 : : }
406 : :
407 : 4918 : copy_base(dest->shape, dest->itemsize,
408 : 4918 : dest->buf, dest->strides, dest->suboffsets,
409 : 4918 : src->buf, src->strides, src->suboffsets,
410 : : mem);
411 : :
412 [ + + ]: 4918 : if (mem)
413 : 158 : PyMem_Free(mem);
414 : :
415 : 4918 : return 0;
416 : : }
417 : :
418 : : /* Recursively copy src to dest. Both buffers must have the same basic
419 : : structure. Copying is atomic, the function never fails with a partial
420 : : copy. */
421 : : static int
422 : 221063 : copy_buffer(const Py_buffer *dest, const Py_buffer *src)
423 : : {
424 : 221063 : char *mem = NULL;
425 : :
426 : : assert(dest->ndim > 0);
427 : :
428 [ - + ]: 221063 : if (!equiv_structure(dest, src))
429 : 0 : return -1;
430 : :
431 [ + + ]: 221063 : if (!last_dim_is_contiguous(dest, src)) {
432 : 195579 : mem = PyMem_Malloc(dest->shape[dest->ndim-1] * dest->itemsize);
433 [ - + ]: 195579 : if (mem == NULL) {
434 : : PyErr_NoMemory();
435 : 0 : return -1;
436 : : }
437 : : }
438 : :
439 : 221063 : copy_rec(dest->shape, dest->ndim, dest->itemsize,
440 : 221063 : dest->buf, dest->strides, dest->suboffsets,
441 : 221063 : src->buf, src->strides, src->suboffsets,
442 : : mem);
443 : :
444 [ + + ]: 221063 : if (mem)
445 : 195579 : PyMem_Free(mem);
446 : :
447 : 221063 : return 0;
448 : : }
449 : :
450 : : /* Initialize strides for a C-contiguous array. */
451 : : static inline void
452 : 179459 : init_strides_from_shape(Py_buffer *view)
453 : : {
454 : : Py_ssize_t i;
455 : :
456 : : assert(view->ndim > 0);
457 : :
458 : 179459 : view->strides[view->ndim-1] = view->itemsize;
459 [ + + ]: 259986 : for (i = view->ndim-2; i >= 0; i--)
460 : 80527 : view->strides[i] = view->strides[i+1] * view->shape[i+1];
461 : 179459 : }
462 : :
463 : : /* Initialize strides for a Fortran-contiguous array. */
464 : : static inline void
465 : 53492 : init_fortran_strides_from_shape(Py_buffer *view)
466 : : {
467 : : Py_ssize_t i;
468 : :
469 : : assert(view->ndim > 0);
470 : :
471 : 53492 : view->strides[0] = view->itemsize;
472 [ + + ]: 76697 : for (i = 1; i < view->ndim; i++)
473 : 23205 : view->strides[i] = view->strides[i-1] * view->shape[i-1];
474 : 53492 : }
475 : :
476 : : /* Copy src to a contiguous representation. order is one of 'C', 'F' (Fortran)
477 : : or 'A' (Any). Assumptions: src has PyBUF_FULL information, src->ndim >= 1,
478 : : len(mem) == src->len. */
479 : : static int
480 : 198443 : buffer_to_contiguous(char *mem, const Py_buffer *src, char order)
481 : : {
482 : : Py_buffer dest;
483 : : Py_ssize_t *strides;
484 : : int ret;
485 : :
486 : : assert(src->ndim >= 1);
487 : : assert(src->shape != NULL);
488 : : assert(src->strides != NULL);
489 : :
490 : 198443 : strides = PyMem_Malloc(src->ndim * (sizeof *src->strides));
491 [ - + ]: 198443 : if (strides == NULL) {
492 : : PyErr_NoMemory();
493 : 0 : return -1;
494 : : }
495 : :
496 : : /* initialize dest */
497 : 198443 : dest = *src;
498 : 198443 : dest.buf = mem;
499 : : /* shape is constant and shared: the logical representation of the
500 : : array is unaltered. */
501 : :
502 : : /* The physical representation determined by strides (and possibly
503 : : suboffsets) may change. */
504 : 198443 : dest.strides = strides;
505 [ + + + + ]: 198443 : if (order == 'C' || order == 'A') {
506 : 152593 : init_strides_from_shape(&dest);
507 : : }
508 : : else {
509 : 45850 : init_fortran_strides_from_shape(&dest);
510 : : }
511 : :
512 : 198443 : dest.suboffsets = NULL;
513 : :
514 : 198443 : ret = copy_buffer(&dest, src);
515 : :
516 : 198443 : PyMem_Free(strides);
517 : 198443 : return ret;
518 : : }
519 : :
520 : :
521 : : /****************************************************************************/
522 : : /* Constructors */
523 : : /****************************************************************************/
524 : :
525 : : /* Initialize values that are shared with the managed buffer. */
526 : : static inline void
527 : 2422963 : init_shared_values(Py_buffer *dest, const Py_buffer *src)
528 : : {
529 : 2422963 : dest->obj = src->obj;
530 : 2422963 : dest->buf = src->buf;
531 : 2422963 : dest->len = src->len;
532 : 2422963 : dest->itemsize = src->itemsize;
533 : 2422963 : dest->readonly = src->readonly;
534 [ + + ]: 2422963 : dest->format = src->format ? src->format : "B";
535 : 2422963 : dest->internal = src->internal;
536 : 2422963 : }
537 : :
538 : : /* Copy shape and strides. Reconstruct missing values. */
539 : : static void
540 : 2360501 : init_shape_strides(Py_buffer *dest, const Py_buffer *src)
541 : : {
542 : : Py_ssize_t i;
543 : :
544 [ + + ]: 2360501 : if (src->ndim == 0) {
545 : 5428 : dest->shape = NULL;
546 : 5428 : dest->strides = NULL;
547 : 5428 : return;
548 : : }
549 [ + + ]: 2355073 : if (src->ndim == 1) {
550 [ + + ]: 2065957 : dest->shape[0] = src->shape ? src->shape[0] : src->len / src->itemsize;
551 [ + + ]: 2065957 : dest->strides[0] = src->strides ? src->strides[0] : src->itemsize;
552 : 2065957 : return;
553 : : }
554 : :
555 [ + + ]: 934327 : for (i = 0; i < src->ndim; i++)
556 : 645211 : dest->shape[i] = src->shape[i];
557 [ + + ]: 289116 : if (src->strides) {
558 [ + + ]: 934303 : for (i = 0; i < src->ndim; i++)
559 : 645193 : dest->strides[i] = src->strides[i];
560 : : }
561 : : else {
562 : 6 : init_strides_from_shape(dest);
563 : : }
564 : : }
565 : :
566 : : static inline void
567 : 2360501 : init_suboffsets(Py_buffer *dest, const Py_buffer *src)
568 : : {
569 : : Py_ssize_t i;
570 : :
571 [ + + ]: 2360501 : if (src->suboffsets == NULL) {
572 : 2197754 : dest->suboffsets = NULL;
573 : 2197754 : return;
574 : : }
575 [ + + ]: 396888 : for (i = 0; i < src->ndim; i++)
576 : 234141 : dest->suboffsets[i] = src->suboffsets[i];
577 : : }
578 : :
579 : : /* len = product(shape) * itemsize */
580 : : static inline void
581 : 198334 : init_len(Py_buffer *view)
582 : : {
583 : : Py_ssize_t i, len;
584 : :
585 : 198334 : len = 1;
586 [ + + ]: 396670 : for (i = 0; i < view->ndim; i++)
587 : 198336 : len *= view->shape[i];
588 : 198334 : len *= view->itemsize;
589 : :
590 : 198334 : view->len = len;
591 : 198334 : }
592 : :
593 : : /* Initialize memoryview buffer properties. */
594 : : static void
595 : 2426511 : init_flags(PyMemoryViewObject *mv)
596 : : {
597 : 2426511 : const Py_buffer *view = &mv->view;
598 : 2426511 : int flags = 0;
599 : :
600 [ + + + ]: 2426511 : switch (view->ndim) {
601 : 5429 : case 0:
602 : 5429 : flags |= (_Py_MEMORYVIEW_SCALAR|_Py_MEMORYVIEW_C|
603 : : _Py_MEMORYVIEW_FORTRAN);
604 : 5429 : break;
605 : 2198519 : case 1:
606 [ + + + + ]: 2198519 : if (MV_CONTIGUOUS_NDIM1(view))
607 : 2067996 : flags |= (_Py_MEMORYVIEW_C|_Py_MEMORYVIEW_FORTRAN);
608 : 2198519 : break;
609 : 222563 : default:
610 [ + + ]: 222563 : if (PyBuffer_IsContiguous(view, 'C'))
611 : 117547 : flags |= _Py_MEMORYVIEW_C;
612 [ + + ]: 222563 : if (PyBuffer_IsContiguous(view, 'F'))
613 : 100804 : flags |= _Py_MEMORYVIEW_FORTRAN;
614 : 222563 : break;
615 : : }
616 : :
617 [ + + ]: 2426511 : if (view->suboffsets) {
618 : 88700 : flags |= _Py_MEMORYVIEW_PIL;
619 : 88700 : flags &= ~(_Py_MEMORYVIEW_C|_Py_MEMORYVIEW_FORTRAN);
620 : : }
621 : :
622 : 2426511 : mv->flags = flags;
623 : 2426511 : }
624 : :
625 : : /* Allocate a new memoryview and perform basic initialization. New memoryviews
626 : : are exclusively created through the mbuf_add functions. */
627 : : static inline PyMemoryViewObject *
628 : 2224524 : memory_alloc(int ndim)
629 : : {
630 : : PyMemoryViewObject *mv;
631 : :
632 : : mv = (PyMemoryViewObject *)
633 : 2224524 : PyObject_GC_NewVar(PyMemoryViewObject, &PyMemoryView_Type, 3*ndim);
634 [ - + ]: 2224524 : if (mv == NULL)
635 : 0 : return NULL;
636 : :
637 : 2224524 : mv->mbuf = NULL;
638 : 2224524 : mv->hash = -1;
639 : 2224524 : mv->flags = 0;
640 : 2224524 : mv->exports = 0;
641 : 2224524 : mv->view.ndim = ndim;
642 : 2224524 : mv->view.shape = mv->ob_array;
643 : 2224524 : mv->view.strides = mv->ob_array + ndim;
644 : 2224524 : mv->view.suboffsets = mv->ob_array + 2 * ndim;
645 : 2224524 : mv->weakreflist = NULL;
646 : :
647 : 2224524 : _PyObject_GC_TRACK(mv);
648 : 2224524 : return mv;
649 : : }
650 : :
651 : : /*
652 : : Return a new memoryview that is registered with mbuf. If src is NULL,
653 : : use mbuf->master as the underlying buffer. Otherwise, use src.
654 : :
655 : : The new memoryview has full buffer information: shape and strides
656 : : are always present, suboffsets as needed. Arrays are copied to
657 : : the memoryview's ob_array field.
658 : : */
659 : : static PyObject *
660 : 2162068 : mbuf_add_view(_PyManagedBufferObject *mbuf, const Py_buffer *src)
661 : : {
662 : : PyMemoryViewObject *mv;
663 : : Py_buffer *dest;
664 : :
665 [ + + ]: 2162068 : if (src == NULL)
666 : 1904071 : src = &mbuf->master;
667 : :
668 [ + + ]: 2162068 : if (src->ndim > PyBUF_MAX_NDIM) {
669 : 6 : PyErr_SetString(PyExc_ValueError,
670 : : "memoryview: number of dimensions must not exceed "
671 : : Py_STRINGIFY(PyBUF_MAX_NDIM));
672 : 6 : return NULL;
673 : : }
674 : :
675 : 2162062 : mv = memory_alloc(src->ndim);
676 [ - + ]: 2162062 : if (mv == NULL)
677 : 0 : return NULL;
678 : :
679 : 2162062 : dest = &mv->view;
680 : 2162062 : init_shared_values(dest, src);
681 : 2162062 : init_shape_strides(dest, src);
682 : 2162062 : init_suboffsets(dest, src);
683 : 2162062 : init_flags(mv);
684 : :
685 : 2162062 : mv->mbuf = mbuf;
686 : 2162062 : Py_INCREF(mbuf);
687 : 2162062 : mbuf->exports++;
688 : :
689 : 2162062 : return (PyObject *)mv;
690 : : }
691 : :
692 : : /* Register an incomplete view: shape, strides, suboffsets and flags still
693 : : need to be initialized. Use 'ndim' instead of src->ndim to determine the
694 : : size of the memoryview's ob_array.
695 : :
696 : : Assumption: ndim <= PyBUF_MAX_NDIM. */
697 : : static PyObject *
698 : 62462 : mbuf_add_incomplete_view(_PyManagedBufferObject *mbuf, const Py_buffer *src,
699 : : int ndim)
700 : : {
701 : : PyMemoryViewObject *mv;
702 : : Py_buffer *dest;
703 : :
704 [ + + ]: 62462 : if (src == NULL)
705 : 22620 : src = &mbuf->master;
706 : :
707 : : assert(ndim <= PyBUF_MAX_NDIM);
708 : :
709 : 62462 : mv = memory_alloc(ndim);
710 [ - + ]: 62462 : if (mv == NULL)
711 : 0 : return NULL;
712 : :
713 : 62462 : dest = &mv->view;
714 : 62462 : init_shared_values(dest, src);
715 : :
716 : 62462 : mv->mbuf = mbuf;
717 : 62462 : Py_INCREF(mbuf);
718 : 62462 : mbuf->exports++;
719 : :
720 : 62462 : return (PyObject *)mv;
721 : : }
722 : :
723 : : /* Expose a raw memory area as a view of contiguous bytes. flags can be
724 : : PyBUF_READ or PyBUF_WRITE. view->format is set to "B" (unsigned bytes).
725 : : The memoryview has complete buffer information. */
726 : : PyObject *
727 : 180347 : PyMemoryView_FromMemory(char *mem, Py_ssize_t size, int flags)
728 : : {
729 : : _PyManagedBufferObject *mbuf;
730 : : PyObject *mv;
731 : : int readonly;
732 : :
733 : : assert(mem != NULL);
734 : : assert(flags == PyBUF_READ || flags == PyBUF_WRITE);
735 : :
736 : 180347 : mbuf = mbuf_alloc();
737 [ - + ]: 180347 : if (mbuf == NULL)
738 : 0 : return NULL;
739 : :
740 : 180347 : readonly = (flags == PyBUF_WRITE) ? 0 : 1;
741 : 180347 : (void)PyBuffer_FillInfo(&mbuf->master, NULL, mem, size, readonly,
742 : : PyBUF_FULL_RO);
743 : :
744 : 180347 : mv = mbuf_add_view(mbuf, NULL);
745 : 180347 : Py_DECREF(mbuf);
746 : :
747 : 180347 : return mv;
748 : : }
749 : :
750 : : /* Create a memoryview from a given Py_buffer. For simple byte views,
751 : : PyMemoryView_FromMemory() should be used instead.
752 : : This function is the only entry point that can create a master buffer
753 : : without full information. Because of this fact init_shape_strides()
754 : : must be able to reconstruct missing values. */
755 : : PyObject *
756 : 1041534 : PyMemoryView_FromBuffer(const Py_buffer *info)
757 : : {
758 : : _PyManagedBufferObject *mbuf;
759 : : PyObject *mv;
760 : :
761 [ + + ]: 1041534 : if (info->buf == NULL) {
762 : 1 : PyErr_SetString(PyExc_ValueError,
763 : : "PyMemoryView_FromBuffer(): info->buf must not be NULL");
764 : 1 : return NULL;
765 : : }
766 : :
767 : 1041533 : mbuf = mbuf_alloc();
768 [ - + ]: 1041533 : if (mbuf == NULL)
769 : 0 : return NULL;
770 : :
771 : : /* info->obj is either NULL or a borrowed reference. This reference
772 : : should not be decremented in PyBuffer_Release(). */
773 : 1041533 : mbuf->master = *info;
774 : 1041533 : mbuf->master.obj = NULL;
775 : :
776 : 1041533 : mv = mbuf_add_view(mbuf, NULL);
777 : 1041533 : Py_DECREF(mbuf);
778 : :
779 : 1041533 : return mv;
780 : : }
781 : :
782 : : /* Create a memoryview from an object that implements the buffer protocol.
783 : : If the object is a memoryview, the new memoryview must be registered
784 : : with the same managed buffer. Otherwise, a new managed buffer is created. */
785 : : PyObject *
786 : 714796 : PyMemoryView_FromObject(PyObject *v)
787 : : {
788 : : _PyManagedBufferObject *mbuf;
789 : :
790 [ + + ]: 714796 : if (PyMemoryView_Check(v)) {
791 : 32003 : PyMemoryViewObject *mv = (PyMemoryViewObject *)v;
792 [ + + - + ]: 32003 : CHECK_RELEASED(mv);
793 : 32002 : return mbuf_add_view(mv->mbuf, &mv->view);
794 : : }
795 [ + + ]: 682793 : else if (PyObject_CheckBuffer(v)) {
796 : : PyObject *ret;
797 : 682708 : mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(v);
798 [ + + ]: 682708 : if (mbuf == NULL)
799 : 517 : return NULL;
800 : 682191 : ret = mbuf_add_view(mbuf, NULL);
801 : 682191 : Py_DECREF(mbuf);
802 : 682191 : return ret;
803 : : }
804 : :
805 : 85 : PyErr_Format(PyExc_TypeError,
806 : : "memoryview: a bytes-like object is required, not '%.200s'",
807 : 85 : Py_TYPE(v)->tp_name);
808 : 85 : return NULL;
809 : : }
810 : :
811 : : /* Copy the format string from a base object that might vanish. */
812 : : static int
813 : 22620 : mbuf_copy_format(_PyManagedBufferObject *mbuf, const char *fmt)
814 : : {
815 [ + - ]: 22620 : if (fmt != NULL) {
816 : 22620 : char *cp = PyMem_Malloc(strlen(fmt)+1);
817 [ - + ]: 22620 : if (cp == NULL) {
818 : : PyErr_NoMemory();
819 : 0 : return -1;
820 : : }
821 : 22620 : mbuf->master.format = strcpy(cp, fmt);
822 : 22620 : mbuf->flags |= _Py_MANAGED_BUFFER_FREE_FORMAT;
823 : : }
824 : :
825 : 22620 : return 0;
826 : : }
827 : :
828 : : /*
829 : : Return a memoryview that is based on a contiguous copy of src.
830 : : Assumptions: src has PyBUF_FULL_RO information, src->ndim > 0.
831 : :
832 : : Ownership rules:
833 : : 1) As usual, the returned memoryview has a private copy
834 : : of src->shape, src->strides and src->suboffsets.
835 : : 2) src->format is copied to the master buffer and released
836 : : in mbuf_dealloc(). The releasebufferproc of the bytes
837 : : object is NULL, so it does not matter that mbuf_release()
838 : : passes the altered format pointer to PyBuffer_Release().
839 : : */
840 : : static PyObject *
841 : 22620 : memory_from_contiguous_copy(const Py_buffer *src, char order)
842 : : {
843 : : _PyManagedBufferObject *mbuf;
844 : : PyMemoryViewObject *mv;
845 : : PyObject *bytes;
846 : : Py_buffer *dest;
847 : : int i;
848 : :
849 : : assert(src->ndim > 0);
850 : : assert(src->shape != NULL);
851 : :
852 : 22620 : bytes = PyBytes_FromStringAndSize(NULL, src->len);
853 [ - + ]: 22620 : if (bytes == NULL)
854 : 0 : return NULL;
855 : :
856 : 22620 : mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(bytes);
857 : 22620 : Py_DECREF(bytes);
858 [ - + ]: 22620 : if (mbuf == NULL)
859 : 0 : return NULL;
860 : :
861 [ - + ]: 22620 : if (mbuf_copy_format(mbuf, src->format) < 0) {
862 : 0 : Py_DECREF(mbuf);
863 : 0 : return NULL;
864 : : }
865 : :
866 : 22620 : mv = (PyMemoryViewObject *)mbuf_add_incomplete_view(mbuf, NULL, src->ndim);
867 : 22620 : Py_DECREF(mbuf);
868 [ - + ]: 22620 : if (mv == NULL)
869 : 0 : return NULL;
870 : :
871 : 22620 : dest = &mv->view;
872 : :
873 : : /* shared values are initialized correctly except for itemsize */
874 : 22620 : dest->itemsize = src->itemsize;
875 : :
876 : : /* shape and strides */
877 [ + + ]: 54863 : for (i = 0; i < src->ndim; i++) {
878 : 32243 : dest->shape[i] = src->shape[i];
879 : : }
880 [ + + + + ]: 22620 : if (order == 'C' || order == 'A') {
881 : 14978 : init_strides_from_shape(dest);
882 : : }
883 : : else {
884 : 7642 : init_fortran_strides_from_shape(dest);
885 : : }
886 : : /* suboffsets */
887 : 22620 : dest->suboffsets = NULL;
888 : :
889 : : /* flags */
890 : 22620 : init_flags(mv);
891 : :
892 [ - + ]: 22620 : if (copy_buffer(dest, src) < 0) {
893 : 0 : Py_DECREF(mv);
894 : 0 : return NULL;
895 : : }
896 : :
897 : 22620 : return (PyObject *)mv;
898 : : }
899 : :
900 : : /*
901 : : Return a new memoryview object based on a contiguous exporter with
902 : : buffertype={PyBUF_READ, PyBUF_WRITE} and order={'C', 'F'ortran, or 'A'ny}.
903 : : The logical structure of the input and output buffers is the same
904 : : (i.e. tolist(input) == tolist(output)), but the physical layout in
905 : : memory can be explicitly chosen.
906 : :
907 : : As usual, if buffertype=PyBUF_WRITE, the exporter's buffer must be writable,
908 : : otherwise it may be writable or read-only.
909 : :
910 : : If the exporter is already contiguous with the desired target order,
911 : : the memoryview will be directly based on the exporter.
912 : :
913 : : Otherwise, if the buffertype is PyBUF_READ, the memoryview will be
914 : : based on a new bytes object. If order={'C', 'A'ny}, use 'C' order,
915 : : 'F'ortran order otherwise.
916 : : */
917 : : PyObject *
918 : 34059 : PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char order)
919 : : {
920 : : PyMemoryViewObject *mv;
921 : : PyObject *ret;
922 : : Py_buffer *view;
923 : :
924 : : assert(buffertype == PyBUF_READ || buffertype == PyBUF_WRITE);
925 : : assert(order == 'C' || order == 'F' || order == 'A');
926 : :
927 : 34059 : mv = (PyMemoryViewObject *)PyMemoryView_FromObject(obj);
928 [ + + ]: 34059 : if (mv == NULL)
929 : 4 : return NULL;
930 : :
931 : 34055 : view = &mv->view;
932 [ + + + + ]: 34055 : if (buffertype == PyBUF_WRITE && view->readonly) {
933 : 2 : PyErr_SetString(PyExc_BufferError,
934 : : "underlying buffer is not writable");
935 : 2 : Py_DECREF(mv);
936 : 2 : return NULL;
937 : : }
938 : :
939 [ + + ]: 34053 : if (PyBuffer_IsContiguous(view, order))
940 : 11428 : return (PyObject *)mv;
941 : :
942 [ + + ]: 22625 : if (buffertype == PyBUF_WRITE) {
943 : 5 : PyErr_SetString(PyExc_BufferError,
944 : : "writable contiguous buffer requested "
945 : : "for a non-contiguous object.");
946 : 5 : Py_DECREF(mv);
947 : 5 : return NULL;
948 : : }
949 : :
950 : 22620 : ret = memory_from_contiguous_copy(view, order);
951 : 22620 : Py_DECREF(mv);
952 : 22620 : return ret;
953 : : }
954 : :
955 : :
956 : : /*[clinic input]
957 : : @classmethod
958 : : memoryview.__new__
959 : :
960 : : object: object
961 : :
962 : : Create a new memoryview object which references the given object.
963 : : [clinic start generated code]*/
964 : :
965 : : static PyObject *
966 : 608988 : memoryview_impl(PyTypeObject *type, PyObject *object)
967 : : /*[clinic end generated code: output=7de78e184ed66db8 input=f04429eb0bdf8c6e]*/
968 : : {
969 : 608988 : return PyMemoryView_FromObject(object);
970 : : }
971 : :
972 : :
973 : : /****************************************************************************/
974 : : /* Previously in abstract.c */
975 : : /****************************************************************************/
976 : :
977 : : typedef struct {
978 : : Py_buffer view;
979 : : Py_ssize_t array[1];
980 : : } Py_buffer_full;
981 : :
982 : : int
983 : 575490 : PyBuffer_ToContiguous(void *buf, const Py_buffer *src, Py_ssize_t len, char order)
984 : : {
985 : 575490 : Py_buffer_full *fb = NULL;
986 : : int ret;
987 : :
988 : : assert(order == 'C' || order == 'F' || order == 'A');
989 : :
990 [ - + ]: 575490 : if (len != src->len) {
991 : 0 : PyErr_SetString(PyExc_ValueError,
992 : : "PyBuffer_ToContiguous: len != view->len");
993 : 0 : return -1;
994 : : }
995 : :
996 [ + + ]: 575490 : if (PyBuffer_IsContiguous(src, order)) {
997 : 377051 : memcpy((char *)buf, src->buf, len);
998 : 377051 : return 0;
999 : : }
1000 : :
1001 : : /* buffer_to_contiguous() assumes PyBUF_FULL */
1002 : 198439 : fb = PyMem_Malloc(sizeof *fb + 3 * src->ndim * (sizeof *fb->array));
1003 [ - + ]: 198439 : if (fb == NULL) {
1004 : : PyErr_NoMemory();
1005 : 0 : return -1;
1006 : : }
1007 : 198439 : fb->view.ndim = src->ndim;
1008 : 198439 : fb->view.shape = fb->array;
1009 : 198439 : fb->view.strides = fb->array + src->ndim;
1010 : 198439 : fb->view.suboffsets = fb->array + 2 * src->ndim;
1011 : :
1012 : 198439 : init_shared_values(&fb->view, src);
1013 : 198439 : init_shape_strides(&fb->view, src);
1014 : 198439 : init_suboffsets(&fb->view, src);
1015 : :
1016 : 198439 : src = &fb->view;
1017 : :
1018 : 198439 : ret = buffer_to_contiguous(buf, src, order);
1019 : 198439 : PyMem_Free(fb);
1020 : 198439 : return ret;
1021 : : }
1022 : :
1023 : :
1024 : : /****************************************************************************/
1025 : : /* Release/GC management */
1026 : : /****************************************************************************/
1027 : :
1028 : : /* Inform the managed buffer that this particular memoryview will not access
1029 : : the underlying buffer again. If no other memoryviews are registered with
1030 : : the managed buffer, the underlying buffer is released instantly and
1031 : : marked as inaccessible for both the memoryview and the managed buffer.
1032 : :
1033 : : This function fails if the memoryview itself has exported buffers. */
1034 : : static int
1035 : 2269847 : _memory_release(PyMemoryViewObject *self)
1036 : : {
1037 [ + + ]: 2269847 : if (self->flags & _Py_MEMORYVIEW_RELEASED)
1038 : 45367 : return 0;
1039 : :
1040 [ + + ]: 2224480 : if (self->exports == 0) {
1041 : 2224475 : self->flags |= _Py_MEMORYVIEW_RELEASED;
1042 : : assert(self->mbuf->exports > 0);
1043 [ + + ]: 2224475 : if (--self->mbuf->exports == 0)
1044 : 1926641 : mbuf_release(self->mbuf);
1045 : 2224475 : return 0;
1046 : : }
1047 [ + - ]: 5 : if (self->exports > 0) {
1048 : 5 : PyErr_Format(PyExc_BufferError,
1049 : : "memoryview has %zd exported buffer%s", self->exports,
1050 [ + + ]: 5 : self->exports==1 ? "" : "s");
1051 : 5 : return -1;
1052 : : }
1053 : :
1054 : 0 : PyErr_SetString(PyExc_SystemError,
1055 : : "_memory_release(): negative export count");
1056 : 0 : return -1;
1057 : : }
1058 : :
1059 : : /*[clinic input]
1060 : : memoryview.release
1061 : :
1062 : : Release the underlying buffer exposed by the memoryview object.
1063 : : [clinic start generated code]*/
1064 : :
1065 : : static PyObject *
1066 : 45370 : memoryview_release_impl(PyMemoryViewObject *self)
1067 : : /*[clinic end generated code: output=d0b7e3ba95b7fcb9 input=bc71d1d51f4a52f0]*/
1068 : : {
1069 [ + + ]: 45370 : if (_memory_release(self) < 0)
1070 : 5 : return NULL;
1071 : 45365 : Py_RETURN_NONE;
1072 : : }
1073 : :
1074 : : static void
1075 : 2224475 : memory_dealloc(PyMemoryViewObject *self)
1076 : : {
1077 : : assert(self->exports == 0);
1078 : 2224475 : _PyObject_GC_UNTRACK(self);
1079 : 2224475 : (void)_memory_release(self);
1080 [ + + ]: 2224475 : Py_CLEAR(self->mbuf);
1081 [ + + ]: 2224475 : if (self->weakreflist != NULL)
1082 : 9 : PyObject_ClearWeakRefs((PyObject *) self);
1083 : 2224475 : PyObject_GC_Del(self);
1084 : 2224475 : }
1085 : :
1086 : : static int
1087 : 36514 : memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
1088 : : {
1089 [ + - - + ]: 36514 : Py_VISIT(self->mbuf);
1090 : 36514 : return 0;
1091 : : }
1092 : :
1093 : : static int
1094 : 2 : memory_clear(PyMemoryViewObject *self)
1095 : : {
1096 : 2 : (void)_memory_release(self);
1097 [ + - ]: 2 : Py_CLEAR(self->mbuf);
1098 : 2 : return 0;
1099 : : }
1100 : :
1101 : : static PyObject *
1102 : 45043 : memory_enter(PyObject *self, PyObject *args)
1103 : : {
1104 [ + + - + ]: 45043 : CHECK_RELEASED(self);
1105 : 45016 : Py_INCREF(self);
1106 : 45016 : return self;
1107 : : }
1108 : :
1109 : : static PyObject *
1110 : 45016 : memory_exit(PyObject *self, PyObject *args)
1111 : : {
1112 : 45016 : return memoryview_release_impl((PyMemoryViewObject *)self);
1113 : : }
1114 : :
1115 : :
1116 : : /****************************************************************************/
1117 : : /* Casting format and shape */
1118 : : /****************************************************************************/
1119 : :
1120 : : #define IS_BYTE_FORMAT(f) (f == 'b' || f == 'B' || f == 'c')
1121 : :
1122 : : static inline Py_ssize_t
1123 : 398439 : get_native_fmtchar(char *result, const char *fmt)
1124 : : {
1125 : 398439 : Py_ssize_t size = -1;
1126 : :
1127 [ + + ]: 398439 : if (fmt[0] == '@') fmt++;
1128 : :
1129 [ + + + + : 398439 : switch (fmt[0]) {
+ + + + +
+ + ]
1130 : 184025 : case 'c': case 'b': case 'B': size = sizeof(char); break;
1131 : 13181 : case 'h': case 'H': size = sizeof(short); break;
1132 : 16501 : case 'i': case 'I': size = sizeof(int); break;
1133 : 61036 : case 'l': case 'L': size = sizeof(long); break;
1134 : 8727 : case 'q': case 'Q': size = sizeof(long long); break;
1135 : 7762 : case 'n': case 'N': size = sizeof(Py_ssize_t); break;
1136 : 6664 : case 'f': size = sizeof(float); break;
1137 : 6803 : case 'd': size = sizeof(double); break;
1138 : 50569 : case '?': size = sizeof(_Bool); break;
1139 : 4448 : case 'P': size = sizeof(void *); break;
1140 : : }
1141 : :
1142 [ + + + + ]: 398439 : if (size > 0 && fmt[1] == '\0') {
1143 : 359666 : *result = fmt[0];
1144 : 359666 : return size;
1145 : : }
1146 : :
1147 : 38773 : return -1;
1148 : : }
1149 : :
1150 : : static inline const char *
1151 : 31614 : get_native_fmtstr(const char *fmt)
1152 : : {
1153 : 31614 : int at = 0;
1154 : :
1155 [ + + ]: 31614 : if (fmt[0] == '@') {
1156 : 8579 : at = 1;
1157 : 8579 : fmt++;
1158 : : }
1159 [ + - - + ]: 31614 : if (fmt[0] == '\0' || fmt[1] != '\0') {
1160 : 0 : return NULL;
1161 : : }
1162 : :
1163 : : #define RETURN(s) do { return at ? "@" s : s; } while (0)
1164 : :
1165 [ + + + + : 31614 : switch (fmt[0]) {
+ + + + +
+ + + + +
+ + + - ]
1166 [ + + ]: 3290 : case 'c': RETURN("c");
1167 [ + + ]: 3282 : case 'b': RETURN("b");
1168 [ + + ]: 13737 : case 'B': RETURN("B");
1169 [ + + ]: 607 : case 'h': RETURN("h");
1170 [ + + ]: 613 : case 'H': RETURN("H");
1171 [ + + ]: 928 : case 'i': RETURN("i");
1172 [ + + ]: 3317 : case 'I': RETURN("I");
1173 [ + + ]: 607 : case 'l': RETURN("l");
1174 [ + + ]: 607 : case 'L': RETURN("L");
1175 [ + + ]: 604 : case 'q': RETURN("q");
1176 [ + + ]: 604 : case 'Q': RETURN("Q");
1177 [ + + ]: 604 : case 'n': RETURN("n");
1178 [ + + ]: 604 : case 'N': RETURN("N");
1179 [ + + ]: 596 : case 'f': RETURN("f");
1180 [ + + ]: 606 : case 'd': RETURN("d");
1181 [ + + ]: 405 : case '?': RETURN("?");
1182 [ + + ]: 603 : case 'P': RETURN("P");
1183 : : }
1184 : :
1185 : 0 : return NULL;
1186 : : }
1187 : :
1188 : :
1189 : : /* Cast a memoryview's data type to 'format'. The input array must be
1190 : : C-contiguous. At least one of input-format, output-format must have
1191 : : byte size. The output array is 1-D, with the same byte length as the
1192 : : input array. Thus, view->len must be a multiple of the new itemsize. */
1193 : : static int
1194 : 39842 : cast_to_1D(PyMemoryViewObject *mv, PyObject *format)
1195 : : {
1196 : 39842 : Py_buffer *view = &mv->view;
1197 : : PyObject *asciifmt;
1198 : : char srcchar, destchar;
1199 : : Py_ssize_t itemsize;
1200 : 39842 : int ret = -1;
1201 : :
1202 : : assert(view->ndim >= 1);
1203 : : assert(Py_SIZE(mv) == 3*view->ndim);
1204 : : assert(view->shape == mv->ob_array);
1205 : : assert(view->strides == mv->ob_array + view->ndim);
1206 : : assert(view->suboffsets == mv->ob_array + 2*view->ndim);
1207 : :
1208 : 39842 : asciifmt = PyUnicode_AsASCIIString(format);
1209 [ - + ]: 39842 : if (asciifmt == NULL)
1210 : 0 : return ret;
1211 : :
1212 : 39842 : itemsize = get_native_fmtchar(&destchar, PyBytes_AS_STRING(asciifmt));
1213 [ + + ]: 39842 : if (itemsize < 0) {
1214 : 7506 : PyErr_SetString(PyExc_ValueError,
1215 : : "memoryview: destination format must be a native single "
1216 : : "character format prefixed with an optional '@'");
1217 : 7506 : goto out;
1218 : : }
1219 : :
1220 [ + + ]: 32336 : if ((get_native_fmtchar(&srcchar, view->format) < 0 ||
1221 [ + + + + : 32336 : !IS_BYTE_FORMAT(srcchar)) && !IS_BYTE_FORMAT(destchar)) {
+ + + + +
+ + + ]
1222 : 721 : PyErr_SetString(PyExc_TypeError,
1223 : : "memoryview: cannot cast between two non-byte formats");
1224 : 721 : goto out;
1225 : : }
1226 [ + + ]: 31615 : if (view->len % itemsize) {
1227 : 1 : PyErr_SetString(PyExc_TypeError,
1228 : : "memoryview: length is not a multiple of itemsize");
1229 : 1 : goto out;
1230 : : }
1231 : :
1232 : 31614 : view->format = (char *)get_native_fmtstr(PyBytes_AS_STRING(asciifmt));
1233 [ - + ]: 31614 : if (view->format == NULL) {
1234 : : /* NOT_REACHED: get_native_fmtchar() already validates the format. */
1235 : 0 : PyErr_SetString(PyExc_RuntimeError,
1236 : : "memoryview: internal error");
1237 : 0 : goto out;
1238 : : }
1239 : 31614 : view->itemsize = itemsize;
1240 : :
1241 : 31614 : view->ndim = 1;
1242 : 31614 : view->shape[0] = view->len / view->itemsize;
1243 : 31614 : view->strides[0] = view->itemsize;
1244 : 31614 : view->suboffsets = NULL;
1245 : :
1246 : 31614 : init_flags(mv);
1247 : :
1248 : 31614 : ret = 0;
1249 : :
1250 : 39842 : out:
1251 : 39842 : Py_DECREF(asciifmt);
1252 : 39842 : return ret;
1253 : : }
1254 : :
1255 : : /* The memoryview must have space for 3*len(seq) elements. */
1256 : : static Py_ssize_t
1257 : 11889 : copy_shape(Py_ssize_t *shape, const PyObject *seq, Py_ssize_t ndim,
1258 : : Py_ssize_t itemsize)
1259 : : {
1260 : : Py_ssize_t x, i;
1261 : 11889 : Py_ssize_t len = itemsize;
1262 : :
1263 [ + + ]: 30647 : for (i = 0; i < ndim; i++) {
1264 [ + + ]: 18765 : PyObject *tmp = PySequence_Fast_GET_ITEM(seq, i);
1265 [ + + ]: 18765 : if (!PyLong_Check(tmp)) {
1266 : 1 : PyErr_SetString(PyExc_TypeError,
1267 : : "memoryview.cast(): elements of shape must be integers");
1268 : 1 : return -1;
1269 : : }
1270 : 18764 : x = PyLong_AsSsize_t(tmp);
1271 [ + + + + ]: 18764 : if (x == -1 && PyErr_Occurred()) {
1272 : 1 : return -1;
1273 : : }
1274 [ + + ]: 18763 : if (x <= 0) {
1275 : : /* In general elements of shape may be 0, but not for casting. */
1276 : 3 : PyErr_Format(PyExc_ValueError,
1277 : : "memoryview.cast(): elements of shape must be integers > 0");
1278 : 3 : return -1;
1279 : : }
1280 [ + + ]: 18760 : if (x > PY_SSIZE_T_MAX / len) {
1281 : 2 : PyErr_Format(PyExc_ValueError,
1282 : : "memoryview.cast(): product(shape) > SSIZE_MAX");
1283 : 2 : return -1;
1284 : : }
1285 : 18758 : len *= x;
1286 : 18758 : shape[i] = x;
1287 : : }
1288 : :
1289 : 11882 : return len;
1290 : : }
1291 : :
1292 : : /* Cast a 1-D array to a new shape. The result array will be C-contiguous.
1293 : : If the result array does not have exactly the same byte length as the
1294 : : input array, raise ValueError. */
1295 : : static int
1296 : 11890 : cast_to_ND(PyMemoryViewObject *mv, const PyObject *shape, int ndim)
1297 : : {
1298 : 11890 : Py_buffer *view = &mv->view;
1299 : : Py_ssize_t len;
1300 : :
1301 : : assert(view->ndim == 1); /* ndim from cast_to_1D() */
1302 : : assert(Py_SIZE(mv) == 3*(ndim==0?1:ndim)); /* ndim of result array */
1303 : : assert(view->shape == mv->ob_array);
1304 : : assert(view->strides == mv->ob_array + (ndim==0?1:ndim));
1305 : : assert(view->suboffsets == NULL);
1306 : :
1307 : 11890 : view->ndim = ndim;
1308 [ + + ]: 11890 : if (view->ndim == 0) {
1309 : 1 : view->shape = NULL;
1310 : 1 : view->strides = NULL;
1311 : 1 : len = view->itemsize;
1312 : : }
1313 : : else {
1314 : 11889 : len = copy_shape(view->shape, shape, ndim, view->itemsize);
1315 [ + + ]: 11889 : if (len < 0)
1316 : 7 : return -1;
1317 : 11882 : init_strides_from_shape(view);
1318 : : }
1319 : :
1320 [ + + ]: 11883 : if (view->len != len) {
1321 : 2 : PyErr_SetString(PyExc_TypeError,
1322 : : "memoryview: product(shape) * itemsize != buffer size");
1323 : 2 : return -1;
1324 : : }
1325 : :
1326 : 11881 : init_flags(mv);
1327 : :
1328 : 11881 : return 0;
1329 : : }
1330 : :
1331 : : static int
1332 : 26300 : zero_in_shape(PyMemoryViewObject *mv)
1333 : : {
1334 : 26300 : Py_buffer *view = &mv->view;
1335 : : Py_ssize_t i;
1336 : :
1337 [ + + ]: 66108 : for (i = 0; i < view->ndim; i++)
1338 [ + + ]: 39811 : if (view->shape[i] == 0)
1339 : 3 : return 1;
1340 : :
1341 : 26297 : return 0;
1342 : : }
1343 : :
1344 : : /*
1345 : : Cast a copy of 'self' to a different view. The input view must
1346 : : be C-contiguous. The function always casts the input view to a
1347 : : 1-D output according to 'format'. At least one of input-format,
1348 : : output-format must have byte size.
1349 : :
1350 : : If 'shape' is given, the 1-D view from the previous step will
1351 : : be cast to a C-contiguous view with new shape and strides.
1352 : :
1353 : : All casts must result in views that will have the exact byte
1354 : : size of the original input. Otherwise, an error is raised.
1355 : : */
1356 : : /*[clinic input]
1357 : : memoryview.cast
1358 : :
1359 : : format: unicode
1360 : : shape: object = NULL
1361 : :
1362 : : Cast a memoryview to a new format or shape.
1363 : : [clinic start generated code]*/
1364 : :
1365 : : static PyObject *
1366 : 40031 : memoryview_cast_impl(PyMemoryViewObject *self, PyObject *format,
1367 : : PyObject *shape)
1368 : : /*[clinic end generated code: output=bae520b3a389cbab input=138936cc9041b1a3]*/
1369 : : {
1370 : 40031 : PyMemoryViewObject *mv = NULL;
1371 : 40031 : Py_ssize_t ndim = 1;
1372 : :
1373 [ + + - + ]: 40031 : CHECK_RELEASED(self);
1374 : :
1375 [ + + ]: 40030 : if (!MV_C_CONTIGUOUS(self->flags)) {
1376 : 1 : PyErr_SetString(PyExc_TypeError,
1377 : : "memoryview: casts are restricted to C-contiguous views");
1378 : 1 : return NULL;
1379 : : }
1380 [ + + + + : 40029 : if ((shape || self->view.ndim != 1) && zero_in_shape(self)) {
+ + ]
1381 : 3 : PyErr_SetString(PyExc_TypeError,
1382 : : "memoryview: cannot cast view with zeros in shape or strides");
1383 : 3 : return NULL;
1384 : : }
1385 [ + + ]: 40026 : if (shape) {
1386 [ + + + + ]: 20293 : CHECK_LIST_OR_TUPLE(shape)
1387 [ + + ]: 20292 : ndim = PySequence_Fast_GET_SIZE(shape);
1388 [ + + ]: 20292 : if (ndim > PyBUF_MAX_NDIM) {
1389 : 1 : PyErr_SetString(PyExc_ValueError,
1390 : : "memoryview: number of dimensions must not exceed "
1391 : : Py_STRINGIFY(PyBUF_MAX_NDIM));
1392 : 1 : return NULL;
1393 : : }
1394 [ + + + + ]: 20291 : if (self->view.ndim != 1 && ndim != 1) {
1395 : 182 : PyErr_SetString(PyExc_TypeError,
1396 : : "memoryview: cast must be 1D -> ND or ND -> 1D");
1397 : 182 : return NULL;
1398 : : }
1399 : : }
1400 : :
1401 : : mv = (PyMemoryViewObject *)
1402 [ + + ]: 39842 : mbuf_add_incomplete_view(self->mbuf, &self->view, ndim==0 ? 1 : (int)ndim);
1403 [ - + ]: 39842 : if (mv == NULL)
1404 : 0 : return NULL;
1405 : :
1406 [ + + ]: 39842 : if (cast_to_1D(mv, format) < 0)
1407 : 8228 : goto error;
1408 [ + + + + ]: 31614 : if (shape && cast_to_ND(mv, shape, (int)ndim) < 0)
1409 : 9 : goto error;
1410 : :
1411 : 31605 : return (PyObject *)mv;
1412 : :
1413 : 8237 : error:
1414 : 8237 : Py_DECREF(mv);
1415 : 8237 : return NULL;
1416 : : }
1417 : :
1418 : : /*[clinic input]
1419 : : memoryview.toreadonly
1420 : :
1421 : : Return a readonly version of the memoryview.
1422 : : [clinic start generated code]*/
1423 : :
1424 : : static PyObject *
1425 : 27659 : memoryview_toreadonly_impl(PyMemoryViewObject *self)
1426 : : /*[clinic end generated code: output=2c7e056f04c99e62 input=dc06d20f19ba236f]*/
1427 : : {
1428 [ + - - + ]: 27659 : CHECK_RELEASED(self);
1429 : : /* Even if self is already readonly, we still need to create a new
1430 : : * object for .release() to work correctly.
1431 : : */
1432 : 27659 : self = (PyMemoryViewObject *) mbuf_add_view(self->mbuf, &self->view);
1433 [ + - ]: 27659 : if (self != NULL) {
1434 : 27659 : self->view.readonly = 1;
1435 : : };
1436 : 27659 : return (PyObject *) self;
1437 : : }
1438 : :
1439 : :
1440 : : /**************************************************************************/
1441 : : /* getbuffer */
1442 : : /**************************************************************************/
1443 : :
1444 : : static int
1445 : 4547042 : memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
1446 : : {
1447 : 4547042 : Py_buffer *base = &self->view;
1448 : 4547042 : int baseflags = self->flags;
1449 : :
1450 [ + + - + ]: 4547042 : CHECK_RELEASED_INT(self);
1451 : :
1452 : : /* start with complete information */
1453 : 4547013 : *view = *base;
1454 : 4547013 : view->obj = NULL;
1455 : :
1456 [ + + + + ]: 4547013 : if (REQ_WRITABLE(flags) && base->readonly) {
1457 : 6692 : PyErr_SetString(PyExc_BufferError,
1458 : : "memoryview: underlying buffer is not writable");
1459 : 6692 : return -1;
1460 : : }
1461 [ + + ]: 4540321 : if (!REQ_FORMAT(flags)) {
1462 : : /* NULL indicates that the buffer's data type has been cast to 'B'.
1463 : : view->itemsize is the _previous_ itemsize. If shape is present,
1464 : : the equality product(shape) * itemsize = len still holds at this
1465 : : point. The equality calcsize(format) = itemsize does _not_ hold
1466 : : from here on! */
1467 : 4445245 : view->format = NULL;
1468 : : }
1469 : :
1470 [ + + + + ]: 4540321 : if (REQ_C_CONTIGUOUS(flags) && !MV_C_CONTIGUOUS(baseflags)) {
1471 : 816 : PyErr_SetString(PyExc_BufferError,
1472 : : "memoryview: underlying buffer is not C-contiguous");
1473 : 816 : return -1;
1474 : : }
1475 [ + + + + ]: 4539505 : if (REQ_F_CONTIGUOUS(flags) && !MV_F_CONTIGUOUS(baseflags)) {
1476 : 816 : PyErr_SetString(PyExc_BufferError,
1477 : : "memoryview: underlying buffer is not Fortran contiguous");
1478 : 816 : return -1;
1479 : : }
1480 [ + + + + ]: 4538689 : if (REQ_ANY_CONTIGUOUS(flags) && !MV_ANY_CONTIGUOUS(baseflags)) {
1481 : 792 : PyErr_SetString(PyExc_BufferError,
1482 : : "memoryview: underlying buffer is not contiguous");
1483 : 792 : return -1;
1484 : : }
1485 [ + + + + ]: 4537897 : if (!REQ_INDIRECT(flags) && (baseflags & _Py_MEMORYVIEW_PIL)) {
1486 : 3456 : PyErr_SetString(PyExc_BufferError,
1487 : : "memoryview: underlying buffer requires suboffsets");
1488 : 3456 : return -1;
1489 : : }
1490 [ + + ]: 4534441 : if (!REQ_STRIDES(flags)) {
1491 [ + + ]: 4442077 : if (!MV_C_CONTIGUOUS(baseflags)) {
1492 : 1413 : PyErr_SetString(PyExc_BufferError,
1493 : : "memoryview: underlying buffer is not C-contiguous");
1494 : 1413 : return -1;
1495 : : }
1496 : 4440664 : view->strides = NULL;
1497 : : }
1498 [ + + ]: 4533028 : if (!REQ_SHAPE(flags)) {
1499 : : /* PyBUF_SIMPLE or PyBUF_WRITABLE: at this point buf is C-contiguous,
1500 : : so base->buf = ndbuf->data. */
1501 [ + + ]: 4397011 : if (view->format != NULL) {
1502 : : /* PyBUF_SIMPLE|PyBUF_FORMAT and PyBUF_WRITABLE|PyBUF_FORMAT do
1503 : : not make sense. */
1504 : 120 : PyErr_Format(PyExc_BufferError,
1505 : : "memoryview: cannot cast to unsigned bytes if the format flag "
1506 : : "is present");
1507 : 120 : return -1;
1508 : : }
1509 : : /* product(shape) * itemsize = len and calcsize(format) = itemsize
1510 : : do _not_ hold from here on! */
1511 : 4396891 : view->ndim = 1;
1512 : 4396891 : view->shape = NULL;
1513 : : }
1514 : :
1515 : :
1516 : 4532908 : view->obj = (PyObject *)self;
1517 : 4532908 : Py_INCREF(view->obj);
1518 : 4532908 : self->exports++;
1519 : :
1520 : 4532908 : return 0;
1521 : : }
1522 : :
1523 : : static void
1524 : 4532903 : memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
1525 : : {
1526 : 4532903 : self->exports--;
1527 : 4532903 : return;
1528 : : /* PyBuffer_Release() decrements view->obj after this function returns. */
1529 : : }
1530 : :
1531 : : /* Buffer methods */
1532 : : static PyBufferProcs memory_as_buffer = {
1533 : : (getbufferproc)memory_getbuf, /* bf_getbuffer */
1534 : : (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
1535 : : };
1536 : :
1537 : :
1538 : : /****************************************************************************/
1539 : : /* Optimized pack/unpack for all native format specifiers */
1540 : : /****************************************************************************/
1541 : :
1542 : : /*
1543 : : Fix exceptions:
1544 : : 1) Include format string in the error message.
1545 : : 2) OverflowError -> ValueError.
1546 : : 3) The error message from PyNumber_Index() is not ideal.
1547 : : */
1548 : : static int
1549 : 690 : type_error_int(const char *fmt)
1550 : : {
1551 : 690 : PyErr_Format(PyExc_TypeError,
1552 : : "memoryview: invalid type for format '%s'", fmt);
1553 : 690 : return -1;
1554 : : }
1555 : :
1556 : : static int
1557 : 33 : value_error_int(const char *fmt)
1558 : : {
1559 : 33 : PyErr_Format(PyExc_ValueError,
1560 : : "memoryview: invalid value for format '%s'", fmt);
1561 : 33 : return -1;
1562 : : }
1563 : :
1564 : : static int
1565 : 663 : fix_error_int(const char *fmt)
1566 : : {
1567 : : assert(PyErr_Occurred());
1568 [ + + ]: 663 : if (PyErr_ExceptionMatches(PyExc_TypeError)) {
1569 : 643 : PyErr_Clear();
1570 : 643 : return type_error_int(fmt);
1571 : : }
1572 [ - + - - ]: 20 : else if (PyErr_ExceptionMatches(PyExc_OverflowError) ||
1573 : 0 : PyErr_ExceptionMatches(PyExc_ValueError)) {
1574 : 20 : PyErr_Clear();
1575 : 20 : return value_error_int(fmt);
1576 : : }
1577 : :
1578 : 0 : return -1;
1579 : : }
1580 : :
1581 : : /* Accept integer objects or objects with an __index__() method. */
1582 : : static long
1583 : 16088 : pylong_as_ld(PyObject *item)
1584 : : {
1585 : : PyObject *tmp;
1586 : : long ld;
1587 : :
1588 : 16088 : tmp = _PyNumber_Index(item);
1589 [ + + ]: 16088 : if (tmp == NULL)
1590 : 192 : return -1;
1591 : :
1592 : 15896 : ld = PyLong_AsLong(tmp);
1593 : 15896 : Py_DECREF(tmp);
1594 : 15896 : return ld;
1595 : : }
1596 : :
1597 : : static unsigned long
1598 : 3086 : pylong_as_lu(PyObject *item)
1599 : : {
1600 : : PyObject *tmp;
1601 : : unsigned long lu;
1602 : :
1603 : 3086 : tmp = _PyNumber_Index(item);
1604 [ + + ]: 3086 : if (tmp == NULL)
1605 : 193 : return (unsigned long)-1;
1606 : :
1607 : 2893 : lu = PyLong_AsUnsignedLong(tmp);
1608 : 2893 : Py_DECREF(tmp);
1609 : 2893 : return lu;
1610 : : }
1611 : :
1612 : : static long long
1613 : 57 : pylong_as_lld(PyObject *item)
1614 : : {
1615 : : PyObject *tmp;
1616 : : long long lld;
1617 : :
1618 : 57 : tmp = _PyNumber_Index(item);
1619 [ + + ]: 57 : if (tmp == NULL)
1620 : 45 : return -1;
1621 : :
1622 : 12 : lld = PyLong_AsLongLong(tmp);
1623 : 12 : Py_DECREF(tmp);
1624 : 12 : return lld;
1625 : : }
1626 : :
1627 : : static unsigned long long
1628 : 57 : pylong_as_llu(PyObject *item)
1629 : : {
1630 : : PyObject *tmp;
1631 : : unsigned long long llu;
1632 : :
1633 : 57 : tmp = _PyNumber_Index(item);
1634 [ + + ]: 57 : if (tmp == NULL)
1635 : 45 : return (unsigned long long)-1;
1636 : :
1637 : 12 : llu = PyLong_AsUnsignedLongLong(tmp);
1638 : 12 : Py_DECREF(tmp);
1639 : 12 : return llu;
1640 : : }
1641 : :
1642 : : static Py_ssize_t
1643 : 62 : pylong_as_zd(PyObject *item)
1644 : : {
1645 : : PyObject *tmp;
1646 : : Py_ssize_t zd;
1647 : :
1648 : 62 : tmp = _PyNumber_Index(item);
1649 [ + + ]: 62 : if (tmp == NULL)
1650 : 45 : return -1;
1651 : :
1652 : 17 : zd = PyLong_AsSsize_t(tmp);
1653 : 17 : Py_DECREF(tmp);
1654 : 17 : return zd;
1655 : : }
1656 : :
1657 : : static size_t
1658 : 75 : pylong_as_zu(PyObject *item)
1659 : : {
1660 : : PyObject *tmp;
1661 : : size_t zu;
1662 : :
1663 : 75 : tmp = _PyNumber_Index(item);
1664 [ + + ]: 75 : if (tmp == NULL)
1665 : 45 : return (size_t)-1;
1666 : :
1667 : 30 : zu = PyLong_AsSize_t(tmp);
1668 : 30 : Py_DECREF(tmp);
1669 : 30 : return zu;
1670 : : }
1671 : :
1672 : : /* Timings with the ndarray from _testbuffer.c indicate that using the
1673 : : struct module is around 15x slower than the two functions below. */
1674 : :
1675 : : #define UNPACK_SINGLE(dest, ptr, type) \
1676 : : do { \
1677 : : type x; \
1678 : : memcpy((char *)&x, ptr, sizeof x); \
1679 : : dest = x; \
1680 : : } while (0)
1681 : :
1682 : : /* Unpack a single item. 'fmt' can be any native format character in struct
1683 : : module syntax. This function is very sensitive to small changes. With this
1684 : : layout gcc automatically generates a fast jump table. */
1685 : : static inline PyObject *
1686 : 3285423 : unpack_single(PyMemoryViewObject *self, const char *ptr, const char *fmt)
1687 : : {
1688 : : unsigned long long llu;
1689 : : unsigned long lu;
1690 : : size_t zu;
1691 : : long long lld;
1692 : : long ld;
1693 : : Py_ssize_t zd;
1694 : : double d;
1695 : : unsigned char uc;
1696 : : void *p;
1697 : :
1698 [ + + - + ]: 3285423 : CHECK_RELEASED_AGAIN(self);
1699 : :
1700 [ + + + + : 3285421 : switch (fmt[0]) {
+ + + + +
+ + + + +
+ + + + ]
1701 : :
1702 : : /* signed integers and fast path for 'B' */
1703 : 866261 : case 'B': uc = *((const unsigned char *)ptr); goto convert_uc;
1704 : 859674 : case 'b': ld = *((const signed char *)ptr); goto convert_ld;
1705 : 32391 : case 'h': UNPACK_SINGLE(ld, ptr, short); goto convert_ld;
1706 : 91481 : case 'i': UNPACK_SINGLE(ld, ptr, int); goto convert_ld;
1707 : 42505 : case 'l': UNPACK_SINGLE(ld, ptr, long); goto convert_ld;
1708 : :
1709 : : /* boolean */
1710 : 32602 : case '?': UNPACK_SINGLE(ld, ptr, _Bool); goto convert_bool;
1711 : :
1712 : : /* unsigned integers */
1713 : 32212 : case 'H': UNPACK_SINGLE(lu, ptr, unsigned short); goto convert_lu;
1714 : 204467 : case 'I': UNPACK_SINGLE(lu, ptr, unsigned int); goto convert_lu;
1715 : 35911 : case 'L': UNPACK_SINGLE(lu, ptr, unsigned long); goto convert_lu;
1716 : :
1717 : : /* native 64-bit */
1718 : 31954 : case 'q': UNPACK_SINGLE(lld, ptr, long long); goto convert_lld;
1719 : 31210 : case 'Q': UNPACK_SINGLE(llu, ptr, unsigned long long); goto convert_llu;
1720 : :
1721 : : /* ssize_t and size_t */
1722 : 31465 : case 'n': UNPACK_SINGLE(zd, ptr, Py_ssize_t); goto convert_zd;
1723 : 31247 : case 'N': UNPACK_SINGLE(zu, ptr, size_t); goto convert_zu;
1724 : :
1725 : : /* floats */
1726 : 43341 : case 'f': UNPACK_SINGLE(d, ptr, float); goto convert_double;
1727 : 32619 : case 'd': UNPACK_SINGLE(d, ptr, double); goto convert_double;
1728 : :
1729 : : /* bytes object */
1730 : 854333 : case 'c': goto convert_bytes;
1731 : :
1732 : : /* pointer */
1733 : 31746 : case 'P': UNPACK_SINGLE(p, ptr, void *); goto convert_pointer;
1734 : :
1735 : : /* default */
1736 : 2 : default: goto err_format;
1737 : : }
1738 : :
1739 : 866261 : convert_uc:
1740 : : /* PyLong_FromUnsignedLong() is slower */
1741 : 866261 : return PyLong_FromLong(uc);
1742 : 1026051 : convert_ld:
1743 : 1026051 : return PyLong_FromLong(ld);
1744 : 272590 : convert_lu:
1745 : 272590 : return PyLong_FromUnsignedLong(lu);
1746 : 31954 : convert_lld:
1747 : 31954 : return PyLong_FromLongLong(lld);
1748 : 31210 : convert_llu:
1749 : 31210 : return PyLong_FromUnsignedLongLong(llu);
1750 : 31465 : convert_zd:
1751 : 31465 : return PyLong_FromSsize_t(zd);
1752 : 31247 : convert_zu:
1753 : 31247 : return PyLong_FromSize_t(zu);
1754 : 75960 : convert_double:
1755 : 75960 : return PyFloat_FromDouble(d);
1756 : 32602 : convert_bool:
1757 : 32602 : return PyBool_FromLong(ld);
1758 : 854333 : convert_bytes:
1759 : 854333 : return PyBytes_FromStringAndSize(ptr, 1);
1760 : 31746 : convert_pointer:
1761 : 31746 : return PyLong_FromVoidPtr(p);
1762 : 2 : err_format:
1763 : 2 : PyErr_Format(PyExc_NotImplementedError,
1764 : : "memoryview: format %s not supported", fmt);
1765 : 2 : return NULL;
1766 : : }
1767 : :
1768 : : #define PACK_SINGLE(ptr, src, type) \
1769 : : do { \
1770 : : type x; \
1771 : : x = (type)src; \
1772 : : memcpy(ptr, (char *)&x, sizeof x); \
1773 : : } while (0)
1774 : :
1775 : : /* Pack a single item. 'fmt' can be any native format character in
1776 : : struct module syntax. */
1777 : : static int
1778 : 21127 : pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt)
1779 : : {
1780 : : unsigned long long llu;
1781 : : unsigned long lu;
1782 : : size_t zu;
1783 : : long long lld;
1784 : : long ld;
1785 : : Py_ssize_t zd;
1786 : : double d;
1787 : : void *p;
1788 : :
1789 [ + + + + : 21127 : switch (fmt[0]) {
+ + + + +
+ + ]
1790 : : /* signed integers */
1791 : 16088 : case 'b': case 'h': case 'i': case 'l':
1792 : 16088 : ld = pylong_as_ld(item);
1793 [ + + + + ]: 16088 : if (ld == -1 && PyErr_Occurred())
1794 : 194 : goto err_occurred;
1795 [ + + - + ]: 15894 : CHECK_RELEASED_INT_AGAIN(self);
1796 [ + + + + ]: 15890 : switch (fmt[0]) {
1797 : 671 : case 'b':
1798 [ + + + + ]: 671 : if (ld < SCHAR_MIN || ld > SCHAR_MAX) goto err_range;
1799 : 669 : *((signed char *)ptr) = (signed char)ld; break;
1800 : 729 : case 'h':
1801 [ + + + + ]: 729 : if (ld < SHRT_MIN || ld > SHRT_MAX) goto err_range;
1802 : 727 : PACK_SINGLE(ptr, ld, short); break;
1803 : 13812 : case 'i':
1804 [ + + + + ]: 13812 : if (ld < INT_MIN || ld > INT_MAX) goto err_range;
1805 : 13810 : PACK_SINGLE(ptr, ld, int); break;
1806 : 678 : default: /* 'l' */
1807 : 678 : PACK_SINGLE(ptr, ld, long); break;
1808 : : }
1809 : 15884 : break;
1810 : :
1811 : : /* unsigned integers */
1812 : 3086 : case 'B': case 'H': case 'I': case 'L':
1813 : 3086 : lu = pylong_as_lu(item);
1814 [ + + + - ]: 3086 : if (lu == (unsigned long)-1 && PyErr_Occurred())
1815 : 198 : goto err_occurred;
1816 [ + + - + ]: 2888 : CHECK_RELEASED_INT_AGAIN(self);
1817 [ + + + + ]: 2880 : switch (fmt[0]) {
1818 : 707 : case 'B':
1819 [ + + ]: 707 : if (lu > UCHAR_MAX) goto err_range;
1820 : 705 : *((unsigned char *)ptr) = (unsigned char)lu; break;
1821 : 750 : case 'H':
1822 [ + + ]: 750 : if (lu > USHRT_MAX) goto err_range;
1823 : 749 : PACK_SINGLE(ptr, lu, unsigned short); break;
1824 : 700 : case 'I':
1825 [ + + ]: 700 : if (lu > UINT_MAX) goto err_range;
1826 : 699 : PACK_SINGLE(ptr, lu, unsigned int); break;
1827 : 723 : default: /* 'L' */
1828 : 723 : PACK_SINGLE(ptr, lu, unsigned long); break;
1829 : : }
1830 : 2876 : break;
1831 : :
1832 : : /* native 64-bit */
1833 : 57 : case 'q':
1834 : 57 : lld = pylong_as_lld(item);
1835 [ + + + - ]: 57 : if (lld == -1 && PyErr_Occurred())
1836 : 47 : goto err_occurred;
1837 [ + + - + ]: 10 : CHECK_RELEASED_INT_AGAIN(self);
1838 : 9 : PACK_SINGLE(ptr, lld, long long);
1839 : 9 : break;
1840 : 57 : case 'Q':
1841 : 57 : llu = pylong_as_llu(item);
1842 [ + + + - ]: 57 : if (llu == (unsigned long long)-1 && PyErr_Occurred())
1843 : 47 : goto err_occurred;
1844 [ + + - + ]: 10 : CHECK_RELEASED_INT_AGAIN(self);
1845 : 9 : PACK_SINGLE(ptr, llu, unsigned long long);
1846 : 9 : break;
1847 : :
1848 : : /* ssize_t and size_t */
1849 : 62 : case 'n':
1850 : 62 : zd = pylong_as_zd(item);
1851 [ + + + - ]: 62 : if (zd == -1 && PyErr_Occurred())
1852 : 47 : goto err_occurred;
1853 [ + + - + ]: 15 : CHECK_RELEASED_INT_AGAIN(self);
1854 : 14 : PACK_SINGLE(ptr, zd, Py_ssize_t);
1855 : 14 : break;
1856 : 75 : case 'N':
1857 : 75 : zu = pylong_as_zu(item);
1858 [ + + + - ]: 75 : if (zu == (size_t)-1 && PyErr_Occurred())
1859 : 47 : goto err_occurred;
1860 [ + + - + ]: 28 : CHECK_RELEASED_INT_AGAIN(self);
1861 : 27 : PACK_SINGLE(ptr, zu, size_t);
1862 : 27 : break;
1863 : :
1864 : : /* floats */
1865 : 1551 : case 'f': case 'd':
1866 : 1551 : d = PyFloat_AsDouble(item);
1867 [ + + + - ]: 1551 : if (d == -1.0 && PyErr_Occurred())
1868 : 82 : goto err_occurred;
1869 [ + + - + ]: 1469 : CHECK_RELEASED_INT_AGAIN(self);
1870 [ + + ]: 1467 : if (fmt[0] == 'f') {
1871 : 732 : PACK_SINGLE(ptr, d, float);
1872 : : }
1873 : : else {
1874 : 735 : PACK_SINGLE(ptr, d, double);
1875 : : }
1876 : 1467 : break;
1877 : :
1878 : : /* bool */
1879 : 63 : case '?':
1880 : 63 : ld = PyObject_IsTrue(item);
1881 [ - + ]: 63 : if (ld < 0)
1882 : 0 : return -1; /* preserve original error */
1883 [ + + - + ]: 63 : CHECK_RELEASED_INT_AGAIN(self);
1884 : 62 : PACK_SINGLE(ptr, ld, _Bool);
1885 : 62 : break;
1886 : :
1887 : : /* bytes object */
1888 : 64 : case 'c':
1889 [ + + ]: 64 : if (!PyBytes_Check(item))
1890 : 47 : return type_error_int(fmt);
1891 [ + + ]: 17 : if (PyBytes_GET_SIZE(item) != 1)
1892 : 3 : return value_error_int(fmt);
1893 : 14 : *ptr = PyBytes_AS_STRING(item)[0];
1894 : 14 : break;
1895 : :
1896 : : /* pointer */
1897 : 23 : case 'P':
1898 : 23 : p = PyLong_AsVoidPtr(item);
1899 [ + + + - ]: 23 : if (p == NULL && PyErr_Occurred())
1900 : 1 : goto err_occurred;
1901 [ + - - + ]: 22 : CHECK_RELEASED_INT_AGAIN(self);
1902 : 22 : PACK_SINGLE(ptr, p, void *);
1903 : 22 : break;
1904 : :
1905 : : /* default */
1906 : 1 : default: goto err_format;
1907 : : }
1908 : :
1909 : 20384 : return 0;
1910 : :
1911 : 663 : err_occurred:
1912 : 663 : return fix_error_int(fmt);
1913 : 10 : err_range:
1914 : 10 : return value_error_int(fmt);
1915 : 1 : err_format:
1916 : 1 : PyErr_Format(PyExc_NotImplementedError,
1917 : : "memoryview: format %s not supported", fmt);
1918 : 1 : return -1;
1919 : : }
1920 : :
1921 : :
1922 : : /****************************************************************************/
1923 : : /* unpack using the struct module */
1924 : : /****************************************************************************/
1925 : :
1926 : : /* For reasonable performance it is necessary to cache all objects required
1927 : : for unpacking. An unpacker can handle the format passed to unpack_from().
1928 : : Invariant: All pointer fields of the struct should either be NULL or valid
1929 : : pointers. */
1930 : : struct unpacker {
1931 : : PyObject *unpack_from; /* Struct.unpack_from(format) */
1932 : : PyObject *mview; /* cached memoryview */
1933 : : char *item; /* buffer for mview */
1934 : : Py_ssize_t itemsize; /* len(item) */
1935 : : };
1936 : :
1937 : : static struct unpacker *
1938 : 30787 : unpacker_new(void)
1939 : : {
1940 : 30787 : struct unpacker *x = PyMem_Malloc(sizeof *x);
1941 : :
1942 [ - + ]: 30787 : if (x == NULL) {
1943 : : PyErr_NoMemory();
1944 : 0 : return NULL;
1945 : : }
1946 : :
1947 : 30787 : x->unpack_from = NULL;
1948 : 30787 : x->mview = NULL;
1949 : 30787 : x->item = NULL;
1950 : 30787 : x->itemsize = 0;
1951 : :
1952 : 30787 : return x;
1953 : : }
1954 : :
1955 : : static void
1956 : 326631 : unpacker_free(struct unpacker *x)
1957 : : {
1958 [ + + ]: 326631 : if (x) {
1959 : 30787 : Py_XDECREF(x->unpack_from);
1960 : 30787 : Py_XDECREF(x->mview);
1961 : 30787 : PyMem_Free(x->item);
1962 : 30787 : PyMem_Free(x);
1963 : : }
1964 : 326631 : }
1965 : :
1966 : : /* Return a new unpacker for the given format. */
1967 : : static struct unpacker *
1968 : 30787 : struct_get_unpacker(const char *fmt, Py_ssize_t itemsize)
1969 : : {
1970 : 30787 : PyObject *Struct = NULL; /* XXX cache it in globals? */
1971 : 30787 : PyObject *structobj = NULL;
1972 : 30787 : PyObject *format = NULL;
1973 : 30787 : struct unpacker *x = NULL;
1974 : :
1975 : 30787 : Struct = _PyImport_GetModuleAttrString("struct", "Struct");
1976 [ - + ]: 30787 : if (Struct == NULL)
1977 : 0 : return NULL;
1978 : :
1979 : 30787 : x = unpacker_new();
1980 [ - + ]: 30787 : if (x == NULL)
1981 : 0 : goto error;
1982 : :
1983 : 30787 : format = PyBytes_FromString(fmt);
1984 [ - + ]: 30787 : if (format == NULL)
1985 : 0 : goto error;
1986 : :
1987 : 30787 : structobj = PyObject_CallOneArg(Struct, format);
1988 [ + + ]: 30787 : if (structobj == NULL)
1989 : 5 : goto error;
1990 : :
1991 : 30782 : x->unpack_from = PyObject_GetAttrString(structobj, "unpack_from");
1992 [ - + ]: 30782 : if (x->unpack_from == NULL)
1993 : 0 : goto error;
1994 : :
1995 : 30782 : x->item = PyMem_Malloc(itemsize);
1996 [ - + ]: 30782 : if (x->item == NULL) {
1997 : : PyErr_NoMemory();
1998 : 0 : goto error;
1999 : : }
2000 : 30782 : x->itemsize = itemsize;
2001 : :
2002 : 30782 : x->mview = PyMemoryView_FromMemory(x->item, itemsize, PyBUF_WRITE);
2003 [ - + ]: 30782 : if (x->mview == NULL)
2004 : 0 : goto error;
2005 : :
2006 : :
2007 : 30782 : out:
2008 : 30787 : Py_XDECREF(Struct);
2009 : 30787 : Py_XDECREF(format);
2010 : 30787 : Py_XDECREF(structobj);
2011 : 30787 : return x;
2012 : :
2013 : 5 : error:
2014 : 5 : unpacker_free(x);
2015 : 5 : x = NULL;
2016 : 5 : goto out;
2017 : : }
2018 : :
2019 : : /* unpack a single item */
2020 : : static PyObject *
2021 : 356146 : struct_unpack_single(const char *ptr, struct unpacker *x)
2022 : : {
2023 : : PyObject *v;
2024 : :
2025 : 356146 : memcpy(x->item, ptr, x->itemsize);
2026 : 356146 : v = PyObject_CallOneArg(x->unpack_from, x->mview);
2027 [ - + ]: 356146 : if (v == NULL)
2028 : 0 : return NULL;
2029 : :
2030 [ + + ]: 356146 : if (PyTuple_GET_SIZE(v) == 1) {
2031 : 172862 : PyObject *tmp = PyTuple_GET_ITEM(v, 0);
2032 : 172862 : Py_INCREF(tmp);
2033 : 172862 : Py_DECREF(v);
2034 : 172862 : return tmp;
2035 : : }
2036 : :
2037 : 183284 : return v;
2038 : : }
2039 : :
2040 : :
2041 : : /****************************************************************************/
2042 : : /* Representations */
2043 : : /****************************************************************************/
2044 : :
2045 : : /* allow explicit form of native format */
2046 : : static inline const char *
2047 : 157714 : adjust_fmt(const Py_buffer *view)
2048 : : {
2049 : : const char *fmt;
2050 : :
2051 [ + + ]: 157714 : fmt = (view->format[0] == '@') ? view->format+1 : view->format;
2052 [ + - + + ]: 157714 : if (fmt[0] && fmt[1] == '\0')
2053 : 157707 : return fmt;
2054 : :
2055 : 7 : PyErr_Format(PyExc_NotImplementedError,
2056 : 7 : "memoryview: unsupported format %s", view->format);
2057 : 7 : return NULL;
2058 : : }
2059 : :
2060 : : /* Base case for multi-dimensional unpacking. Assumption: ndim == 1. */
2061 : : static PyObject *
2062 : 359072 : tolist_base(PyMemoryViewObject *self, const char *ptr, const Py_ssize_t *shape,
2063 : : const Py_ssize_t *strides, const Py_ssize_t *suboffsets,
2064 : : const char *fmt)
2065 : : {
2066 : : PyObject *lst, *item;
2067 : : Py_ssize_t i;
2068 : :
2069 : 359072 : lst = PyList_New(shape[0]);
2070 [ - + ]: 359072 : if (lst == NULL)
2071 : 0 : return NULL;
2072 : :
2073 [ + + ]: 3580411 : for (i = 0; i < shape[0]; ptr+=strides[0], i++) {
2074 [ + + + + ]: 3221341 : const char *xptr = ADJUST_PTR(ptr, suboffsets, 0);
2075 : 3221341 : item = unpack_single(self, xptr, fmt);
2076 [ + + ]: 3221341 : if (item == NULL) {
2077 : 2 : Py_DECREF(lst);
2078 : 2 : return NULL;
2079 : : }
2080 : 3221339 : PyList_SET_ITEM(lst, i, item);
2081 : : }
2082 : :
2083 : 359070 : return lst;
2084 : : }
2085 : :
2086 : : /* Unpack a multi-dimensional array into a nested list.
2087 : : Assumption: ndim >= 1. */
2088 : : static PyObject *
2089 : 380912 : tolist_rec(PyMemoryViewObject *self, const char *ptr, Py_ssize_t ndim, const Py_ssize_t *shape,
2090 : : const Py_ssize_t *strides, const Py_ssize_t *suboffsets,
2091 : : const char *fmt)
2092 : : {
2093 : : PyObject *lst, *item;
2094 : : Py_ssize_t i;
2095 : :
2096 : : assert(ndim >= 1);
2097 : : assert(shape != NULL);
2098 : : assert(strides != NULL);
2099 : :
2100 [ + + ]: 380912 : if (ndim == 1)
2101 : 314805 : return tolist_base(self, ptr, shape, strides, suboffsets, fmt);
2102 : :
2103 : 66107 : lst = PyList_New(shape[0]);
2104 [ - + ]: 66107 : if (lst == NULL)
2105 : 0 : return NULL;
2106 : :
2107 [ + + ]: 424647 : for (i = 0; i < shape[0]; ptr+=strides[0], i++) {
2108 [ + + + + ]: 358541 : const char *xptr = ADJUST_PTR(ptr, suboffsets, 0);
2109 [ + + ]: 358541 : item = tolist_rec(self, xptr, ndim-1, shape+1,
2110 : : strides+1, suboffsets ? suboffsets+1 : NULL,
2111 : : fmt);
2112 [ + + ]: 358541 : if (item == NULL) {
2113 : 1 : Py_DECREF(lst);
2114 : 1 : return NULL;
2115 : : }
2116 : 358540 : PyList_SET_ITEM(lst, i, item);
2117 : : }
2118 : :
2119 : 66106 : return lst;
2120 : : }
2121 : :
2122 : : /* Return a list representation of the memoryview. Currently only buffers
2123 : : with native format strings are supported. */
2124 : : /*[clinic input]
2125 : : memoryview.tolist
2126 : :
2127 : : Return the data in the buffer as a list of elements.
2128 : : [clinic start generated code]*/
2129 : :
2130 : : static PyObject *
2131 : 67354 : memoryview_tolist_impl(PyMemoryViewObject *self)
2132 : : /*[clinic end generated code: output=a6cda89214fd5a1b input=21e7d0c1860b211a]*/
2133 : : {
2134 : 67354 : const Py_buffer *view = &self->view;
2135 : : const char *fmt;
2136 : :
2137 [ + + - + ]: 67354 : CHECK_RELEASED(self);
2138 : :
2139 : 67326 : fmt = adjust_fmt(view);
2140 [ + + ]: 67326 : if (fmt == NULL)
2141 : 3 : return NULL;
2142 [ + + ]: 67323 : if (view->ndim == 0) {
2143 : 685 : return unpack_single(self, view->buf, fmt);
2144 : : }
2145 [ + + ]: 66638 : else if (view->ndim == 1) {
2146 : 44267 : return tolist_base(self, view->buf, view->shape,
2147 : 44267 : view->strides, view->suboffsets,
2148 : : fmt);
2149 : : }
2150 : : else {
2151 : 22371 : return tolist_rec(self, view->buf, view->ndim, view->shape,
2152 : 22371 : view->strides, view->suboffsets,
2153 : : fmt);
2154 : : }
2155 : : }
2156 : :
2157 : : /*[clinic input]
2158 : : memoryview.tobytes
2159 : :
2160 : : order: str(accept={str, NoneType}, c_default="NULL") = 'C'
2161 : :
2162 : : Return the data in the buffer as a byte string.
2163 : :
2164 : : Order can be {'C', 'F', 'A'}. When order is 'C' or 'F', the data of the
2165 : : original array is converted to C or Fortran order. For contiguous views,
2166 : : 'A' returns an exact copy of the physical memory. In particular, in-memory
2167 : : Fortran order is preserved. For non-contiguous views, the data is converted
2168 : : to C first. order=None is the same as order='C'.
2169 : : [clinic start generated code]*/
2170 : :
2171 : : static PyObject *
2172 : 221268 : memoryview_tobytes_impl(PyMemoryViewObject *self, const char *order)
2173 : : /*[clinic end generated code: output=1288b62560a32a23 input=0efa3ddaeda573a8]*/
2174 : : {
2175 : 221268 : Py_buffer *src = VIEW_ADDR(self);
2176 : 221268 : char ord = 'C';
2177 : : PyObject *bytes;
2178 : :
2179 [ + + - + ]: 221268 : CHECK_RELEASED(self);
2180 : :
2181 [ + + ]: 221240 : if (order) {
2182 [ + + ]: 94239 : if (strcmp(order, "F") == 0) {
2183 : 31413 : ord = 'F';
2184 : : }
2185 [ + + ]: 62826 : else if (strcmp(order, "A") == 0) {
2186 : 31413 : ord = 'A';
2187 : : }
2188 [ - + ]: 31413 : else if (strcmp(order, "C") != 0) {
2189 : 0 : PyErr_SetString(PyExc_ValueError,
2190 : : "order must be 'C', 'F' or 'A'");
2191 : 0 : return NULL;
2192 : : }
2193 : : }
2194 : :
2195 : 221240 : bytes = PyBytes_FromStringAndSize(NULL, src->len);
2196 [ - + ]: 221240 : if (bytes == NULL)
2197 : 0 : return NULL;
2198 : :
2199 [ - + ]: 221240 : if (PyBuffer_ToContiguous(PyBytes_AS_STRING(bytes), src, src->len, ord) < 0) {
2200 : 0 : Py_DECREF(bytes);
2201 : 0 : return NULL;
2202 : : }
2203 : :
2204 : 221240 : return bytes;
2205 : : }
2206 : :
2207 : : /*[clinic input]
2208 : : memoryview.hex
2209 : :
2210 : : sep: object = NULL
2211 : : An optional single character or byte to separate hex bytes.
2212 : : bytes_per_sep: int = 1
2213 : : How many bytes between separators. Positive values count from the
2214 : : right, negative values count from the left.
2215 : :
2216 : : Return the data in the buffer as a str of hexadecimal numbers.
2217 : :
2218 : : Example:
2219 : : >>> value = memoryview(b'\xb9\x01\xef')
2220 : : >>> value.hex()
2221 : : 'b901ef'
2222 : : >>> value.hex(':')
2223 : : 'b9:01:ef'
2224 : : >>> value.hex(':', 2)
2225 : : 'b9:01ef'
2226 : : >>> value.hex(':', -2)
2227 : : 'b901:ef'
2228 : : [clinic start generated code]*/
2229 : :
2230 : : static PyObject *
2231 : 11344 : memoryview_hex_impl(PyMemoryViewObject *self, PyObject *sep,
2232 : : int bytes_per_sep)
2233 : : /*[clinic end generated code: output=430ca760f94f3ca7 input=539f6a3a5fb56946]*/
2234 : : {
2235 : 11344 : Py_buffer *src = VIEW_ADDR(self);
2236 : : PyObject *bytes;
2237 : : PyObject *ret;
2238 : :
2239 [ + - - + ]: 11344 : CHECK_RELEASED(self);
2240 : :
2241 [ + + ]: 11344 : if (MV_C_CONTIGUOUS(self->flags)) {
2242 : 3707 : return _Py_strhex_with_sep(src->buf, src->len, sep, bytes_per_sep);
2243 : : }
2244 : :
2245 : 7637 : bytes = PyBytes_FromStringAndSize(NULL, src->len);
2246 [ - + ]: 7637 : if (bytes == NULL)
2247 : 0 : return NULL;
2248 : :
2249 [ - + ]: 7637 : if (PyBuffer_ToContiguous(PyBytes_AS_STRING(bytes), src, src->len, 'C') < 0) {
2250 : 0 : Py_DECREF(bytes);
2251 : 0 : return NULL;
2252 : : }
2253 : :
2254 : 15274 : ret = _Py_strhex_with_sep(
2255 : 7637 : PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes),
2256 : : sep, bytes_per_sep);
2257 : 7637 : Py_DECREF(bytes);
2258 : :
2259 : 7637 : return ret;
2260 : : }
2261 : :
2262 : : static PyObject *
2263 : 57 : memory_repr(PyMemoryViewObject *self)
2264 : : {
2265 [ + + ]: 57 : if (self->flags & _Py_MEMORYVIEW_RELEASED)
2266 : 55 : return PyUnicode_FromFormat("<released memory at %p>", self);
2267 : : else
2268 : 2 : return PyUnicode_FromFormat("<memory at %p>", self);
2269 : : }
2270 : :
2271 : :
2272 : : /**************************************************************************/
2273 : : /* Indexing and slicing */
2274 : : /**************************************************************************/
2275 : :
2276 : : static char *
2277 : 84355 : lookup_dimension(const Py_buffer *view, char *ptr, int dim, Py_ssize_t index)
2278 : : {
2279 : : Py_ssize_t nitems; /* items in the given dimension */
2280 : :
2281 : : assert(view->shape);
2282 : : assert(view->strides);
2283 : :
2284 : 84355 : nitems = view->shape[dim];
2285 [ + + ]: 84355 : if (index < 0) {
2286 : 275 : index += nitems;
2287 : : }
2288 [ + + + + ]: 84355 : if (index < 0 || index >= nitems) {
2289 : 101 : PyErr_Format(PyExc_IndexError,
2290 : : "index out of bounds on dimension %d", dim + 1);
2291 : 101 : return NULL;
2292 : : }
2293 : :
2294 : 84254 : ptr += view->strides[dim] * index;
2295 : :
2296 [ + + + - ]: 84254 : ptr = ADJUST_PTR(ptr, view->suboffsets, dim);
2297 : :
2298 : 84254 : return ptr;
2299 : : }
2300 : :
2301 : : /* Get the pointer to the item at index. */
2302 : : static char *
2303 : 84307 : ptr_from_index(const Py_buffer *view, Py_ssize_t index)
2304 : : {
2305 : 84307 : char *ptr = (char *)view->buf;
2306 : 84307 : return lookup_dimension(view, ptr, 0, index);
2307 : : }
2308 : :
2309 : : /* Get the pointer to the item at tuple. */
2310 : : static char *
2311 : 37 : ptr_from_tuple(const Py_buffer *view, PyObject *tup)
2312 : : {
2313 : 37 : char *ptr = (char *)view->buf;
2314 : 37 : Py_ssize_t dim, nindices = PyTuple_GET_SIZE(tup);
2315 : :
2316 [ + + ]: 37 : if (nindices > view->ndim) {
2317 : 2 : PyErr_Format(PyExc_TypeError,
2318 : : "cannot index %zd-dimension view with %zd-element tuple",
2319 : 2 : view->ndim, nindices);
2320 : 2 : return NULL;
2321 : : }
2322 : :
2323 [ + + ]: 75 : for (dim = 0; dim < nindices; dim++) {
2324 : : Py_ssize_t index;
2325 : 52 : index = PyNumber_AsSsize_t(PyTuple_GET_ITEM(tup, dim),
2326 : : PyExc_IndexError);
2327 [ + + + + ]: 52 : if (index == -1 && PyErr_Occurred())
2328 : 4 : return NULL;
2329 : 48 : ptr = lookup_dimension(view, ptr, (int)dim, index);
2330 [ + + ]: 48 : if (ptr == NULL)
2331 : 8 : return NULL;
2332 : : }
2333 : 23 : return ptr;
2334 : : }
2335 : :
2336 : : /* Return the item at index. In a one-dimensional view, this is an object
2337 : : with the type specified by view->format. Otherwise, the item is a sub-view.
2338 : : The function is used in memory_subscript() and memory_as_sequence. */
2339 : : static PyObject *
2340 : 63165 : memory_item(PyMemoryViewObject *self, Py_ssize_t index)
2341 : : {
2342 : 63165 : Py_buffer *view = &(self->view);
2343 : : const char *fmt;
2344 : :
2345 [ + + - + ]: 63165 : CHECK_RELEASED(self);
2346 : :
2347 : 63164 : fmt = adjust_fmt(view);
2348 [ + + ]: 63164 : if (fmt == NULL)
2349 : 1 : return NULL;
2350 : :
2351 [ - + ]: 63163 : if (view->ndim == 0) {
2352 : 0 : PyErr_SetString(PyExc_TypeError, "invalid indexing of 0-dim memory");
2353 : 0 : return NULL;
2354 : : }
2355 [ + + ]: 63163 : if (view->ndim == 1) {
2356 : 63162 : char *ptr = ptr_from_index(view, index);
2357 [ + + ]: 63162 : if (ptr == NULL)
2358 : 51 : return NULL;
2359 : 63111 : return unpack_single(self, ptr, fmt);
2360 : : }
2361 : :
2362 : 1 : PyErr_SetString(PyExc_NotImplementedError,
2363 : : "multi-dimensional sub-views are not implemented");
2364 : 1 : return NULL;
2365 : : }
2366 : :
2367 : : /* Return the item at position *key* (a tuple of indices). */
2368 : : static PyObject *
2369 : 16 : memory_item_multi(PyMemoryViewObject *self, PyObject *tup)
2370 : : {
2371 : 16 : Py_buffer *view = &(self->view);
2372 : : const char *fmt;
2373 : 16 : Py_ssize_t nindices = PyTuple_GET_SIZE(tup);
2374 : : char *ptr;
2375 : :
2376 [ + - - + ]: 16 : CHECK_RELEASED(self);
2377 : :
2378 : 16 : fmt = adjust_fmt(view);
2379 [ - + ]: 16 : if (fmt == NULL)
2380 : 0 : return NULL;
2381 : :
2382 [ + + ]: 16 : if (nindices < view->ndim) {
2383 : 2 : PyErr_SetString(PyExc_NotImplementedError,
2384 : : "sub-views are not implemented");
2385 : 2 : return NULL;
2386 : : }
2387 : 14 : ptr = ptr_from_tuple(view, tup);
2388 [ + + ]: 14 : if (ptr == NULL)
2389 : 7 : return NULL;
2390 : 7 : return unpack_single(self, ptr, fmt);
2391 : : }
2392 : :
2393 : : static inline int
2394 : 204200 : init_slice(Py_buffer *base, PyObject *key, int dim)
2395 : : {
2396 : : Py_ssize_t start, stop, step, slicelength;
2397 : :
2398 [ + + ]: 204200 : if (PySlice_Unpack(key, &start, &stop, &step) < 0) {
2399 : 3 : return -1;
2400 : : }
2401 : 204197 : slicelength = PySlice_AdjustIndices(base->shape[dim], &start, &stop, step);
2402 : :
2403 : :
2404 [ + + + - ]: 204197 : if (base->suboffsets == NULL || dim == 0) {
2405 : 204197 : adjust_buf:
2406 : 204197 : base->buf = (char *)base->buf + base->strides[dim] * start;
2407 : : }
2408 : : else {
2409 : 0 : Py_ssize_t n = dim-1;
2410 [ # # # # ]: 0 : while (n >= 0 && base->suboffsets[n] < 0)
2411 : 0 : n--;
2412 [ # # ]: 0 : if (n < 0)
2413 : 0 : goto adjust_buf; /* all suboffsets are negative */
2414 : 0 : base->suboffsets[n] = base->suboffsets[n] + base->strides[dim] * start;
2415 : : }
2416 : 204197 : base->shape[dim] = slicelength;
2417 : 204197 : base->strides[dim] = base->strides[dim] * step;
2418 : :
2419 : 204197 : return 0;
2420 : : }
2421 : :
2422 : : static int
2423 : 69 : is_multislice(PyObject *key)
2424 : : {
2425 : : Py_ssize_t size, i;
2426 : :
2427 [ + + ]: 69 : if (!PyTuple_Check(key))
2428 : 44 : return 0;
2429 : 25 : size = PyTuple_GET_SIZE(key);
2430 [ - + ]: 25 : if (size == 0)
2431 : 0 : return 0;
2432 : :
2433 [ + + ]: 51 : for (i = 0; i < size; i++) {
2434 : 42 : PyObject *x = PyTuple_GET_ITEM(key, i);
2435 [ + + ]: 42 : if (!PySlice_Check(x))
2436 : 16 : return 0;
2437 : : }
2438 : 9 : return 1;
2439 : : }
2440 : :
2441 : : static Py_ssize_t
2442 : 109 : is_multiindex(PyObject *key)
2443 : : {
2444 : : Py_ssize_t size, i;
2445 : :
2446 [ + + ]: 109 : if (!PyTuple_Check(key))
2447 : 45 : return 0;
2448 : 64 : size = PyTuple_GET_SIZE(key);
2449 [ + + ]: 134 : for (i = 0; i < size; i++) {
2450 : 95 : PyObject *x = PyTuple_GET_ITEM(key, i);
2451 [ + + ]: 95 : if (!_PyIndex_Check(x)) {
2452 : 25 : return 0;
2453 : : }
2454 : : }
2455 : 39 : return 1;
2456 : : }
2457 : :
2458 : : /* mv[obj] returns an object holding the data for one element if obj
2459 : : fully indexes the memoryview or another memoryview object if it
2460 : : does not.
2461 : :
2462 : : 0-d memoryview objects can be referenced using mv[...] or mv[()]
2463 : : but not with anything else. */
2464 : : static PyObject *
2465 : 261495 : memory_subscript(PyMemoryViewObject *self, PyObject *key)
2466 : : {
2467 : : Py_buffer *view;
2468 : 261495 : view = &(self->view);
2469 : :
2470 [ + + - + ]: 261495 : CHECK_RELEASED(self);
2471 : :
2472 [ + + ]: 261467 : if (view->ndim == 0) {
2473 [ + + + - ]: 22 : if (PyTuple_Check(key) && PyTuple_GET_SIZE(key) == 0) {
2474 : 17 : const char *fmt = adjust_fmt(view);
2475 [ + + ]: 17 : if (fmt == NULL)
2476 : 1 : return NULL;
2477 : 16 : return unpack_single(self, view->buf, fmt);
2478 : : }
2479 [ + + ]: 5 : else if (key == Py_Ellipsis) {
2480 : 3 : Py_INCREF(self);
2481 : 3 : return (PyObject *)self;
2482 : : }
2483 : : else {
2484 : 2 : PyErr_SetString(PyExc_TypeError,
2485 : : "invalid indexing of 0-dim memory");
2486 : 2 : return NULL;
2487 : : }
2488 : : }
2489 : :
2490 [ + + ]: 261445 : if (_PyIndex_Check(key)) {
2491 : : Py_ssize_t index;
2492 : 63059 : index = PyNumber_AsSsize_t(key, PyExc_IndexError);
2493 [ + + + + ]: 63059 : if (index == -1 && PyErr_Occurred())
2494 : 2 : return NULL;
2495 : 63057 : return memory_item(self, index);
2496 : : }
2497 [ + + ]: 198386 : else if (PySlice_Check(key)) {
2498 : : PyMemoryViewObject *sliced;
2499 : :
2500 : 198336 : sliced = (PyMemoryViewObject *)mbuf_add_view(self->mbuf, view);
2501 [ - + ]: 198336 : if (sliced == NULL)
2502 : 0 : return NULL;
2503 : :
2504 [ + + ]: 198336 : if (init_slice(&sliced->view, key, 0) < 0) {
2505 : 2 : Py_DECREF(sliced);
2506 : 2 : return NULL;
2507 : : }
2508 : 198334 : init_len(&sliced->view);
2509 : 198334 : init_flags(sliced);
2510 : :
2511 : 198334 : return (PyObject *)sliced;
2512 : : }
2513 [ + + ]: 50 : else if (is_multiindex(key)) {
2514 : 16 : return memory_item_multi(self, key);
2515 : : }
2516 [ + + ]: 34 : else if (is_multislice(key)) {
2517 : 2 : PyErr_SetString(PyExc_NotImplementedError,
2518 : : "multi-dimensional slicing is not implemented");
2519 : 2 : return NULL;
2520 : : }
2521 : :
2522 : 32 : PyErr_SetString(PyExc_TypeError, "memoryview: invalid slice key");
2523 : 32 : return NULL;
2524 : : }
2525 : :
2526 : : static int
2527 : 27149 : memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
2528 : : {
2529 : 27149 : Py_buffer *view = &(self->view);
2530 : : Py_buffer src;
2531 : : const char *fmt;
2532 : : char *ptr;
2533 : :
2534 [ + + - + ]: 27149 : CHECK_RELEASED_INT(self);
2535 : :
2536 : 27121 : fmt = adjust_fmt(view);
2537 [ + + ]: 27121 : if (fmt == NULL)
2538 : 2 : return -1;
2539 : :
2540 [ + + ]: 27119 : if (view->readonly) {
2541 : 23 : PyErr_SetString(PyExc_TypeError, "cannot modify read-only memory");
2542 : 23 : return -1;
2543 : : }
2544 [ + + ]: 27096 : if (value == NULL) {
2545 : 13 : PyErr_SetString(PyExc_TypeError, "cannot delete memory");
2546 : 13 : return -1;
2547 : : }
2548 [ + + ]: 27083 : if (view->ndim == 0) {
2549 [ + + + + ]: 18 : if (key == Py_Ellipsis ||
2550 [ + - ]: 14 : (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
2551 : 8 : ptr = (char *)view->buf;
2552 : 8 : return pack_single(self, ptr, value, fmt);
2553 : : }
2554 : : else {
2555 : 2 : PyErr_SetString(PyExc_TypeError,
2556 : : "invalid indexing of 0-dim memory");
2557 : 2 : return -1;
2558 : : }
2559 : : }
2560 : :
2561 [ + + ]: 27073 : if (_PyIndex_Check(key)) {
2562 : : Py_ssize_t index;
2563 [ + + ]: 21148 : if (1 < view->ndim) {
2564 : 1 : PyErr_SetString(PyExc_NotImplementedError,
2565 : : "sub-views are not implemented");
2566 : 1 : return -1;
2567 : : }
2568 : 21147 : index = PyNumber_AsSsize_t(key, PyExc_IndexError);
2569 [ + + + + ]: 21147 : if (index == -1 && PyErr_Occurred())
2570 : 2 : return -1;
2571 : 21145 : ptr = ptr_from_index(view, index);
2572 [ + + ]: 21145 : if (ptr == NULL)
2573 : 42 : return -1;
2574 : 21103 : return pack_single(self, ptr, value, fmt);
2575 : : }
2576 : : /* one-dimensional: fast path */
2577 [ + + + + ]: 5925 : if (PySlice_Check(key) && view->ndim == 1) {
2578 : : Py_buffer dest; /* sliced view */
2579 : : Py_ssize_t arrays[3];
2580 : 5866 : int ret = -1;
2581 : :
2582 : : /* rvalue must be an exporter */
2583 [ + + ]: 5866 : if (PyObject_GetBuffer(value, &src, PyBUF_FULL_RO) < 0)
2584 : 2 : return ret;
2585 : :
2586 : 5864 : dest = *view;
2587 : 5864 : dest.shape = &arrays[0]; dest.shape[0] = view->shape[0];
2588 : 5864 : dest.strides = &arrays[1]; dest.strides[0] = view->strides[0];
2589 [ + + ]: 5864 : if (view->suboffsets) {
2590 : 278 : dest.suboffsets = &arrays[2]; dest.suboffsets[0] = view->suboffsets[0];
2591 : : }
2592 : :
2593 [ + + ]: 5864 : if (init_slice(&dest, key, 0) < 0)
2594 : 1 : goto end_block;
2595 : 5863 : dest.len = dest.shape[0] * dest.itemsize;
2596 : :
2597 : 5863 : ret = copy_single(self, &dest, &src);
2598 : :
2599 : 5864 : end_block:
2600 : 5864 : PyBuffer_Release(&src);
2601 : 5864 : return ret;
2602 : : }
2603 [ + + ]: 59 : if (is_multiindex(key)) {
2604 : : char *ptr;
2605 [ - + ]: 23 : if (PyTuple_GET_SIZE(key) < view->ndim) {
2606 : 0 : PyErr_SetString(PyExc_NotImplementedError,
2607 : : "sub-views are not implemented");
2608 : 0 : return -1;
2609 : : }
2610 : 23 : ptr = ptr_from_tuple(view, key);
2611 [ + + ]: 23 : if (ptr == NULL)
2612 : 7 : return -1;
2613 : 16 : return pack_single(self, ptr, value, fmt);
2614 : : }
2615 [ + + + + ]: 36 : if (PySlice_Check(key) || is_multislice(key)) {
2616 : : /* Call memory_subscript() to produce a sliced lvalue, then copy
2617 : : rvalue into lvalue. This is already implemented in _testbuffer.c. */
2618 : 8 : PyErr_SetString(PyExc_NotImplementedError,
2619 : : "memoryview slice assignments are currently restricted "
2620 : : "to ndim = 1");
2621 : 8 : return -1;
2622 : : }
2623 : :
2624 : 28 : PyErr_SetString(PyExc_TypeError, "memoryview: invalid slice key");
2625 : 28 : return -1;
2626 : : }
2627 : :
2628 : : static Py_ssize_t
2629 : 203781 : memory_length(PyMemoryViewObject *self)
2630 : : {
2631 [ + + - + ]: 203781 : CHECK_RELEASED_INT(self);
2632 [ + + ]: 203753 : return self->view.ndim == 0 ? 1 : self->view.shape[0];
2633 : : }
2634 : :
2635 : : /* As mapping */
2636 : : static PyMappingMethods memory_as_mapping = {
2637 : : (lenfunc)memory_length, /* mp_length */
2638 : : (binaryfunc)memory_subscript, /* mp_subscript */
2639 : : (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
2640 : : };
2641 : :
2642 : : /* As sequence */
2643 : : static PySequenceMethods memory_as_sequence = {
2644 : : (lenfunc)memory_length, /* sq_length */
2645 : : 0, /* sq_concat */
2646 : : 0, /* sq_repeat */
2647 : : (ssizeargfunc)memory_item, /* sq_item */
2648 : : };
2649 : :
2650 : :
2651 : : /**************************************************************************/
2652 : : /* Comparisons */
2653 : : /**************************************************************************/
2654 : :
2655 : : #define MV_COMPARE_EX -1 /* exception */
2656 : : #define MV_COMPARE_NOT_IMPL -2 /* not implemented */
2657 : :
2658 : : /* Translate a StructError to "not equal". Preserve other exceptions. */
2659 : : static int
2660 : 5 : fix_struct_error_int(void)
2661 : : {
2662 : : assert(PyErr_Occurred());
2663 : : /* XXX Cannot get at StructError directly? */
2664 [ + - - + ]: 10 : if (PyErr_ExceptionMatches(PyExc_ImportError) ||
2665 : 5 : PyErr_ExceptionMatches(PyExc_MemoryError)) {
2666 : 0 : return MV_COMPARE_EX;
2667 : : }
2668 : : /* StructError: invalid or unknown format -> not equal */
2669 : 5 : PyErr_Clear();
2670 : 5 : return 0;
2671 : : }
2672 : :
2673 : : /* Unpack and compare single items of p and q using the struct module. */
2674 : : static int
2675 : 178073 : struct_unpack_cmp(const char *p, const char *q,
2676 : : struct unpacker *unpack_p, struct unpacker *unpack_q)
2677 : : {
2678 : : PyObject *v, *w;
2679 : : int ret;
2680 : :
2681 : : /* At this point any exception from the struct module should not be
2682 : : StructError, since both formats have been accepted already. */
2683 : 178073 : v = struct_unpack_single(p, unpack_p);
2684 [ - + ]: 178073 : if (v == NULL)
2685 : 0 : return MV_COMPARE_EX;
2686 : :
2687 : 178073 : w = struct_unpack_single(q, unpack_q);
2688 [ - + ]: 178073 : if (w == NULL) {
2689 : 0 : Py_DECREF(v);
2690 : 0 : return MV_COMPARE_EX;
2691 : : }
2692 : :
2693 : : /* MV_COMPARE_EX == -1: exceptions are preserved */
2694 : 178073 : ret = PyObject_RichCompareBool(v, w, Py_EQ);
2695 : 178073 : Py_DECREF(v);
2696 : 178073 : Py_DECREF(w);
2697 : :
2698 : 178073 : return ret;
2699 : : }
2700 : :
2701 : : /* Unpack and compare single items of p and q. If both p and q have the same
2702 : : single element native format, the comparison uses a fast path (gcc creates
2703 : : a jump table and converts memcpy into simple assignments on x86/x64).
2704 : :
2705 : : Otherwise, the comparison is delegated to the struct module, which is
2706 : : 30-60x slower. */
2707 : : #define CMP_SINGLE(p, q, type) \
2708 : : do { \
2709 : : type x; \
2710 : : type y; \
2711 : : memcpy((char *)&x, p, sizeof x); \
2712 : : memcpy((char *)&y, q, sizeof y); \
2713 : : equal = (x == y); \
2714 : : } while (0)
2715 : :
2716 : : static inline int
2717 : 5768676 : unpack_cmp(const char *p, const char *q, char fmt,
2718 : : struct unpacker *unpack_p, struct unpacker *unpack_q)
2719 : : {
2720 : : int equal;
2721 : :
2722 [ + + + + : 5768676 : switch (fmt) {
+ + + + +
+ + + + +
+ + + +
- ]
2723 : :
2724 : : /* signed integers and fast path for 'B' */
2725 : 3530155 : case 'B': return *((const unsigned char *)p) == *((const unsigned char *)q);
2726 : 718587 : case 'b': return *((const signed char *)p) == *((const signed char *)q);
2727 : 24830 : case 'h': CMP_SINGLE(p, q, short); return equal;
2728 : 26412 : case 'i': CMP_SINGLE(p, q, int); return equal;
2729 : 176243 : case 'l': CMP_SINGLE(p, q, long); return equal;
2730 : :
2731 : : /* boolean */
2732 : 167710 : case '?': CMP_SINGLE(p, q, _Bool); return equal;
2733 : :
2734 : : /* unsigned integers */
2735 : 26482 : case 'H': CMP_SINGLE(p, q, unsigned short); return equal;
2736 : 27423 : case 'I': CMP_SINGLE(p, q, unsigned int); return equal;
2737 : 28816 : case 'L': CMP_SINGLE(p, q, unsigned long); return equal;
2738 : :
2739 : : /* native 64-bit */
2740 : 22921 : case 'q': CMP_SINGLE(p, q, long long); return equal;
2741 : 23203 : case 'Q': CMP_SINGLE(p, q, unsigned long long); return equal;
2742 : :
2743 : : /* ssize_t and size_t */
2744 : 21603 : case 'n': CMP_SINGLE(p, q, Py_ssize_t); return equal;
2745 : 20709 : case 'N': CMP_SINGLE(p, q, size_t); return equal;
2746 : :
2747 : : /* floats */
2748 : : /* XXX DBL_EPSILON? */
2749 : 155351 : case 'f': CMP_SINGLE(p, q, float); return equal;
2750 : 25648 : case 'd': CMP_SINGLE(p, q, double); return equal;
2751 : :
2752 : : /* bytes object */
2753 : 570610 : case 'c': return *p == *q;
2754 : :
2755 : : /* pointer */
2756 : 23900 : case 'P': CMP_SINGLE(p, q, void *); return equal;
2757 : :
2758 : : /* use the struct module */
2759 : 178073 : case '_':
2760 : : assert(unpack_p);
2761 : : assert(unpack_q);
2762 : 178073 : return struct_unpack_cmp(p, q, unpack_p, unpack_q);
2763 : : }
2764 : :
2765 : : /* NOT REACHED */
2766 : 0 : PyErr_SetString(PyExc_RuntimeError,
2767 : : "memoryview: internal error in richcompare");
2768 : 0 : return MV_COMPARE_EX;
2769 : : }
2770 : :
2771 : : /* Base case for recursive array comparisons. Assumption: ndim == 1. */
2772 : : static int
2773 : 446504 : cmp_base(const char *p, const char *q, const Py_ssize_t *shape,
2774 : : const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
2775 : : const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
2776 : : char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
2777 : : {
2778 : : Py_ssize_t i;
2779 : : int equal;
2780 : :
2781 [ + + ]: 6210028 : for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) {
2782 [ + + + + ]: 5767053 : const char *xp = ADJUST_PTR(p, psuboffsets, 0);
2783 [ + + + + ]: 5767053 : const char *xq = ADJUST_PTR(q, qsuboffsets, 0);
2784 : 5767053 : equal = unpack_cmp(xp, xq, fmt, unpack_p, unpack_q);
2785 [ + + ]: 5767053 : if (equal <= 0)
2786 : 3529 : return equal;
2787 : : }
2788 : :
2789 : 442975 : return 1;
2790 : : }
2791 : :
2792 : : /* Recursively compare two multi-dimensional arrays that have the same
2793 : : logical structure. Assumption: ndim >= 1. */
2794 : : static int
2795 : 468086 : cmp_rec(const char *p, const char *q,
2796 : : Py_ssize_t ndim, const Py_ssize_t *shape,
2797 : : const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
2798 : : const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
2799 : : char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
2800 : : {
2801 : : Py_ssize_t i;
2802 : : int equal;
2803 : :
2804 : : assert(ndim >= 1);
2805 : : assert(shape != NULL);
2806 : : assert(pstrides != NULL);
2807 : : assert(qstrides != NULL);
2808 : :
2809 [ + + ]: 468086 : if (ndim == 1) {
2810 : 352146 : return cmp_base(p, q, shape,
2811 : : pstrides, psuboffsets,
2812 : : qstrides, qsuboffsets,
2813 : : fmt, unpack_p, unpack_q);
2814 : : }
2815 : :
2816 [ + + ]: 516892 : for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) {
2817 [ + + + + ]: 401081 : const char *xp = ADJUST_PTR(p, psuboffsets, 0);
2818 [ + + + + ]: 401081 : const char *xq = ADJUST_PTR(q, qsuboffsets, 0);
2819 [ + + + + ]: 401081 : equal = cmp_rec(xp, xq, ndim-1, shape+1,
2820 : : pstrides+1, psuboffsets ? psuboffsets+1 : NULL,
2821 : : qstrides+1, qsuboffsets ? qsuboffsets+1 : NULL,
2822 : : fmt, unpack_p, unpack_q);
2823 [ + + ]: 401081 : if (equal <= 0)
2824 : 129 : return equal;
2825 : : }
2826 : :
2827 : 115811 : return 1;
2828 : : }
2829 : :
2830 : : static PyObject *
2831 : 163313 : memory_richcompare(PyObject *v, PyObject *w, int op)
2832 : : {
2833 : : PyObject *res;
2834 : : Py_buffer wbuf, *vv;
2835 : 163313 : Py_buffer *ww = NULL;
2836 : 163313 : struct unpacker *unpack_v = NULL;
2837 : 163313 : struct unpacker *unpack_w = NULL;
2838 : : char vfmt, wfmt;
2839 : 163313 : int equal = MV_COMPARE_NOT_IMPL;
2840 : :
2841 [ + + + + ]: 163313 : if (op != Py_EQ && op != Py_NE)
2842 : 112 : goto result; /* Py_NotImplemented */
2843 : :
2844 : : assert(PyMemoryView_Check(v));
2845 [ + + - + ]: 163201 : if (BASE_INACCESSIBLE(v)) {
2846 : 88 : equal = (v == w);
2847 : 88 : goto result;
2848 : : }
2849 : 163113 : vv = VIEW_ADDR(v);
2850 : :
2851 [ + + ]: 163113 : if (PyMemoryView_Check(w)) {
2852 [ + + - + ]: 130916 : if (BASE_INACCESSIBLE(w)) {
2853 : 1 : equal = (v == w);
2854 : 1 : goto result;
2855 : : }
2856 : 130915 : ww = VIEW_ADDR(w);
2857 : : }
2858 : : else {
2859 [ + + ]: 32197 : if (PyObject_GetBuffer(w, &wbuf, PyBUF_FULL_RO) < 0) {
2860 : 49 : PyErr_Clear();
2861 : 49 : goto result; /* Py_NotImplemented */
2862 : : }
2863 : 32148 : ww = &wbuf;
2864 : : }
2865 : :
2866 [ + + ]: 163063 : if (!equiv_shape(vv, ww)) {
2867 : 72 : PyErr_Clear();
2868 : 72 : equal = 0;
2869 : 72 : goto result;
2870 : : }
2871 : :
2872 : : /* Use fast unpacking for identical primitive C type formats. */
2873 [ + + ]: 162991 : if (get_native_fmtchar(&vfmt, vv->format) < 0)
2874 : 15386 : vfmt = '_';
2875 [ + + ]: 162991 : if (get_native_fmtchar(&wfmt, ww->format) < 0)
2876 : 15386 : wfmt = '_';
2877 [ + + + - : 162991 : if (vfmt == '_' || wfmt == '_' || vfmt != wfmt) {
+ + ]
2878 : : /* Use struct module unpacking. NOTE: Even for equal format strings,
2879 : : memcmp() cannot be used for item comparison since it would give
2880 : : incorrect results in the case of NaNs or uninitialized padding
2881 : : bytes. */
2882 : 15396 : vfmt = '_';
2883 : 15396 : unpack_v = struct_get_unpacker(vv->format, vv->itemsize);
2884 [ + + ]: 15396 : if (unpack_v == NULL) {
2885 : 5 : equal = fix_struct_error_int();
2886 : 5 : goto result;
2887 : : }
2888 : 15391 : unpack_w = struct_get_unpacker(ww->format, ww->itemsize);
2889 [ - + ]: 15391 : if (unpack_w == NULL) {
2890 : 0 : equal = fix_struct_error_int();
2891 : 0 : goto result;
2892 : : }
2893 : : }
2894 : :
2895 [ + + ]: 162986 : if (vv->ndim == 0) {
2896 : 1623 : equal = unpack_cmp(vv->buf, ww->buf,
2897 : : vfmt, unpack_v, unpack_w);
2898 : : }
2899 [ + + ]: 161363 : else if (vv->ndim == 1) {
2900 : 94358 : equal = cmp_base(vv->buf, ww->buf, vv->shape,
2901 : 94358 : vv->strides, vv->suboffsets,
2902 : 94358 : ww->strides, ww->suboffsets,
2903 : : vfmt, unpack_v, unpack_w);
2904 : : }
2905 : : else {
2906 : 67005 : equal = cmp_rec(vv->buf, ww->buf, vv->ndim, vv->shape,
2907 : 67005 : vv->strides, vv->suboffsets,
2908 : 67005 : ww->strides, ww->suboffsets,
2909 : : vfmt, unpack_v, unpack_w);
2910 : : }
2911 : :
2912 : 163313 : result:
2913 [ + + ]: 163313 : if (equal < 0) {
2914 [ + - ]: 161 : if (equal == MV_COMPARE_NOT_IMPL)
2915 : 161 : res = Py_NotImplemented;
2916 : : else /* exception */
2917 : 0 : res = NULL;
2918 : : }
2919 [ + + + + : 163152 : else if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
+ + + + ]
2920 : 163084 : res = Py_True;
2921 : : else
2922 : 68 : res = Py_False;
2923 : :
2924 [ + + ]: 163313 : if (ww == &wbuf)
2925 : 32148 : PyBuffer_Release(ww);
2926 : :
2927 : 163313 : unpacker_free(unpack_v);
2928 : 163313 : unpacker_free(unpack_w);
2929 : :
2930 : 163313 : Py_XINCREF(res);
2931 : 163313 : return res;
2932 : : }
2933 : :
2934 : : /**************************************************************************/
2935 : : /* Hash */
2936 : : /**************************************************************************/
2937 : :
2938 : : static Py_hash_t
2939 : 293 : memory_hash(PyMemoryViewObject *self)
2940 : : {
2941 [ + + ]: 293 : if (self->hash == -1) {
2942 : 288 : Py_buffer *view = &self->view;
2943 : 288 : char *mem = view->buf;
2944 : : Py_ssize_t ret;
2945 : : char fmt;
2946 : :
2947 [ + + - + ]: 298 : CHECK_RELEASED_INT(self);
2948 : :
2949 [ + + ]: 285 : if (!view->readonly) {
2950 : 6 : PyErr_SetString(PyExc_ValueError,
2951 : : "cannot hash writable memoryview object");
2952 : 6 : return -1;
2953 : : }
2954 : 279 : ret = get_native_fmtchar(&fmt, view->format);
2955 [ + + + + : 279 : if (ret < 0 || !IS_BYTE_FORMAT(fmt)) {
+ + + + ]
2956 : 4 : PyErr_SetString(PyExc_ValueError,
2957 : : "memoryview: hashing is restricted to formats 'B', 'b' or 'c'");
2958 : 4 : return -1;
2959 : : }
2960 [ + - - + ]: 275 : if (view->obj != NULL && PyObject_Hash(view->obj) == -1) {
2961 : : /* Keep the original error message */
2962 : 0 : return -1;
2963 : : }
2964 : :
2965 [ + + ]: 275 : if (!MV_C_CONTIGUOUS(self->flags)) {
2966 : 4 : mem = PyMem_Malloc(view->len);
2967 [ - + ]: 4 : if (mem == NULL) {
2968 : : PyErr_NoMemory();
2969 : 0 : return -1;
2970 : : }
2971 [ - + ]: 4 : if (buffer_to_contiguous(mem, view, 'C') < 0) {
2972 : 0 : PyMem_Free(mem);
2973 : 0 : return -1;
2974 : : }
2975 : : }
2976 : :
2977 : : /* Can't fail */
2978 : 275 : self->hash = _Py_HashBytes(mem, view->len);
2979 : :
2980 [ + + ]: 275 : if (mem != view->buf)
2981 : 4 : PyMem_Free(mem);
2982 : : }
2983 : :
2984 : 280 : return self->hash;
2985 : : }
2986 : :
2987 : :
2988 : : /**************************************************************************/
2989 : : /* getters */
2990 : : /**************************************************************************/
2991 : :
2992 : : static PyObject *
2993 : 246424 : _IntTupleFromSsizet(int len, Py_ssize_t *vals)
2994 : : {
2995 : : int i;
2996 : : PyObject *o;
2997 : : PyObject *intTuple;
2998 : :
2999 [ + + ]: 246424 : if (vals == NULL)
3000 : 96469 : return PyTuple_New(0);
3001 : :
3002 : 149955 : intTuple = PyTuple_New(len);
3003 [ - + ]: 149955 : if (!intTuple)
3004 : 0 : return NULL;
3005 [ + + ]: 370399 : for (i=0; i<len; i++) {
3006 : 220444 : o = PyLong_FromSsize_t(vals[i]);
3007 [ - + ]: 220444 : if (!o) {
3008 : 0 : Py_DECREF(intTuple);
3009 : 0 : return NULL;
3010 : : }
3011 : 220444 : PyTuple_SET_ITEM(intTuple, i, o);
3012 : : }
3013 : 149955 : return intTuple;
3014 : : }
3015 : :
3016 : : static PyObject *
3017 : 91944 : memory_obj_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
3018 : : {
3019 : 91944 : Py_buffer *view = &self->view;
3020 : :
3021 [ + + - + ]: 91944 : CHECK_RELEASED(self);
3022 [ + + ]: 91943 : if (view->obj == NULL) {
3023 : 36 : Py_RETURN_NONE;
3024 : : }
3025 : 91907 : Py_INCREF(view->obj);
3026 : 91907 : return view->obj;
3027 : : }
3028 : :
3029 : : static PyObject *
3030 : 93641 : memory_nbytes_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
3031 : : {
3032 [ + + - + ]: 93641 : CHECK_RELEASED(self);
3033 : 93640 : return PyLong_FromSsize_t(self->view.len);
3034 : : }
3035 : :
3036 : : static PyObject *
3037 : 88201 : memory_format_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
3038 : : {
3039 [ + + - + ]: 88201 : CHECK_RELEASED(self);
3040 : 88173 : return PyUnicode_FromString(self->view.format);
3041 : : }
3042 : :
3043 : : static PyObject *
3044 : 101628 : memory_itemsize_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
3045 : : {
3046 [ + + - + ]: 101628 : CHECK_RELEASED(self);
3047 : 101600 : return PyLong_FromSsize_t(self->view.itemsize);
3048 : : }
3049 : :
3050 : : static PyObject *
3051 : 73702 : memory_shape_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
3052 : : {
3053 [ + + - + ]: 73702 : CHECK_RELEASED(self);
3054 : 73674 : return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
3055 : : }
3056 : :
3057 : : static PyObject *
3058 : 71747 : memory_strides_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
3059 : : {
3060 [ + + - + ]: 71747 : CHECK_RELEASED(self);
3061 : 71719 : return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
3062 : : }
3063 : :
3064 : : static PyObject *
3065 : 101032 : memory_suboffsets_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
3066 : : {
3067 [ + + - + ]: 101032 : CHECK_RELEASED(self);
3068 : 101031 : return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
3069 : : }
3070 : :
3071 : : static PyObject *
3072 : 98424 : memory_readonly_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
3073 : : {
3074 [ + + - + ]: 98424 : CHECK_RELEASED(self);
3075 : 98396 : return PyBool_FromLong(self->view.readonly);
3076 : : }
3077 : :
3078 : : static PyObject *
3079 : 81090 : memory_ndim_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
3080 : : {
3081 [ + + - + ]: 81090 : CHECK_RELEASED(self);
3082 : 81062 : return PyLong_FromLong(self->view.ndim);
3083 : : }
3084 : :
3085 : : static PyObject *
3086 : 3368 : memory_c_contiguous(PyMemoryViewObject *self, PyObject *dummy)
3087 : : {
3088 [ + + - + ]: 3368 : CHECK_RELEASED(self);
3089 : 3367 : return PyBool_FromLong(MV_C_CONTIGUOUS(self->flags));
3090 : : }
3091 : :
3092 : : static PyObject *
3093 : 1079 : memory_f_contiguous(PyMemoryViewObject *self, PyObject *dummy)
3094 : : {
3095 [ + + - + ]: 1079 : CHECK_RELEASED(self);
3096 : 1078 : return PyBool_FromLong(MV_F_CONTIGUOUS(self->flags));
3097 : : }
3098 : :
3099 : : static PyObject *
3100 : 1119 : memory_contiguous(PyMemoryViewObject *self, PyObject *dummy)
3101 : : {
3102 [ + + - + ]: 1119 : CHECK_RELEASED(self);
3103 : 1118 : return PyBool_FromLong(MV_ANY_CONTIGUOUS(self->flags));
3104 : : }
3105 : :
3106 : : PyDoc_STRVAR(memory_obj_doc,
3107 : : "The underlying object of the memoryview.");
3108 : : PyDoc_STRVAR(memory_nbytes_doc,
3109 : : "The amount of space in bytes that the array would use in\n"
3110 : : " a contiguous representation.");
3111 : : PyDoc_STRVAR(memory_readonly_doc,
3112 : : "A bool indicating whether the memory is read only.");
3113 : : PyDoc_STRVAR(memory_itemsize_doc,
3114 : : "The size in bytes of each element of the memoryview.");
3115 : : PyDoc_STRVAR(memory_format_doc,
3116 : : "A string containing the format (in struct module style)\n"
3117 : : " for each element in the view.");
3118 : : PyDoc_STRVAR(memory_ndim_doc,
3119 : : "An integer indicating how many dimensions of a multi-dimensional\n"
3120 : : " array the memory represents.");
3121 : : PyDoc_STRVAR(memory_shape_doc,
3122 : : "A tuple of ndim integers giving the shape of the memory\n"
3123 : : " as an N-dimensional array.");
3124 : : PyDoc_STRVAR(memory_strides_doc,
3125 : : "A tuple of ndim integers giving the size in bytes to access\n"
3126 : : " each element for each dimension of the array.");
3127 : : PyDoc_STRVAR(memory_suboffsets_doc,
3128 : : "A tuple of integers used internally for PIL-style arrays.");
3129 : : PyDoc_STRVAR(memory_c_contiguous_doc,
3130 : : "A bool indicating whether the memory is C contiguous.");
3131 : : PyDoc_STRVAR(memory_f_contiguous_doc,
3132 : : "A bool indicating whether the memory is Fortran contiguous.");
3133 : : PyDoc_STRVAR(memory_contiguous_doc,
3134 : : "A bool indicating whether the memory is contiguous.");
3135 : :
3136 : :
3137 : : static PyGetSetDef memory_getsetlist[] = {
3138 : : {"obj", (getter)memory_obj_get, NULL, memory_obj_doc},
3139 : : {"nbytes", (getter)memory_nbytes_get, NULL, memory_nbytes_doc},
3140 : : {"readonly", (getter)memory_readonly_get, NULL, memory_readonly_doc},
3141 : : {"itemsize", (getter)memory_itemsize_get, NULL, memory_itemsize_doc},
3142 : : {"format", (getter)memory_format_get, NULL, memory_format_doc},
3143 : : {"ndim", (getter)memory_ndim_get, NULL, memory_ndim_doc},
3144 : : {"shape", (getter)memory_shape_get, NULL, memory_shape_doc},
3145 : : {"strides", (getter)memory_strides_get, NULL, memory_strides_doc},
3146 : : {"suboffsets", (getter)memory_suboffsets_get, NULL, memory_suboffsets_doc},
3147 : : {"c_contiguous", (getter)memory_c_contiguous, NULL, memory_c_contiguous_doc},
3148 : : {"f_contiguous", (getter)memory_f_contiguous, NULL, memory_f_contiguous_doc},
3149 : : {"contiguous", (getter)memory_contiguous, NULL, memory_contiguous_doc},
3150 : : {NULL, NULL, NULL, NULL},
3151 : : };
3152 : :
3153 : :
3154 : : static PyMethodDef memory_methods[] = {
3155 : : MEMORYVIEW_RELEASE_METHODDEF
3156 : : MEMORYVIEW_TOBYTES_METHODDEF
3157 : : MEMORYVIEW_HEX_METHODDEF
3158 : : MEMORYVIEW_TOLIST_METHODDEF
3159 : : MEMORYVIEW_CAST_METHODDEF
3160 : : MEMORYVIEW_TOREADONLY_METHODDEF
3161 : : {"__enter__", memory_enter, METH_NOARGS, NULL},
3162 : : {"__exit__", memory_exit, METH_VARARGS, NULL},
3163 : : {NULL, NULL}
3164 : : };
3165 : :
3166 : : /**************************************************************************/
3167 : : /* Memoryview Iterator */
3168 : : /**************************************************************************/
3169 : :
3170 : : PyTypeObject _PyMemoryIter_Type;
3171 : :
3172 : : typedef struct {
3173 : : PyObject_HEAD
3174 : : Py_ssize_t it_index;
3175 : : PyMemoryViewObject *it_seq; // Set to NULL when iterator is exhausted
3176 : : Py_ssize_t it_length;
3177 : : const char *it_fmt;
3178 : : } memoryiterobject;
3179 : :
3180 : : static void
3181 : 70 : memoryiter_dealloc(memoryiterobject *it)
3182 : : {
3183 : 70 : _PyObject_GC_UNTRACK(it);
3184 : 70 : Py_XDECREF(it->it_seq);
3185 : 70 : PyObject_GC_Del(it);
3186 : 70 : }
3187 : :
3188 : : static int
3189 : 0 : memoryiter_traverse(memoryiterobject *it, visitproc visit, void *arg)
3190 : : {
3191 [ # # # # ]: 0 : Py_VISIT(it->it_seq);
3192 : 0 : return 0;
3193 : : }
3194 : :
3195 : : static PyObject *
3196 : 292 : memoryiter_next(memoryiterobject *it)
3197 : : {
3198 : : PyMemoryViewObject *seq;
3199 : 292 : seq = it->it_seq;
3200 [ - + ]: 292 : if (seq == NULL) {
3201 : 0 : return NULL;
3202 : : }
3203 : :
3204 [ + + ]: 292 : if (it->it_index < it->it_length) {
3205 [ + - - + ]: 263 : CHECK_RELEASED(seq);
3206 : 263 : Py_buffer *view = &(seq->view);
3207 : 263 : char *ptr = (char *)seq->view.buf;
3208 : :
3209 : 263 : ptr += view->strides[0] * it->it_index++;
3210 [ - + - - ]: 263 : ptr = ADJUST_PTR(ptr, view->suboffsets, 0);
3211 [ - + ]: 263 : if (ptr == NULL) {
3212 : 0 : return NULL;
3213 : : }
3214 : 263 : return unpack_single(seq, ptr, it->it_fmt);
3215 : : }
3216 : :
3217 : 29 : it->it_seq = NULL;
3218 : 29 : Py_DECREF(seq);
3219 : 29 : return NULL;
3220 : : }
3221 : :
3222 : : static PyObject *
3223 : 72 : memory_iter(PyObject *seq)
3224 : : {
3225 [ - + ]: 72 : if (!PyMemoryView_Check(seq)) {
3226 : 0 : PyErr_BadInternalCall();
3227 : 0 : return NULL;
3228 : : }
3229 : 72 : PyMemoryViewObject *obj = (PyMemoryViewObject *)seq;
3230 : 72 : int ndims = obj->view.ndim;
3231 [ + + ]: 72 : if (ndims == 0) {
3232 : 2 : PyErr_SetString(PyExc_TypeError, "invalid indexing of 0-dim memory");
3233 : 2 : return NULL;
3234 : : }
3235 [ - + ]: 70 : if (ndims != 1) {
3236 : 0 : PyErr_SetString(PyExc_NotImplementedError,
3237 : : "multi-dimensional sub-views are not implemented");
3238 : 0 : return NULL;
3239 : : }
3240 : :
3241 : 70 : const char *fmt = adjust_fmt(&obj->view);
3242 [ - + ]: 70 : if (fmt == NULL) {
3243 : 0 : return NULL;
3244 : : }
3245 : :
3246 : : memoryiterobject *it;
3247 : 70 : it = PyObject_GC_New(memoryiterobject, &_PyMemoryIter_Type);
3248 [ - + ]: 70 : if (it == NULL) {
3249 : 0 : return NULL;
3250 : : }
3251 : 70 : it->it_fmt = fmt;
3252 : 70 : it->it_length = memory_length(obj);
3253 : 70 : it->it_index = 0;
3254 : 70 : Py_INCREF(seq);
3255 : 70 : it->it_seq = obj;
3256 : 70 : _PyObject_GC_TRACK(it);
3257 : 70 : return (PyObject *)it;
3258 : : }
3259 : :
3260 : : PyTypeObject _PyMemoryIter_Type = {
3261 : : PyVarObject_HEAD_INIT(&PyType_Type, 0)
3262 : : .tp_name = "memory_iterator",
3263 : : .tp_basicsize = sizeof(memoryiterobject),
3264 : : // methods
3265 : : .tp_dealloc = (destructor)memoryiter_dealloc,
3266 : : .tp_getattro = PyObject_GenericGetAttr,
3267 : : .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
3268 : : .tp_traverse = (traverseproc)memoryiter_traverse,
3269 : : .tp_iter = PyObject_SelfIter,
3270 : : .tp_iternext = (iternextfunc)memoryiter_next,
3271 : : };
3272 : :
3273 : : PyTypeObject PyMemoryView_Type = {
3274 : : PyVarObject_HEAD_INIT(&PyType_Type, 0)
3275 : : "memoryview", /* tp_name */
3276 : : offsetof(PyMemoryViewObject, ob_array), /* tp_basicsize */
3277 : : sizeof(Py_ssize_t), /* tp_itemsize */
3278 : : (destructor)memory_dealloc, /* tp_dealloc */
3279 : : 0, /* tp_vectorcall_offset */
3280 : : 0, /* tp_getattr */
3281 : : 0, /* tp_setattr */
3282 : : 0, /* tp_as_async */
3283 : : (reprfunc)memory_repr, /* tp_repr */
3284 : : 0, /* tp_as_number */
3285 : : &memory_as_sequence, /* tp_as_sequence */
3286 : : &memory_as_mapping, /* tp_as_mapping */
3287 : : (hashfunc)memory_hash, /* tp_hash */
3288 : : 0, /* tp_call */
3289 : : 0, /* tp_str */
3290 : : PyObject_GenericGetAttr, /* tp_getattro */
3291 : : 0, /* tp_setattro */
3292 : : &memory_as_buffer, /* tp_as_buffer */
3293 : : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
3294 : : Py_TPFLAGS_SEQUENCE, /* tp_flags */
3295 : : memoryview__doc__, /* tp_doc */
3296 : : (traverseproc)memory_traverse, /* tp_traverse */
3297 : : (inquiry)memory_clear, /* tp_clear */
3298 : : memory_richcompare, /* tp_richcompare */
3299 : : offsetof(PyMemoryViewObject, weakreflist),/* tp_weaklistoffset */
3300 : : memory_iter, /* tp_iter */
3301 : : 0, /* tp_iternext */
3302 : : memory_methods, /* tp_methods */
3303 : : 0, /* tp_members */
3304 : : memory_getsetlist, /* tp_getset */
3305 : : 0, /* tp_base */
3306 : : 0, /* tp_dict */
3307 : : 0, /* tp_descr_get */
3308 : : 0, /* tp_descr_set */
3309 : : 0, /* tp_dictoffset */
3310 : : 0, /* tp_init */
3311 : : 0, /* tp_alloc */
3312 : : memoryview, /* tp_new */
3313 : : };
|