blob: 5b3caf272c8b0a8e3fa9c38f8c6c95b114444375 [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;
Antoine Pitrou05b7c562010-02-02 22:47:00 +000079 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000080
Antoine Pitrou35b7e832009-01-03 19:20:36 +000081 if (!PyObject_CheckBuffer(base)) {
82 PyErr_SetString(PyExc_TypeError,
83 "cannot make memory view because object does "
84 "not have the buffer interface");
85 return NULL;
86 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +000087
Antoine Pitrou05b7c562010-02-02 22:47:00 +000088 if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)
Antoine Pitrou35b7e832009-01-03 19:20:36 +000089 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +000090
Antoine Pitrou05b7c562010-02-02 22:47:00 +000091 mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);
92 if (mview == NULL) {
93 PyBuffer_Release(&view);
Antoine Pitrou35b7e832009-01-03 19:20:36 +000094 return NULL;
95 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000096
Antoine Pitrou35b7e832009-01-03 19:20:36 +000097 mview->base = base;
98 Py_INCREF(base);
Antoine Pitrou35b7e832009-01-03 19:20:36 +000099 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000100}
101
102static PyObject *
103memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
104{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000105 PyObject *obj;
106 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000107
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000108 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
109 &obj)) {
110 return NULL;
111 }
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000112
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000113 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000114}
115
116
117static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000118_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +0000119 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000120{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000121 int k;
122 Py_ssize_t outstride;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000123
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000124 if (nd==0) {
125 memcpy(dest, src, itemsize);
126 }
127 else if (nd == 1) {
128 for (k = 0; k<shape[0]; k++) {
129 memcpy(dest, src, itemsize);
130 dest += itemsize;
131 src += strides[0];
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000132 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000133 }
134 else {
135 if (fort == 'F') {
136 /* Copy first dimension first,
137 second dimension second, etc...
138 Set up the recursive loop backwards so that final
139 dimension is actually copied last.
140 */
141 outstride = itemsize;
142 for (k=1; k<nd-1;k++) {
143 outstride *= shape[k];
144 }
145 for (k=0; k<shape[nd-1]; k++) {
146 _strided_copy_nd(dest, src, nd-1, shape,
147 strides, itemsize, fort);
148 dest += outstride;
149 src += strides[nd-1];
150 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000151 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000152
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000153 else {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000154 /* Copy last dimension first,
155 second-to-last dimension second, etc.
156 Set up the recursion so that the
157 first dimension is copied last
158 */
159 outstride = itemsize;
160 for (k=1; k < nd; k++) {
161 outstride *= shape[k];
162 }
163 for (k=0; k<shape[0]; k++) {
164 _strided_copy_nd(dest, src, nd-1, shape+1,
165 strides+1, itemsize,
166 fort);
167 dest += outstride;
168 src += strides[0];
169 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000170 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000171 }
172 return;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000173}
174
175void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
176void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
177
178static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000179_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000180{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000181 Py_ssize_t *indices;
182 int k;
183 Py_ssize_t elements;
184 char *ptr;
185 void (*func)(int, Py_ssize_t *, Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000186
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000187 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
188 PyErr_NoMemory();
189 return -1;
190 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000191
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000192 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
193 if (indices == NULL) {
194 PyErr_NoMemory();
195 return -1;
196 }
197 for (k=0; k<view->ndim;k++) {
198 indices[k] = 0;
199 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000200
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000201 elements = 1;
202 for (k=0; k<view->ndim; k++) {
203 elements *= view->shape[k];
204 }
205 if (fort == 'F') {
206 func = _add_one_to_index_F;
207 }
208 else {
209 func = _add_one_to_index_C;
210 }
211 while (elements--) {
212 func(view->ndim, indices, view->shape);
213 ptr = PyBuffer_GetPointer(view, indices);
214 memcpy(dest, ptr, view->itemsize);
215 dest += view->itemsize;
216 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000217
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000218 PyMem_Free(indices);
219 return 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000220}
221
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000222/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000223 Get a the data from an object as a contiguous chunk of memory (in
224 either 'C' or 'F'ortran order) even if it means copying it into a
225 separate memory area.
226
227 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000228 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000229 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000230 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000231
232 buffertype
233
234 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000235 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000236 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000237 a contiguous buffer if it is not. The view will point to
238 the shadow buffer which can be written to and then
239 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000240 view is de-allocated. While the shadow buffer is
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000241 being used, it will have an exclusive write lock on
242 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000243 */
244
245PyObject *
246PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
247{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000248 PyMemoryViewObject *mem;
249 PyObject *bytes;
250 Py_buffer *view;
251 int flags;
252 char *dest;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000253
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000254 if (!PyObject_CheckBuffer(obj)) {
255 PyErr_SetString(PyExc_TypeError,
Georg Brandl61b96dc2009-08-04 20:29:27 +0000256 "object does not support the buffer interface");
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000257 return NULL;
258 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000259
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000260 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
261 if (mem == NULL)
262 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000263
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000264 view = &mem->view;
265 flags = PyBUF_FULL_RO;
266 switch(buffertype) {
267 case PyBUF_WRITE:
268 flags = PyBUF_FULL;
269 break;
270 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000271
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000272 if (PyObject_GetBuffer(obj, view, flags) != 0) {
273 Py_DECREF(mem);
274 return NULL;
275 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000276
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000277 if (PyBuffer_IsContiguous(view, fort)) {
278 /* no copy needed */
279 Py_INCREF(obj);
280 mem->base = obj;
281 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000282 return (PyObject *)mem;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000283 }
284 /* otherwise a copy is needed */
285 if (buffertype == PyBUF_WRITE) {
286 Py_DECREF(mem);
287 PyErr_SetString(PyExc_BufferError,
288 "writable contiguous buffer requested "
289 "for a non-contiguousobject.");
290 return NULL;
291 }
292 bytes = PyBytes_FromStringAndSize(NULL, view->len);
293 if (bytes == NULL) {
294 Py_DECREF(mem);
295 return NULL;
296 }
297 dest = PyBytes_AS_STRING(bytes);
298 /* different copying strategy depending on whether
299 or not any pointer de-referencing is needed
300 */
301 /* strided or in-direct copy */
302 if (view->suboffsets==NULL) {
303 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
304 view->strides, view->itemsize, fort);
305 }
306 else {
307 if (_indirect_copy_nd(dest, view, fort) < 0) {
308 Py_DECREF(bytes);
309 Py_DECREF(mem);
310 return NULL;
311 }
312 }
313 if (buffertype == PyBUF_SHADOW) {
314 /* return a shadowed memory-view object */
315 view->buf = dest;
316 mem->base = PyTuple_Pack(2, obj, bytes);
317 Py_DECREF(bytes);
318 if (mem->base == NULL) {
319 Py_DECREF(mem);
320 return NULL;
321 }
322 }
323 else {
324 PyBuffer_Release(view); /* XXX ? */
325 /* steal the reference */
326 mem->base = bytes;
327 }
328 _PyObject_GC_TRACK(mem);
329 return (PyObject *)mem;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000330}
331
332
333static PyObject *
334memory_format_get(PyMemoryViewObject *self)
335{
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 Pitrou35b7e832009-01-03 19:20:36 +0000342 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000343}
344
345static PyObject *
346_IntTupleFromSsizet(int len, Py_ssize_t *vals)
347{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000348 int i;
349 PyObject *o;
350 PyObject *intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000351
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000352 if (vals == NULL) {
353 Py_INCREF(Py_None);
354 return Py_None;
355 }
356 intTuple = PyTuple_New(len);
357 if (!intTuple) return NULL;
358 for(i=0; i<len; i++) {
359 o = PyLong_FromSsize_t(vals[i]);
360 if (!o) {
361 Py_DECREF(intTuple);
362 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000363 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000364 PyTuple_SET_ITEM(intTuple, i, o);
365 }
366 return intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000367}
368
369static PyObject *
370memory_shape_get(PyMemoryViewObject *self)
371{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000372 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000373}
374
375static PyObject *
376memory_strides_get(PyMemoryViewObject *self)
377{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000378 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000379}
380
381static PyObject *
382memory_suboffsets_get(PyMemoryViewObject *self)
383{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000384 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000385}
386
387static PyObject *
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000388memory_readonly_get(PyMemoryViewObject *self)
389{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000390 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000391}
392
393static PyObject *
394memory_ndim_get(PyMemoryViewObject *self)
395{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000396 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000397}
398
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000399static PyGetSetDef memory_getsetlist[] ={
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000400 {"format", (getter)memory_format_get, NULL, NULL},
401 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
402 {"shape", (getter)memory_shape_get, NULL, NULL},
403 {"strides", (getter)memory_strides_get, NULL, NULL},
404 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
405 {"readonly", (getter)memory_readonly_get, NULL, NULL},
406 {"ndim", (getter)memory_ndim_get, NULL, NULL},
407 {NULL, NULL, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000408};
409
410
411static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000412memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000413{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000414 return PyObject_CallFunctionObjArgs(
415 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000416}
417
Antoine Pitrou616d2852008-08-19 22:09:34 +0000418/* TODO: rewrite this function using the struct module to unpack
419 each buffer item */
420
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000421static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000422memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000423{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000424 Py_buffer *view = &(mem->view);
425 Py_ssize_t i;
426 PyObject *res, *item;
427 char *buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000428
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000429 if (strcmp(view->format, "B") || view->itemsize != 1) {
430 PyErr_SetString(PyExc_NotImplementedError,
431 "tolist() only supports byte views");
432 return NULL;
433 }
434 if (view->ndim != 1) {
435 PyErr_SetString(PyExc_NotImplementedError,
436 "tolist() only supports one-dimensional objects");
437 return NULL;
438 }
439 res = PyList_New(view->len);
440 if (res == NULL)
441 return NULL;
442 buf = view->buf;
443 for (i = 0; i < view->len; i++) {
444 item = PyLong_FromUnsignedLong((unsigned char) *buf);
445 if (item == NULL) {
446 Py_DECREF(res);
447 return NULL;
448 }
449 PyList_SET_ITEM(res, i, item);
450 buf++;
451 }
452 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000453}
454
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000455static PyMethodDef memory_methods[] = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000456 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
457 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
458 {NULL, NULL} /* sentinel */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000459};
460
461
462static void
463memory_dealloc(PyMemoryViewObject *self)
464{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000465 _PyObject_GC_UNTRACK(self);
466 if (self->view.obj != NULL) {
467 if (self->base && PyTuple_Check(self->base)) {
468 /* Special case when first element is generic object
469 with buffer interface and the second element is a
470 contiguous "shadow" that must be copied back into
471 the data areay of the first tuple element before
472 releasing the buffer on the first element.
473 */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000474
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000475 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
476 PyTuple_GET_ITEM(self->base,1));
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000477
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000478 /* The view member should have readonly == -1 in
479 this instance indicating that the memory can
480 be "locked" and was locked and will be unlocked
481 again after this call.
482 */
483 PyBuffer_Release(&(self->view));
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000484 }
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000485 else {
486 PyBuffer_Release(&(self->view));
487 }
488 Py_CLEAR(self->base);
489 }
490 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000491}
492
493static PyObject *
494memory_repr(PyMemoryViewObject *self)
495{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000496 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000497}
498
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000499/* Sequence methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000500static Py_ssize_t
501memory_length(PyMemoryViewObject *self)
502{
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000503 return get_shape0(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000504}
505
Raymond Hettinger159eac92009-06-23 20:38:54 +0000506/* Alternate version of memory_subcript that only accepts indices.
507 Used by PySeqIter_New().
508*/
509static PyObject *
510memory_item(PyMemoryViewObject *self, Py_ssize_t result)
511{
512 Py_buffer *view = &(self->view);
513
514 if (view->ndim == 0) {
515 PyErr_SetString(PyExc_IndexError,
516 "invalid indexing of 0-dim memory");
517 return NULL;
518 }
519 if (view->ndim == 1) {
520 /* Return a bytes object */
521 char *ptr;
522 ptr = (char *)view->buf;
523 if (result < 0) {
524 result += get_shape0(view);
525 }
526 if ((result < 0) || (result >= get_shape0(view))) {
527 PyErr_SetString(PyExc_IndexError,
528 "index out of bounds");
529 return NULL;
530 }
531 if (view->strides == NULL)
532 ptr += view->itemsize * result;
533 else
534 ptr += view->strides[0] * result;
535 if (view->suboffsets != NULL &&
536 view->suboffsets[0] >= 0) {
537 ptr = *((char **)ptr) + view->suboffsets[0];
538 }
539 return PyBytes_FromStringAndSize(ptr, view->itemsize);
540 } else {
541 /* Return a new memory-view object */
542 Py_buffer newview;
543 memset(&newview, 0, sizeof(newview));
544 /* XXX: This needs to be fixed so it actually returns a sub-view */
545 return PyMemoryView_FromBuffer(&newview);
546 }
547}
548
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000549/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000550 mem[obj] returns a bytes object holding the data for one element if
551 obj fully indexes the memory view or another memory-view object
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000552 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000553
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000554 0-d memory-view objects can be referenced using ... or () but
555 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000556 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000557static PyObject *
558memory_subscript(PyMemoryViewObject *self, PyObject *key)
559{
Antoine Pitroubc420402008-12-07 20:14:49 +0000560 Py_buffer *view;
561 view = &(self->view);
562
563 if (view->ndim == 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000564 if (key == Py_Ellipsis ||
565 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
566 Py_INCREF(self);
567 return (PyObject *)self;
568 }
569 else {
570 PyErr_SetString(PyExc_IndexError,
571 "invalid indexing of 0-dim memory");
572 return NULL;
573 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000574 }
575 if (PyIndex_Check(key)) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000576 Py_ssize_t result;
577 result = PyNumber_AsSsize_t(key, NULL);
578 if (result == -1 && PyErr_Occurred())
579 return NULL;
Raymond Hettinger159eac92009-06-23 20:38:54 +0000580 return memory_item(self, result);
Antoine Pitroubc420402008-12-07 20:14:49 +0000581 }
582 else if (PySlice_Check(key)) {
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000583 Py_ssize_t start, stop, step, slicelength;
584
Antoine Pitroubc420402008-12-07 20:14:49 +0000585 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000586 &start, &stop, &step, &slicelength) < 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000587 return NULL;
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000588 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000589
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000590 if (step == 1 && view->ndim == 1) {
591 Py_buffer newview;
592 void *newbuf = (char *) view->buf
593 + start * view->itemsize;
594 int newflags = view->readonly
595 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
Antoine Pitroubc420402008-12-07 20:14:49 +0000596
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000597 /* XXX There should be an API to create a subbuffer */
598 if (view->obj != NULL) {
599 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
600 return NULL;
601 }
602 else {
603 newview = *view;
604 }
605 newview.buf = newbuf;
606 newview.len = slicelength * newview.itemsize;
607 newview.format = view->format;
608 newview.shape = &(newview.smalltable[0]);
609 newview.shape[0] = slicelength;
610 newview.strides = &(newview.itemsize);
611 return PyMemoryView_FromBuffer(&newview);
612 }
613 PyErr_SetNone(PyExc_NotImplementedError);
614 return NULL;
Antoine Pitroubc420402008-12-07 20:14:49 +0000615 }
616 PyErr_Format(PyExc_TypeError,
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000617 "cannot index memory using \"%.200s\"",
618 key->ob_type->tp_name);
Antoine Pitroubc420402008-12-07 20:14:49 +0000619 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000620}
621
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000622
623/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000624static int
625memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
626{
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000627 Py_ssize_t start, len, bytelen;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000628 Py_buffer srcview;
629 Py_buffer *view = &(self->view);
630 char *srcbuf, *destbuf;
631
632 if (view->readonly) {
633 PyErr_SetString(PyExc_TypeError,
634 "cannot modify read-only memory");
635 return -1;
636 }
637 if (view->ndim != 1) {
638 PyErr_SetNone(PyExc_NotImplementedError);
639 return -1;
640 }
641 if (PyIndex_Check(key)) {
642 start = PyNumber_AsSsize_t(key, NULL);
643 if (start == -1 && PyErr_Occurred())
644 return -1;
645 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000646 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000647 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000648 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000649 PyErr_SetString(PyExc_IndexError,
650 "index out of bounds");
651 return -1;
652 }
653 len = 1;
654 }
655 else if (PySlice_Check(key)) {
656 Py_ssize_t stop, step;
657
Antoine Pitroubc420402008-12-07 20:14:49 +0000658 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000659 &start, &stop, &step, &len) < 0) {
660 return -1;
661 }
662 if (step != 1) {
663 PyErr_SetNone(PyExc_NotImplementedError);
664 return -1;
665 }
666 }
667 else {
668 PyErr_Format(PyExc_TypeError,
669 "cannot index memory using \"%.200s\"",
670 key->ob_type->tp_name);
671 return -1;
672 }
673 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
674 return -1;
675 }
676 /* XXX should we allow assignment of different item sizes
677 as long as the byte length is the same?
678 (e.g. assign 2 shorts to a 4-byte slice) */
679 if (srcview.itemsize != view->itemsize) {
680 PyErr_Format(PyExc_TypeError,
681 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
682 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
683 goto _error;
684 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000685 bytelen = len * view->itemsize;
686 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000687 PyErr_SetString(PyExc_ValueError,
688 "cannot modify size of memoryview object");
689 goto _error;
690 }
691 /* Do the actual copy */
692 destbuf = (char *) view->buf + start * view->itemsize;
693 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000694 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
695 /* No overlapping */
696 memcpy(destbuf, srcbuf, bytelen);
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000697 else
698 memmove(destbuf, srcbuf, bytelen);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000699
700 PyBuffer_Release(&srcview);
701 return 0;
702
703_error:
704 PyBuffer_Release(&srcview);
705 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000706}
707
Antoine Pitrou616d2852008-08-19 22:09:34 +0000708static PyObject *
709memory_richcompare(PyObject *v, PyObject *w, int op)
710{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000711 Py_buffer vv, ww;
712 int equal = 0;
713 PyObject *res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000714
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000715 vv.obj = NULL;
716 ww.obj = NULL;
717 if (op != Py_EQ && op != Py_NE)
718 goto _notimpl;
719 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
720 PyErr_Clear();
721 goto _notimpl;
722 }
723 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
724 PyErr_Clear();
725 goto _notimpl;
726 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000727
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000728 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
729 goto _end;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000730
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000731 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000732
733_end:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000734 PyBuffer_Release(&vv);
735 PyBuffer_Release(&ww);
736 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
737 res = Py_True;
738 else
739 res = Py_False;
740 Py_INCREF(res);
741 return res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000742
743_notimpl:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000744 PyBuffer_Release(&vv);
745 PyBuffer_Release(&ww);
746 Py_INCREF(Py_NotImplemented);
747 return Py_NotImplemented;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000748}
749
750
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000751static int
752memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
753{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000754 if (self->base != NULL)
755 Py_VISIT(self->base);
756 if (self->view.obj != NULL)
757 Py_VISIT(self->view.obj);
758 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000759}
760
761static int
762memory_clear(PyMemoryViewObject *self)
763{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000764 Py_CLEAR(self->base);
765 PyBuffer_Release(&self->view);
766 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000767}
768
769
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000770/* As mapping */
771static PyMappingMethods memory_as_mapping = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000772 (lenfunc)memory_length, /* mp_length */
773 (binaryfunc)memory_subscript, /* mp_subscript */
774 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000775};
776
Raymond Hettinger159eac92009-06-23 20:38:54 +0000777static PySequenceMethods memory_as_sequence = {
778 0, /* sq_length */
779 0, /* sq_concat */
780 0, /* sq_repeat */
781 (ssizeargfunc)memory_item, /* sq_item */
782};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000783
784/* Buffer methods */
785
786static PyBufferProcs memory_as_buffer = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000787 (getbufferproc)memory_getbuf, /* bf_getbuffer */
788 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000789};
790
791
792PyTypeObject PyMemoryView_Type = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000793 PyVarObject_HEAD_INIT(&PyType_Type, 0)
794 "memoryview",
795 sizeof(PyMemoryViewObject),
796 0,
797 (destructor)memory_dealloc, /* tp_dealloc */
798 0, /* tp_print */
799 0, /* tp_getattr */
800 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000801 0, /* tp_reserved */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000802 (reprfunc)memory_repr, /* tp_repr */
803 0, /* tp_as_number */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000804 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000805 &memory_as_mapping, /* tp_as_mapping */
806 0, /* tp_hash */
807 0, /* tp_call */
Benjamin Peterson87618552009-02-08 15:00:52 +0000808 0, /* tp_str */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000809 PyObject_GenericGetAttr, /* tp_getattro */
810 0, /* tp_setattro */
811 &memory_as_buffer, /* tp_as_buffer */
812 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
813 memory_doc, /* tp_doc */
814 (traverseproc)memory_traverse, /* tp_traverse */
815 (inquiry)memory_clear, /* tp_clear */
816 memory_richcompare, /* tp_richcompare */
817 0, /* tp_weaklistoffset */
818 0, /* tp_iter */
819 0, /* tp_iternext */
820 memory_methods, /* tp_methods */
821 0, /* tp_members */
822 memory_getsetlist, /* tp_getset */
823 0, /* tp_base */
824 0, /* tp_dict */
825 0, /* tp_descr_get */
826 0, /* tp_descr_set */
827 0, /* tp_dictoffset */
828 0, /* tp_init */
829 0, /* tp_alloc */
830 memory_new, /* tp_new */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000831};