blob: 432673091da838ee0e3fb389bbfcc8c148ddb2de [file] [log] [blame]
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001
2/* Memoryview object implementation */
3
4#include "Python.h"
5
Antoine Pitrou6e6cc832010-09-09 12:59:39 +00006#define IS_RELEASED(memobj) \
7 (((PyMemoryViewObject *) memobj)->view.buf == NULL)
8
9#define CHECK_RELEASED(memobj) \
10 if (IS_RELEASED(memobj)) { \
11 PyErr_SetString(PyExc_ValueError, \
12 "operation forbidden on released memoryview object"); \
13 return NULL; \
14 }
15
16#define CHECK_RELEASED_INT(memobj) \
17 if (IS_RELEASED(memobj)) { \
18 PyErr_SetString(PyExc_ValueError, \
19 "operation forbidden on released memoryview object"); \
20 return -1; \
21 }
22
Antoine Pitroubc420402008-12-07 20:14:49 +000023static Py_ssize_t
24get_shape0(Py_buffer *buf)
25{
26 if (buf->shape != NULL)
27 return buf->shape[0];
Antoine Pitrouc3b39242009-01-03 16:59:18 +000028 if (buf->ndim == 0)
29 return 1;
30 PyErr_SetString(PyExc_TypeError,
31 "exported buffer does not have any shape information associated "
32 "to it");
33 return -1;
34}
35
36static void
37dup_buffer(Py_buffer *dest, Py_buffer *src)
38{
39 *dest = *src;
40 if (src->ndim == 1 && src->shape != NULL) {
41 dest->shape = &(dest->smalltable[0]);
42 dest->shape[0] = get_shape0(src);
43 }
44 if (src->ndim == 1 && src->strides != NULL) {
45 dest->strides = &(dest->smalltable[1]);
46 dest->strides[0] = src->strides[0];
47 }
Antoine Pitroubc420402008-12-07 20:14:49 +000048}
49
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000050static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000051memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000052{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000053 int res = 0;
Antoine Pitrou6e6cc832010-09-09 12:59:39 +000054 CHECK_RELEASED_INT(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +000055 /* XXX for whatever reason fixing the flags seems necessary */
56 if (self->view.readonly)
57 flags &= ~PyBUF_WRITABLE;
58 if (self->view.obj != NULL)
59 res = PyObject_GetBuffer(self->view.obj, view, flags);
60 if (view)
61 dup_buffer(view, &self->view);
62 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000063}
64
65static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000066memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000067{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000068 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000069}
70
71PyDoc_STRVAR(memory_doc,
72"memoryview(object)\n\
73\n\
74Create a new memoryview object which references the given object.");
75
76PyObject *
Antoine Pitrouee58fa42008-08-19 18:22:14 +000077PyMemoryView_FromBuffer(Py_buffer *info)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000078{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000079 PyMemoryViewObject *mview;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000080
Antoine Pitrou35b7e832009-01-03 19:20:36 +000081 mview = (PyMemoryViewObject *)
82 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
83 if (mview == NULL)
84 return NULL;
85 mview->base = NULL;
86 dup_buffer(&mview->view, info);
87 /* NOTE: mview->view.obj should already have been incref'ed as
88 part of PyBuffer_FillInfo(). */
89 _PyObject_GC_TRACK(mview);
90 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000091}
92
93PyObject *
94PyMemoryView_FromObject(PyObject *base)
95{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000096 PyMemoryViewObject *mview;
Antoine Pitrou05b7c562010-02-02 22:47:00 +000097 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000098
Antoine Pitrou35b7e832009-01-03 19:20:36 +000099 if (!PyObject_CheckBuffer(base)) {
100 PyErr_SetString(PyExc_TypeError,
101 "cannot make memory view because object does "
102 "not have the buffer interface");
103 return NULL;
104 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000105
Antoine Pitrou05b7c562010-02-02 22:47:00 +0000106 if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000107 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000108
Antoine Pitrou05b7c562010-02-02 22:47:00 +0000109 mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);
110 if (mview == NULL) {
111 PyBuffer_Release(&view);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000112 return NULL;
113 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000114
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000115 mview->base = base;
116 Py_INCREF(base);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000117 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000118}
119
120static PyObject *
121memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
122{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000123 PyObject *obj;
124 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000125
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000126 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
127 &obj)) {
128 return NULL;
129 }
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000130
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000131 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000132}
133
134
135static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000136_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +0000137 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000138{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000139 int k;
140 Py_ssize_t outstride;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000141
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000142 if (nd==0) {
143 memcpy(dest, src, itemsize);
144 }
145 else if (nd == 1) {
146 for (k = 0; k<shape[0]; k++) {
147 memcpy(dest, src, itemsize);
148 dest += itemsize;
149 src += strides[0];
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000150 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000151 }
152 else {
153 if (fort == 'F') {
154 /* Copy first dimension first,
155 second dimension second, etc...
156 Set up the recursive loop backwards so that final
157 dimension is actually copied last.
158 */
159 outstride = itemsize;
160 for (k=1; k<nd-1;k++) {
161 outstride *= shape[k];
162 }
163 for (k=0; k<shape[nd-1]; k++) {
164 _strided_copy_nd(dest, src, nd-1, shape,
165 strides, itemsize, fort);
166 dest += outstride;
167 src += strides[nd-1];
168 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000169 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000170
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000171 else {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000172 /* Copy last dimension first,
173 second-to-last dimension second, etc.
174 Set up the recursion so that the
175 first dimension is copied last
176 */
177 outstride = itemsize;
178 for (k=1; k < nd; k++) {
179 outstride *= shape[k];
180 }
181 for (k=0; k<shape[0]; k++) {
182 _strided_copy_nd(dest, src, nd-1, shape+1,
183 strides+1, itemsize,
184 fort);
185 dest += outstride;
186 src += strides[0];
187 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000188 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000189 }
190 return;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000191}
192
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000193static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000194_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000195{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000196 Py_ssize_t *indices;
197 int k;
198 Py_ssize_t elements;
199 char *ptr;
Antoine Pitrouc73b9092010-09-01 21:14:46 +0000200 void (*func)(int, Py_ssize_t *, const Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000201
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000202 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
203 PyErr_NoMemory();
204 return -1;
205 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000206
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000207 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
208 if (indices == NULL) {
209 PyErr_NoMemory();
210 return -1;
211 }
212 for (k=0; k<view->ndim;k++) {
213 indices[k] = 0;
214 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000215
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000216 elements = 1;
217 for (k=0; k<view->ndim; k++) {
218 elements *= view->shape[k];
219 }
220 if (fort == 'F') {
Antoine Pitrouf68c2a72010-09-01 12:58:21 +0000221 func = _Py_add_one_to_index_F;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000222 }
223 else {
Antoine Pitrouf68c2a72010-09-01 12:58:21 +0000224 func = _Py_add_one_to_index_C;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000225 }
226 while (elements--) {
227 func(view->ndim, indices, view->shape);
228 ptr = PyBuffer_GetPointer(view, indices);
229 memcpy(dest, ptr, view->itemsize);
230 dest += view->itemsize;
231 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000232
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000233 PyMem_Free(indices);
234 return 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000235}
236
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000237/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000238 Get a the data from an object as a contiguous chunk of memory (in
239 either 'C' or 'F'ortran order) even if it means copying it into a
240 separate memory area.
241
242 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000243 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000244 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000245 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000246
247 buffertype
248
249 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000250 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000251 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000252 a contiguous buffer if it is not. The view will point to
253 the shadow buffer which can be written to and then
254 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000255 view is de-allocated. While the shadow buffer is
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000256 being used, it will have an exclusive write lock on
257 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000258 */
259
260PyObject *
261PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
262{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000263 PyMemoryViewObject *mem;
264 PyObject *bytes;
265 Py_buffer *view;
266 int flags;
267 char *dest;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000268
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000269 if (!PyObject_CheckBuffer(obj)) {
270 PyErr_SetString(PyExc_TypeError,
Georg Brandl61b96dc2009-08-04 20:29:27 +0000271 "object does not support the buffer interface");
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000272 return NULL;
273 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000274
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000275 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
276 if (mem == NULL)
277 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000278
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000279 view = &mem->view;
280 flags = PyBUF_FULL_RO;
281 switch(buffertype) {
282 case PyBUF_WRITE:
283 flags = PyBUF_FULL;
284 break;
285 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000286
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000287 if (PyObject_GetBuffer(obj, view, flags) != 0) {
288 Py_DECREF(mem);
289 return NULL;
290 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000291
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000292 if (PyBuffer_IsContiguous(view, fort)) {
293 /* no copy needed */
294 Py_INCREF(obj);
295 mem->base = obj;
296 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000297 return (PyObject *)mem;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000298 }
299 /* otherwise a copy is needed */
300 if (buffertype == PyBUF_WRITE) {
301 Py_DECREF(mem);
302 PyErr_SetString(PyExc_BufferError,
303 "writable contiguous buffer requested "
304 "for a non-contiguousobject.");
305 return NULL;
306 }
307 bytes = PyBytes_FromStringAndSize(NULL, view->len);
308 if (bytes == NULL) {
309 Py_DECREF(mem);
310 return NULL;
311 }
312 dest = PyBytes_AS_STRING(bytes);
313 /* different copying strategy depending on whether
314 or not any pointer de-referencing is needed
315 */
316 /* strided or in-direct copy */
317 if (view->suboffsets==NULL) {
318 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
319 view->strides, view->itemsize, fort);
320 }
321 else {
322 if (_indirect_copy_nd(dest, view, fort) < 0) {
323 Py_DECREF(bytes);
324 Py_DECREF(mem);
325 return NULL;
326 }
327 }
328 if (buffertype == PyBUF_SHADOW) {
329 /* return a shadowed memory-view object */
330 view->buf = dest;
331 mem->base = PyTuple_Pack(2, obj, bytes);
332 Py_DECREF(bytes);
333 if (mem->base == NULL) {
334 Py_DECREF(mem);
335 return NULL;
336 }
337 }
338 else {
339 PyBuffer_Release(view); /* XXX ? */
340 /* steal the reference */
341 mem->base = bytes;
342 }
343 _PyObject_GC_TRACK(mem);
344 return (PyObject *)mem;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000345}
346
347
348static PyObject *
349memory_format_get(PyMemoryViewObject *self)
350{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000351 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000352 return PyUnicode_FromString(self->view.format);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000353}
354
355static PyObject *
356memory_itemsize_get(PyMemoryViewObject *self)
357{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000358 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000359 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000360}
361
362static PyObject *
363_IntTupleFromSsizet(int len, Py_ssize_t *vals)
364{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000365 int i;
366 PyObject *o;
367 PyObject *intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000368
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000369 if (vals == NULL) {
370 Py_INCREF(Py_None);
371 return Py_None;
372 }
373 intTuple = PyTuple_New(len);
Benjamin Peterson83473282010-11-03 23:11:10 +0000374 if (!intTuple)
375 return NULL;
376 for (i=0; i<len; i++) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000377 o = PyLong_FromSsize_t(vals[i]);
378 if (!o) {
379 Py_DECREF(intTuple);
380 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000381 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000382 PyTuple_SET_ITEM(intTuple, i, o);
383 }
384 return intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000385}
386
387static PyObject *
388memory_shape_get(PyMemoryViewObject *self)
389{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000390 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000391 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000392}
393
394static PyObject *
395memory_strides_get(PyMemoryViewObject *self)
396{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000397 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000398 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000399}
400
401static PyObject *
402memory_suboffsets_get(PyMemoryViewObject *self)
403{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000404 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000405 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000406}
407
408static PyObject *
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000409memory_readonly_get(PyMemoryViewObject *self)
410{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000411 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000412 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000413}
414
415static PyObject *
416memory_ndim_get(PyMemoryViewObject *self)
417{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000418 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000419 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000420}
421
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000422static PyGetSetDef memory_getsetlist[] ={
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000423 {"format", (getter)memory_format_get, NULL, NULL},
424 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
425 {"shape", (getter)memory_shape_get, NULL, NULL},
426 {"strides", (getter)memory_strides_get, NULL, NULL},
427 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
428 {"readonly", (getter)memory_readonly_get, NULL, NULL},
429 {"ndim", (getter)memory_ndim_get, NULL, NULL},
430 {NULL, NULL, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000431};
432
433
434static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000435memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000436{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000437 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000438 return PyObject_CallFunctionObjArgs(
439 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000440}
441
Antoine Pitrou616d2852008-08-19 22:09:34 +0000442/* TODO: rewrite this function using the struct module to unpack
443 each buffer item */
444
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000445static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000446memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000447{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000448 Py_buffer *view = &(mem->view);
449 Py_ssize_t i;
450 PyObject *res, *item;
451 char *buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000452
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000453 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000454 if (strcmp(view->format, "B") || view->itemsize != 1) {
455 PyErr_SetString(PyExc_NotImplementedError,
456 "tolist() only supports byte views");
457 return NULL;
458 }
459 if (view->ndim != 1) {
460 PyErr_SetString(PyExc_NotImplementedError,
461 "tolist() only supports one-dimensional objects");
462 return NULL;
463 }
464 res = PyList_New(view->len);
465 if (res == NULL)
466 return NULL;
467 buf = view->buf;
468 for (i = 0; i < view->len; i++) {
469 item = PyLong_FromUnsignedLong((unsigned char) *buf);
470 if (item == NULL) {
471 Py_DECREF(res);
472 return NULL;
473 }
474 PyList_SET_ITEM(res, i, item);
475 buf++;
476 }
477 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000478}
479
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000480static void
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000481do_release(PyMemoryViewObject *self)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000482{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000483 if (self->view.obj != NULL) {
484 if (self->base && PyTuple_Check(self->base)) {
485 /* Special case when first element is generic object
486 with buffer interface and the second element is a
487 contiguous "shadow" that must be copied back into
488 the data areay of the first tuple element before
489 releasing the buffer on the first element.
490 */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000491
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000492 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
493 PyTuple_GET_ITEM(self->base,1));
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000494
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000495 /* The view member should have readonly == -1 in
496 this instance indicating that the memory can
497 be "locked" and was locked and will be unlocked
498 again after this call.
499 */
500 PyBuffer_Release(&(self->view));
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000501 }
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000502 else {
503 PyBuffer_Release(&(self->view));
504 }
505 Py_CLEAR(self->base);
506 }
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000507 self->view.obj = NULL;
508 self->view.buf = NULL;
509}
510
511static PyObject *
512memory_enter(PyObject *self, PyObject *args)
513{
514 CHECK_RELEASED(self);
515 Py_INCREF(self);
516 return self;
517}
518
519static PyObject *
520memory_exit(PyObject *self, PyObject *args)
521{
522 do_release((PyMemoryViewObject *) self);
523 Py_RETURN_NONE;
524}
525
526static PyMethodDef memory_methods[] = {
527 {"release", memory_exit, METH_NOARGS},
528 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
529 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
530 {"__enter__", memory_enter, METH_NOARGS},
531 {"__exit__", memory_exit, METH_VARARGS},
532 {NULL, NULL} /* sentinel */
533};
534
535
536static void
537memory_dealloc(PyMemoryViewObject *self)
538{
539 _PyObject_GC_UNTRACK(self);
540 do_release(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000541 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000542}
543
544static PyObject *
545memory_repr(PyMemoryViewObject *self)
546{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000547 if (IS_RELEASED(self))
548 return PyUnicode_FromFormat("<released memory at %p>", self);
549 else
550 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000551}
552
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000553/* Sequence methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000554static Py_ssize_t
555memory_length(PyMemoryViewObject *self)
556{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000557 CHECK_RELEASED_INT(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000558 return get_shape0(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000559}
560
Raymond Hettinger159eac92009-06-23 20:38:54 +0000561/* Alternate version of memory_subcript that only accepts indices.
562 Used by PySeqIter_New().
563*/
564static PyObject *
565memory_item(PyMemoryViewObject *self, Py_ssize_t result)
566{
567 Py_buffer *view = &(self->view);
568
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000569 CHECK_RELEASED(self);
Raymond Hettinger159eac92009-06-23 20:38:54 +0000570 if (view->ndim == 0) {
571 PyErr_SetString(PyExc_IndexError,
572 "invalid indexing of 0-dim memory");
573 return NULL;
574 }
575 if (view->ndim == 1) {
576 /* Return a bytes object */
577 char *ptr;
578 ptr = (char *)view->buf;
579 if (result < 0) {
580 result += get_shape0(view);
581 }
582 if ((result < 0) || (result >= get_shape0(view))) {
583 PyErr_SetString(PyExc_IndexError,
584 "index out of bounds");
585 return NULL;
586 }
587 if (view->strides == NULL)
588 ptr += view->itemsize * result;
589 else
590 ptr += view->strides[0] * result;
591 if (view->suboffsets != NULL &&
592 view->suboffsets[0] >= 0) {
593 ptr = *((char **)ptr) + view->suboffsets[0];
594 }
595 return PyBytes_FromStringAndSize(ptr, view->itemsize);
596 } else {
597 /* Return a new memory-view object */
598 Py_buffer newview;
599 memset(&newview, 0, sizeof(newview));
600 /* XXX: This needs to be fixed so it actually returns a sub-view */
601 return PyMemoryView_FromBuffer(&newview);
602 }
603}
604
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000605/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000606 mem[obj] returns a bytes object holding the data for one element if
607 obj fully indexes the memory view or another memory-view object
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000608 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000609
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000610 0-d memory-view objects can be referenced using ... or () but
611 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000612 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000613static PyObject *
614memory_subscript(PyMemoryViewObject *self, PyObject *key)
615{
Antoine Pitroubc420402008-12-07 20:14:49 +0000616 Py_buffer *view;
617 view = &(self->view);
618
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000619 CHECK_RELEASED(self);
Antoine Pitroubc420402008-12-07 20:14:49 +0000620 if (view->ndim == 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000621 if (key == Py_Ellipsis ||
622 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
623 Py_INCREF(self);
624 return (PyObject *)self;
625 }
626 else {
627 PyErr_SetString(PyExc_IndexError,
628 "invalid indexing of 0-dim memory");
629 return NULL;
630 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000631 }
632 if (PyIndex_Check(key)) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000633 Py_ssize_t result;
634 result = PyNumber_AsSsize_t(key, NULL);
635 if (result == -1 && PyErr_Occurred())
636 return NULL;
Raymond Hettinger159eac92009-06-23 20:38:54 +0000637 return memory_item(self, result);
Antoine Pitroubc420402008-12-07 20:14:49 +0000638 }
639 else if (PySlice_Check(key)) {
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000640 Py_ssize_t start, stop, step, slicelength;
641
Antoine Pitroubc420402008-12-07 20:14:49 +0000642 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000643 &start, &stop, &step, &slicelength) < 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000644 return NULL;
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000645 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000646
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000647 if (step == 1 && view->ndim == 1) {
648 Py_buffer newview;
649 void *newbuf = (char *) view->buf
650 + start * view->itemsize;
651 int newflags = view->readonly
652 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
Antoine Pitroubc420402008-12-07 20:14:49 +0000653
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000654 /* XXX There should be an API to create a subbuffer */
655 if (view->obj != NULL) {
656 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
657 return NULL;
658 }
659 else {
660 newview = *view;
661 }
662 newview.buf = newbuf;
663 newview.len = slicelength * newview.itemsize;
664 newview.format = view->format;
665 newview.shape = &(newview.smalltable[0]);
666 newview.shape[0] = slicelength;
667 newview.strides = &(newview.itemsize);
668 return PyMemoryView_FromBuffer(&newview);
669 }
670 PyErr_SetNone(PyExc_NotImplementedError);
671 return NULL;
Antoine Pitroubc420402008-12-07 20:14:49 +0000672 }
673 PyErr_Format(PyExc_TypeError,
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000674 "cannot index memory using \"%.200s\"",
675 key->ob_type->tp_name);
Antoine Pitroubc420402008-12-07 20:14:49 +0000676 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000677}
678
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000679
680/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000681static int
682memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
683{
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000684 Py_ssize_t start, len, bytelen;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000685 Py_buffer srcview;
686 Py_buffer *view = &(self->view);
687 char *srcbuf, *destbuf;
688
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000689 CHECK_RELEASED_INT(self);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000690 if (view->readonly) {
691 PyErr_SetString(PyExc_TypeError,
692 "cannot modify read-only memory");
693 return -1;
694 }
Antoine Pitroue0793ba2010-09-01 21:14:16 +0000695 if (value == NULL) {
696 PyErr_SetString(PyExc_TypeError,
697 "cannot delete memory");
698 return -1;
699 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000700 if (view->ndim != 1) {
701 PyErr_SetNone(PyExc_NotImplementedError);
702 return -1;
703 }
704 if (PyIndex_Check(key)) {
705 start = PyNumber_AsSsize_t(key, NULL);
706 if (start == -1 && PyErr_Occurred())
707 return -1;
708 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000709 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000710 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000711 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000712 PyErr_SetString(PyExc_IndexError,
713 "index out of bounds");
714 return -1;
715 }
716 len = 1;
717 }
718 else if (PySlice_Check(key)) {
719 Py_ssize_t stop, step;
720
Antoine Pitroubc420402008-12-07 20:14:49 +0000721 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000722 &start, &stop, &step, &len) < 0) {
723 return -1;
724 }
725 if (step != 1) {
726 PyErr_SetNone(PyExc_NotImplementedError);
727 return -1;
728 }
729 }
730 else {
731 PyErr_Format(PyExc_TypeError,
732 "cannot index memory using \"%.200s\"",
733 key->ob_type->tp_name);
734 return -1;
735 }
736 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
737 return -1;
738 }
739 /* XXX should we allow assignment of different item sizes
740 as long as the byte length is the same?
741 (e.g. assign 2 shorts to a 4-byte slice) */
742 if (srcview.itemsize != view->itemsize) {
743 PyErr_Format(PyExc_TypeError,
744 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
745 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
746 goto _error;
747 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000748 bytelen = len * view->itemsize;
749 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000750 PyErr_SetString(PyExc_ValueError,
751 "cannot modify size of memoryview object");
752 goto _error;
753 }
754 /* Do the actual copy */
755 destbuf = (char *) view->buf + start * view->itemsize;
756 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000757 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
758 /* No overlapping */
759 memcpy(destbuf, srcbuf, bytelen);
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000760 else
761 memmove(destbuf, srcbuf, bytelen);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000762
763 PyBuffer_Release(&srcview);
764 return 0;
765
766_error:
767 PyBuffer_Release(&srcview);
768 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000769}
770
Antoine Pitrou616d2852008-08-19 22:09:34 +0000771static PyObject *
772memory_richcompare(PyObject *v, PyObject *w, int op)
773{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000774 Py_buffer vv, ww;
775 int equal = 0;
776 PyObject *res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000777
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000778 vv.obj = NULL;
779 ww.obj = NULL;
780 if (op != Py_EQ && op != Py_NE)
781 goto _notimpl;
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000782 if ((PyMemoryView_Check(v) && IS_RELEASED(v)) ||
783 (PyMemoryView_Check(w) && IS_RELEASED(w))) {
784 equal = (v == w);
785 goto _end;
786 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000787 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
788 PyErr_Clear();
789 goto _notimpl;
790 }
791 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
792 PyErr_Clear();
793 goto _notimpl;
794 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000795
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000796 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
797 goto _end;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000798
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000799 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000800
801_end:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000802 PyBuffer_Release(&vv);
803 PyBuffer_Release(&ww);
804 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
805 res = Py_True;
806 else
807 res = Py_False;
808 Py_INCREF(res);
809 return res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000810
811_notimpl:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000812 PyBuffer_Release(&vv);
813 PyBuffer_Release(&ww);
814 Py_INCREF(Py_NotImplemented);
815 return Py_NotImplemented;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000816}
817
818
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000819static int
820memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
821{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000822 if (self->base != NULL)
823 Py_VISIT(self->base);
824 if (self->view.obj != NULL)
825 Py_VISIT(self->view.obj);
826 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000827}
828
829static int
830memory_clear(PyMemoryViewObject *self)
831{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000832 Py_CLEAR(self->base);
833 PyBuffer_Release(&self->view);
834 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000835}
836
837
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000838/* As mapping */
839static PyMappingMethods memory_as_mapping = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000840 (lenfunc)memory_length, /* mp_length */
841 (binaryfunc)memory_subscript, /* mp_subscript */
842 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000843};
844
Raymond Hettinger159eac92009-06-23 20:38:54 +0000845static PySequenceMethods memory_as_sequence = {
Alexander Belopolskyf0f45142010-08-11 17:31:17 +0000846 0, /* sq_length */
847 0, /* sq_concat */
848 0, /* sq_repeat */
849 (ssizeargfunc)memory_item, /* sq_item */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000850};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000851
852/* Buffer methods */
853
854static PyBufferProcs memory_as_buffer = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000855 (getbufferproc)memory_getbuf, /* bf_getbuffer */
856 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000857};
858
859
860PyTypeObject PyMemoryView_Type = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000861 PyVarObject_HEAD_INIT(&PyType_Type, 0)
862 "memoryview",
863 sizeof(PyMemoryViewObject),
864 0,
865 (destructor)memory_dealloc, /* tp_dealloc */
866 0, /* tp_print */
867 0, /* tp_getattr */
868 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000869 0, /* tp_reserved */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000870 (reprfunc)memory_repr, /* tp_repr */
871 0, /* tp_as_number */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000872 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000873 &memory_as_mapping, /* tp_as_mapping */
874 0, /* tp_hash */
875 0, /* tp_call */
Benjamin Peterson87618552009-02-08 15:00:52 +0000876 0, /* tp_str */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000877 PyObject_GenericGetAttr, /* tp_getattro */
878 0, /* tp_setattro */
879 &memory_as_buffer, /* tp_as_buffer */
880 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
881 memory_doc, /* tp_doc */
882 (traverseproc)memory_traverse, /* tp_traverse */
883 (inquiry)memory_clear, /* tp_clear */
884 memory_richcompare, /* tp_richcompare */
885 0, /* tp_weaklistoffset */
886 0, /* tp_iter */
887 0, /* tp_iternext */
888 memory_methods, /* tp_methods */
889 0, /* tp_members */
890 memory_getsetlist, /* tp_getset */
891 0, /* tp_base */
892 0, /* tp_dict */
893 0, /* tp_descr_get */
894 0, /* tp_descr_set */
895 0, /* tp_dictoffset */
896 0, /* tp_init */
897 0, /* tp_alloc */
898 memory_new, /* tp_new */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000899};