blob: 36626b2cdd427d7ed1adb440de4d70cc14ab6cd2 [file] [log] [blame]
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001
2/* Memoryview object implementation */
3
4#include "Python.h"
5
Antoine Pitrou6e6cc832010-09-09 12:59:39 +00006#define IS_RELEASED(memobj) \
7 (((PyMemoryViewObject *) memobj)->view.buf == NULL)
8
9#define CHECK_RELEASED(memobj) \
10 if (IS_RELEASED(memobj)) { \
11 PyErr_SetString(PyExc_ValueError, \
12 "operation forbidden on released memoryview object"); \
13 return NULL; \
14 }
15
16#define CHECK_RELEASED_INT(memobj) \
17 if (IS_RELEASED(memobj)) { \
18 PyErr_SetString(PyExc_ValueError, \
19 "operation forbidden on released memoryview object"); \
20 return -1; \
21 }
22
Antoine Pitroubc420402008-12-07 20:14:49 +000023static Py_ssize_t
24get_shape0(Py_buffer *buf)
25{
26 if (buf->shape != NULL)
27 return buf->shape[0];
Antoine Pitrouc3b39242009-01-03 16:59:18 +000028 if (buf->ndim == 0)
29 return 1;
30 PyErr_SetString(PyExc_TypeError,
31 "exported buffer does not have any shape information associated "
32 "to it");
33 return -1;
34}
35
36static void
37dup_buffer(Py_buffer *dest, Py_buffer *src)
38{
39 *dest = *src;
40 if (src->ndim == 1 && src->shape != NULL) {
41 dest->shape = &(dest->smalltable[0]);
42 dest->shape[0] = get_shape0(src);
43 }
44 if (src->ndim == 1 && src->strides != NULL) {
45 dest->strides = &(dest->smalltable[1]);
46 dest->strides[0] = src->strides[0];
47 }
Antoine Pitroubc420402008-12-07 20:14:49 +000048}
49
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000050static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000051memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000052{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000053 int res = 0;
Antoine Pitrou6e6cc832010-09-09 12:59:39 +000054 CHECK_RELEASED_INT(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +000055 /* XXX for whatever reason fixing the flags seems necessary */
56 if (self->view.readonly)
57 flags &= ~PyBUF_WRITABLE;
58 if (self->view.obj != NULL)
59 res = PyObject_GetBuffer(self->view.obj, view, flags);
60 if (view)
61 dup_buffer(view, &self->view);
62 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000063}
64
65static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000066memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000067{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000068 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000069}
70
71PyDoc_STRVAR(memory_doc,
72"memoryview(object)\n\
73\n\
74Create a new memoryview object which references the given object.");
75
76PyObject *
Antoine Pitrouee58fa42008-08-19 18:22:14 +000077PyMemoryView_FromBuffer(Py_buffer *info)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000078{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000079 PyMemoryViewObject *mview;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000080
Antoine Pitrou35b7e832009-01-03 19:20:36 +000081 mview = (PyMemoryViewObject *)
82 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
83 if (mview == NULL)
84 return NULL;
85 mview->base = NULL;
86 dup_buffer(&mview->view, info);
87 /* NOTE: mview->view.obj should already have been incref'ed as
88 part of PyBuffer_FillInfo(). */
89 _PyObject_GC_TRACK(mview);
90 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000091}
92
93PyObject *
94PyMemoryView_FromObject(PyObject *base)
95{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000096 PyMemoryViewObject *mview;
Antoine Pitrou05b7c562010-02-02 22:47:00 +000097 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000098
Antoine Pitrou35b7e832009-01-03 19:20:36 +000099 if (!PyObject_CheckBuffer(base)) {
100 PyErr_SetString(PyExc_TypeError,
101 "cannot make memory view because object does "
102 "not have the buffer interface");
103 return NULL;
104 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000105
Antoine Pitrou05b7c562010-02-02 22:47:00 +0000106 if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000107 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000108
Antoine Pitrou05b7c562010-02-02 22:47:00 +0000109 mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);
110 if (mview == NULL) {
111 PyBuffer_Release(&view);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000112 return NULL;
113 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000114
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000115 mview->base = base;
116 Py_INCREF(base);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000117 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000118}
119
120static PyObject *
121memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
122{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000123 PyObject *obj;
124 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000125
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000126 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
127 &obj)) {
128 return NULL;
129 }
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000130
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000131 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000132}
133
134
135static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000136_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +0000137 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000138{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000139 int k;
140 Py_ssize_t outstride;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000141
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000142 if (nd==0) {
143 memcpy(dest, src, itemsize);
144 }
145 else if (nd == 1) {
146 for (k = 0; k<shape[0]; k++) {
147 memcpy(dest, src, itemsize);
148 dest += itemsize;
149 src += strides[0];
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000150 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000151 }
152 else {
153 if (fort == 'F') {
154 /* Copy first dimension first,
155 second dimension second, etc...
156 Set up the recursive loop backwards so that final
157 dimension is actually copied last.
158 */
159 outstride = itemsize;
160 for (k=1; k<nd-1;k++) {
161 outstride *= shape[k];
162 }
163 for (k=0; k<shape[nd-1]; k++) {
164 _strided_copy_nd(dest, src, nd-1, shape,
165 strides, itemsize, fort);
166 dest += outstride;
167 src += strides[nd-1];
168 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000169 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000170
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000171 else {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000172 /* Copy last dimension first,
173 second-to-last dimension second, etc.
174 Set up the recursion so that the
175 first dimension is copied last
176 */
177 outstride = itemsize;
178 for (k=1; k < nd; k++) {
179 outstride *= shape[k];
180 }
181 for (k=0; k<shape[0]; k++) {
182 _strided_copy_nd(dest, src, nd-1, shape+1,
183 strides+1, itemsize,
184 fort);
185 dest += outstride;
186 src += strides[0];
187 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000188 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000189 }
190 return;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000191}
192
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000193static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000194_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000195{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000196 Py_ssize_t *indices;
197 int k;
198 Py_ssize_t elements;
199 char *ptr;
Antoine Pitrouc73b9092010-09-01 21:14:46 +0000200 void (*func)(int, Py_ssize_t *, const Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000201
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000202 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
203 PyErr_NoMemory();
204 return -1;
205 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000206
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000207 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
208 if (indices == NULL) {
209 PyErr_NoMemory();
210 return -1;
211 }
212 for (k=0; k<view->ndim;k++) {
213 indices[k] = 0;
214 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000215
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000216 elements = 1;
217 for (k=0; k<view->ndim; k++) {
218 elements *= view->shape[k];
219 }
220 if (fort == 'F') {
Antoine Pitrouf68c2a72010-09-01 12:58:21 +0000221 func = _Py_add_one_to_index_F;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000222 }
223 else {
Antoine Pitrouf68c2a72010-09-01 12:58:21 +0000224 func = _Py_add_one_to_index_C;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000225 }
226 while (elements--) {
227 func(view->ndim, indices, view->shape);
228 ptr = PyBuffer_GetPointer(view, indices);
229 memcpy(dest, ptr, view->itemsize);
230 dest += view->itemsize;
231 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000232
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000233 PyMem_Free(indices);
234 return 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000235}
236
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000237/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000238 Get a the data from an object as a contiguous chunk of memory (in
239 either 'C' or 'F'ortran order) even if it means copying it into a
240 separate memory area.
241
242 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000243 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000244 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000245 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000246
247 buffertype
248
249 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000250 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000251 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000252 a contiguous buffer if it is not. The view will point to
253 the shadow buffer which can be written to and then
254 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000255 view is de-allocated. While the shadow buffer is
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000256 being used, it will have an exclusive write lock on
257 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000258 */
259
260PyObject *
261PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
262{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000263 PyMemoryViewObject *mem;
264 PyObject *bytes;
265 Py_buffer *view;
266 int flags;
267 char *dest;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000268
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000269 if (!PyObject_CheckBuffer(obj)) {
270 PyErr_SetString(PyExc_TypeError,
Georg Brandl61b96dc2009-08-04 20:29:27 +0000271 "object does not support the buffer interface");
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000272 return NULL;
273 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000274
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000275 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
276 if (mem == NULL)
277 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000278
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000279 view = &mem->view;
280 flags = PyBUF_FULL_RO;
281 switch(buffertype) {
282 case PyBUF_WRITE:
283 flags = PyBUF_FULL;
284 break;
285 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000286
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000287 if (PyObject_GetBuffer(obj, view, flags) != 0) {
288 Py_DECREF(mem);
289 return NULL;
290 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000291
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000292 if (PyBuffer_IsContiguous(view, fort)) {
293 /* no copy needed */
294 Py_INCREF(obj);
295 mem->base = obj;
296 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000297 return (PyObject *)mem;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000298 }
299 /* otherwise a copy is needed */
300 if (buffertype == PyBUF_WRITE) {
301 Py_DECREF(mem);
302 PyErr_SetString(PyExc_BufferError,
303 "writable contiguous buffer requested "
304 "for a non-contiguousobject.");
305 return NULL;
306 }
307 bytes = PyBytes_FromStringAndSize(NULL, view->len);
308 if (bytes == NULL) {
309 Py_DECREF(mem);
310 return NULL;
311 }
312 dest = PyBytes_AS_STRING(bytes);
313 /* different copying strategy depending on whether
314 or not any pointer de-referencing is needed
315 */
316 /* strided or in-direct copy */
317 if (view->suboffsets==NULL) {
318 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
319 view->strides, view->itemsize, fort);
320 }
321 else {
322 if (_indirect_copy_nd(dest, view, fort) < 0) {
323 Py_DECREF(bytes);
324 Py_DECREF(mem);
325 return NULL;
326 }
327 }
328 if (buffertype == PyBUF_SHADOW) {
329 /* return a shadowed memory-view object */
330 view->buf = dest;
331 mem->base = PyTuple_Pack(2, obj, bytes);
332 Py_DECREF(bytes);
333 if (mem->base == NULL) {
334 Py_DECREF(mem);
335 return NULL;
336 }
337 }
338 else {
339 PyBuffer_Release(view); /* XXX ? */
340 /* steal the reference */
341 mem->base = bytes;
342 }
343 _PyObject_GC_TRACK(mem);
344 return (PyObject *)mem;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000345}
346
347
348static PyObject *
349memory_format_get(PyMemoryViewObject *self)
350{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000351 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000352 return PyUnicode_FromString(self->view.format);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000353}
354
355static PyObject *
356memory_itemsize_get(PyMemoryViewObject *self)
357{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000358 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000359 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000360}
361
362static PyObject *
363_IntTupleFromSsizet(int len, Py_ssize_t *vals)
364{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000365 int i;
366 PyObject *o;
367 PyObject *intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000368
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000369 if (vals == NULL) {
370 Py_INCREF(Py_None);
371 return Py_None;
372 }
373 intTuple = PyTuple_New(len);
374 if (!intTuple) return NULL;
375 for(i=0; i<len; i++) {
376 o = PyLong_FromSsize_t(vals[i]);
377 if (!o) {
378 Py_DECREF(intTuple);
379 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000380 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000381 PyTuple_SET_ITEM(intTuple, i, o);
382 }
383 return intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000384}
385
386static PyObject *
387memory_shape_get(PyMemoryViewObject *self)
388{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000389 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000390 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000391}
392
393static PyObject *
394memory_strides_get(PyMemoryViewObject *self)
395{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000396 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000397 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000398}
399
400static PyObject *
401memory_suboffsets_get(PyMemoryViewObject *self)
402{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000403 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000404 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000405}
406
407static PyObject *
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000408memory_readonly_get(PyMemoryViewObject *self)
409{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000410 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000411 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000412}
413
414static PyObject *
415memory_ndim_get(PyMemoryViewObject *self)
416{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000417 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000418 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000419}
420
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000421static PyGetSetDef memory_getsetlist[] ={
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000422 {"format", (getter)memory_format_get, NULL, NULL},
423 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
424 {"shape", (getter)memory_shape_get, NULL, NULL},
425 {"strides", (getter)memory_strides_get, NULL, NULL},
426 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
427 {"readonly", (getter)memory_readonly_get, NULL, NULL},
428 {"ndim", (getter)memory_ndim_get, NULL, NULL},
429 {NULL, NULL, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000430};
431
432
433static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000434memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000435{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000436 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000437 return PyObject_CallFunctionObjArgs(
438 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000439}
440
Antoine Pitrou616d2852008-08-19 22:09:34 +0000441/* TODO: rewrite this function using the struct module to unpack
442 each buffer item */
443
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000444static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000445memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000446{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000447 Py_buffer *view = &(mem->view);
448 Py_ssize_t i;
449 PyObject *res, *item;
450 char *buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000451
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000452 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000453 if (strcmp(view->format, "B") || view->itemsize != 1) {
454 PyErr_SetString(PyExc_NotImplementedError,
455 "tolist() only supports byte views");
456 return NULL;
457 }
458 if (view->ndim != 1) {
459 PyErr_SetString(PyExc_NotImplementedError,
460 "tolist() only supports one-dimensional objects");
461 return NULL;
462 }
463 res = PyList_New(view->len);
464 if (res == NULL)
465 return NULL;
466 buf = view->buf;
467 for (i = 0; i < view->len; i++) {
468 item = PyLong_FromUnsignedLong((unsigned char) *buf);
469 if (item == NULL) {
470 Py_DECREF(res);
471 return NULL;
472 }
473 PyList_SET_ITEM(res, i, item);
474 buf++;
475 }
476 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000477}
478
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000479static void
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000480do_release(PyMemoryViewObject *self)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000481{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000482 if (self->view.obj != NULL) {
483 if (self->base && PyTuple_Check(self->base)) {
484 /* Special case when first element is generic object
485 with buffer interface and the second element is a
486 contiguous "shadow" that must be copied back into
487 the data areay of the first tuple element before
488 releasing the buffer on the first element.
489 */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000490
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000491 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
492 PyTuple_GET_ITEM(self->base,1));
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000493
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000494 /* The view member should have readonly == -1 in
495 this instance indicating that the memory can
496 be "locked" and was locked and will be unlocked
497 again after this call.
498 */
499 PyBuffer_Release(&(self->view));
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000500 }
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000501 else {
502 PyBuffer_Release(&(self->view));
503 }
504 Py_CLEAR(self->base);
505 }
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000506 self->view.obj = NULL;
507 self->view.buf = NULL;
508}
509
510static PyObject *
511memory_enter(PyObject *self, PyObject *args)
512{
513 CHECK_RELEASED(self);
514 Py_INCREF(self);
515 return self;
516}
517
518static PyObject *
519memory_exit(PyObject *self, PyObject *args)
520{
521 do_release((PyMemoryViewObject *) self);
522 Py_RETURN_NONE;
523}
524
525static PyMethodDef memory_methods[] = {
526 {"release", memory_exit, METH_NOARGS},
527 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
528 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
529 {"__enter__", memory_enter, METH_NOARGS},
530 {"__exit__", memory_exit, METH_VARARGS},
531 {NULL, NULL} /* sentinel */
532};
533
534
535static void
536memory_dealloc(PyMemoryViewObject *self)
537{
538 _PyObject_GC_UNTRACK(self);
539 do_release(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000540 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000541}
542
543static PyObject *
544memory_repr(PyMemoryViewObject *self)
545{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000546 if (IS_RELEASED(self))
547 return PyUnicode_FromFormat("<released memory at %p>", self);
548 else
549 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000550}
551
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000552/* Sequence methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000553static Py_ssize_t
554memory_length(PyMemoryViewObject *self)
555{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000556 CHECK_RELEASED_INT(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000557 return get_shape0(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000558}
559
Raymond Hettinger159eac92009-06-23 20:38:54 +0000560/* Alternate version of memory_subcript that only accepts indices.
561 Used by PySeqIter_New().
562*/
563static PyObject *
564memory_item(PyMemoryViewObject *self, Py_ssize_t result)
565{
566 Py_buffer *view = &(self->view);
567
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000568 CHECK_RELEASED(self);
Raymond Hettinger159eac92009-06-23 20:38:54 +0000569 if (view->ndim == 0) {
570 PyErr_SetString(PyExc_IndexError,
571 "invalid indexing of 0-dim memory");
572 return NULL;
573 }
574 if (view->ndim == 1) {
575 /* Return a bytes object */
576 char *ptr;
577 ptr = (char *)view->buf;
578 if (result < 0) {
579 result += get_shape0(view);
580 }
581 if ((result < 0) || (result >= get_shape0(view))) {
582 PyErr_SetString(PyExc_IndexError,
583 "index out of bounds");
584 return NULL;
585 }
586 if (view->strides == NULL)
587 ptr += view->itemsize * result;
588 else
589 ptr += view->strides[0] * result;
590 if (view->suboffsets != NULL &&
591 view->suboffsets[0] >= 0) {
592 ptr = *((char **)ptr) + view->suboffsets[0];
593 }
594 return PyBytes_FromStringAndSize(ptr, view->itemsize);
595 } else {
596 /* Return a new memory-view object */
597 Py_buffer newview;
598 memset(&newview, 0, sizeof(newview));
599 /* XXX: This needs to be fixed so it actually returns a sub-view */
600 return PyMemoryView_FromBuffer(&newview);
601 }
602}
603
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000604/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000605 mem[obj] returns a bytes object holding the data for one element if
606 obj fully indexes the memory view or another memory-view object
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000607 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000608
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000609 0-d memory-view objects can be referenced using ... or () but
610 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000611 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000612static PyObject *
613memory_subscript(PyMemoryViewObject *self, PyObject *key)
614{
Antoine Pitroubc420402008-12-07 20:14:49 +0000615 Py_buffer *view;
616 view = &(self->view);
617
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000618 CHECK_RELEASED(self);
Antoine Pitroubc420402008-12-07 20:14:49 +0000619 if (view->ndim == 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000620 if (key == Py_Ellipsis ||
621 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
622 Py_INCREF(self);
623 return (PyObject *)self;
624 }
625 else {
626 PyErr_SetString(PyExc_IndexError,
627 "invalid indexing of 0-dim memory");
628 return NULL;
629 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000630 }
631 if (PyIndex_Check(key)) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000632 Py_ssize_t result;
633 result = PyNumber_AsSsize_t(key, NULL);
634 if (result == -1 && PyErr_Occurred())
635 return NULL;
Raymond Hettinger159eac92009-06-23 20:38:54 +0000636 return memory_item(self, result);
Antoine Pitroubc420402008-12-07 20:14:49 +0000637 }
638 else if (PySlice_Check(key)) {
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000639 Py_ssize_t start, stop, step, slicelength;
640
Antoine Pitroubc420402008-12-07 20:14:49 +0000641 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000642 &start, &stop, &step, &slicelength) < 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000643 return NULL;
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000644 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000645
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000646 if (step == 1 && view->ndim == 1) {
647 Py_buffer newview;
648 void *newbuf = (char *) view->buf
649 + start * view->itemsize;
650 int newflags = view->readonly
651 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
Antoine Pitroubc420402008-12-07 20:14:49 +0000652
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000653 /* XXX There should be an API to create a subbuffer */
654 if (view->obj != NULL) {
655 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
656 return NULL;
657 }
658 else {
659 newview = *view;
660 }
661 newview.buf = newbuf;
662 newview.len = slicelength * newview.itemsize;
663 newview.format = view->format;
664 newview.shape = &(newview.smalltable[0]);
665 newview.shape[0] = slicelength;
666 newview.strides = &(newview.itemsize);
667 return PyMemoryView_FromBuffer(&newview);
668 }
669 PyErr_SetNone(PyExc_NotImplementedError);
670 return NULL;
Antoine Pitroubc420402008-12-07 20:14:49 +0000671 }
672 PyErr_Format(PyExc_TypeError,
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000673 "cannot index memory using \"%.200s\"",
674 key->ob_type->tp_name);
Antoine Pitroubc420402008-12-07 20:14:49 +0000675 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000676}
677
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000678
679/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000680static int
681memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
682{
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000683 Py_ssize_t start, len, bytelen;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000684 Py_buffer srcview;
685 Py_buffer *view = &(self->view);
686 char *srcbuf, *destbuf;
687
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000688 CHECK_RELEASED_INT(self);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000689 if (view->readonly) {
690 PyErr_SetString(PyExc_TypeError,
691 "cannot modify read-only memory");
692 return -1;
693 }
Antoine Pitroue0793ba2010-09-01 21:14:16 +0000694 if (value == NULL) {
695 PyErr_SetString(PyExc_TypeError,
696 "cannot delete memory");
697 return -1;
698 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000699 if (view->ndim != 1) {
700 PyErr_SetNone(PyExc_NotImplementedError);
701 return -1;
702 }
703 if (PyIndex_Check(key)) {
704 start = PyNumber_AsSsize_t(key, NULL);
705 if (start == -1 && PyErr_Occurred())
706 return -1;
707 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000708 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000709 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000710 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000711 PyErr_SetString(PyExc_IndexError,
712 "index out of bounds");
713 return -1;
714 }
715 len = 1;
716 }
717 else if (PySlice_Check(key)) {
718 Py_ssize_t stop, step;
719
Antoine Pitroubc420402008-12-07 20:14:49 +0000720 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000721 &start, &stop, &step, &len) < 0) {
722 return -1;
723 }
724 if (step != 1) {
725 PyErr_SetNone(PyExc_NotImplementedError);
726 return -1;
727 }
728 }
729 else {
730 PyErr_Format(PyExc_TypeError,
731 "cannot index memory using \"%.200s\"",
732 key->ob_type->tp_name);
733 return -1;
734 }
735 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
736 return -1;
737 }
738 /* XXX should we allow assignment of different item sizes
739 as long as the byte length is the same?
740 (e.g. assign 2 shorts to a 4-byte slice) */
741 if (srcview.itemsize != view->itemsize) {
742 PyErr_Format(PyExc_TypeError,
743 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
744 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
745 goto _error;
746 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000747 bytelen = len * view->itemsize;
748 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000749 PyErr_SetString(PyExc_ValueError,
750 "cannot modify size of memoryview object");
751 goto _error;
752 }
753 /* Do the actual copy */
754 destbuf = (char *) view->buf + start * view->itemsize;
755 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000756 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
757 /* No overlapping */
758 memcpy(destbuf, srcbuf, bytelen);
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000759 else
760 memmove(destbuf, srcbuf, bytelen);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000761
762 PyBuffer_Release(&srcview);
763 return 0;
764
765_error:
766 PyBuffer_Release(&srcview);
767 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000768}
769
Antoine Pitrou616d2852008-08-19 22:09:34 +0000770static PyObject *
771memory_richcompare(PyObject *v, PyObject *w, int op)
772{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000773 Py_buffer vv, ww;
774 int equal = 0;
775 PyObject *res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000776
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000777 vv.obj = NULL;
778 ww.obj = NULL;
779 if (op != Py_EQ && op != Py_NE)
780 goto _notimpl;
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000781 if ((PyMemoryView_Check(v) && IS_RELEASED(v)) ||
782 (PyMemoryView_Check(w) && IS_RELEASED(w))) {
783 equal = (v == w);
784 goto _end;
785 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000786 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
787 PyErr_Clear();
788 goto _notimpl;
789 }
790 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
791 PyErr_Clear();
792 goto _notimpl;
793 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000794
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000795 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
796 goto _end;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000797
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000798 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000799
800_end:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000801 PyBuffer_Release(&vv);
802 PyBuffer_Release(&ww);
803 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
804 res = Py_True;
805 else
806 res = Py_False;
807 Py_INCREF(res);
808 return res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000809
810_notimpl:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000811 PyBuffer_Release(&vv);
812 PyBuffer_Release(&ww);
813 Py_INCREF(Py_NotImplemented);
814 return Py_NotImplemented;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000815}
816
817
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000818static int
819memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
820{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000821 if (self->base != NULL)
822 Py_VISIT(self->base);
823 if (self->view.obj != NULL)
824 Py_VISIT(self->view.obj);
825 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000826}
827
828static int
829memory_clear(PyMemoryViewObject *self)
830{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000831 Py_CLEAR(self->base);
832 PyBuffer_Release(&self->view);
833 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000834}
835
836
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000837/* As mapping */
838static PyMappingMethods memory_as_mapping = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000839 (lenfunc)memory_length, /* mp_length */
840 (binaryfunc)memory_subscript, /* mp_subscript */
841 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000842};
843
Raymond Hettinger159eac92009-06-23 20:38:54 +0000844static PySequenceMethods memory_as_sequence = {
Alexander Belopolskyf0f45142010-08-11 17:31:17 +0000845 0, /* sq_length */
846 0, /* sq_concat */
847 0, /* sq_repeat */
848 (ssizeargfunc)memory_item, /* sq_item */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000849};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000850
851/* Buffer methods */
852
853static PyBufferProcs memory_as_buffer = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000854 (getbufferproc)memory_getbuf, /* bf_getbuffer */
855 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000856};
857
858
859PyTypeObject PyMemoryView_Type = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000860 PyVarObject_HEAD_INIT(&PyType_Type, 0)
861 "memoryview",
862 sizeof(PyMemoryViewObject),
863 0,
864 (destructor)memory_dealloc, /* tp_dealloc */
865 0, /* tp_print */
866 0, /* tp_getattr */
867 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000868 0, /* tp_reserved */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000869 (reprfunc)memory_repr, /* tp_repr */
870 0, /* tp_as_number */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000871 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000872 &memory_as_mapping, /* tp_as_mapping */
873 0, /* tp_hash */
874 0, /* tp_call */
Benjamin Peterson87618552009-02-08 15:00:52 +0000875 0, /* tp_str */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000876 PyObject_GenericGetAttr, /* tp_getattro */
877 0, /* tp_setattro */
878 &memory_as_buffer, /* tp_as_buffer */
879 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
880 memory_doc, /* tp_doc */
881 (traverseproc)memory_traverse, /* tp_traverse */
882 (inquiry)memory_clear, /* tp_clear */
883 memory_richcompare, /* tp_richcompare */
884 0, /* tp_weaklistoffset */
885 0, /* tp_iter */
886 0, /* tp_iternext */
887 memory_methods, /* tp_methods */
888 0, /* tp_members */
889 memory_getsetlist, /* tp_getset */
890 0, /* tp_base */
891 0, /* tp_dict */
892 0, /* tp_descr_get */
893 0, /* tp_descr_set */
894 0, /* tp_dictoffset */
895 0, /* tp_init */
896 0, /* tp_alloc */
897 memory_new, /* tp_new */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000898};