blob: e92a771dfd26968a258b20f6032c94c040b3a2ce [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 Pitrou616d2852008-08-19 22:09:34 +0000627 Py_ssize_t start, len, bytelen, i;
628 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);
697 else if (destbuf < srcbuf) {
698 /* Copy in ascending order */
699 for (i = 0; i < bytelen; i++)
700 destbuf[i] = srcbuf[i];
701 }
702 else {
703 /* Copy in descencing order */
704 for (i = bytelen - 1; i >= 0; i--)
705 destbuf[i] = srcbuf[i];
706 }
707
708 PyBuffer_Release(&srcview);
709 return 0;
710
711_error:
712 PyBuffer_Release(&srcview);
713 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000714}
715
Antoine Pitrou616d2852008-08-19 22:09:34 +0000716static PyObject *
717memory_richcompare(PyObject *v, PyObject *w, int op)
718{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000719 Py_buffer vv, ww;
720 int equal = 0;
721 PyObject *res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000722
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000723 vv.obj = NULL;
724 ww.obj = NULL;
725 if (op != Py_EQ && op != Py_NE)
726 goto _notimpl;
727 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
728 PyErr_Clear();
729 goto _notimpl;
730 }
731 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
732 PyErr_Clear();
733 goto _notimpl;
734 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000735
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000736 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
737 goto _end;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000738
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000739 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000740
741_end:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000742 PyBuffer_Release(&vv);
743 PyBuffer_Release(&ww);
744 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
745 res = Py_True;
746 else
747 res = Py_False;
748 Py_INCREF(res);
749 return res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000750
751_notimpl:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000752 PyBuffer_Release(&vv);
753 PyBuffer_Release(&ww);
754 Py_INCREF(Py_NotImplemented);
755 return Py_NotImplemented;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000756}
757
758
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000759static int
760memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
761{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000762 if (self->base != NULL)
763 Py_VISIT(self->base);
764 if (self->view.obj != NULL)
765 Py_VISIT(self->view.obj);
766 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000767}
768
769static int
770memory_clear(PyMemoryViewObject *self)
771{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000772 Py_CLEAR(self->base);
773 PyBuffer_Release(&self->view);
774 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000775}
776
777
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000778/* As mapping */
779static PyMappingMethods memory_as_mapping = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000780 (lenfunc)memory_length, /* mp_length */
781 (binaryfunc)memory_subscript, /* mp_subscript */
782 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000783};
784
Raymond Hettinger159eac92009-06-23 20:38:54 +0000785static PySequenceMethods memory_as_sequence = {
786 0, /* sq_length */
787 0, /* sq_concat */
788 0, /* sq_repeat */
789 (ssizeargfunc)memory_item, /* sq_item */
790};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000791
792/* Buffer methods */
793
794static PyBufferProcs memory_as_buffer = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000795 (getbufferproc)memory_getbuf, /* bf_getbuffer */
796 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000797};
798
799
800PyTypeObject PyMemoryView_Type = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000801 PyVarObject_HEAD_INIT(&PyType_Type, 0)
802 "memoryview",
803 sizeof(PyMemoryViewObject),
804 0,
805 (destructor)memory_dealloc, /* tp_dealloc */
806 0, /* tp_print */
807 0, /* tp_getattr */
808 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000809 0, /* tp_reserved */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000810 (reprfunc)memory_repr, /* tp_repr */
811 0, /* tp_as_number */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000812 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000813 &memory_as_mapping, /* tp_as_mapping */
814 0, /* tp_hash */
815 0, /* tp_call */
Benjamin Peterson87618552009-02-08 15:00:52 +0000816 0, /* tp_str */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000817 PyObject_GenericGetAttr, /* tp_getattro */
818 0, /* tp_setattro */
819 &memory_as_buffer, /* tp_as_buffer */
820 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
821 memory_doc, /* tp_doc */
822 (traverseproc)memory_traverse, /* tp_traverse */
823 (inquiry)memory_clear, /* tp_clear */
824 memory_richcompare, /* tp_richcompare */
825 0, /* tp_weaklistoffset */
826 0, /* tp_iter */
827 0, /* tp_iternext */
828 memory_methods, /* tp_methods */
829 0, /* tp_members */
830 memory_getsetlist, /* tp_getset */
831 0, /* tp_base */
832 0, /* tp_dict */
833 0, /* tp_descr_get */
834 0, /* tp_descr_set */
835 0, /* tp_dictoffset */
836 0, /* tp_init */
837 0, /* tp_alloc */
838 memory_new, /* tp_new */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000839};