blob: 7782076a5b50a15dd5cd7602aa386d925525cba2 [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 Pitrou35b7e832009-01-03 19:20:36 +000078 mview = (PyMemoryViewObject *)
79 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
80 if (mview == NULL)
81 return NULL;
Antoine Pitrou35b7e832009-01-03 19:20:36 +000082 dup_buffer(&mview->view, info);
83 /* NOTE: mview->view.obj should already have been incref'ed as
84 part of PyBuffer_FillInfo(). */
85 _PyObject_GC_TRACK(mview);
86 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000087}
88
89PyObject *
90PyMemoryView_FromObject(PyObject *base)
91{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000092 PyMemoryViewObject *mview;
Antoine Pitrou05b7c562010-02-02 22:47:00 +000093 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000094
Antoine Pitrou35b7e832009-01-03 19:20:36 +000095 if (!PyObject_CheckBuffer(base)) {
96 PyErr_SetString(PyExc_TypeError,
97 "cannot make memory view because object does "
98 "not have the buffer interface");
99 return NULL;
100 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000101
Antoine Pitrou05b7c562010-02-02 22:47:00 +0000102 if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000103 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000104
Antoine Pitrou05b7c562010-02-02 22:47:00 +0000105 mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);
106 if (mview == NULL) {
107 PyBuffer_Release(&view);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000108 return NULL;
109 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000110
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000111 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000112}
113
114static PyObject *
115memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
116{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000117 PyObject *obj;
118 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000119
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000120 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
121 &obj)) {
122 return NULL;
123 }
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000124
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000125 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000126}
127
128
129static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000130_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +0000131 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000132{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000133 int k;
134 Py_ssize_t outstride;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000135
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000136 if (nd==0) {
137 memcpy(dest, src, itemsize);
138 }
139 else if (nd == 1) {
140 for (k = 0; k<shape[0]; k++) {
141 memcpy(dest, src, itemsize);
142 dest += itemsize;
143 src += strides[0];
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000144 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000145 }
146 else {
147 if (fort == 'F') {
148 /* Copy first dimension first,
149 second dimension second, etc...
150 Set up the recursive loop backwards so that final
151 dimension is actually copied last.
152 */
153 outstride = itemsize;
154 for (k=1; k<nd-1;k++) {
155 outstride *= shape[k];
156 }
157 for (k=0; k<shape[nd-1]; k++) {
158 _strided_copy_nd(dest, src, nd-1, shape,
159 strides, itemsize, fort);
160 dest += outstride;
161 src += strides[nd-1];
162 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000163 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000164
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000165 else {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000166 /* Copy last dimension first,
167 second-to-last dimension second, etc.
168 Set up the recursion so that the
169 first dimension is copied last
170 */
171 outstride = itemsize;
172 for (k=1; k < nd; k++) {
173 outstride *= shape[k];
174 }
175 for (k=0; k<shape[0]; k++) {
176 _strided_copy_nd(dest, src, nd-1, shape+1,
177 strides+1, itemsize,
178 fort);
179 dest += outstride;
180 src += strides[0];
181 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000182 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000183 }
184 return;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000185}
186
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000187static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000188_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000189{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000190 Py_ssize_t *indices;
191 int k;
192 Py_ssize_t elements;
193 char *ptr;
Antoine Pitrouc73b9092010-09-01 21:14:46 +0000194 void (*func)(int, Py_ssize_t *, const Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000195
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000196 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
197 PyErr_NoMemory();
198 return -1;
199 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000200
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000201 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
202 if (indices == NULL) {
203 PyErr_NoMemory();
204 return -1;
205 }
206 for (k=0; k<view->ndim;k++) {
207 indices[k] = 0;
208 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000209
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000210 elements = 1;
211 for (k=0; k<view->ndim; k++) {
212 elements *= view->shape[k];
213 }
214 if (fort == 'F') {
Antoine Pitrouf68c2a72010-09-01 12:58:21 +0000215 func = _Py_add_one_to_index_F;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000216 }
217 else {
Antoine Pitrouf68c2a72010-09-01 12:58:21 +0000218 func = _Py_add_one_to_index_C;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000219 }
220 while (elements--) {
221 func(view->ndim, indices, view->shape);
222 ptr = PyBuffer_GetPointer(view, indices);
223 memcpy(dest, ptr, view->itemsize);
224 dest += view->itemsize;
225 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000226
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000227 PyMem_Free(indices);
228 return 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000229}
230
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000231/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000232 Get a the data from an object as a contiguous chunk of memory (in
233 either 'C' or 'F'ortran order) even if it means copying it into a
234 separate memory area.
235
236 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000237 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000238 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000239 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000240
241 buffertype
242
243 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000244 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000245 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000246 a contiguous buffer if it is not. The view will point to
247 the shadow buffer which can be written to and then
248 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000249 view is de-allocated. While the shadow buffer is
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000250 being used, it will have an exclusive write lock on
251 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000252 */
253
254PyObject *
255PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
256{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000257 PyMemoryViewObject *mem;
258 PyObject *bytes;
259 Py_buffer *view;
260 int flags;
261 char *dest;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000262
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000263 if (!PyObject_CheckBuffer(obj)) {
264 PyErr_SetString(PyExc_TypeError,
Georg Brandl61b96dc2009-08-04 20:29:27 +0000265 "object does not support the buffer interface");
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000266 return NULL;
267 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000268
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000269 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
270 if (mem == NULL)
271 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000272
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000273 view = &mem->view;
274 flags = PyBUF_FULL_RO;
275 switch(buffertype) {
276 case PyBUF_WRITE:
277 flags = PyBUF_FULL;
278 break;
279 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000280
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000281 if (PyObject_GetBuffer(obj, view, flags) != 0) {
282 Py_DECREF(mem);
283 return NULL;
284 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000285
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000286 if (PyBuffer_IsContiguous(view, fort)) {
287 /* no copy needed */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000288 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000289 return (PyObject *)mem;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000290 }
291 /* otherwise a copy is needed */
292 if (buffertype == PyBUF_WRITE) {
293 Py_DECREF(mem);
294 PyErr_SetString(PyExc_BufferError,
295 "writable contiguous buffer requested "
296 "for a non-contiguousobject.");
297 return NULL;
298 }
299 bytes = PyBytes_FromStringAndSize(NULL, view->len);
300 if (bytes == NULL) {
301 Py_DECREF(mem);
302 return NULL;
303 }
304 dest = PyBytes_AS_STRING(bytes);
305 /* different copying strategy depending on whether
306 or not any pointer de-referencing is needed
307 */
308 /* strided or in-direct copy */
309 if (view->suboffsets==NULL) {
310 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
311 view->strides, view->itemsize, fort);
312 }
313 else {
314 if (_indirect_copy_nd(dest, view, fort) < 0) {
315 Py_DECREF(bytes);
316 Py_DECREF(mem);
317 return NULL;
318 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000319 PyBuffer_Release(view); /* XXX ? */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000320 }
321 _PyObject_GC_TRACK(mem);
322 return (PyObject *)mem;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000323}
324
325
326static PyObject *
327memory_format_get(PyMemoryViewObject *self)
328{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000329 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000330 return PyUnicode_FromString(self->view.format);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000331}
332
333static PyObject *
334memory_itemsize_get(PyMemoryViewObject *self)
335{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000336 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000337 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000338}
339
340static PyObject *
341_IntTupleFromSsizet(int len, Py_ssize_t *vals)
342{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000343 int i;
344 PyObject *o;
345 PyObject *intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000346
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000347 if (vals == NULL) {
348 Py_INCREF(Py_None);
349 return Py_None;
350 }
351 intTuple = PyTuple_New(len);
Benjamin Peterson83473282010-11-03 23:11:10 +0000352 if (!intTuple)
353 return NULL;
354 for (i=0; i<len; i++) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000355 o = PyLong_FromSsize_t(vals[i]);
356 if (!o) {
357 Py_DECREF(intTuple);
358 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000359 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000360 PyTuple_SET_ITEM(intTuple, i, o);
361 }
362 return intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000363}
364
365static PyObject *
366memory_shape_get(PyMemoryViewObject *self)
367{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000368 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000369 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000370}
371
372static PyObject *
373memory_strides_get(PyMemoryViewObject *self)
374{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000375 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000376 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000377}
378
379static PyObject *
380memory_suboffsets_get(PyMemoryViewObject *self)
381{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000382 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000383 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000384}
385
386static PyObject *
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000387memory_readonly_get(PyMemoryViewObject *self)
388{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000389 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000390 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000391}
392
393static PyObject *
394memory_ndim_get(PyMemoryViewObject *self)
395{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000396 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000397 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000398}
399
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000400static PyGetSetDef memory_getsetlist[] ={
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000401 {"format", (getter)memory_format_get, NULL, NULL},
402 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
403 {"shape", (getter)memory_shape_get, NULL, NULL},
404 {"strides", (getter)memory_strides_get, NULL, NULL},
405 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
406 {"readonly", (getter)memory_readonly_get, NULL, NULL},
407 {"ndim", (getter)memory_ndim_get, NULL, NULL},
408 {NULL, NULL, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000409};
410
411
412static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000413memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000414{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000415 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000416 return PyObject_CallFunctionObjArgs(
417 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000418}
419
Antoine Pitrou616d2852008-08-19 22:09:34 +0000420/* TODO: rewrite this function using the struct module to unpack
421 each buffer item */
422
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000423static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000424memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000425{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000426 Py_buffer *view = &(mem->view);
427 Py_ssize_t i;
428 PyObject *res, *item;
429 char *buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000430
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000431 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000432 if (strcmp(view->format, "B") || view->itemsize != 1) {
433 PyErr_SetString(PyExc_NotImplementedError,
434 "tolist() only supports byte views");
435 return NULL;
436 }
437 if (view->ndim != 1) {
438 PyErr_SetString(PyExc_NotImplementedError,
439 "tolist() only supports one-dimensional objects");
440 return NULL;
441 }
442 res = PyList_New(view->len);
443 if (res == NULL)
444 return NULL;
445 buf = view->buf;
446 for (i = 0; i < view->len; i++) {
447 item = PyLong_FromUnsignedLong((unsigned char) *buf);
448 if (item == NULL) {
449 Py_DECREF(res);
450 return NULL;
451 }
452 PyList_SET_ITEM(res, i, item);
453 buf++;
454 }
455 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000456}
457
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000458static void
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000459do_release(PyMemoryViewObject *self)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000460{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000461 if (self->view.obj != NULL) {
Antoine Pitrouaeb6cee2010-11-04 20:30:33 +0000462 PyBuffer_Release(&(self->view));
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000463 }
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000464 self->view.obj = NULL;
465 self->view.buf = NULL;
466}
467
468static PyObject *
469memory_enter(PyObject *self, PyObject *args)
470{
471 CHECK_RELEASED(self);
472 Py_INCREF(self);
473 return self;
474}
475
476static PyObject *
477memory_exit(PyObject *self, PyObject *args)
478{
479 do_release((PyMemoryViewObject *) self);
480 Py_RETURN_NONE;
481}
482
483static PyMethodDef memory_methods[] = {
484 {"release", memory_exit, METH_NOARGS},
485 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
486 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
487 {"__enter__", memory_enter, METH_NOARGS},
488 {"__exit__", memory_exit, METH_VARARGS},
489 {NULL, NULL} /* sentinel */
490};
491
492
493static void
494memory_dealloc(PyMemoryViewObject *self)
495{
496 _PyObject_GC_UNTRACK(self);
497 do_release(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000498 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000499}
500
501static PyObject *
502memory_repr(PyMemoryViewObject *self)
503{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000504 if (IS_RELEASED(self))
505 return PyUnicode_FromFormat("<released memory at %p>", self);
506 else
507 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000508}
509
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000510/* Sequence methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000511static Py_ssize_t
512memory_length(PyMemoryViewObject *self)
513{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000514 CHECK_RELEASED_INT(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000515 return get_shape0(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000516}
517
Raymond Hettinger159eac92009-06-23 20:38:54 +0000518/* Alternate version of memory_subcript that only accepts indices.
519 Used by PySeqIter_New().
520*/
521static PyObject *
522memory_item(PyMemoryViewObject *self, Py_ssize_t result)
523{
524 Py_buffer *view = &(self->view);
525
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000526 CHECK_RELEASED(self);
Raymond Hettinger159eac92009-06-23 20:38:54 +0000527 if (view->ndim == 0) {
528 PyErr_SetString(PyExc_IndexError,
529 "invalid indexing of 0-dim memory");
530 return NULL;
531 }
532 if (view->ndim == 1) {
533 /* Return a bytes object */
534 char *ptr;
535 ptr = (char *)view->buf;
536 if (result < 0) {
537 result += get_shape0(view);
538 }
539 if ((result < 0) || (result >= get_shape0(view))) {
540 PyErr_SetString(PyExc_IndexError,
541 "index out of bounds");
542 return NULL;
543 }
544 if (view->strides == NULL)
545 ptr += view->itemsize * result;
546 else
547 ptr += view->strides[0] * result;
548 if (view->suboffsets != NULL &&
549 view->suboffsets[0] >= 0) {
550 ptr = *((char **)ptr) + view->suboffsets[0];
551 }
552 return PyBytes_FromStringAndSize(ptr, view->itemsize);
553 } else {
554 /* Return a new memory-view object */
555 Py_buffer newview;
556 memset(&newview, 0, sizeof(newview));
557 /* XXX: This needs to be fixed so it actually returns a sub-view */
558 return PyMemoryView_FromBuffer(&newview);
559 }
560}
561
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000562/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000563 mem[obj] returns a bytes object holding the data for one element if
564 obj fully indexes the memory view or another memory-view object
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000565 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000566
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000567 0-d memory-view objects can be referenced using ... or () but
568 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000569 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000570static PyObject *
571memory_subscript(PyMemoryViewObject *self, PyObject *key)
572{
Antoine Pitroubc420402008-12-07 20:14:49 +0000573 Py_buffer *view;
574 view = &(self->view);
575
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000576 CHECK_RELEASED(self);
Antoine Pitroubc420402008-12-07 20:14:49 +0000577 if (view->ndim == 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000578 if (key == Py_Ellipsis ||
579 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
580 Py_INCREF(self);
581 return (PyObject *)self;
582 }
583 else {
584 PyErr_SetString(PyExc_IndexError,
585 "invalid indexing of 0-dim memory");
586 return NULL;
587 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000588 }
589 if (PyIndex_Check(key)) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000590 Py_ssize_t result;
591 result = PyNumber_AsSsize_t(key, NULL);
592 if (result == -1 && PyErr_Occurred())
593 return NULL;
Raymond Hettinger159eac92009-06-23 20:38:54 +0000594 return memory_item(self, result);
Antoine Pitroubc420402008-12-07 20:14:49 +0000595 }
596 else if (PySlice_Check(key)) {
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000597 Py_ssize_t start, stop, step, slicelength;
598
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000599 if (PySlice_GetIndicesEx(key, get_shape0(view),
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000600 &start, &stop, &step, &slicelength) < 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000601 return NULL;
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000602 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000603
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000604 if (step == 1 && view->ndim == 1) {
605 Py_buffer newview;
606 void *newbuf = (char *) view->buf
607 + start * view->itemsize;
608 int newflags = view->readonly
609 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
Antoine Pitroubc420402008-12-07 20:14:49 +0000610
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000611 /* XXX There should be an API to create a subbuffer */
612 if (view->obj != NULL) {
613 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
614 return NULL;
615 }
616 else {
617 newview = *view;
618 }
619 newview.buf = newbuf;
620 newview.len = slicelength * newview.itemsize;
621 newview.format = view->format;
622 newview.shape = &(newview.smalltable[0]);
623 newview.shape[0] = slicelength;
624 newview.strides = &(newview.itemsize);
625 return PyMemoryView_FromBuffer(&newview);
626 }
627 PyErr_SetNone(PyExc_NotImplementedError);
628 return NULL;
Antoine Pitroubc420402008-12-07 20:14:49 +0000629 }
630 PyErr_Format(PyExc_TypeError,
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000631 "cannot index memory using \"%.200s\"",
632 key->ob_type->tp_name);
Antoine Pitroubc420402008-12-07 20:14:49 +0000633 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000634}
635
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000636
637/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000638static int
639memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
640{
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000641 Py_ssize_t start, len, bytelen;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000642 Py_buffer srcview;
643 Py_buffer *view = &(self->view);
644 char *srcbuf, *destbuf;
645
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000646 CHECK_RELEASED_INT(self);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000647 if (view->readonly) {
648 PyErr_SetString(PyExc_TypeError,
649 "cannot modify read-only memory");
650 return -1;
651 }
Antoine Pitroue0793ba2010-09-01 21:14:16 +0000652 if (value == NULL) {
653 PyErr_SetString(PyExc_TypeError,
654 "cannot delete memory");
655 return -1;
656 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000657 if (view->ndim != 1) {
658 PyErr_SetNone(PyExc_NotImplementedError);
659 return -1;
660 }
661 if (PyIndex_Check(key)) {
662 start = PyNumber_AsSsize_t(key, NULL);
663 if (start == -1 && PyErr_Occurred())
664 return -1;
665 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000666 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000667 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000668 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000669 PyErr_SetString(PyExc_IndexError,
670 "index out of bounds");
671 return -1;
672 }
673 len = 1;
674 }
675 else if (PySlice_Check(key)) {
676 Py_ssize_t stop, step;
677
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000678 if (PySlice_GetIndicesEx(key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000679 &start, &stop, &step, &len) < 0) {
680 return -1;
681 }
682 if (step != 1) {
683 PyErr_SetNone(PyExc_NotImplementedError);
684 return -1;
685 }
686 }
687 else {
688 PyErr_Format(PyExc_TypeError,
689 "cannot index memory using \"%.200s\"",
690 key->ob_type->tp_name);
691 return -1;
692 }
693 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
694 return -1;
695 }
696 /* XXX should we allow assignment of different item sizes
697 as long as the byte length is the same?
698 (e.g. assign 2 shorts to a 4-byte slice) */
699 if (srcview.itemsize != view->itemsize) {
700 PyErr_Format(PyExc_TypeError,
701 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
702 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
703 goto _error;
704 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000705 bytelen = len * view->itemsize;
706 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000707 PyErr_SetString(PyExc_ValueError,
708 "cannot modify size of memoryview object");
709 goto _error;
710 }
711 /* Do the actual copy */
712 destbuf = (char *) view->buf + start * view->itemsize;
713 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000714 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
715 /* No overlapping */
716 memcpy(destbuf, srcbuf, bytelen);
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000717 else
718 memmove(destbuf, srcbuf, bytelen);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000719
720 PyBuffer_Release(&srcview);
721 return 0;
722
723_error:
724 PyBuffer_Release(&srcview);
725 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000726}
727
Antoine Pitrou616d2852008-08-19 22:09:34 +0000728static PyObject *
729memory_richcompare(PyObject *v, PyObject *w, int op)
730{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000731 Py_buffer vv, ww;
732 int equal = 0;
733 PyObject *res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000734
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000735 vv.obj = NULL;
736 ww.obj = NULL;
737 if (op != Py_EQ && op != Py_NE)
738 goto _notimpl;
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000739 if ((PyMemoryView_Check(v) && IS_RELEASED(v)) ||
740 (PyMemoryView_Check(w) && IS_RELEASED(w))) {
741 equal = (v == w);
742 goto _end;
743 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000744 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
745 PyErr_Clear();
746 goto _notimpl;
747 }
748 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
749 PyErr_Clear();
750 goto _notimpl;
751 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000752
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000753 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
754 goto _end;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000755
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000756 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000757
758_end:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000759 PyBuffer_Release(&vv);
760 PyBuffer_Release(&ww);
761 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
762 res = Py_True;
763 else
764 res = Py_False;
765 Py_INCREF(res);
766 return res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000767
768_notimpl:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000769 PyBuffer_Release(&vv);
770 PyBuffer_Release(&ww);
771 Py_INCREF(Py_NotImplemented);
772 return Py_NotImplemented;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000773}
774
775
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000776static int
777memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
778{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000779 if (self->view.obj != NULL)
780 Py_VISIT(self->view.obj);
781 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000782}
783
784static int
785memory_clear(PyMemoryViewObject *self)
786{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000787 PyBuffer_Release(&self->view);
788 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000789}
790
791
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000792/* As mapping */
793static PyMappingMethods memory_as_mapping = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000794 (lenfunc)memory_length, /* mp_length */
795 (binaryfunc)memory_subscript, /* mp_subscript */
796 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000797};
798
Raymond Hettinger159eac92009-06-23 20:38:54 +0000799static PySequenceMethods memory_as_sequence = {
Alexander Belopolskyf0f45142010-08-11 17:31:17 +0000800 0, /* sq_length */
801 0, /* sq_concat */
802 0, /* sq_repeat */
803 (ssizeargfunc)memory_item, /* sq_item */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000804};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000805
806/* Buffer methods */
807
808static PyBufferProcs memory_as_buffer = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000809 (getbufferproc)memory_getbuf, /* bf_getbuffer */
810 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000811};
812
813
814PyTypeObject PyMemoryView_Type = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000815 PyVarObject_HEAD_INIT(&PyType_Type, 0)
816 "memoryview",
817 sizeof(PyMemoryViewObject),
818 0,
819 (destructor)memory_dealloc, /* tp_dealloc */
820 0, /* tp_print */
821 0, /* tp_getattr */
822 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000823 0, /* tp_reserved */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000824 (reprfunc)memory_repr, /* tp_repr */
825 0, /* tp_as_number */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000826 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000827 &memory_as_mapping, /* tp_as_mapping */
828 0, /* tp_hash */
829 0, /* tp_call */
Benjamin Peterson87618552009-02-08 15:00:52 +0000830 0, /* tp_str */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000831 PyObject_GenericGetAttr, /* tp_getattro */
832 0, /* tp_setattro */
833 &memory_as_buffer, /* tp_as_buffer */
834 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
835 memory_doc, /* tp_doc */
836 (traverseproc)memory_traverse, /* tp_traverse */
837 (inquiry)memory_clear, /* tp_clear */
838 memory_richcompare, /* tp_richcompare */
839 0, /* tp_weaklistoffset */
840 0, /* tp_iter */
841 0, /* tp_iternext */
842 memory_methods, /* tp_methods */
843 0, /* tp_members */
844 memory_getsetlist, /* tp_getset */
845 0, /* tp_base */
846 0, /* tp_dict */
847 0, /* tp_descr_get */
848 0, /* tp_descr_set */
849 0, /* tp_dictoffset */
850 0, /* tp_init */
851 0, /* tp_alloc */
852 memory_new, /* tp_new */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000853};