blob: 295a742d6d39f818ec793b6b1687c1c8ad52e94b [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 Pitrou5bffa792011-02-24 20:50:49 +000078 if (info->buf == NULL) {
79 PyErr_SetString(PyExc_ValueError,
80 "cannot make memory view from a buffer with a NULL data pointer");
81 return NULL;
82 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +000083 mview = (PyMemoryViewObject *)
84 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
85 if (mview == NULL)
86 return NULL;
Antoine Pitrouce4a9da2011-11-21 20:46:33 +010087 mview->hash = -1;
Antoine Pitrou35b7e832009-01-03 19:20:36 +000088 dup_buffer(&mview->view, info);
89 /* NOTE: mview->view.obj should already have been incref'ed as
90 part of PyBuffer_FillInfo(). */
91 _PyObject_GC_TRACK(mview);
92 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000093}
94
95PyObject *
96PyMemoryView_FromObject(PyObject *base)
97{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000098 PyMemoryViewObject *mview;
Antoine Pitrou05b7c562010-02-02 22:47:00 +000099 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000100
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000101 if (!PyObject_CheckBuffer(base)) {
102 PyErr_SetString(PyExc_TypeError,
103 "cannot make memory view because object does "
104 "not have the buffer interface");
105 return NULL;
106 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000107
Antoine Pitrou05b7c562010-02-02 22:47:00 +0000108 if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000109 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000110
Antoine Pitrou05b7c562010-02-02 22:47:00 +0000111 mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);
112 if (mview == NULL) {
113 PyBuffer_Release(&view);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000114 return NULL;
115 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000116
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 */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000294 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000295 return (PyObject *)mem;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000296 }
297 /* otherwise a copy is needed */
298 if (buffertype == PyBUF_WRITE) {
299 Py_DECREF(mem);
300 PyErr_SetString(PyExc_BufferError,
301 "writable contiguous buffer requested "
302 "for a non-contiguousobject.");
303 return NULL;
304 }
305 bytes = PyBytes_FromStringAndSize(NULL, view->len);
306 if (bytes == NULL) {
307 Py_DECREF(mem);
308 return NULL;
309 }
310 dest = PyBytes_AS_STRING(bytes);
311 /* different copying strategy depending on whether
312 or not any pointer de-referencing is needed
313 */
314 /* strided or in-direct copy */
315 if (view->suboffsets==NULL) {
316 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
317 view->strides, view->itemsize, fort);
318 }
319 else {
320 if (_indirect_copy_nd(dest, view, fort) < 0) {
321 Py_DECREF(bytes);
322 Py_DECREF(mem);
323 return NULL;
324 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000325 PyBuffer_Release(view); /* XXX ? */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000326 }
327 _PyObject_GC_TRACK(mem);
328 return (PyObject *)mem;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000329}
330
331
332static PyObject *
333memory_format_get(PyMemoryViewObject *self)
334{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000335 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000336 return PyUnicode_FromString(self->view.format);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000337}
338
339static PyObject *
340memory_itemsize_get(PyMemoryViewObject *self)
341{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000342 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000343 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000344}
345
346static PyObject *
347_IntTupleFromSsizet(int len, Py_ssize_t *vals)
348{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000349 int i;
350 PyObject *o;
351 PyObject *intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000352
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000353 if (vals == NULL) {
354 Py_INCREF(Py_None);
355 return Py_None;
356 }
357 intTuple = PyTuple_New(len);
Benjamin Peterson83473282010-11-03 23:11:10 +0000358 if (!intTuple)
359 return NULL;
360 for (i=0; i<len; i++) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000361 o = PyLong_FromSsize_t(vals[i]);
362 if (!o) {
363 Py_DECREF(intTuple);
364 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000365 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000366 PyTuple_SET_ITEM(intTuple, i, o);
367 }
368 return intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000369}
370
371static PyObject *
372memory_shape_get(PyMemoryViewObject *self)
373{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000374 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000375 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000376}
377
378static PyObject *
379memory_strides_get(PyMemoryViewObject *self)
380{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000381 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000382 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000383}
384
385static PyObject *
386memory_suboffsets_get(PyMemoryViewObject *self)
387{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000388 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000389 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000390}
391
392static PyObject *
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000393memory_readonly_get(PyMemoryViewObject *self)
394{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000395 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000396 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000397}
398
399static PyObject *
400memory_ndim_get(PyMemoryViewObject *self)
401{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000402 CHECK_RELEASED(self);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000403 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000404}
405
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000406static PyGetSetDef memory_getsetlist[] ={
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000407 {"format", (getter)memory_format_get, NULL, NULL},
408 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
409 {"shape", (getter)memory_shape_get, NULL, NULL},
410 {"strides", (getter)memory_strides_get, NULL, NULL},
411 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
412 {"readonly", (getter)memory_readonly_get, NULL, NULL},
413 {"ndim", (getter)memory_ndim_get, NULL, NULL},
414 {NULL, NULL, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000415};
416
417
418static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000419memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000420{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000421 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000422 return PyObject_CallFunctionObjArgs(
423 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000424}
425
Antoine Pitrou616d2852008-08-19 22:09:34 +0000426/* TODO: rewrite this function using the struct module to unpack
427 each buffer item */
428
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000429static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000430memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000431{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000432 Py_buffer *view = &(mem->view);
433 Py_ssize_t i;
434 PyObject *res, *item;
435 char *buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000436
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000437 CHECK_RELEASED(mem);
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000438 if (strcmp(view->format, "B") || view->itemsize != 1) {
439 PyErr_SetString(PyExc_NotImplementedError,
440 "tolist() only supports byte views");
441 return NULL;
442 }
443 if (view->ndim != 1) {
444 PyErr_SetString(PyExc_NotImplementedError,
445 "tolist() only supports one-dimensional objects");
446 return NULL;
447 }
448 res = PyList_New(view->len);
449 if (res == NULL)
450 return NULL;
451 buf = view->buf;
452 for (i = 0; i < view->len; i++) {
453 item = PyLong_FromUnsignedLong((unsigned char) *buf);
454 if (item == NULL) {
455 Py_DECREF(res);
456 return NULL;
457 }
458 PyList_SET_ITEM(res, i, item);
459 buf++;
460 }
461 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000462}
463
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000464static void
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000465do_release(PyMemoryViewObject *self)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000466{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000467 if (self->view.obj != NULL) {
Antoine Pitrouaeb6cee2010-11-04 20:30:33 +0000468 PyBuffer_Release(&(self->view));
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000469 }
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000470 self->view.obj = NULL;
471 self->view.buf = NULL;
472}
473
474static PyObject *
475memory_enter(PyObject *self, PyObject *args)
476{
477 CHECK_RELEASED(self);
478 Py_INCREF(self);
479 return self;
480}
481
482static PyObject *
483memory_exit(PyObject *self, PyObject *args)
484{
485 do_release((PyMemoryViewObject *) self);
486 Py_RETURN_NONE;
487}
488
489static PyMethodDef memory_methods[] = {
490 {"release", memory_exit, METH_NOARGS},
491 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
492 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
493 {"__enter__", memory_enter, METH_NOARGS},
494 {"__exit__", memory_exit, METH_VARARGS},
495 {NULL, NULL} /* sentinel */
496};
497
498
499static void
500memory_dealloc(PyMemoryViewObject *self)
501{
502 _PyObject_GC_UNTRACK(self);
503 do_release(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000504 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000505}
506
507static PyObject *
508memory_repr(PyMemoryViewObject *self)
509{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000510 if (IS_RELEASED(self))
511 return PyUnicode_FromFormat("<released memory at %p>", self);
512 else
513 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000514}
515
Antoine Pitrouce4a9da2011-11-21 20:46:33 +0100516static Py_hash_t
517memory_hash(PyMemoryViewObject *self)
518{
519 if (self->hash == -1) {
520 Py_buffer *view = &self->view;
521 CHECK_RELEASED_INT(self);
522 if (view->ndim > 1) {
523 PyErr_SetString(PyExc_NotImplementedError,
524 "can't hash multi-dimensional memoryview object");
525 return -1;
526 }
527 if (view->strides && view->strides[0] != view->itemsize) {
528 PyErr_SetString(PyExc_NotImplementedError,
529 "can't hash strided memoryview object");
530 return -1;
531 }
532 if (!view->readonly) {
533 PyErr_SetString(PyExc_ValueError,
534 "can't hash writable memoryview object");
535 return -1;
536 }
537 if (view->obj != NULL && PyObject_Hash(view->obj) == -1) {
538 /* Keep the original error message */
539 return -1;
540 }
541 /* Can't fail */
542 self->hash = _Py_HashBytes((unsigned char *) view->buf, view->len);
543 }
544 return self->hash;
545}
546
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000547/* Sequence methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000548static Py_ssize_t
549memory_length(PyMemoryViewObject *self)
550{
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000551 CHECK_RELEASED_INT(self);
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000552 return get_shape0(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000553}
554
Raymond Hettinger159eac92009-06-23 20:38:54 +0000555/* Alternate version of memory_subcript that only accepts indices.
556 Used by PySeqIter_New().
557*/
558static PyObject *
559memory_item(PyMemoryViewObject *self, Py_ssize_t result)
560{
561 Py_buffer *view = &(self->view);
562
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000563 CHECK_RELEASED(self);
Raymond Hettinger159eac92009-06-23 20:38:54 +0000564 if (view->ndim == 0) {
565 PyErr_SetString(PyExc_IndexError,
566 "invalid indexing of 0-dim memory");
567 return NULL;
568 }
569 if (view->ndim == 1) {
570 /* Return a bytes object */
571 char *ptr;
572 ptr = (char *)view->buf;
573 if (result < 0) {
574 result += get_shape0(view);
575 }
576 if ((result < 0) || (result >= get_shape0(view))) {
577 PyErr_SetString(PyExc_IndexError,
578 "index out of bounds");
579 return NULL;
580 }
581 if (view->strides == NULL)
582 ptr += view->itemsize * result;
583 else
584 ptr += view->strides[0] * result;
585 if (view->suboffsets != NULL &&
586 view->suboffsets[0] >= 0) {
587 ptr = *((char **)ptr) + view->suboffsets[0];
588 }
589 return PyBytes_FromStringAndSize(ptr, view->itemsize);
590 } else {
591 /* Return a new memory-view object */
592 Py_buffer newview;
593 memset(&newview, 0, sizeof(newview));
594 /* XXX: This needs to be fixed so it actually returns a sub-view */
595 return PyMemoryView_FromBuffer(&newview);
596 }
597}
598
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000599/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000600 mem[obj] returns a bytes object holding the data for one element if
601 obj fully indexes the memory view or another memory-view object
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000602 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000603
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000604 0-d memory-view objects can be referenced using ... or () but
605 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000606 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000607static PyObject *
608memory_subscript(PyMemoryViewObject *self, PyObject *key)
609{
Antoine Pitroubc420402008-12-07 20:14:49 +0000610 Py_buffer *view;
611 view = &(self->view);
612
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000613 CHECK_RELEASED(self);
Antoine Pitroubc420402008-12-07 20:14:49 +0000614 if (view->ndim == 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000615 if (key == Py_Ellipsis ||
616 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
617 Py_INCREF(self);
618 return (PyObject *)self;
619 }
620 else {
621 PyErr_SetString(PyExc_IndexError,
622 "invalid indexing of 0-dim memory");
623 return NULL;
624 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000625 }
626 if (PyIndex_Check(key)) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000627 Py_ssize_t result;
628 result = PyNumber_AsSsize_t(key, NULL);
629 if (result == -1 && PyErr_Occurred())
630 return NULL;
Raymond Hettinger159eac92009-06-23 20:38:54 +0000631 return memory_item(self, result);
Antoine Pitroubc420402008-12-07 20:14:49 +0000632 }
633 else if (PySlice_Check(key)) {
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000634 Py_ssize_t start, stop, step, slicelength;
635
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000636 if (PySlice_GetIndicesEx(key, get_shape0(view),
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000637 &start, &stop, &step, &slicelength) < 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000638 return NULL;
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000639 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000640
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000641 if (step == 1 && view->ndim == 1) {
642 Py_buffer newview;
643 void *newbuf = (char *) view->buf
644 + start * view->itemsize;
645 int newflags = view->readonly
646 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
Antoine Pitroubc420402008-12-07 20:14:49 +0000647
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000648 /* XXX There should be an API to create a subbuffer */
649 if (view->obj != NULL) {
650 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
651 return NULL;
652 }
653 else {
654 newview = *view;
655 }
656 newview.buf = newbuf;
657 newview.len = slicelength * newview.itemsize;
658 newview.format = view->format;
659 newview.shape = &(newview.smalltable[0]);
660 newview.shape[0] = slicelength;
661 newview.strides = &(newview.itemsize);
662 return PyMemoryView_FromBuffer(&newview);
663 }
664 PyErr_SetNone(PyExc_NotImplementedError);
665 return NULL;
Antoine Pitroubc420402008-12-07 20:14:49 +0000666 }
667 PyErr_Format(PyExc_TypeError,
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000668 "cannot index memory using \"%.200s\"",
669 key->ob_type->tp_name);
Antoine Pitroubc420402008-12-07 20:14:49 +0000670 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000671}
672
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000673
674/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000675static int
676memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
677{
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000678 Py_ssize_t start, len, bytelen;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000679 Py_buffer srcview;
680 Py_buffer *view = &(self->view);
681 char *srcbuf, *destbuf;
682
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000683 CHECK_RELEASED_INT(self);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000684 if (view->readonly) {
685 PyErr_SetString(PyExc_TypeError,
686 "cannot modify read-only memory");
687 return -1;
688 }
Antoine Pitroue0793ba2010-09-01 21:14:16 +0000689 if (value == NULL) {
690 PyErr_SetString(PyExc_TypeError,
691 "cannot delete memory");
692 return -1;
693 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000694 if (view->ndim != 1) {
695 PyErr_SetNone(PyExc_NotImplementedError);
696 return -1;
697 }
698 if (PyIndex_Check(key)) {
699 start = PyNumber_AsSsize_t(key, NULL);
700 if (start == -1 && PyErr_Occurred())
701 return -1;
702 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000703 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000704 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000705 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000706 PyErr_SetString(PyExc_IndexError,
707 "index out of bounds");
708 return -1;
709 }
710 len = 1;
711 }
712 else if (PySlice_Check(key)) {
713 Py_ssize_t stop, step;
714
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000715 if (PySlice_GetIndicesEx(key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000716 &start, &stop, &step, &len) < 0) {
717 return -1;
718 }
719 if (step != 1) {
720 PyErr_SetNone(PyExc_NotImplementedError);
721 return -1;
722 }
723 }
724 else {
725 PyErr_Format(PyExc_TypeError,
726 "cannot index memory using \"%.200s\"",
727 key->ob_type->tp_name);
728 return -1;
729 }
730 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
731 return -1;
732 }
733 /* XXX should we allow assignment of different item sizes
734 as long as the byte length is the same?
735 (e.g. assign 2 shorts to a 4-byte slice) */
736 if (srcview.itemsize != view->itemsize) {
737 PyErr_Format(PyExc_TypeError,
738 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
739 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
740 goto _error;
741 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000742 bytelen = len * view->itemsize;
743 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000744 PyErr_SetString(PyExc_ValueError,
745 "cannot modify size of memoryview object");
746 goto _error;
747 }
748 /* Do the actual copy */
749 destbuf = (char *) view->buf + start * view->itemsize;
750 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000751 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
752 /* No overlapping */
753 memcpy(destbuf, srcbuf, bytelen);
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000754 else
755 memmove(destbuf, srcbuf, bytelen);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000756
757 PyBuffer_Release(&srcview);
758 return 0;
759
760_error:
761 PyBuffer_Release(&srcview);
762 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000763}
764
Antoine Pitrou616d2852008-08-19 22:09:34 +0000765static PyObject *
766memory_richcompare(PyObject *v, PyObject *w, int op)
767{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000768 Py_buffer vv, ww;
769 int equal = 0;
770 PyObject *res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000771
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000772 vv.obj = NULL;
773 ww.obj = NULL;
774 if (op != Py_EQ && op != Py_NE)
775 goto _notimpl;
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000776 if ((PyMemoryView_Check(v) && IS_RELEASED(v)) ||
777 (PyMemoryView_Check(w) && IS_RELEASED(w))) {
778 equal = (v == w);
779 goto _end;
780 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000781 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
782 PyErr_Clear();
783 goto _notimpl;
784 }
785 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
786 PyErr_Clear();
787 goto _notimpl;
788 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000789
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000790 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
791 goto _end;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000792
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000793 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000794
795_end:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000796 PyBuffer_Release(&vv);
797 PyBuffer_Release(&ww);
798 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
799 res = Py_True;
800 else
801 res = Py_False;
802 Py_INCREF(res);
803 return res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000804
805_notimpl:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000806 PyBuffer_Release(&vv);
807 PyBuffer_Release(&ww);
Brian Curtindfc80e32011-08-10 20:28:54 -0500808 Py_RETURN_NOTIMPLEMENTED;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000809}
810
811
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000812static int
813memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
814{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000815 if (self->view.obj != NULL)
816 Py_VISIT(self->view.obj);
817 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000818}
819
820static int
821memory_clear(PyMemoryViewObject *self)
822{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000823 PyBuffer_Release(&self->view);
824 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000825}
826
827
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000828/* As mapping */
829static PyMappingMethods memory_as_mapping = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000830 (lenfunc)memory_length, /* mp_length */
831 (binaryfunc)memory_subscript, /* mp_subscript */
832 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000833};
834
Raymond Hettinger159eac92009-06-23 20:38:54 +0000835static PySequenceMethods memory_as_sequence = {
Alexander Belopolskyf0f45142010-08-11 17:31:17 +0000836 0, /* sq_length */
837 0, /* sq_concat */
838 0, /* sq_repeat */
839 (ssizeargfunc)memory_item, /* sq_item */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000840};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000841
842/* Buffer methods */
843
844static PyBufferProcs memory_as_buffer = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000845 (getbufferproc)memory_getbuf, /* bf_getbuffer */
846 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000847};
848
849
850PyTypeObject PyMemoryView_Type = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000851 PyVarObject_HEAD_INIT(&PyType_Type, 0)
852 "memoryview",
853 sizeof(PyMemoryViewObject),
854 0,
855 (destructor)memory_dealloc, /* tp_dealloc */
856 0, /* tp_print */
857 0, /* tp_getattr */
858 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000859 0, /* tp_reserved */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000860 (reprfunc)memory_repr, /* tp_repr */
861 0, /* tp_as_number */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000862 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000863 &memory_as_mapping, /* tp_as_mapping */
Antoine Pitrouce4a9da2011-11-21 20:46:33 +0100864 (hashfunc)memory_hash, /* tp_hash */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000865 0, /* tp_call */
Benjamin Peterson87618552009-02-08 15:00:52 +0000866 0, /* tp_str */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000867 PyObject_GenericGetAttr, /* tp_getattro */
868 0, /* tp_setattro */
869 &memory_as_buffer, /* tp_as_buffer */
870 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
871 memory_doc, /* tp_doc */
872 (traverseproc)memory_traverse, /* tp_traverse */
873 (inquiry)memory_clear, /* tp_clear */
874 memory_richcompare, /* tp_richcompare */
875 0, /* tp_weaklistoffset */
876 0, /* tp_iter */
877 0, /* tp_iternext */
878 memory_methods, /* tp_methods */
879 0, /* tp_members */
880 memory_getsetlist, /* tp_getset */
881 0, /* tp_base */
882 0, /* tp_dict */
883 0, /* tp_descr_get */
884 0, /* tp_descr_set */
885 0, /* tp_dictoffset */
886 0, /* tp_init */
887 0, /* tp_alloc */
888 memory_new, /* tp_new */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000889};