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