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