blob: 7acd569d73bf4e5160bc47dbac735b11a3f91619 [file] [log] [blame]
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001
2/* Memoryview object implementation */
3
4#include "Python.h"
5
Antoine Pitroubc420402008-12-07 20:14:49 +00006static Py_ssize_t
7get_shape0(Py_buffer *buf)
8{
9 if (buf->shape != NULL)
10 return buf->shape[0];
Antoine Pitrouc3b39242009-01-03 16:59:18 +000011 if (buf->ndim == 0)
12 return 1;
13 PyErr_SetString(PyExc_TypeError,
14 "exported buffer does not have any shape information associated "
15 "to it");
16 return -1;
17}
18
19static void
20dup_buffer(Py_buffer *dest, Py_buffer *src)
21{
22 *dest = *src;
23 if (src->ndim == 1 && src->shape != NULL) {
24 dest->shape = &(dest->smalltable[0]);
25 dest->shape[0] = get_shape0(src);
26 }
27 if (src->ndim == 1 && src->strides != NULL) {
28 dest->strides = &(dest->smalltable[1]);
29 dest->strides[0] = src->strides[0];
30 }
Antoine Pitroubc420402008-12-07 20:14:49 +000031}
32
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000033static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000034memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000035{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000036 int res = 0;
37 /* XXX for whatever reason fixing the flags seems necessary */
38 if (self->view.readonly)
39 flags &= ~PyBUF_WRITABLE;
40 if (self->view.obj != NULL)
41 res = PyObject_GetBuffer(self->view.obj, view, flags);
42 if (view)
43 dup_buffer(view, &self->view);
44 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000045}
46
47static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000048memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000049{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000050 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000051}
52
53PyDoc_STRVAR(memory_doc,
54"memoryview(object)\n\
55\n\
56Create a new memoryview object which references the given object.");
57
58PyObject *
Antoine Pitrouee58fa42008-08-19 18:22:14 +000059PyMemoryView_FromBuffer(Py_buffer *info)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000060{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000061 PyMemoryViewObject *mview;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000062
Antoine Pitrou35b7e832009-01-03 19:20:36 +000063 mview = (PyMemoryViewObject *)
64 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
65 if (mview == NULL)
66 return NULL;
67 mview->base = NULL;
68 dup_buffer(&mview->view, info);
69 /* NOTE: mview->view.obj should already have been incref'ed as
70 part of PyBuffer_FillInfo(). */
71 _PyObject_GC_TRACK(mview);
72 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000073}
74
75PyObject *
76PyMemoryView_FromObject(PyObject *base)
77{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000078 PyMemoryViewObject *mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000079
Antoine Pitrou35b7e832009-01-03 19:20:36 +000080 if (!PyObject_CheckBuffer(base)) {
81 PyErr_SetString(PyExc_TypeError,
82 "cannot make memory view because object does "
83 "not have the buffer interface");
84 return NULL;
85 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +000086
Antoine Pitrou35b7e832009-01-03 19:20:36 +000087 mview = (PyMemoryViewObject *)
88 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
89 if (mview == NULL)
90 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +000091
Antoine Pitrou35b7e832009-01-03 19:20:36 +000092 mview->base = NULL;
93 if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL_RO) < 0) {
94 Py_DECREF(mview);
95 return NULL;
96 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000097
Antoine Pitrou35b7e832009-01-03 19:20:36 +000098 mview->base = base;
99 Py_INCREF(base);
100 _PyObject_GC_TRACK(mview);
101 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000102}
103
104static PyObject *
105memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
106{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000107 PyObject *obj;
108 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000109
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000110 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
111 &obj)) {
112 return NULL;
113 }
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000114
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000115 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000116}
117
118
119static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000120_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +0000121 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000122{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000123 int k;
124 Py_ssize_t outstride;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000125
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000126 if (nd==0) {
127 memcpy(dest, src, itemsize);
128 }
129 else if (nd == 1) {
130 for (k = 0; k<shape[0]; k++) {
131 memcpy(dest, src, itemsize);
132 dest += itemsize;
133 src += strides[0];
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000134 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000135 }
136 else {
137 if (fort == 'F') {
138 /* Copy first dimension first,
139 second dimension second, etc...
140 Set up the recursive loop backwards so that final
141 dimension is actually copied last.
142 */
143 outstride = itemsize;
144 for (k=1; k<nd-1;k++) {
145 outstride *= shape[k];
146 }
147 for (k=0; k<shape[nd-1]; k++) {
148 _strided_copy_nd(dest, src, nd-1, shape,
149 strides, itemsize, fort);
150 dest += outstride;
151 src += strides[nd-1];
152 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000153 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000154
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000155 else {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000156 /* Copy last dimension first,
157 second-to-last dimension second, etc.
158 Set up the recursion so that the
159 first dimension is copied last
160 */
161 outstride = itemsize;
162 for (k=1; k < nd; k++) {
163 outstride *= shape[k];
164 }
165 for (k=0; k<shape[0]; k++) {
166 _strided_copy_nd(dest, src, nd-1, shape+1,
167 strides+1, itemsize,
168 fort);
169 dest += outstride;
170 src += strides[0];
171 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000172 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000173 }
174 return;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000175}
176
177void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
178void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
179
180static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000181_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000182{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000183 Py_ssize_t *indices;
184 int k;
185 Py_ssize_t elements;
186 char *ptr;
187 void (*func)(int, Py_ssize_t *, Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000188
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000189 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
190 PyErr_NoMemory();
191 return -1;
192 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000193
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000194 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
195 if (indices == NULL) {
196 PyErr_NoMemory();
197 return -1;
198 }
199 for (k=0; k<view->ndim;k++) {
200 indices[k] = 0;
201 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000202
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000203 elements = 1;
204 for (k=0; k<view->ndim; k++) {
205 elements *= view->shape[k];
206 }
207 if (fort == 'F') {
208 func = _add_one_to_index_F;
209 }
210 else {
211 func = _add_one_to_index_C;
212 }
213 while (elements--) {
214 func(view->ndim, indices, view->shape);
215 ptr = PyBuffer_GetPointer(view, indices);
216 memcpy(dest, ptr, view->itemsize);
217 dest += view->itemsize;
218 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000219
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000220 PyMem_Free(indices);
221 return 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000222}
223
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000224/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000225 Get a the data from an object as a contiguous chunk of memory (in
226 either 'C' or 'F'ortran order) even if it means copying it into a
227 separate memory area.
228
229 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000230 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000231 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000232 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000233
234 buffertype
235
236 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000237 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000238 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000239 a contiguous buffer if it is not. The view will point to
240 the shadow buffer which can be written to and then
241 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000242 view is de-allocated. While the shadow buffer is
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000243 being used, it will have an exclusive write lock on
244 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000245 */
246
247PyObject *
248PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
249{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000250 PyMemoryViewObject *mem;
251 PyObject *bytes;
252 Py_buffer *view;
253 int flags;
254 char *dest;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000255
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000256 if (!PyObject_CheckBuffer(obj)) {
257 PyErr_SetString(PyExc_TypeError,
Georg Brandl61b96dc2009-08-04 20:29:27 +0000258 "object does not support the buffer interface");
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000259 return NULL;
260 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000261
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000262 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
263 if (mem == NULL)
264 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000265
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000266 view = &mem->view;
267 flags = PyBUF_FULL_RO;
268 switch(buffertype) {
269 case PyBUF_WRITE:
270 flags = PyBUF_FULL;
271 break;
272 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000273
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000274 if (PyObject_GetBuffer(obj, view, flags) != 0) {
275 Py_DECREF(mem);
276 return NULL;
277 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000278
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000279 if (PyBuffer_IsContiguous(view, fort)) {
280 /* no copy needed */
281 Py_INCREF(obj);
282 mem->base = obj;
283 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000284 return (PyObject *)mem;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000285 }
286 /* otherwise a copy is needed */
287 if (buffertype == PyBUF_WRITE) {
288 Py_DECREF(mem);
289 PyErr_SetString(PyExc_BufferError,
290 "writable contiguous buffer requested "
291 "for a non-contiguousobject.");
292 return NULL;
293 }
294 bytes = PyBytes_FromStringAndSize(NULL, view->len);
295 if (bytes == NULL) {
296 Py_DECREF(mem);
297 return NULL;
298 }
299 dest = PyBytes_AS_STRING(bytes);
300 /* different copying strategy depending on whether
301 or not any pointer de-referencing is needed
302 */
303 /* strided or in-direct copy */
304 if (view->suboffsets==NULL) {
305 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
306 view->strides, view->itemsize, fort);
307 }
308 else {
309 if (_indirect_copy_nd(dest, view, fort) < 0) {
310 Py_DECREF(bytes);
311 Py_DECREF(mem);
312 return NULL;
313 }
314 }
315 if (buffertype == PyBUF_SHADOW) {
316 /* return a shadowed memory-view object */
317 view->buf = dest;
318 mem->base = PyTuple_Pack(2, obj, bytes);
319 Py_DECREF(bytes);
320 if (mem->base == NULL) {
321 Py_DECREF(mem);
322 return NULL;
323 }
324 }
325 else {
326 PyBuffer_Release(view); /* XXX ? */
327 /* steal the reference */
328 mem->base = bytes;
329 }
330 _PyObject_GC_TRACK(mem);
331 return (PyObject *)mem;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000332}
333
334
335static PyObject *
336memory_format_get(PyMemoryViewObject *self)
337{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000338 return PyUnicode_FromString(self->view.format);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000339}
340
341static PyObject *
342memory_itemsize_get(PyMemoryViewObject *self)
343{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000344 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000345}
346
347static PyObject *
348_IntTupleFromSsizet(int len, Py_ssize_t *vals)
349{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000350 int i;
351 PyObject *o;
352 PyObject *intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000353
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000354 if (vals == NULL) {
355 Py_INCREF(Py_None);
356 return Py_None;
357 }
358 intTuple = PyTuple_New(len);
359 if (!intTuple) return NULL;
360 for(i=0; i<len; i++) {
361 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 Pitrou35b7e832009-01-03 19:20:36 +0000374 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000375}
376
377static PyObject *
378memory_strides_get(PyMemoryViewObject *self)
379{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000380 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000381}
382
383static PyObject *
384memory_suboffsets_get(PyMemoryViewObject *self)
385{
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 Pitrou35b7e832009-01-03 19:20:36 +0000392 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000393}
394
395static PyObject *
396memory_ndim_get(PyMemoryViewObject *self)
397{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000398 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000399}
400
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000401static PyGetSetDef memory_getsetlist[] ={
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000402 {"format", (getter)memory_format_get, NULL, NULL},
403 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
404 {"shape", (getter)memory_shape_get, NULL, NULL},
405 {"strides", (getter)memory_strides_get, NULL, NULL},
406 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
407 {"readonly", (getter)memory_readonly_get, NULL, NULL},
408 {"ndim", (getter)memory_ndim_get, NULL, NULL},
409 {NULL, NULL, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000410};
411
412
413static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000414memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000415{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000416 return PyObject_CallFunctionObjArgs(
417 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000418}
419
Antoine Pitrou616d2852008-08-19 22:09:34 +0000420/* TODO: rewrite this function using the struct module to unpack
421 each buffer item */
422
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000423static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000424memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000425{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000426 Py_buffer *view = &(mem->view);
427 Py_ssize_t i;
428 PyObject *res, *item;
429 char *buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000430
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000431 if (strcmp(view->format, "B") || view->itemsize != 1) {
432 PyErr_SetString(PyExc_NotImplementedError,
433 "tolist() only supports byte views");
434 return NULL;
435 }
436 if (view->ndim != 1) {
437 PyErr_SetString(PyExc_NotImplementedError,
438 "tolist() only supports one-dimensional objects");
439 return NULL;
440 }
441 res = PyList_New(view->len);
442 if (res == NULL)
443 return NULL;
444 buf = view->buf;
445 for (i = 0; i < view->len; i++) {
446 item = PyLong_FromUnsignedLong((unsigned char) *buf);
447 if (item == NULL) {
448 Py_DECREF(res);
449 return NULL;
450 }
451 PyList_SET_ITEM(res, i, item);
452 buf++;
453 }
454 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000455}
456
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000457static PyMethodDef memory_methods[] = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000458 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
459 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
460 {NULL, NULL} /* sentinel */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000461};
462
463
464static void
465memory_dealloc(PyMemoryViewObject *self)
466{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000467 _PyObject_GC_UNTRACK(self);
468 if (self->view.obj != NULL) {
469 if (self->base && PyTuple_Check(self->base)) {
470 /* Special case when first element is generic object
471 with buffer interface and the second element is a
472 contiguous "shadow" that must be copied back into
473 the data areay of the first tuple element before
474 releasing the buffer on the first element.
475 */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000476
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000477 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
478 PyTuple_GET_ITEM(self->base,1));
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000479
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000480 /* The view member should have readonly == -1 in
481 this instance indicating that the memory can
482 be "locked" and was locked and will be unlocked
483 again after this call.
484 */
485 PyBuffer_Release(&(self->view));
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000486 }
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000487 else {
488 PyBuffer_Release(&(self->view));
489 }
490 Py_CLEAR(self->base);
491 }
492 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000493}
494
495static PyObject *
496memory_repr(PyMemoryViewObject *self)
497{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000498 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000499}
500
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000501/* Sequence methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000502static Py_ssize_t
503memory_length(PyMemoryViewObject *self)
504{
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000505 return get_shape0(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000506}
507
Raymond Hettinger159eac92009-06-23 20:38:54 +0000508/* Alternate version of memory_subcript that only accepts indices.
509 Used by PySeqIter_New().
510*/
511static PyObject *
512memory_item(PyMemoryViewObject *self, Py_ssize_t result)
513{
514 Py_buffer *view = &(self->view);
515
516 if (view->ndim == 0) {
517 PyErr_SetString(PyExc_IndexError,
518 "invalid indexing of 0-dim memory");
519 return NULL;
520 }
521 if (view->ndim == 1) {
522 /* Return a bytes object */
523 char *ptr;
524 ptr = (char *)view->buf;
525 if (result < 0) {
526 result += get_shape0(view);
527 }
528 if ((result < 0) || (result >= get_shape0(view))) {
529 PyErr_SetString(PyExc_IndexError,
530 "index out of bounds");
531 return NULL;
532 }
533 if (view->strides == NULL)
534 ptr += view->itemsize * result;
535 else
536 ptr += view->strides[0] * result;
537 if (view->suboffsets != NULL &&
538 view->suboffsets[0] >= 0) {
539 ptr = *((char **)ptr) + view->suboffsets[0];
540 }
541 return PyBytes_FromStringAndSize(ptr, view->itemsize);
542 } else {
543 /* Return a new memory-view object */
544 Py_buffer newview;
545 memset(&newview, 0, sizeof(newview));
546 /* XXX: This needs to be fixed so it actually returns a sub-view */
547 return PyMemoryView_FromBuffer(&newview);
548 }
549}
550
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000551/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000552 mem[obj] returns a bytes object holding the data for one element if
553 obj fully indexes the memory view or another memory-view object
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000554 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000555
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000556 0-d memory-view objects can be referenced using ... or () but
557 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000558 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000559static PyObject *
560memory_subscript(PyMemoryViewObject *self, PyObject *key)
561{
Antoine Pitroubc420402008-12-07 20:14:49 +0000562 Py_buffer *view;
563 view = &(self->view);
564
565 if (view->ndim == 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000566 if (key == Py_Ellipsis ||
567 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
568 Py_INCREF(self);
569 return (PyObject *)self;
570 }
571 else {
572 PyErr_SetString(PyExc_IndexError,
573 "invalid indexing of 0-dim memory");
574 return NULL;
575 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000576 }
577 if (PyIndex_Check(key)) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000578 Py_ssize_t result;
579 result = PyNumber_AsSsize_t(key, NULL);
580 if (result == -1 && PyErr_Occurred())
581 return NULL;
Raymond Hettinger159eac92009-06-23 20:38:54 +0000582 return memory_item(self, result);
Antoine Pitroubc420402008-12-07 20:14:49 +0000583 }
584 else if (PySlice_Check(key)) {
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000585 Py_ssize_t start, stop, step, slicelength;
586
Antoine Pitroubc420402008-12-07 20:14:49 +0000587 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000588 &start, &stop, &step, &slicelength) < 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000589 return NULL;
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000590 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000591
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000592 if (step == 1 && view->ndim == 1) {
593 Py_buffer newview;
594 void *newbuf = (char *) view->buf
595 + start * view->itemsize;
596 int newflags = view->readonly
597 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
Antoine Pitroubc420402008-12-07 20:14:49 +0000598
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000599 /* XXX There should be an API to create a subbuffer */
600 if (view->obj != NULL) {
601 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
602 return NULL;
603 }
604 else {
605 newview = *view;
606 }
607 newview.buf = newbuf;
608 newview.len = slicelength * newview.itemsize;
609 newview.format = view->format;
610 newview.shape = &(newview.smalltable[0]);
611 newview.shape[0] = slicelength;
612 newview.strides = &(newview.itemsize);
613 return PyMemoryView_FromBuffer(&newview);
614 }
615 PyErr_SetNone(PyExc_NotImplementedError);
616 return NULL;
Antoine Pitroubc420402008-12-07 20:14:49 +0000617 }
618 PyErr_Format(PyExc_TypeError,
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000619 "cannot index memory using \"%.200s\"",
620 key->ob_type->tp_name);
Antoine Pitroubc420402008-12-07 20:14:49 +0000621 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000622}
623
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000624
625/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000626static int
627memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
628{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000629 Py_ssize_t start, len, bytelen, i;
630 Py_buffer srcview;
631 Py_buffer *view = &(self->view);
632 char *srcbuf, *destbuf;
633
634 if (view->readonly) {
635 PyErr_SetString(PyExc_TypeError,
636 "cannot modify read-only memory");
637 return -1;
638 }
639 if (view->ndim != 1) {
640 PyErr_SetNone(PyExc_NotImplementedError);
641 return -1;
642 }
643 if (PyIndex_Check(key)) {
644 start = PyNumber_AsSsize_t(key, NULL);
645 if (start == -1 && PyErr_Occurred())
646 return -1;
647 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000648 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000649 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000650 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000651 PyErr_SetString(PyExc_IndexError,
652 "index out of bounds");
653 return -1;
654 }
655 len = 1;
656 }
657 else if (PySlice_Check(key)) {
658 Py_ssize_t stop, step;
659
Antoine Pitroubc420402008-12-07 20:14:49 +0000660 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000661 &start, &stop, &step, &len) < 0) {
662 return -1;
663 }
664 if (step != 1) {
665 PyErr_SetNone(PyExc_NotImplementedError);
666 return -1;
667 }
668 }
669 else {
670 PyErr_Format(PyExc_TypeError,
671 "cannot index memory using \"%.200s\"",
672 key->ob_type->tp_name);
673 return -1;
674 }
675 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
676 return -1;
677 }
678 /* XXX should we allow assignment of different item sizes
679 as long as the byte length is the same?
680 (e.g. assign 2 shorts to a 4-byte slice) */
681 if (srcview.itemsize != view->itemsize) {
682 PyErr_Format(PyExc_TypeError,
683 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
684 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
685 goto _error;
686 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000687 bytelen = len * view->itemsize;
688 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000689 PyErr_SetString(PyExc_ValueError,
690 "cannot modify size of memoryview object");
691 goto _error;
692 }
693 /* Do the actual copy */
694 destbuf = (char *) view->buf + start * view->itemsize;
695 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000696 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
697 /* No overlapping */
698 memcpy(destbuf, srcbuf, bytelen);
699 else if (destbuf < srcbuf) {
700 /* Copy in ascending order */
701 for (i = 0; i < bytelen; i++)
702 destbuf[i] = srcbuf[i];
703 }
704 else {
705 /* Copy in descencing order */
706 for (i = bytelen - 1; i >= 0; i--)
707 destbuf[i] = srcbuf[i];
708 }
709
710 PyBuffer_Release(&srcview);
711 return 0;
712
713_error:
714 PyBuffer_Release(&srcview);
715 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000716}
717
Antoine Pitrou616d2852008-08-19 22:09:34 +0000718static PyObject *
719memory_richcompare(PyObject *v, PyObject *w, int op)
720{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000721 Py_buffer vv, ww;
722 int equal = 0;
723 PyObject *res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000724
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000725 vv.obj = NULL;
726 ww.obj = NULL;
727 if (op != Py_EQ && op != Py_NE)
728 goto _notimpl;
729 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
730 PyErr_Clear();
731 goto _notimpl;
732 }
733 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
734 PyErr_Clear();
735 goto _notimpl;
736 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000737
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000738 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
739 goto _end;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000740
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000741 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000742
743_end:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000744 PyBuffer_Release(&vv);
745 PyBuffer_Release(&ww);
746 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
747 res = Py_True;
748 else
749 res = Py_False;
750 Py_INCREF(res);
751 return res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000752
753_notimpl:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000754 PyBuffer_Release(&vv);
755 PyBuffer_Release(&ww);
756 Py_INCREF(Py_NotImplemented);
757 return Py_NotImplemented;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000758}
759
760
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000761static int
762memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
763{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000764 if (self->base != NULL)
765 Py_VISIT(self->base);
766 if (self->view.obj != NULL)
767 Py_VISIT(self->view.obj);
768 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000769}
770
771static int
772memory_clear(PyMemoryViewObject *self)
773{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000774 Py_CLEAR(self->base);
775 PyBuffer_Release(&self->view);
776 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000777}
778
779
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000780/* As mapping */
781static PyMappingMethods memory_as_mapping = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000782 (lenfunc)memory_length, /* mp_length */
783 (binaryfunc)memory_subscript, /* mp_subscript */
784 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000785};
786
Raymond Hettinger159eac92009-06-23 20:38:54 +0000787static PySequenceMethods memory_as_sequence = {
788 0, /* sq_length */
789 0, /* sq_concat */
790 0, /* sq_repeat */
791 (ssizeargfunc)memory_item, /* sq_item */
792};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000793
794/* Buffer methods */
795
796static PyBufferProcs memory_as_buffer = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000797 (getbufferproc)memory_getbuf, /* bf_getbuffer */
798 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000799};
800
801
802PyTypeObject PyMemoryView_Type = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000803 PyVarObject_HEAD_INIT(&PyType_Type, 0)
804 "memoryview",
805 sizeof(PyMemoryViewObject),
806 0,
807 (destructor)memory_dealloc, /* tp_dealloc */
808 0, /* tp_print */
809 0, /* tp_getattr */
810 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000811 0, /* tp_reserved */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000812 (reprfunc)memory_repr, /* tp_repr */
813 0, /* tp_as_number */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000814 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000815 &memory_as_mapping, /* tp_as_mapping */
816 0, /* tp_hash */
817 0, /* tp_call */
Benjamin Peterson87618552009-02-08 15:00:52 +0000818 0, /* tp_str */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000819 PyObject_GenericGetAttr, /* tp_getattro */
820 0, /* tp_setattro */
821 &memory_as_buffer, /* tp_as_buffer */
822 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
823 memory_doc, /* tp_doc */
824 (traverseproc)memory_traverse, /* tp_traverse */
825 (inquiry)memory_clear, /* tp_clear */
826 memory_richcompare, /* tp_richcompare */
827 0, /* tp_weaklistoffset */
828 0, /* tp_iter */
829 0, /* tp_iternext */
830 memory_methods, /* tp_methods */
831 0, /* tp_members */
832 memory_getsetlist, /* tp_getset */
833 0, /* tp_base */
834 0, /* tp_dict */
835 0, /* tp_descr_get */
836 0, /* tp_descr_set */
837 0, /* tp_dictoffset */
838 0, /* tp_init */
839 0, /* tp_alloc */
840 memory_new, /* tp_new */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000841};