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