blob: 2e32b2a0e9f51c560b2f2b7d2d2cf8e758867109 [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
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000405static PyGetSetDef memory_getsetlist[] ={
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000406 {"format", (getter)memory_format_get, NULL, NULL},
407 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
408 {"shape", (getter)memory_shape_get, NULL, NULL},
409 {"strides", (getter)memory_strides_get, NULL, NULL},
410 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
411 {"readonly", (getter)memory_readonly_get, NULL, NULL},
412 {"ndim", (getter)memory_ndim_get, NULL, NULL},
413 {NULL, NULL, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000414};
415
416
417static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000418memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000419{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000420 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000421 return PyObject_CallFunctionObjArgs(
422 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000423}
424
Antoine Pitrou616d2852008-08-19 22:09:34 +0000425/* TODO: rewrite this function using the struct module to unpack
426 each buffer item */
427
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000428static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000429memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000430{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000431 Py_buffer *view = &(mem->view);
432 Py_ssize_t i;
433 PyObject *res, *item;
434 char *buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000435
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000436 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000437 if (strcmp(view->format, "B") || view->itemsize != 1) {
438 PyErr_SetString(PyExc_NotImplementedError,
439 "tolist() only supports byte views");
440 return NULL;
441 }
442 if (view->ndim != 1) {
443 PyErr_SetString(PyExc_NotImplementedError,
444 "tolist() only supports one-dimensional objects");
445 return NULL;
446 }
447 res = PyList_New(view->len);
448 if (res == NULL)
449 return NULL;
450 buf = view->buf;
451 for (i = 0; i < view->len; i++) {
452 item = PyLong_FromUnsignedLong((unsigned char) *buf);
453 if (item == NULL) {
454 Py_DECREF(res);
455 return NULL;
456 }
457 PyList_SET_ITEM(res, i, item);
458 buf++;
459 }
460 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000461}
462
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000463static void
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000464do_release(PyMemoryViewObject *self)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000465{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000466 if (self->view.obj != NULL) {
Antoine Pitrouaeb6cee2010-11-04 20:30:33 +0000467 PyBuffer_Release(&(self->view));
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000468 }
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000469 self->view.obj = NULL;
470 self->view.buf = NULL;
471}
472
473static PyObject *
474memory_enter(PyObject *self, PyObject *args)
475{
476 CHECK_RELEASED(self);
477 Py_INCREF(self);
478 return self;
479}
480
481static PyObject *
482memory_exit(PyObject *self, PyObject *args)
483{
484 do_release((PyMemoryViewObject *) self);
485 Py_RETURN_NONE;
486}
487
488static PyMethodDef memory_methods[] = {
489 {"release", memory_exit, METH_NOARGS},
490 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
491 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
492 {"__enter__", memory_enter, METH_NOARGS},
493 {"__exit__", memory_exit, METH_VARARGS},
494 {NULL, NULL} /* sentinel */
495};
496
497
498static void
499memory_dealloc(PyMemoryViewObject *self)
500{
501 _PyObject_GC_UNTRACK(self);
502 do_release(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000503 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000504}
505
506static PyObject *
507memory_repr(PyMemoryViewObject *self)
508{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000509 if (IS_RELEASED(self))
510 return PyUnicode_FromFormat("<released memory at %p>", self);
511 else
512 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000513}
514
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000515/* Sequence methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000516static Py_ssize_t
517memory_length(PyMemoryViewObject *self)
518{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000519 CHECK_RELEASED_INT(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000520 return get_shape0(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000521}
522
Raymond Hettinger159eac92009-06-23 20:38:54 +0000523/* Alternate version of memory_subcript that only accepts indices.
524 Used by PySeqIter_New().
525*/
526static PyObject *
527memory_item(PyMemoryViewObject *self, Py_ssize_t result)
528{
529 Py_buffer *view = &(self->view);
530
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000531 CHECK_RELEASED(self);
Raymond Hettinger159eac92009-06-23 20:38:54 +0000532 if (view->ndim == 0) {
533 PyErr_SetString(PyExc_IndexError,
534 "invalid indexing of 0-dim memory");
535 return NULL;
536 }
537 if (view->ndim == 1) {
538 /* Return a bytes object */
539 char *ptr;
540 ptr = (char *)view->buf;
541 if (result < 0) {
542 result += get_shape0(view);
543 }
544 if ((result < 0) || (result >= get_shape0(view))) {
545 PyErr_SetString(PyExc_IndexError,
546 "index out of bounds");
547 return NULL;
548 }
549 if (view->strides == NULL)
550 ptr += view->itemsize * result;
551 else
552 ptr += view->strides[0] * result;
553 if (view->suboffsets != NULL &&
554 view->suboffsets[0] >= 0) {
555 ptr = *((char **)ptr) + view->suboffsets[0];
556 }
557 return PyBytes_FromStringAndSize(ptr, view->itemsize);
558 } else {
559 /* Return a new memory-view object */
560 Py_buffer newview;
561 memset(&newview, 0, sizeof(newview));
562 /* XXX: This needs to be fixed so it actually returns a sub-view */
563 return PyMemoryView_FromBuffer(&newview);
564 }
565}
566
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000567/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000568 mem[obj] returns a bytes object holding the data for one element if
569 obj fully indexes the memory view or another memory-view object
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000570 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000571
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000572 0-d memory-view objects can be referenced using ... or () but
573 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000574 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000575static PyObject *
576memory_subscript(PyMemoryViewObject *self, PyObject *key)
577{
Antoine Pitroubc420402008-12-07 20:14:49 +0000578 Py_buffer *view;
579 view = &(self->view);
580
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000581 CHECK_RELEASED(self);
Antoine Pitroubc420402008-12-07 20:14:49 +0000582 if (view->ndim == 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000583 if (key == Py_Ellipsis ||
584 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
585 Py_INCREF(self);
586 return (PyObject *)self;
587 }
588 else {
589 PyErr_SetString(PyExc_IndexError,
590 "invalid indexing of 0-dim memory");
591 return NULL;
592 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000593 }
594 if (PyIndex_Check(key)) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000595 Py_ssize_t result;
596 result = PyNumber_AsSsize_t(key, NULL);
597 if (result == -1 && PyErr_Occurred())
598 return NULL;
Raymond Hettinger159eac92009-06-23 20:38:54 +0000599 return memory_item(self, result);
Antoine Pitroubc420402008-12-07 20:14:49 +0000600 }
601 else if (PySlice_Check(key)) {
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000602 Py_ssize_t start, stop, step, slicelength;
603
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000604 if (PySlice_GetIndicesEx(key, get_shape0(view),
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000605 &start, &stop, &step, &slicelength) < 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000606 return NULL;
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000607 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000608
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000609 if (step == 1 && view->ndim == 1) {
610 Py_buffer newview;
611 void *newbuf = (char *) view->buf
612 + start * view->itemsize;
613 int newflags = view->readonly
614 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
Antoine Pitroubc420402008-12-07 20:14:49 +0000615
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000616 /* XXX There should be an API to create a subbuffer */
617 if (view->obj != NULL) {
618 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
619 return NULL;
620 }
621 else {
622 newview = *view;
623 }
624 newview.buf = newbuf;
625 newview.len = slicelength * newview.itemsize;
626 newview.format = view->format;
627 newview.shape = &(newview.smalltable[0]);
628 newview.shape[0] = slicelength;
629 newview.strides = &(newview.itemsize);
630 return PyMemoryView_FromBuffer(&newview);
631 }
632 PyErr_SetNone(PyExc_NotImplementedError);
633 return NULL;
Antoine Pitroubc420402008-12-07 20:14:49 +0000634 }
635 PyErr_Format(PyExc_TypeError,
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000636 "cannot index memory using \"%.200s\"",
637 key->ob_type->tp_name);
Antoine Pitroubc420402008-12-07 20:14:49 +0000638 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000639}
640
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000641
642/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000643static int
644memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
645{
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000646 Py_ssize_t start, len, bytelen;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000647 Py_buffer srcview;
648 Py_buffer *view = &(self->view);
649 char *srcbuf, *destbuf;
650
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000651 CHECK_RELEASED_INT(self);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000652 if (view->readonly) {
653 PyErr_SetString(PyExc_TypeError,
654 "cannot modify read-only memory");
655 return -1;
656 }
Antoine Pitroue0793ba2010-09-01 21:14:16 +0000657 if (value == NULL) {
658 PyErr_SetString(PyExc_TypeError,
659 "cannot delete memory");
660 return -1;
661 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000662 if (view->ndim != 1) {
663 PyErr_SetNone(PyExc_NotImplementedError);
664 return -1;
665 }
666 if (PyIndex_Check(key)) {
667 start = PyNumber_AsSsize_t(key, NULL);
668 if (start == -1 && PyErr_Occurred())
669 return -1;
670 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000671 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000672 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000673 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000674 PyErr_SetString(PyExc_IndexError,
675 "index out of bounds");
676 return -1;
677 }
678 len = 1;
679 }
680 else if (PySlice_Check(key)) {
681 Py_ssize_t stop, step;
682
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000683 if (PySlice_GetIndicesEx(key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000684 &start, &stop, &step, &len) < 0) {
685 return -1;
686 }
687 if (step != 1) {
688 PyErr_SetNone(PyExc_NotImplementedError);
689 return -1;
690 }
691 }
692 else {
693 PyErr_Format(PyExc_TypeError,
694 "cannot index memory using \"%.200s\"",
695 key->ob_type->tp_name);
696 return -1;
697 }
698 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
699 return -1;
700 }
701 /* XXX should we allow assignment of different item sizes
702 as long as the byte length is the same?
703 (e.g. assign 2 shorts to a 4-byte slice) */
704 if (srcview.itemsize != view->itemsize) {
705 PyErr_Format(PyExc_TypeError,
706 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
707 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
708 goto _error;
709 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000710 bytelen = len * view->itemsize;
711 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000712 PyErr_SetString(PyExc_ValueError,
713 "cannot modify size of memoryview object");
714 goto _error;
715 }
716 /* Do the actual copy */
717 destbuf = (char *) view->buf + start * view->itemsize;
718 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000719 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
720 /* No overlapping */
721 memcpy(destbuf, srcbuf, bytelen);
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000722 else
723 memmove(destbuf, srcbuf, bytelen);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000724
725 PyBuffer_Release(&srcview);
726 return 0;
727
728_error:
729 PyBuffer_Release(&srcview);
730 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000731}
732
Antoine Pitrou616d2852008-08-19 22:09:34 +0000733static PyObject *
734memory_richcompare(PyObject *v, PyObject *w, int op)
735{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000736 Py_buffer vv, ww;
737 int equal = 0;
738 PyObject *res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000739
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000740 vv.obj = NULL;
741 ww.obj = NULL;
742 if (op != Py_EQ && op != Py_NE)
743 goto _notimpl;
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000744 if ((PyMemoryView_Check(v) && IS_RELEASED(v)) ||
745 (PyMemoryView_Check(w) && IS_RELEASED(w))) {
746 equal = (v == w);
747 goto _end;
748 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000749 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
750 PyErr_Clear();
751 goto _notimpl;
752 }
753 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
754 PyErr_Clear();
755 goto _notimpl;
756 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000757
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000758 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
759 goto _end;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000760
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000761 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000762
763_end:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000764 PyBuffer_Release(&vv);
765 PyBuffer_Release(&ww);
766 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
767 res = Py_True;
768 else
769 res = Py_False;
770 Py_INCREF(res);
771 return res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000772
773_notimpl:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000774 PyBuffer_Release(&vv);
775 PyBuffer_Release(&ww);
776 Py_INCREF(Py_NotImplemented);
777 return Py_NotImplemented;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000778}
779
780
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000781static int
782memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
783{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000784 if (self->view.obj != NULL)
785 Py_VISIT(self->view.obj);
786 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000787}
788
789static int
790memory_clear(PyMemoryViewObject *self)
791{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000792 PyBuffer_Release(&self->view);
793 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000794}
795
796
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000797/* As mapping */
798static PyMappingMethods memory_as_mapping = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000799 (lenfunc)memory_length, /* mp_length */
800 (binaryfunc)memory_subscript, /* mp_subscript */
801 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000802};
803
Raymond Hettinger159eac92009-06-23 20:38:54 +0000804static PySequenceMethods memory_as_sequence = {
Alexander Belopolskyf0f45142010-08-11 17:31:17 +0000805 0, /* sq_length */
806 0, /* sq_concat */
807 0, /* sq_repeat */
808 (ssizeargfunc)memory_item, /* sq_item */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000809};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000810
811/* Buffer methods */
812
813static PyBufferProcs memory_as_buffer = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000814 (getbufferproc)memory_getbuf, /* bf_getbuffer */
815 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000816};
817
818
819PyTypeObject PyMemoryView_Type = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000820 PyVarObject_HEAD_INIT(&PyType_Type, 0)
821 "memoryview",
822 sizeof(PyMemoryViewObject),
823 0,
824 (destructor)memory_dealloc, /* tp_dealloc */
825 0, /* tp_print */
826 0, /* tp_getattr */
827 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000828 0, /* tp_reserved */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000829 (reprfunc)memory_repr, /* tp_repr */
830 0, /* tp_as_number */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000831 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000832 &memory_as_mapping, /* tp_as_mapping */
833 0, /* tp_hash */
834 0, /* tp_call */
Benjamin Peterson87618552009-02-08 15:00:52 +0000835 0, /* tp_str */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000836 PyObject_GenericGetAttr, /* tp_getattro */
837 0, /* tp_setattro */
838 &memory_as_buffer, /* tp_as_buffer */
839 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
840 memory_doc, /* tp_doc */
841 (traverseproc)memory_traverse, /* tp_traverse */
842 (inquiry)memory_clear, /* tp_clear */
843 memory_richcompare, /* tp_richcompare */
844 0, /* tp_weaklistoffset */
845 0, /* tp_iter */
846 0, /* tp_iternext */
847 memory_methods, /* tp_methods */
848 0, /* tp_members */
849 memory_getsetlist, /* tp_getset */
850 0, /* tp_base */
851 0, /* tp_dict */
852 0, /* tp_descr_get */
853 0, /* tp_descr_set */
854 0, /* tp_dictoffset */
855 0, /* tp_init */
856 0, /* tp_alloc */
857 memory_new, /* tp_new */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000858};