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