blob: a05b97b977bfeddf80b48d909831296dda064c01 [file] [log] [blame]
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001
2/* Memoryview object implementation */
3
4#include "Python.h"
5
Antoine Pitrou6e6cc832010-09-09 12:59:39 +00006#define IS_RELEASED(memobj) \
7 (((PyMemoryViewObject *) memobj)->view.buf == NULL)
8
9#define CHECK_RELEASED(memobj) \
10 if (IS_RELEASED(memobj)) { \
11 PyErr_SetString(PyExc_ValueError, \
12 "operation forbidden on released memoryview object"); \
13 return NULL; \
14 }
15
16#define CHECK_RELEASED_INT(memobj) \
17 if (IS_RELEASED(memobj)) { \
18 PyErr_SetString(PyExc_ValueError, \
19 "operation forbidden on released memoryview object"); \
20 return -1; \
21 }
22
Antoine Pitroubc420402008-12-07 20:14:49 +000023static Py_ssize_t
24get_shape0(Py_buffer *buf)
25{
26 if (buf->shape != NULL)
27 return buf->shape[0];
Antoine Pitrouc3b39242009-01-03 16:59:18 +000028 if (buf->ndim == 0)
29 return 1;
30 PyErr_SetString(PyExc_TypeError,
31 "exported buffer does not have any shape information associated "
32 "to it");
33 return -1;
34}
35
36static void
37dup_buffer(Py_buffer *dest, Py_buffer *src)
38{
39 *dest = *src;
40 if (src->ndim == 1 && src->shape != NULL) {
41 dest->shape = &(dest->smalltable[0]);
42 dest->shape[0] = get_shape0(src);
43 }
44 if (src->ndim == 1 && src->strides != NULL) {
45 dest->strides = &(dest->smalltable[1]);
46 dest->strides[0] = src->strides[0];
47 }
Antoine Pitroubc420402008-12-07 20:14:49 +000048}
49
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000050static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000051memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000052{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000053 int res = 0;
Antoine Pitrou6e6cc832010-09-09 12:59:39 +000054 CHECK_RELEASED_INT(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +000055 /* XXX for whatever reason fixing the flags seems necessary */
56 if (self->view.readonly)
57 flags &= ~PyBUF_WRITABLE;
58 if (self->view.obj != NULL)
59 res = PyObject_GetBuffer(self->view.obj, view, flags);
60 if (view)
61 dup_buffer(view, &self->view);
62 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000063}
64
65static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000066memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000067{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000068 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000069}
70
71PyDoc_STRVAR(memory_doc,
72"memoryview(object)\n\
73\n\
74Create a new memoryview object which references the given object.");
75
76PyObject *
Antoine Pitrouee58fa42008-08-19 18:22:14 +000077PyMemoryView_FromBuffer(Py_buffer *info)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000078{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000079 PyMemoryViewObject *mview;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000080
Antoine Pitrou35b7e832009-01-03 19:20:36 +000081 mview = (PyMemoryViewObject *)
82 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
83 if (mview == NULL)
84 return NULL;
Antoine Pitrou35b7e832009-01-03 19:20:36 +000085 dup_buffer(&mview->view, info);
86 /* NOTE: mview->view.obj should already have been incref'ed as
87 part of PyBuffer_FillInfo(). */
88 _PyObject_GC_TRACK(mview);
89 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000090}
91
92PyObject *
93PyMemoryView_FromObject(PyObject *base)
94{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000095 PyMemoryViewObject *mview;
Antoine Pitrou05b7c562010-02-02 22:47:00 +000096 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000097
Antoine Pitrou35b7e832009-01-03 19:20:36 +000098 if (!PyObject_CheckBuffer(base)) {
99 PyErr_SetString(PyExc_TypeError,
100 "cannot make memory view because object does "
101 "not have the buffer interface");
102 return NULL;
103 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000104
Antoine Pitrou05b7c562010-02-02 22:47:00 +0000105 if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000106 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000107
Antoine Pitrou05b7c562010-02-02 22:47:00 +0000108 mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);
109 if (mview == NULL) {
110 PyBuffer_Release(&view);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000111 return NULL;
112 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000113
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000114 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000115}
116
117static PyObject *
118memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
119{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000120 PyObject *obj;
121 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000122
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000123 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
124 &obj)) {
125 return NULL;
126 }
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000127
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000128 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000129}
130
131
132static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000133_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +0000134 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000135{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000136 int k;
137 Py_ssize_t outstride;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000138
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000139 if (nd==0) {
140 memcpy(dest, src, itemsize);
141 }
142 else if (nd == 1) {
143 for (k = 0; k<shape[0]; k++) {
144 memcpy(dest, src, itemsize);
145 dest += itemsize;
146 src += strides[0];
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000147 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000148 }
149 else {
150 if (fort == 'F') {
151 /* Copy first dimension first,
152 second dimension second, etc...
153 Set up the recursive loop backwards so that final
154 dimension is actually copied last.
155 */
156 outstride = itemsize;
157 for (k=1; k<nd-1;k++) {
158 outstride *= shape[k];
159 }
160 for (k=0; k<shape[nd-1]; k++) {
161 _strided_copy_nd(dest, src, nd-1, shape,
162 strides, itemsize, fort);
163 dest += outstride;
164 src += strides[nd-1];
165 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000166 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000167
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000168 else {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000169 /* Copy last dimension first,
170 second-to-last dimension second, etc.
171 Set up the recursion so that the
172 first dimension is copied last
173 */
174 outstride = itemsize;
175 for (k=1; k < nd; k++) {
176 outstride *= shape[k];
177 }
178 for (k=0; k<shape[0]; k++) {
179 _strided_copy_nd(dest, src, nd-1, shape+1,
180 strides+1, itemsize,
181 fort);
182 dest += outstride;
183 src += strides[0];
184 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000185 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000186 }
187 return;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000188}
189
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000190static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000191_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000192{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000193 Py_ssize_t *indices;
194 int k;
195 Py_ssize_t elements;
196 char *ptr;
Antoine Pitrouc73b9092010-09-01 21:14:46 +0000197 void (*func)(int, Py_ssize_t *, const Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000198
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000199 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
200 PyErr_NoMemory();
201 return -1;
202 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000203
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000204 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
205 if (indices == NULL) {
206 PyErr_NoMemory();
207 return -1;
208 }
209 for (k=0; k<view->ndim;k++) {
210 indices[k] = 0;
211 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000212
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000213 elements = 1;
214 for (k=0; k<view->ndim; k++) {
215 elements *= view->shape[k];
216 }
217 if (fort == 'F') {
Antoine Pitrouf68c2a72010-09-01 12:58:21 +0000218 func = _Py_add_one_to_index_F;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000219 }
220 else {
Antoine Pitrouf68c2a72010-09-01 12:58:21 +0000221 func = _Py_add_one_to_index_C;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000222 }
223 while (elements--) {
224 func(view->ndim, indices, view->shape);
225 ptr = PyBuffer_GetPointer(view, indices);
226 memcpy(dest, ptr, view->itemsize);
227 dest += view->itemsize;
228 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000229
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000230 PyMem_Free(indices);
231 return 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000232}
233
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000234/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000235 Get a the data from an object as a contiguous chunk of memory (in
236 either 'C' or 'F'ortran order) even if it means copying it into a
237 separate memory area.
238
239 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000240 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000241 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000242 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000243
244 buffertype
245
246 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000247 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000248 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000249 a contiguous buffer if it is not. The view will point to
250 the shadow buffer which can be written to and then
251 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000252 view is de-allocated. While the shadow buffer is
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000253 being used, it will have an exclusive write lock on
254 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000255 */
256
257PyObject *
258PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
259{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000260 PyMemoryViewObject *mem;
261 PyObject *bytes;
262 Py_buffer *view;
263 int flags;
264 char *dest;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000265
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000266 if (!PyObject_CheckBuffer(obj)) {
267 PyErr_SetString(PyExc_TypeError,
Georg Brandl61b96dc2009-08-04 20:29:27 +0000268 "object does not support the buffer interface");
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000269 return NULL;
270 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000271
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000272 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
273 if (mem == NULL)
274 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000275
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000276 view = &mem->view;
277 flags = PyBUF_FULL_RO;
278 switch(buffertype) {
279 case PyBUF_WRITE:
280 flags = PyBUF_FULL;
281 break;
282 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000283
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000284 if (PyObject_GetBuffer(obj, view, flags) != 0) {
285 Py_DECREF(mem);
286 return NULL;
287 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000288
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000289 if (PyBuffer_IsContiguous(view, fort)) {
290 /* no copy needed */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000291 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000292 return (PyObject *)mem;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000293 }
294 /* otherwise a copy is needed */
295 if (buffertype == PyBUF_WRITE) {
296 Py_DECREF(mem);
297 PyErr_SetString(PyExc_BufferError,
298 "writable contiguous buffer requested "
299 "for a non-contiguousobject.");
300 return NULL;
301 }
302 bytes = PyBytes_FromStringAndSize(NULL, view->len);
303 if (bytes == NULL) {
304 Py_DECREF(mem);
305 return NULL;
306 }
307 dest = PyBytes_AS_STRING(bytes);
308 /* different copying strategy depending on whether
309 or not any pointer de-referencing is needed
310 */
311 /* strided or in-direct copy */
312 if (view->suboffsets==NULL) {
313 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
314 view->strides, view->itemsize, fort);
315 }
316 else {
317 if (_indirect_copy_nd(dest, view, fort) < 0) {
318 Py_DECREF(bytes);
319 Py_DECREF(mem);
320 return NULL;
321 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000322 PyBuffer_Release(view); /* XXX ? */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000323 }
324 _PyObject_GC_TRACK(mem);
325 return (PyObject *)mem;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000326}
327
328
329static PyObject *
330memory_format_get(PyMemoryViewObject *self)
331{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000332 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000333 return PyUnicode_FromString(self->view.format);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000334}
335
336static PyObject *
337memory_itemsize_get(PyMemoryViewObject *self)
338{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000339 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000340 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000341}
342
343static PyObject *
344_IntTupleFromSsizet(int len, Py_ssize_t *vals)
345{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000346 int i;
347 PyObject *o;
348 PyObject *intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000349
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000350 if (vals == NULL) {
351 Py_INCREF(Py_None);
352 return Py_None;
353 }
354 intTuple = PyTuple_New(len);
Benjamin Peterson83473282010-11-03 23:11:10 +0000355 if (!intTuple)
356 return NULL;
357 for (i=0; i<len; i++) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000358 o = PyLong_FromSsize_t(vals[i]);
359 if (!o) {
360 Py_DECREF(intTuple);
361 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000362 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000363 PyTuple_SET_ITEM(intTuple, i, o);
364 }
365 return intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000366}
367
368static PyObject *
369memory_shape_get(PyMemoryViewObject *self)
370{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000371 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000372 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000373}
374
375static PyObject *
376memory_strides_get(PyMemoryViewObject *self)
377{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000378 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000379 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000380}
381
382static PyObject *
383memory_suboffsets_get(PyMemoryViewObject *self)
384{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000385 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000386 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000387}
388
389static PyObject *
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000390memory_readonly_get(PyMemoryViewObject *self)
391{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000392 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000393 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000394}
395
396static PyObject *
397memory_ndim_get(PyMemoryViewObject *self)
398{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000399 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000400 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000401}
402
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000403static PyGetSetDef memory_getsetlist[] ={
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000404 {"format", (getter)memory_format_get, NULL, NULL},
405 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
406 {"shape", (getter)memory_shape_get, NULL, NULL},
407 {"strides", (getter)memory_strides_get, NULL, NULL},
408 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
409 {"readonly", (getter)memory_readonly_get, NULL, NULL},
410 {"ndim", (getter)memory_ndim_get, NULL, NULL},
411 {NULL, NULL, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000412};
413
414
415static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000416memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000417{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000418 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000419 return PyObject_CallFunctionObjArgs(
420 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000421}
422
Antoine Pitrou616d2852008-08-19 22:09:34 +0000423/* TODO: rewrite this function using the struct module to unpack
424 each buffer item */
425
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000426static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000427memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000428{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000429 Py_buffer *view = &(mem->view);
430 Py_ssize_t i;
431 PyObject *res, *item;
432 char *buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000433
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000434 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000435 if (strcmp(view->format, "B") || view->itemsize != 1) {
436 PyErr_SetString(PyExc_NotImplementedError,
437 "tolist() only supports byte views");
438 return NULL;
439 }
440 if (view->ndim != 1) {
441 PyErr_SetString(PyExc_NotImplementedError,
442 "tolist() only supports one-dimensional objects");
443 return NULL;
444 }
445 res = PyList_New(view->len);
446 if (res == NULL)
447 return NULL;
448 buf = view->buf;
449 for (i = 0; i < view->len; i++) {
450 item = PyLong_FromUnsignedLong((unsigned char) *buf);
451 if (item == NULL) {
452 Py_DECREF(res);
453 return NULL;
454 }
455 PyList_SET_ITEM(res, i, item);
456 buf++;
457 }
458 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000459}
460
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000461static void
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000462do_release(PyMemoryViewObject *self)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000463{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000464 if (self->view.obj != NULL) {
Antoine Pitrouaeb6cee2010-11-04 20:30:33 +0000465 PyBuffer_Release(&(self->view));
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000466 }
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000467 self->view.obj = NULL;
468 self->view.buf = NULL;
469}
470
471static PyObject *
472memory_enter(PyObject *self, PyObject *args)
473{
474 CHECK_RELEASED(self);
475 Py_INCREF(self);
476 return self;
477}
478
479static PyObject *
480memory_exit(PyObject *self, PyObject *args)
481{
482 do_release((PyMemoryViewObject *) self);
483 Py_RETURN_NONE;
484}
485
486static PyMethodDef memory_methods[] = {
487 {"release", memory_exit, METH_NOARGS},
488 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
489 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
490 {"__enter__", memory_enter, METH_NOARGS},
491 {"__exit__", memory_exit, METH_VARARGS},
492 {NULL, NULL} /* sentinel */
493};
494
495
496static void
497memory_dealloc(PyMemoryViewObject *self)
498{
499 _PyObject_GC_UNTRACK(self);
500 do_release(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000501 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000502}
503
504static PyObject *
505memory_repr(PyMemoryViewObject *self)
506{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000507 if (IS_RELEASED(self))
508 return PyUnicode_FromFormat("<released memory at %p>", self);
509 else
510 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000511}
512
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000513/* Sequence methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000514static Py_ssize_t
515memory_length(PyMemoryViewObject *self)
516{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000517 CHECK_RELEASED_INT(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000518 return get_shape0(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000519}
520
Raymond Hettinger159eac92009-06-23 20:38:54 +0000521/* Alternate version of memory_subcript that only accepts indices.
522 Used by PySeqIter_New().
523*/
524static PyObject *
525memory_item(PyMemoryViewObject *self, Py_ssize_t result)
526{
527 Py_buffer *view = &(self->view);
528
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000529 CHECK_RELEASED(self);
Raymond Hettinger159eac92009-06-23 20:38:54 +0000530 if (view->ndim == 0) {
531 PyErr_SetString(PyExc_IndexError,
532 "invalid indexing of 0-dim memory");
533 return NULL;
534 }
535 if (view->ndim == 1) {
536 /* Return a bytes object */
537 char *ptr;
538 ptr = (char *)view->buf;
539 if (result < 0) {
540 result += get_shape0(view);
541 }
542 if ((result < 0) || (result >= get_shape0(view))) {
543 PyErr_SetString(PyExc_IndexError,
544 "index out of bounds");
545 return NULL;
546 }
547 if (view->strides == NULL)
548 ptr += view->itemsize * result;
549 else
550 ptr += view->strides[0] * result;
551 if (view->suboffsets != NULL &&
552 view->suboffsets[0] >= 0) {
553 ptr = *((char **)ptr) + view->suboffsets[0];
554 }
555 return PyBytes_FromStringAndSize(ptr, view->itemsize);
556 } else {
557 /* Return a new memory-view object */
558 Py_buffer newview;
559 memset(&newview, 0, sizeof(newview));
560 /* XXX: This needs to be fixed so it actually returns a sub-view */
561 return PyMemoryView_FromBuffer(&newview);
562 }
563}
564
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000565/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000566 mem[obj] returns a bytes object holding the data for one element if
567 obj fully indexes the memory view or another memory-view object
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000568 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000569
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000570 0-d memory-view objects can be referenced using ... or () but
571 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000572 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000573static PyObject *
574memory_subscript(PyMemoryViewObject *self, PyObject *key)
575{
Antoine Pitroubc420402008-12-07 20:14:49 +0000576 Py_buffer *view;
577 view = &(self->view);
578
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000579 CHECK_RELEASED(self);
Antoine Pitroubc420402008-12-07 20:14:49 +0000580 if (view->ndim == 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000581 if (key == Py_Ellipsis ||
582 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
583 Py_INCREF(self);
584 return (PyObject *)self;
585 }
586 else {
587 PyErr_SetString(PyExc_IndexError,
588 "invalid indexing of 0-dim memory");
589 return NULL;
590 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000591 }
592 if (PyIndex_Check(key)) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000593 Py_ssize_t result;
594 result = PyNumber_AsSsize_t(key, NULL);
595 if (result == -1 && PyErr_Occurred())
596 return NULL;
Raymond Hettinger159eac92009-06-23 20:38:54 +0000597 return memory_item(self, result);
Antoine Pitroubc420402008-12-07 20:14:49 +0000598 }
599 else if (PySlice_Check(key)) {
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000600 Py_ssize_t start, stop, step, slicelength;
601
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000602 if (PySlice_GetIndicesEx(key, get_shape0(view),
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000603 &start, &stop, &step, &slicelength) < 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000604 return NULL;
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000605 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000606
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000607 if (step == 1 && view->ndim == 1) {
608 Py_buffer newview;
609 void *newbuf = (char *) view->buf
610 + start * view->itemsize;
611 int newflags = view->readonly
612 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
Antoine Pitroubc420402008-12-07 20:14:49 +0000613
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000614 /* XXX There should be an API to create a subbuffer */
615 if (view->obj != NULL) {
616 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
617 return NULL;
618 }
619 else {
620 newview = *view;
621 }
622 newview.buf = newbuf;
623 newview.len = slicelength * newview.itemsize;
624 newview.format = view->format;
625 newview.shape = &(newview.smalltable[0]);
626 newview.shape[0] = slicelength;
627 newview.strides = &(newview.itemsize);
628 return PyMemoryView_FromBuffer(&newview);
629 }
630 PyErr_SetNone(PyExc_NotImplementedError);
631 return NULL;
Antoine Pitroubc420402008-12-07 20:14:49 +0000632 }
633 PyErr_Format(PyExc_TypeError,
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000634 "cannot index memory using \"%.200s\"",
635 key->ob_type->tp_name);
Antoine Pitroubc420402008-12-07 20:14:49 +0000636 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000637}
638
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000639
640/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000641static int
642memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
643{
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000644 Py_ssize_t start, len, bytelen;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000645 Py_buffer srcview;
646 Py_buffer *view = &(self->view);
647 char *srcbuf, *destbuf;
648
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000649 CHECK_RELEASED_INT(self);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000650 if (view->readonly) {
651 PyErr_SetString(PyExc_TypeError,
652 "cannot modify read-only memory");
653 return -1;
654 }
Antoine Pitroue0793ba2010-09-01 21:14:16 +0000655 if (value == NULL) {
656 PyErr_SetString(PyExc_TypeError,
657 "cannot delete memory");
658 return -1;
659 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000660 if (view->ndim != 1) {
661 PyErr_SetNone(PyExc_NotImplementedError);
662 return -1;
663 }
664 if (PyIndex_Check(key)) {
665 start = PyNumber_AsSsize_t(key, NULL);
666 if (start == -1 && PyErr_Occurred())
667 return -1;
668 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000669 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000670 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000671 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000672 PyErr_SetString(PyExc_IndexError,
673 "index out of bounds");
674 return -1;
675 }
676 len = 1;
677 }
678 else if (PySlice_Check(key)) {
679 Py_ssize_t stop, step;
680
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000681 if (PySlice_GetIndicesEx(key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000682 &start, &stop, &step, &len) < 0) {
683 return -1;
684 }
685 if (step != 1) {
686 PyErr_SetNone(PyExc_NotImplementedError);
687 return -1;
688 }
689 }
690 else {
691 PyErr_Format(PyExc_TypeError,
692 "cannot index memory using \"%.200s\"",
693 key->ob_type->tp_name);
694 return -1;
695 }
696 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
697 return -1;
698 }
699 /* XXX should we allow assignment of different item sizes
700 as long as the byte length is the same?
701 (e.g. assign 2 shorts to a 4-byte slice) */
702 if (srcview.itemsize != view->itemsize) {
703 PyErr_Format(PyExc_TypeError,
704 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
705 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
706 goto _error;
707 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000708 bytelen = len * view->itemsize;
709 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000710 PyErr_SetString(PyExc_ValueError,
711 "cannot modify size of memoryview object");
712 goto _error;
713 }
714 /* Do the actual copy */
715 destbuf = (char *) view->buf + start * view->itemsize;
716 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000717 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
718 /* No overlapping */
719 memcpy(destbuf, srcbuf, bytelen);
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000720 else
721 memmove(destbuf, srcbuf, bytelen);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000722
723 PyBuffer_Release(&srcview);
724 return 0;
725
726_error:
727 PyBuffer_Release(&srcview);
728 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000729}
730
Antoine Pitrou616d2852008-08-19 22:09:34 +0000731static PyObject *
732memory_richcompare(PyObject *v, PyObject *w, int op)
733{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000734 Py_buffer vv, ww;
735 int equal = 0;
736 PyObject *res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000737
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000738 vv.obj = NULL;
739 ww.obj = NULL;
740 if (op != Py_EQ && op != Py_NE)
741 goto _notimpl;
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000742 if ((PyMemoryView_Check(v) && IS_RELEASED(v)) ||
743 (PyMemoryView_Check(w) && IS_RELEASED(w))) {
744 equal = (v == w);
745 goto _end;
746 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000747 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
748 PyErr_Clear();
749 goto _notimpl;
750 }
751 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
752 PyErr_Clear();
753 goto _notimpl;
754 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000755
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000756 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
757 goto _end;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000758
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000759 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000760
761_end:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000762 PyBuffer_Release(&vv);
763 PyBuffer_Release(&ww);
764 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
765 res = Py_True;
766 else
767 res = Py_False;
768 Py_INCREF(res);
769 return res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000770
771_notimpl:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000772 PyBuffer_Release(&vv);
773 PyBuffer_Release(&ww);
774 Py_INCREF(Py_NotImplemented);
775 return Py_NotImplemented;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000776}
777
778
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000779static int
780memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
781{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000782 if (self->view.obj != NULL)
783 Py_VISIT(self->view.obj);
784 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000785}
786
787static int
788memory_clear(PyMemoryViewObject *self)
789{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000790 PyBuffer_Release(&self->view);
791 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000792}
793
794
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000795/* As mapping */
796static PyMappingMethods memory_as_mapping = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000797 (lenfunc)memory_length, /* mp_length */
798 (binaryfunc)memory_subscript, /* mp_subscript */
799 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000800};
801
Raymond Hettinger159eac92009-06-23 20:38:54 +0000802static PySequenceMethods memory_as_sequence = {
Alexander Belopolskyf0f45142010-08-11 17:31:17 +0000803 0, /* sq_length */
804 0, /* sq_concat */
805 0, /* sq_repeat */
806 (ssizeargfunc)memory_item, /* sq_item */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000807};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000808
809/* Buffer methods */
810
811static PyBufferProcs memory_as_buffer = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000812 (getbufferproc)memory_getbuf, /* bf_getbuffer */
813 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000814};
815
816
817PyTypeObject PyMemoryView_Type = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000818 PyVarObject_HEAD_INIT(&PyType_Type, 0)
819 "memoryview",
820 sizeof(PyMemoryViewObject),
821 0,
822 (destructor)memory_dealloc, /* tp_dealloc */
823 0, /* tp_print */
824 0, /* tp_getattr */
825 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000826 0, /* tp_reserved */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000827 (reprfunc)memory_repr, /* tp_repr */
828 0, /* tp_as_number */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000829 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000830 &memory_as_mapping, /* tp_as_mapping */
831 0, /* tp_hash */
832 0, /* tp_call */
Benjamin Peterson87618552009-02-08 15:00:52 +0000833 0, /* tp_str */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000834 PyObject_GenericGetAttr, /* tp_getattro */
835 0, /* tp_setattro */
836 &memory_as_buffer, /* tp_as_buffer */
837 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
838 memory_doc, /* tp_doc */
839 (traverseproc)memory_traverse, /* tp_traverse */
840 (inquiry)memory_clear, /* tp_clear */
841 memory_richcompare, /* tp_richcompare */
842 0, /* tp_weaklistoffset */
843 0, /* tp_iter */
844 0, /* tp_iternext */
845 memory_methods, /* tp_methods */
846 0, /* tp_members */
847 memory_getsetlist, /* tp_getset */
848 0, /* tp_base */
849 0, /* tp_dict */
850 0, /* tp_descr_get */
851 0, /* tp_descr_set */
852 0, /* tp_dictoffset */
853 0, /* tp_init */
854 0, /* tp_alloc */
855 memory_new, /* tp_new */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000856};