blob: 403aa68a9e9d130de27c0a7291ee0576e036bb56 [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 if (self->view.obj != NULL)
56 res = PyObject_GetBuffer(self->view.obj, view, flags);
57 if (view)
58 dup_buffer(view, &self->view);
59 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000060}
61
62static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000063memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000064{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000065 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000066}
67
68PyDoc_STRVAR(memory_doc,
69"memoryview(object)\n\
70\n\
71Create a new memoryview object which references the given object.");
72
73PyObject *
Antoine Pitrouee58fa42008-08-19 18:22:14 +000074PyMemoryView_FromBuffer(Py_buffer *info)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000075{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000076 PyMemoryViewObject *mview;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000077
Antoine Pitrou915605c2011-02-24 20:53:48 +000078 if (info->buf == NULL) {
79 PyErr_SetString(PyExc_ValueError,
80 "cannot make memory view from a buffer with a NULL data pointer");
81 return NULL;
82 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +000083 mview = (PyMemoryViewObject *)
84 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
85 if (mview == NULL)
86 return NULL;
Antoine Pitrou35b7e832009-01-03 19:20:36 +000087 dup_buffer(&mview->view, info);
88 /* NOTE: mview->view.obj should already have been incref'ed as
89 part of PyBuffer_FillInfo(). */
90 _PyObject_GC_TRACK(mview);
91 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000092}
93
94PyObject *
95PyMemoryView_FromObject(PyObject *base)
96{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000097 PyMemoryViewObject *mview;
Antoine Pitrou05b7c562010-02-02 22:47:00 +000098 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000099
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000100 if (!PyObject_CheckBuffer(base)) {
101 PyErr_SetString(PyExc_TypeError,
102 "cannot make memory view because object does "
103 "not have the buffer interface");
104 return NULL;
105 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000106
Antoine Pitrou05b7c562010-02-02 22:47:00 +0000107 if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000108 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000109
Antoine Pitrou05b7c562010-02-02 22:47:00 +0000110 mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);
111 if (mview == NULL) {
112 PyBuffer_Release(&view);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000113 return NULL;
114 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000115
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000116 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000117}
118
119static PyObject *
120memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
121{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000122 PyObject *obj;
123 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000124
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000125 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
126 &obj)) {
127 return NULL;
128 }
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000129
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000130 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000131}
132
133
134static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000135_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +0000136 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000137{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000138 int k;
139 Py_ssize_t outstride;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000140
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000141 if (nd==0) {
142 memcpy(dest, src, itemsize);
143 }
144 else if (nd == 1) {
145 for (k = 0; k<shape[0]; k++) {
146 memcpy(dest, src, itemsize);
147 dest += itemsize;
148 src += strides[0];
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000149 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000150 }
151 else {
152 if (fort == 'F') {
153 /* Copy first dimension first,
154 second dimension second, etc...
155 Set up the recursive loop backwards so that final
156 dimension is actually copied last.
157 */
158 outstride = itemsize;
159 for (k=1; k<nd-1;k++) {
160 outstride *= shape[k];
161 }
162 for (k=0; k<shape[nd-1]; k++) {
163 _strided_copy_nd(dest, src, nd-1, shape,
164 strides, itemsize, fort);
165 dest += outstride;
166 src += strides[nd-1];
167 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000168 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000169
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000170 else {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000171 /* Copy last dimension first,
172 second-to-last dimension second, etc.
173 Set up the recursion so that the
174 first dimension is copied last
175 */
176 outstride = itemsize;
177 for (k=1; k < nd; k++) {
178 outstride *= shape[k];
179 }
180 for (k=0; k<shape[0]; k++) {
181 _strided_copy_nd(dest, src, nd-1, shape+1,
182 strides+1, itemsize,
183 fort);
184 dest += outstride;
185 src += strides[0];
186 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000187 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000188 }
189 return;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000190}
191
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000192static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000193_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000194{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000195 Py_ssize_t *indices;
196 int k;
197 Py_ssize_t elements;
198 char *ptr;
Antoine Pitrouc73b9092010-09-01 21:14:46 +0000199 void (*func)(int, Py_ssize_t *, const Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000200
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000201 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
202 PyErr_NoMemory();
203 return -1;
204 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000205
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000206 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
207 if (indices == NULL) {
208 PyErr_NoMemory();
209 return -1;
210 }
211 for (k=0; k<view->ndim;k++) {
212 indices[k] = 0;
213 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000214
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000215 elements = 1;
216 for (k=0; k<view->ndim; k++) {
217 elements *= view->shape[k];
218 }
219 if (fort == 'F') {
Antoine Pitrouf68c2a72010-09-01 12:58:21 +0000220 func = _Py_add_one_to_index_F;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000221 }
222 else {
Antoine Pitrouf68c2a72010-09-01 12:58:21 +0000223 func = _Py_add_one_to_index_C;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000224 }
225 while (elements--) {
226 func(view->ndim, indices, view->shape);
227 ptr = PyBuffer_GetPointer(view, indices);
228 memcpy(dest, ptr, view->itemsize);
229 dest += view->itemsize;
230 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000231
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000232 PyMem_Free(indices);
233 return 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000234}
235
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000236/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000237 Get a the data from an object as a contiguous chunk of memory (in
238 either 'C' or 'F'ortran order) even if it means copying it into a
239 separate memory area.
240
241 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000242 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000243 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000244 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000245
246 buffertype
247
248 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000249 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000250 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000251 a contiguous buffer if it is not. The view will point to
252 the shadow buffer which can be written to and then
253 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000254 view is de-allocated. While the shadow buffer is
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000255 being used, it will have an exclusive write lock on
256 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000257 */
258
259PyObject *
260PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
261{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000262 PyMemoryViewObject *mem;
263 PyObject *bytes;
264 Py_buffer *view;
265 int flags;
266 char *dest;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000267
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000268 if (!PyObject_CheckBuffer(obj)) {
269 PyErr_SetString(PyExc_TypeError,
Georg Brandl61b96dc2009-08-04 20:29:27 +0000270 "object does not support the buffer interface");
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000271 return NULL;
272 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000273
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000274 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
275 if (mem == NULL)
276 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000277
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000278 view = &mem->view;
279 flags = PyBUF_FULL_RO;
280 switch(buffertype) {
281 case PyBUF_WRITE:
282 flags = PyBUF_FULL;
283 break;
284 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000285
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000286 if (PyObject_GetBuffer(obj, view, flags) != 0) {
287 Py_DECREF(mem);
288 return NULL;
289 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000290
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000291 if (PyBuffer_IsContiguous(view, fort)) {
292 /* no copy needed */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000293 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000294 return (PyObject *)mem;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000295 }
296 /* otherwise a copy is needed */
297 if (buffertype == PyBUF_WRITE) {
298 Py_DECREF(mem);
299 PyErr_SetString(PyExc_BufferError,
300 "writable contiguous buffer requested "
301 "for a non-contiguousobject.");
302 return NULL;
303 }
304 bytes = PyBytes_FromStringAndSize(NULL, view->len);
305 if (bytes == NULL) {
306 Py_DECREF(mem);
307 return NULL;
308 }
309 dest = PyBytes_AS_STRING(bytes);
310 /* different copying strategy depending on whether
311 or not any pointer de-referencing is needed
312 */
313 /* strided or in-direct copy */
314 if (view->suboffsets==NULL) {
315 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
316 view->strides, view->itemsize, fort);
317 }
318 else {
319 if (_indirect_copy_nd(dest, view, fort) < 0) {
320 Py_DECREF(bytes);
321 Py_DECREF(mem);
322 return NULL;
323 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000324 PyBuffer_Release(view); /* XXX ? */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000325 }
326 _PyObject_GC_TRACK(mem);
327 return (PyObject *)mem;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000328}
329
330
331static PyObject *
332memory_format_get(PyMemoryViewObject *self)
333{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000334 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000335 return PyUnicode_FromString(self->view.format);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000336}
337
338static PyObject *
339memory_itemsize_get(PyMemoryViewObject *self)
340{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000341 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000342 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000343}
344
345static PyObject *
346_IntTupleFromSsizet(int len, Py_ssize_t *vals)
347{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000348 int i;
349 PyObject *o;
350 PyObject *intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000351
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000352 if (vals == NULL) {
353 Py_INCREF(Py_None);
354 return Py_None;
355 }
356 intTuple = PyTuple_New(len);
Benjamin Peterson83473282010-11-03 23:11:10 +0000357 if (!intTuple)
358 return NULL;
359 for (i=0; i<len; i++) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000360 o = PyLong_FromSsize_t(vals[i]);
361 if (!o) {
362 Py_DECREF(intTuple);
363 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000364 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000365 PyTuple_SET_ITEM(intTuple, i, o);
366 }
367 return intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000368}
369
370static PyObject *
371memory_shape_get(PyMemoryViewObject *self)
372{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000373 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000374 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000375}
376
377static PyObject *
378memory_strides_get(PyMemoryViewObject *self)
379{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000380 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000381 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000382}
383
384static PyObject *
385memory_suboffsets_get(PyMemoryViewObject *self)
386{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000387 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000388 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000389}
390
391static PyObject *
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000392memory_readonly_get(PyMemoryViewObject *self)
393{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000394 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000395 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000396}
397
398static PyObject *
399memory_ndim_get(PyMemoryViewObject *self)
400{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000401 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000402 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000403}
404
Alexander Belopolsky397e5c92012-09-03 16:29:11 -0400405PyDoc_STRVAR(memory_format_doc,
406 "A string containing the format (in struct module style)\n"
407 " for each element in the view.");
408PyDoc_STRVAR(memory_itemsize_doc,
409 "The size in bytes of each element of the memoryview.");
410PyDoc_STRVAR(memory_shape_doc,
411 "A tuple of ndim integers giving the shape of the memory\n"
412 " as an N-dimensional array.");
413PyDoc_STRVAR(memory_strides_doc,
414 "A tuple of ndim integers giving the size in bytes to access\n"
415 " each element for each dimension of the array.");
416PyDoc_STRVAR(memory_suboffsets_doc,
417 "A tuple of integers used internally for PIL-style arrays.");
418PyDoc_STRVAR(memory_readonly_doc,
419 "A bool indicating whether the memory is read only.");
420PyDoc_STRVAR(memory_ndim_doc,
421 "An integer indicating how many dimensions of a multi-dimensional\n"
422 " array the memory represents.");
423
424static PyGetSetDef memory_getsetlist[] = {
425 {"format", (getter)memory_format_get, NULL, memory_format_doc},
426 {"itemsize", (getter)memory_itemsize_get, NULL, memory_itemsize_doc},
427 {"shape", (getter)memory_shape_get, NULL, memory_shape_doc},
428 {"strides", (getter)memory_strides_get, NULL, memory_strides_doc},
429 {"suboffsets", (getter)memory_suboffsets_get, NULL, memory_suboffsets_doc},
430 {"readonly", (getter)memory_readonly_get, NULL, memory_readonly_doc},
431 {"ndim", (getter)memory_ndim_get, NULL, memory_ndim_doc},
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000432 {NULL, NULL, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000433};
434
435
436static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000437memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000438{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000439 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000440 return PyObject_CallFunctionObjArgs(
441 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000442}
443
Antoine Pitrou616d2852008-08-19 22:09:34 +0000444/* TODO: rewrite this function using the struct module to unpack
445 each buffer item */
446
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000447static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000448memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000449{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000450 Py_buffer *view = &(mem->view);
451 Py_ssize_t i;
452 PyObject *res, *item;
453 char *buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000454
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000455 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000456 if (strcmp(view->format, "B") || view->itemsize != 1) {
457 PyErr_SetString(PyExc_NotImplementedError,
458 "tolist() only supports byte views");
459 return NULL;
460 }
461 if (view->ndim != 1) {
462 PyErr_SetString(PyExc_NotImplementedError,
463 "tolist() only supports one-dimensional objects");
464 return NULL;
465 }
466 res = PyList_New(view->len);
467 if (res == NULL)
468 return NULL;
469 buf = view->buf;
470 for (i = 0; i < view->len; i++) {
471 item = PyLong_FromUnsignedLong((unsigned char) *buf);
472 if (item == NULL) {
473 Py_DECREF(res);
474 return NULL;
475 }
476 PyList_SET_ITEM(res, i, item);
477 buf++;
478 }
479 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000480}
481
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000482static void
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000483do_release(PyMemoryViewObject *self)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000484{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000485 if (self->view.obj != NULL) {
Antoine Pitrouaeb6cee2010-11-04 20:30:33 +0000486 PyBuffer_Release(&(self->view));
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000487 }
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000488 self->view.obj = NULL;
489 self->view.buf = NULL;
490}
491
492static PyObject *
493memory_enter(PyObject *self, PyObject *args)
494{
495 CHECK_RELEASED(self);
496 Py_INCREF(self);
497 return self;
498}
499
500static PyObject *
501memory_exit(PyObject *self, PyObject *args)
502{
503 do_release((PyMemoryViewObject *) self);
504 Py_RETURN_NONE;
505}
506
Alexander Belopolsky397e5c92012-09-03 16:29:11 -0400507PyDoc_STRVAR(memory_release_doc,
508"M.release() -> None\n\
509\n\
510Release the underlying buffer exposed by the memoryview object.");
511PyDoc_STRVAR(memory_tobytes_doc,
512"M.tobytes() -> bytes\n\
513\n\
514Return the data in the buffer as a byte string.");
515PyDoc_STRVAR(memory_tolist_doc,
516"M.tolist() -> list\n\
517\n\
518Return the data in the buffer as a list of elements.");
519
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000520static PyMethodDef memory_methods[] = {
Alexander Belopolsky397e5c92012-09-03 16:29:11 -0400521 {"release", memory_exit, METH_NOARGS, memory_release_doc},
522 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, memory_tobytes_doc},
523 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, memory_tolist_doc},
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000524 {"__enter__", memory_enter, METH_NOARGS},
525 {"__exit__", memory_exit, METH_VARARGS},
526 {NULL, NULL} /* sentinel */
527};
528
529
530static void
531memory_dealloc(PyMemoryViewObject *self)
532{
533 _PyObject_GC_UNTRACK(self);
534 do_release(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000535 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000536}
537
538static PyObject *
539memory_repr(PyMemoryViewObject *self)
540{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000541 if (IS_RELEASED(self))
542 return PyUnicode_FromFormat("<released memory at %p>", self);
543 else
544 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000545}
546
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000547/* Sequence methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000548static Py_ssize_t
549memory_length(PyMemoryViewObject *self)
550{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000551 CHECK_RELEASED_INT(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000552 return get_shape0(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000553}
554
Raymond Hettinger159eac92009-06-23 20:38:54 +0000555/* Alternate version of memory_subcript that only accepts indices.
556 Used by PySeqIter_New().
557*/
558static PyObject *
559memory_item(PyMemoryViewObject *self, Py_ssize_t result)
560{
561 Py_buffer *view = &(self->view);
562
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000563 CHECK_RELEASED(self);
Raymond Hettinger159eac92009-06-23 20:38:54 +0000564 if (view->ndim == 0) {
565 PyErr_SetString(PyExc_IndexError,
566 "invalid indexing of 0-dim memory");
567 return NULL;
568 }
569 if (view->ndim == 1) {
570 /* Return a bytes object */
571 char *ptr;
572 ptr = (char *)view->buf;
573 if (result < 0) {
574 result += get_shape0(view);
575 }
576 if ((result < 0) || (result >= get_shape0(view))) {
577 PyErr_SetString(PyExc_IndexError,
578 "index out of bounds");
579 return NULL;
580 }
581 if (view->strides == NULL)
582 ptr += view->itemsize * result;
583 else
584 ptr += view->strides[0] * result;
585 if (view->suboffsets != NULL &&
586 view->suboffsets[0] >= 0) {
587 ptr = *((char **)ptr) + view->suboffsets[0];
588 }
589 return PyBytes_FromStringAndSize(ptr, view->itemsize);
590 } else {
591 /* Return a new memory-view object */
592 Py_buffer newview;
593 memset(&newview, 0, sizeof(newview));
594 /* XXX: This needs to be fixed so it actually returns a sub-view */
595 return PyMemoryView_FromBuffer(&newview);
596 }
597}
598
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000599/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000600 mem[obj] returns a bytes object holding the data for one element if
601 obj fully indexes the memory view or another memory-view object
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000602 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000603
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000604 0-d memory-view objects can be referenced using ... or () but
605 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000606 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000607static PyObject *
608memory_subscript(PyMemoryViewObject *self, PyObject *key)
609{
Antoine Pitroubc420402008-12-07 20:14:49 +0000610 Py_buffer *view;
611 view = &(self->view);
612
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000613 CHECK_RELEASED(self);
Antoine Pitroubc420402008-12-07 20:14:49 +0000614 if (view->ndim == 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000615 if (key == Py_Ellipsis ||
616 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
617 Py_INCREF(self);
618 return (PyObject *)self;
619 }
620 else {
621 PyErr_SetString(PyExc_IndexError,
622 "invalid indexing of 0-dim memory");
623 return NULL;
624 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000625 }
626 if (PyIndex_Check(key)) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000627 Py_ssize_t result;
628 result = PyNumber_AsSsize_t(key, NULL);
629 if (result == -1 && PyErr_Occurred())
630 return NULL;
Raymond Hettinger159eac92009-06-23 20:38:54 +0000631 return memory_item(self, result);
Antoine Pitroubc420402008-12-07 20:14:49 +0000632 }
633 else if (PySlice_Check(key)) {
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000634 Py_ssize_t start, stop, step, slicelength;
635
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000636 if (PySlice_GetIndicesEx(key, get_shape0(view),
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000637 &start, &stop, &step, &slicelength) < 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000638 return NULL;
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000639 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000640
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000641 if (step == 1 && view->ndim == 1) {
642 Py_buffer newview;
643 void *newbuf = (char *) view->buf
644 + start * view->itemsize;
645 int newflags = view->readonly
646 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
Antoine Pitroubc420402008-12-07 20:14:49 +0000647
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000648 /* XXX There should be an API to create a subbuffer */
649 if (view->obj != NULL) {
650 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
651 return NULL;
652 }
653 else {
654 newview = *view;
655 }
656 newview.buf = newbuf;
657 newview.len = slicelength * newview.itemsize;
658 newview.format = view->format;
659 newview.shape = &(newview.smalltable[0]);
660 newview.shape[0] = slicelength;
661 newview.strides = &(newview.itemsize);
662 return PyMemoryView_FromBuffer(&newview);
663 }
664 PyErr_SetNone(PyExc_NotImplementedError);
665 return NULL;
Antoine Pitroubc420402008-12-07 20:14:49 +0000666 }
667 PyErr_Format(PyExc_TypeError,
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000668 "cannot index memory using \"%.200s\"",
669 key->ob_type->tp_name);
Antoine Pitroubc420402008-12-07 20:14:49 +0000670 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000671}
672
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000673
674/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000675static int
676memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
677{
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000678 Py_ssize_t start, len, bytelen;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000679 Py_buffer srcview;
680 Py_buffer *view = &(self->view);
681 char *srcbuf, *destbuf;
682
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000683 CHECK_RELEASED_INT(self);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000684 if (view->readonly) {
685 PyErr_SetString(PyExc_TypeError,
686 "cannot modify read-only memory");
687 return -1;
688 }
Antoine Pitroue0793ba2010-09-01 21:14:16 +0000689 if (value == NULL) {
690 PyErr_SetString(PyExc_TypeError,
691 "cannot delete memory");
692 return -1;
693 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000694 if (view->ndim != 1) {
695 PyErr_SetNone(PyExc_NotImplementedError);
696 return -1;
697 }
698 if (PyIndex_Check(key)) {
699 start = PyNumber_AsSsize_t(key, NULL);
700 if (start == -1 && PyErr_Occurred())
701 return -1;
702 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000703 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000704 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000705 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000706 PyErr_SetString(PyExc_IndexError,
707 "index out of bounds");
708 return -1;
709 }
710 len = 1;
711 }
712 else if (PySlice_Check(key)) {
713 Py_ssize_t stop, step;
714
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000715 if (PySlice_GetIndicesEx(key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000716 &start, &stop, &step, &len) < 0) {
717 return -1;
718 }
719 if (step != 1) {
720 PyErr_SetNone(PyExc_NotImplementedError);
721 return -1;
722 }
723 }
724 else {
725 PyErr_Format(PyExc_TypeError,
726 "cannot index memory using \"%.200s\"",
727 key->ob_type->tp_name);
728 return -1;
729 }
730 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
731 return -1;
732 }
733 /* XXX should we allow assignment of different item sizes
734 as long as the byte length is the same?
735 (e.g. assign 2 shorts to a 4-byte slice) */
736 if (srcview.itemsize != view->itemsize) {
737 PyErr_Format(PyExc_TypeError,
738 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
739 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
740 goto _error;
741 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000742 bytelen = len * view->itemsize;
743 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000744 PyErr_SetString(PyExc_ValueError,
745 "cannot modify size of memoryview object");
746 goto _error;
747 }
748 /* Do the actual copy */
749 destbuf = (char *) view->buf + start * view->itemsize;
750 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000751 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
752 /* No overlapping */
753 memcpy(destbuf, srcbuf, bytelen);
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000754 else
755 memmove(destbuf, srcbuf, bytelen);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000756
757 PyBuffer_Release(&srcview);
758 return 0;
759
760_error:
761 PyBuffer_Release(&srcview);
762 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000763}
764
Antoine Pitrou616d2852008-08-19 22:09:34 +0000765static PyObject *
766memory_richcompare(PyObject *v, PyObject *w, int op)
767{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000768 Py_buffer vv, ww;
769 int equal = 0;
770 PyObject *res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000771
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000772 vv.obj = NULL;
773 ww.obj = NULL;
774 if (op != Py_EQ && op != Py_NE)
775 goto _notimpl;
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000776 if ((PyMemoryView_Check(v) && IS_RELEASED(v)) ||
777 (PyMemoryView_Check(w) && IS_RELEASED(w))) {
778 equal = (v == w);
779 goto _end;
780 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000781 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
782 PyErr_Clear();
783 goto _notimpl;
784 }
785 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
786 PyErr_Clear();
787 goto _notimpl;
788 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000789
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000790 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
791 goto _end;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000792
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000793 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000794
795_end:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000796 PyBuffer_Release(&vv);
797 PyBuffer_Release(&ww);
798 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
799 res = Py_True;
800 else
801 res = Py_False;
802 Py_INCREF(res);
803 return res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000804
805_notimpl:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000806 PyBuffer_Release(&vv);
807 PyBuffer_Release(&ww);
808 Py_INCREF(Py_NotImplemented);
809 return Py_NotImplemented;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000810}
811
812
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000813static int
814memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
815{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000816 if (self->view.obj != NULL)
817 Py_VISIT(self->view.obj);
818 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000819}
820
821static int
822memory_clear(PyMemoryViewObject *self)
823{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000824 PyBuffer_Release(&self->view);
825 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000826}
827
828
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000829/* As mapping */
830static PyMappingMethods memory_as_mapping = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000831 (lenfunc)memory_length, /* mp_length */
832 (binaryfunc)memory_subscript, /* mp_subscript */
833 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000834};
835
Raymond Hettinger159eac92009-06-23 20:38:54 +0000836static PySequenceMethods memory_as_sequence = {
Alexander Belopolskyf0f45142010-08-11 17:31:17 +0000837 0, /* sq_length */
838 0, /* sq_concat */
839 0, /* sq_repeat */
840 (ssizeargfunc)memory_item, /* sq_item */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000841};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000842
843/* Buffer methods */
844
845static PyBufferProcs memory_as_buffer = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000846 (getbufferproc)memory_getbuf, /* bf_getbuffer */
847 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000848};
849
850
851PyTypeObject PyMemoryView_Type = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000852 PyVarObject_HEAD_INIT(&PyType_Type, 0)
853 "memoryview",
854 sizeof(PyMemoryViewObject),
855 0,
856 (destructor)memory_dealloc, /* tp_dealloc */
857 0, /* tp_print */
858 0, /* tp_getattr */
859 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000860 0, /* tp_reserved */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000861 (reprfunc)memory_repr, /* tp_repr */
862 0, /* tp_as_number */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000863 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000864 &memory_as_mapping, /* tp_as_mapping */
865 0, /* tp_hash */
866 0, /* tp_call */
Benjamin Peterson87618552009-02-08 15:00:52 +0000867 0, /* tp_str */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000868 PyObject_GenericGetAttr, /* tp_getattro */
869 0, /* tp_setattro */
870 &memory_as_buffer, /* tp_as_buffer */
871 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
872 memory_doc, /* tp_doc */
873 (traverseproc)memory_traverse, /* tp_traverse */
874 (inquiry)memory_clear, /* tp_clear */
875 memory_richcompare, /* tp_richcompare */
876 0, /* tp_weaklistoffset */
877 0, /* tp_iter */
878 0, /* tp_iternext */
879 memory_methods, /* tp_methods */
880 0, /* tp_members */
881 memory_getsetlist, /* tp_getset */
882 0, /* tp_base */
883 0, /* tp_dict */
884 0, /* tp_descr_get */
885 0, /* tp_descr_set */
886 0, /* tp_dictoffset */
887 0, /* tp_init */
888 0, /* tp_alloc */
889 memory_new, /* tp_new */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000890};