blob: 9b77ea726c1793ed0e2444acb4373bc01450f1fa [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;
Antoine Pitrou35b7e832009-01-03 19:20:36 +000037 if (self->view.obj != NULL)
38 res = PyObject_GetBuffer(self->view.obj, view, flags);
39 if (view)
40 dup_buffer(view, &self->view);
41 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000042}
43
44static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000045memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000046{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000047 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000048}
49
50PyDoc_STRVAR(memory_doc,
51"memoryview(object)\n\
52\n\
53Create a new memoryview object which references the given object.");
54
55PyObject *
Antoine Pitrouee58fa42008-08-19 18:22:14 +000056PyMemoryView_FromBuffer(Py_buffer *info)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000057{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000058 PyMemoryViewObject *mview;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000059
Antoine Pitrou35b7e832009-01-03 19:20:36 +000060 mview = (PyMemoryViewObject *)
61 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
62 if (mview == NULL)
63 return NULL;
64 mview->base = NULL;
65 dup_buffer(&mview->view, info);
66 /* NOTE: mview->view.obj should already have been incref'ed as
67 part of PyBuffer_FillInfo(). */
68 _PyObject_GC_TRACK(mview);
69 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000070}
71
72PyObject *
73PyMemoryView_FromObject(PyObject *base)
74{
Antoine Pitrou35b7e832009-01-03 19:20:36 +000075 PyMemoryViewObject *mview;
Antoine Pitrou93368182010-02-02 22:51:34 +000076 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000077
Antoine Pitrou35b7e832009-01-03 19:20:36 +000078 if (!PyObject_CheckBuffer(base)) {
79 PyErr_SetString(PyExc_TypeError,
80 "cannot make memory view because object does "
81 "not have the buffer interface");
82 return NULL;
83 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +000084
Antoine Pitrou93368182010-02-02 22:51:34 +000085 if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)
Antoine Pitrou35b7e832009-01-03 19:20:36 +000086 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +000087
Antoine Pitrou93368182010-02-02 22:51:34 +000088 mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);
89 if (mview == NULL) {
90 PyBuffer_Release(&view);
Antoine Pitrou35b7e832009-01-03 19:20:36 +000091 return NULL;
92 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000093
Antoine Pitrou35b7e832009-01-03 19:20:36 +000094 mview->base = base;
95 Py_INCREF(base);
Antoine Pitrou35b7e832009-01-03 19:20:36 +000096 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000097}
98
99static PyObject *
100memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
101{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000102 PyObject *obj;
103 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000104
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000105 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
106 &obj)) {
107 return NULL;
108 }
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000109
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000110 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000111}
112
113
114static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000115_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +0000116 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000117{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000118 int k;
119 Py_ssize_t outstride;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000120
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000121 if (nd==0) {
122 memcpy(dest, src, itemsize);
123 }
124 else if (nd == 1) {
125 for (k = 0; k<shape[0]; k++) {
126 memcpy(dest, src, itemsize);
127 dest += itemsize;
128 src += strides[0];
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000129 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000130 }
131 else {
132 if (fort == 'F') {
133 /* Copy first dimension first,
134 second dimension second, etc...
135 Set up the recursive loop backwards so that final
136 dimension is actually copied last.
137 */
138 outstride = itemsize;
139 for (k=1; k<nd-1;k++) {
140 outstride *= shape[k];
141 }
142 for (k=0; k<shape[nd-1]; k++) {
143 _strided_copy_nd(dest, src, nd-1, shape,
144 strides, itemsize, fort);
145 dest += outstride;
146 src += strides[nd-1];
147 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000148 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000149
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000150 else {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000151 /* Copy last dimension first,
152 second-to-last dimension second, etc.
153 Set up the recursion so that the
154 first dimension is copied last
155 */
156 outstride = itemsize;
157 for (k=1; k < nd; k++) {
158 outstride *= shape[k];
159 }
160 for (k=0; k<shape[0]; k++) {
161 _strided_copy_nd(dest, src, nd-1, shape+1,
162 strides+1, itemsize,
163 fort);
164 dest += outstride;
165 src += strides[0];
166 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000167 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000168 }
169 return;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000170}
171
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000172static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000173_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000174{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000175 Py_ssize_t *indices;
176 int k;
177 Py_ssize_t elements;
178 char *ptr;
Antoine Pitrouf43f65b2010-09-01 21:16:10 +0000179 void (*func)(int, Py_ssize_t *, const Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000180
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000181 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
182 PyErr_NoMemory();
183 return -1;
184 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000185
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000186 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
187 if (indices == NULL) {
188 PyErr_NoMemory();
189 return -1;
190 }
191 for (k=0; k<view->ndim;k++) {
192 indices[k] = 0;
193 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000194
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000195 elements = 1;
196 for (k=0; k<view->ndim; k++) {
197 elements *= view->shape[k];
198 }
199 if (fort == 'F') {
Antoine Pitroub83df8f2010-09-01 13:01:35 +0000200 func = _Py_add_one_to_index_F;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000201 }
202 else {
Antoine Pitroub83df8f2010-09-01 13:01:35 +0000203 func = _Py_add_one_to_index_C;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000204 }
205 while (elements--) {
206 func(view->ndim, indices, view->shape);
207 ptr = PyBuffer_GetPointer(view, indices);
208 memcpy(dest, ptr, view->itemsize);
209 dest += view->itemsize;
210 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000211
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000212 PyMem_Free(indices);
213 return 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000214}
215
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000216/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000217 Get a the data from an object as a contiguous chunk of memory (in
218 either 'C' or 'F'ortran order) even if it means copying it into a
219 separate memory area.
220
221 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000222 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000223 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000224 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000225
226 buffertype
227
228 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000229 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000230 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000231 a contiguous buffer if it is not. The view will point to
232 the shadow buffer which can be written to and then
233 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000234 view is de-allocated. While the shadow buffer is
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000235 being used, it will have an exclusive write lock on
236 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000237 */
238
239PyObject *
240PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
241{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000242 PyMemoryViewObject *mem;
243 PyObject *bytes;
244 Py_buffer *view;
245 int flags;
246 char *dest;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000247
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000248 if (!PyObject_CheckBuffer(obj)) {
249 PyErr_SetString(PyExc_TypeError,
Georg Brandlc5605df2009-08-13 08:26:44 +0000250 "object does not support the buffer interface");
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000251 return NULL;
252 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000253
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000254 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
255 if (mem == NULL)
256 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000257
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000258 view = &mem->view;
259 flags = PyBUF_FULL_RO;
260 switch(buffertype) {
261 case PyBUF_WRITE:
262 flags = PyBUF_FULL;
263 break;
264 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000265
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000266 if (PyObject_GetBuffer(obj, view, flags) != 0) {
267 Py_DECREF(mem);
268 return NULL;
269 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000270
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000271 if (PyBuffer_IsContiguous(view, fort)) {
272 /* no copy needed */
273 Py_INCREF(obj);
274 mem->base = obj;
275 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000276 return (PyObject *)mem;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000277 }
278 /* otherwise a copy is needed */
279 if (buffertype == PyBUF_WRITE) {
280 Py_DECREF(mem);
281 PyErr_SetString(PyExc_BufferError,
282 "writable contiguous buffer requested "
283 "for a non-contiguousobject.");
284 return NULL;
285 }
286 bytes = PyBytes_FromStringAndSize(NULL, view->len);
287 if (bytes == NULL) {
288 Py_DECREF(mem);
289 return NULL;
290 }
291 dest = PyBytes_AS_STRING(bytes);
292 /* different copying strategy depending on whether
293 or not any pointer de-referencing is needed
294 */
295 /* strided or in-direct copy */
296 if (view->suboffsets==NULL) {
297 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
298 view->strides, view->itemsize, fort);
299 }
300 else {
301 if (_indirect_copy_nd(dest, view, fort) < 0) {
302 Py_DECREF(bytes);
303 Py_DECREF(mem);
304 return NULL;
305 }
306 }
307 if (buffertype == PyBUF_SHADOW) {
308 /* return a shadowed memory-view object */
309 view->buf = dest;
310 mem->base = PyTuple_Pack(2, obj, bytes);
311 Py_DECREF(bytes);
312 if (mem->base == NULL) {
313 Py_DECREF(mem);
314 return NULL;
315 }
316 }
317 else {
318 PyBuffer_Release(view); /* XXX ? */
319 /* steal the reference */
320 mem->base = bytes;
321 }
322 _PyObject_GC_TRACK(mem);
323 return (PyObject *)mem;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000324}
325
326
327static PyObject *
328memory_format_get(PyMemoryViewObject *self)
329{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000330 return PyUnicode_FromString(self->view.format);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000331}
332
333static PyObject *
334memory_itemsize_get(PyMemoryViewObject *self)
335{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000336 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000337}
338
339static PyObject *
340_IntTupleFromSsizet(int len, Py_ssize_t *vals)
341{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000342 int i;
343 PyObject *o;
344 PyObject *intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000345
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000346 if (vals == NULL) {
347 Py_INCREF(Py_None);
348 return Py_None;
349 }
350 intTuple = PyTuple_New(len);
351 if (!intTuple) return NULL;
352 for(i=0; i<len; i++) {
353 o = PyLong_FromSsize_t(vals[i]);
354 if (!o) {
355 Py_DECREF(intTuple);
356 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000357 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000358 PyTuple_SET_ITEM(intTuple, i, o);
359 }
360 return intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000361}
362
363static PyObject *
364memory_shape_get(PyMemoryViewObject *self)
365{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000366 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000367}
368
369static PyObject *
370memory_strides_get(PyMemoryViewObject *self)
371{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000372 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000373}
374
375static PyObject *
376memory_suboffsets_get(PyMemoryViewObject *self)
377{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000378 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000379}
380
381static PyObject *
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000382memory_readonly_get(PyMemoryViewObject *self)
383{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000384 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000385}
386
387static PyObject *
388memory_ndim_get(PyMemoryViewObject *self)
389{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000390 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000391}
392
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000393static PyGetSetDef memory_getsetlist[] ={
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000394 {"format", (getter)memory_format_get, NULL, NULL},
395 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
396 {"shape", (getter)memory_shape_get, NULL, NULL},
397 {"strides", (getter)memory_strides_get, NULL, NULL},
398 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
399 {"readonly", (getter)memory_readonly_get, NULL, NULL},
400 {"ndim", (getter)memory_ndim_get, NULL, NULL},
401 {NULL, NULL, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000402};
403
404
405static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000406memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000407{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000408 return PyObject_CallFunctionObjArgs(
409 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000410}
411
Antoine Pitrou616d2852008-08-19 22:09:34 +0000412/* TODO: rewrite this function using the struct module to unpack
413 each buffer item */
414
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000415static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000416memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000417{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000418 Py_buffer *view = &(mem->view);
419 Py_ssize_t i;
420 PyObject *res, *item;
421 char *buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000422
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000423 if (strcmp(view->format, "B") || view->itemsize != 1) {
424 PyErr_SetString(PyExc_NotImplementedError,
425 "tolist() only supports byte views");
426 return NULL;
427 }
428 if (view->ndim != 1) {
429 PyErr_SetString(PyExc_NotImplementedError,
430 "tolist() only supports one-dimensional objects");
431 return NULL;
432 }
433 res = PyList_New(view->len);
434 if (res == NULL)
435 return NULL;
436 buf = view->buf;
437 for (i = 0; i < view->len; i++) {
438 item = PyLong_FromUnsignedLong((unsigned char) *buf);
439 if (item == NULL) {
440 Py_DECREF(res);
441 return NULL;
442 }
443 PyList_SET_ITEM(res, i, item);
444 buf++;
445 }
446 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000447}
448
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000449static PyMethodDef memory_methods[] = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000450 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
451 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
452 {NULL, NULL} /* sentinel */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000453};
454
455
456static void
457memory_dealloc(PyMemoryViewObject *self)
458{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000459 _PyObject_GC_UNTRACK(self);
460 if (self->view.obj != NULL) {
461 if (self->base && PyTuple_Check(self->base)) {
462 /* Special case when first element is generic object
463 with buffer interface and the second element is a
464 contiguous "shadow" that must be copied back into
465 the data areay of the first tuple element before
466 releasing the buffer on the first element.
467 */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000468
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000469 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
470 PyTuple_GET_ITEM(self->base,1));
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000471
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000472 /* The view member should have readonly == -1 in
473 this instance indicating that the memory can
474 be "locked" and was locked and will be unlocked
475 again after this call.
476 */
477 PyBuffer_Release(&(self->view));
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000478 }
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000479 else {
480 PyBuffer_Release(&(self->view));
481 }
482 Py_CLEAR(self->base);
483 }
484 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000485}
486
487static PyObject *
488memory_repr(PyMemoryViewObject *self)
489{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000490 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000491}
492
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000493/* Sequence methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000494static Py_ssize_t
495memory_length(PyMemoryViewObject *self)
496{
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000497 return get_shape0(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000498}
499
Raymond Hettinger159eac92009-06-23 20:38:54 +0000500/* Alternate version of memory_subcript that only accepts indices.
501 Used by PySeqIter_New().
502*/
503static PyObject *
504memory_item(PyMemoryViewObject *self, Py_ssize_t result)
505{
506 Py_buffer *view = &(self->view);
507
508 if (view->ndim == 0) {
509 PyErr_SetString(PyExc_IndexError,
510 "invalid indexing of 0-dim memory");
511 return NULL;
512 }
513 if (view->ndim == 1) {
514 /* Return a bytes object */
515 char *ptr;
516 ptr = (char *)view->buf;
517 if (result < 0) {
518 result += get_shape0(view);
519 }
520 if ((result < 0) || (result >= get_shape0(view))) {
521 PyErr_SetString(PyExc_IndexError,
522 "index out of bounds");
523 return NULL;
524 }
525 if (view->strides == NULL)
526 ptr += view->itemsize * result;
527 else
528 ptr += view->strides[0] * result;
529 if (view->suboffsets != NULL &&
530 view->suboffsets[0] >= 0) {
531 ptr = *((char **)ptr) + view->suboffsets[0];
532 }
533 return PyBytes_FromStringAndSize(ptr, view->itemsize);
534 } else {
535 /* Return a new memory-view object */
536 Py_buffer newview;
537 memset(&newview, 0, sizeof(newview));
538 /* XXX: This needs to be fixed so it actually returns a sub-view */
539 return PyMemoryView_FromBuffer(&newview);
540 }
541}
542
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000543/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000544 mem[obj] returns a bytes object holding the data for one element if
545 obj fully indexes the memory view or another memory-view object
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000546 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000547
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000548 0-d memory-view objects can be referenced using ... or () but
549 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000550 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000551static PyObject *
552memory_subscript(PyMemoryViewObject *self, PyObject *key)
553{
Antoine Pitroubc420402008-12-07 20:14:49 +0000554 Py_buffer *view;
555 view = &(self->view);
556
557 if (view->ndim == 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000558 if (key == Py_Ellipsis ||
559 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
560 Py_INCREF(self);
561 return (PyObject *)self;
562 }
563 else {
564 PyErr_SetString(PyExc_IndexError,
565 "invalid indexing of 0-dim memory");
566 return NULL;
567 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000568 }
569 if (PyIndex_Check(key)) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000570 Py_ssize_t result;
571 result = PyNumber_AsSsize_t(key, NULL);
572 if (result == -1 && PyErr_Occurred())
573 return NULL;
Raymond Hettinger159eac92009-06-23 20:38:54 +0000574 return memory_item(self, result);
Antoine Pitroubc420402008-12-07 20:14:49 +0000575 }
576 else if (PySlice_Check(key)) {
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000577 Py_ssize_t start, stop, step, slicelength;
578
Antoine Pitroubc420402008-12-07 20:14:49 +0000579 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000580 &start, &stop, &step, &slicelength) < 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000581 return NULL;
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000582 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000583
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000584 if (step == 1 && view->ndim == 1) {
585 Py_buffer newview;
586 void *newbuf = (char *) view->buf
587 + start * view->itemsize;
588 int newflags = view->readonly
589 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
Antoine Pitroubc420402008-12-07 20:14:49 +0000590
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000591 /* XXX There should be an API to create a subbuffer */
592 if (view->obj != NULL) {
593 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
594 return NULL;
595 }
596 else {
597 newview = *view;
598 }
599 newview.buf = newbuf;
600 newview.len = slicelength * newview.itemsize;
601 newview.format = view->format;
602 newview.shape = &(newview.smalltable[0]);
603 newview.shape[0] = slicelength;
604 newview.strides = &(newview.itemsize);
605 return PyMemoryView_FromBuffer(&newview);
606 }
607 PyErr_SetNone(PyExc_NotImplementedError);
608 return NULL;
Antoine Pitroubc420402008-12-07 20:14:49 +0000609 }
610 PyErr_Format(PyExc_TypeError,
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000611 "cannot index memory using \"%.200s\"",
612 key->ob_type->tp_name);
Antoine Pitroubc420402008-12-07 20:14:49 +0000613 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000614}
615
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000616
617/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000618static int
619memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
620{
Antoine Pitroudedbbe62010-07-11 12:15:03 +0000621 Py_ssize_t start, len, bytelen;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000622 Py_buffer srcview;
623 Py_buffer *view = &(self->view);
624 char *srcbuf, *destbuf;
625
626 if (view->readonly) {
627 PyErr_SetString(PyExc_TypeError,
628 "cannot modify read-only memory");
629 return -1;
630 }
Antoine Pitrouf43f65b2010-09-01 21:16:10 +0000631 if (value == NULL) {
632 PyErr_SetString(PyExc_TypeError,
633 "cannot delete memory");
634 return -1;
635 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000636 if (view->ndim != 1) {
637 PyErr_SetNone(PyExc_NotImplementedError);
638 return -1;
639 }
640 if (PyIndex_Check(key)) {
641 start = PyNumber_AsSsize_t(key, NULL);
642 if (start == -1 && PyErr_Occurred())
643 return -1;
644 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000645 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000646 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000647 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000648 PyErr_SetString(PyExc_IndexError,
649 "index out of bounds");
650 return -1;
651 }
652 len = 1;
653 }
654 else if (PySlice_Check(key)) {
655 Py_ssize_t stop, step;
656
Antoine Pitroubc420402008-12-07 20:14:49 +0000657 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000658 &start, &stop, &step, &len) < 0) {
659 return -1;
660 }
661 if (step != 1) {
662 PyErr_SetNone(PyExc_NotImplementedError);
663 return -1;
664 }
665 }
666 else {
667 PyErr_Format(PyExc_TypeError,
668 "cannot index memory using \"%.200s\"",
669 key->ob_type->tp_name);
670 return -1;
671 }
672 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
673 return -1;
674 }
675 /* XXX should we allow assignment of different item sizes
676 as long as the byte length is the same?
677 (e.g. assign 2 shorts to a 4-byte slice) */
678 if (srcview.itemsize != view->itemsize) {
679 PyErr_Format(PyExc_TypeError,
680 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
681 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
682 goto _error;
683 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000684 bytelen = len * view->itemsize;
685 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000686 PyErr_SetString(PyExc_ValueError,
687 "cannot modify size of memoryview object");
688 goto _error;
689 }
690 /* Do the actual copy */
691 destbuf = (char *) view->buf + start * view->itemsize;
692 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000693 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
694 /* No overlapping */
695 memcpy(destbuf, srcbuf, bytelen);
Antoine Pitroudedbbe62010-07-11 12:15:03 +0000696 else
697 memmove(destbuf, srcbuf, bytelen);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000698
699 PyBuffer_Release(&srcview);
700 return 0;
701
702_error:
703 PyBuffer_Release(&srcview);
704 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000705}
706
Antoine Pitrou616d2852008-08-19 22:09:34 +0000707static PyObject *
708memory_richcompare(PyObject *v, PyObject *w, int op)
709{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000710 Py_buffer vv, ww;
711 int equal = 0;
712 PyObject *res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000713
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000714 vv.obj = NULL;
715 ww.obj = NULL;
716 if (op != Py_EQ && op != Py_NE)
717 goto _notimpl;
718 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
719 PyErr_Clear();
720 goto _notimpl;
721 }
722 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
723 PyErr_Clear();
724 goto _notimpl;
725 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000726
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000727 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
728 goto _end;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000729
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000730 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000731
732_end:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000733 PyBuffer_Release(&vv);
734 PyBuffer_Release(&ww);
735 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
736 res = Py_True;
737 else
738 res = Py_False;
739 Py_INCREF(res);
740 return res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000741
742_notimpl:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000743 PyBuffer_Release(&vv);
744 PyBuffer_Release(&ww);
745 Py_INCREF(Py_NotImplemented);
746 return Py_NotImplemented;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000747}
748
749
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000750static int
751memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
752{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000753 if (self->base != NULL)
754 Py_VISIT(self->base);
755 if (self->view.obj != NULL)
756 Py_VISIT(self->view.obj);
757 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000758}
759
760static int
761memory_clear(PyMemoryViewObject *self)
762{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000763 Py_CLEAR(self->base);
764 PyBuffer_Release(&self->view);
765 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000766}
767
768
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000769/* As mapping */
770static PyMappingMethods memory_as_mapping = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000771 (lenfunc)memory_length, /* mp_length */
772 (binaryfunc)memory_subscript, /* mp_subscript */
773 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000774};
775
Raymond Hettinger159eac92009-06-23 20:38:54 +0000776static PySequenceMethods memory_as_sequence = {
777 0, /* sq_length */
778 0, /* sq_concat */
779 0, /* sq_repeat */
780 (ssizeargfunc)memory_item, /* sq_item */
781};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000782
783/* Buffer methods */
784
785static PyBufferProcs memory_as_buffer = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000786 (getbufferproc)memory_getbuf, /* bf_getbuffer */
787 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000788};
789
790
791PyTypeObject PyMemoryView_Type = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000792 PyVarObject_HEAD_INIT(&PyType_Type, 0)
793 "memoryview",
794 sizeof(PyMemoryViewObject),
795 0,
796 (destructor)memory_dealloc, /* tp_dealloc */
797 0, /* tp_print */
798 0, /* tp_getattr */
799 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000800 0, /* tp_reserved */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000801 (reprfunc)memory_repr, /* tp_repr */
802 0, /* tp_as_number */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000803 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000804 &memory_as_mapping, /* tp_as_mapping */
805 0, /* tp_hash */
806 0, /* tp_call */
Benjamin Peterson87618552009-02-08 15:00:52 +0000807 0, /* tp_str */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000808 PyObject_GenericGetAttr, /* tp_getattro */
809 0, /* tp_setattro */
810 &memory_as_buffer, /* tp_as_buffer */
811 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
812 memory_doc, /* tp_doc */
813 (traverseproc)memory_traverse, /* tp_traverse */
814 (inquiry)memory_clear, /* tp_clear */
815 memory_richcompare, /* tp_richcompare */
816 0, /* tp_weaklistoffset */
817 0, /* tp_iter */
818 0, /* tp_iternext */
819 memory_methods, /* tp_methods */
820 0, /* tp_members */
821 memory_getsetlist, /* tp_getset */
822 0, /* tp_base */
823 0, /* tp_dict */
824 0, /* tp_descr_get */
825 0, /* tp_descr_set */
826 0, /* tp_dictoffset */
827 0, /* tp_init */
828 0, /* tp_alloc */
829 memory_new, /* tp_new */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000830};