blob: f5dacb04f20d0fa5ce20843d93b9538c47a2328a [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 Pitrou93368182010-02-02 22:51:34 +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 Pitrou93368182010-02-02 22:51:34 +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 Pitrou93368182010-02-02 22:51:34 +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
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000175static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000176_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000177{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000178 Py_ssize_t *indices;
179 int k;
180 Py_ssize_t elements;
181 char *ptr;
Antoine Pitrouf43f65b2010-09-01 21:16:10 +0000182 void (*func)(int, Py_ssize_t *, const Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000183
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000184 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
185 PyErr_NoMemory();
186 return -1;
187 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000188
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000189 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
190 if (indices == NULL) {
191 PyErr_NoMemory();
192 return -1;
193 }
194 for (k=0; k<view->ndim;k++) {
195 indices[k] = 0;
196 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000197
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000198 elements = 1;
199 for (k=0; k<view->ndim; k++) {
200 elements *= view->shape[k];
201 }
202 if (fort == 'F') {
Antoine Pitroub83df8f2010-09-01 13:01:35 +0000203 func = _Py_add_one_to_index_F;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000204 }
205 else {
Antoine Pitroub83df8f2010-09-01 13:01:35 +0000206 func = _Py_add_one_to_index_C;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000207 }
208 while (elements--) {
209 func(view->ndim, indices, view->shape);
210 ptr = PyBuffer_GetPointer(view, indices);
211 memcpy(dest, ptr, view->itemsize);
212 dest += view->itemsize;
213 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000214
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000215 PyMem_Free(indices);
216 return 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000217}
218
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000219/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000220 Get a the data from an object as a contiguous chunk of memory (in
221 either 'C' or 'F'ortran order) even if it means copying it into a
222 separate memory area.
223
224 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000225 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000226 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000227 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000228
229 buffertype
230
231 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000232 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000233 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000234 a contiguous buffer if it is not. The view will point to
235 the shadow buffer which can be written to and then
236 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000237 view is de-allocated. While the shadow buffer is
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000238 being used, it will have an exclusive write lock on
239 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000240 */
241
242PyObject *
243PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
244{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000245 PyMemoryViewObject *mem;
246 PyObject *bytes;
247 Py_buffer *view;
248 int flags;
249 char *dest;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000250
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000251 if (!PyObject_CheckBuffer(obj)) {
252 PyErr_SetString(PyExc_TypeError,
Georg Brandlc5605df2009-08-13 08:26:44 +0000253 "object does not support the buffer interface");
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000254 return NULL;
255 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000256
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000257 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
258 if (mem == NULL)
259 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000260
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000261 view = &mem->view;
262 flags = PyBUF_FULL_RO;
263 switch(buffertype) {
264 case PyBUF_WRITE:
265 flags = PyBUF_FULL;
266 break;
267 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000268
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000269 if (PyObject_GetBuffer(obj, view, flags) != 0) {
270 Py_DECREF(mem);
271 return NULL;
272 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000273
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000274 if (PyBuffer_IsContiguous(view, fort)) {
275 /* no copy needed */
276 Py_INCREF(obj);
277 mem->base = obj;
278 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000279 return (PyObject *)mem;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000280 }
281 /* otherwise a copy is needed */
282 if (buffertype == PyBUF_WRITE) {
283 Py_DECREF(mem);
284 PyErr_SetString(PyExc_BufferError,
285 "writable contiguous buffer requested "
286 "for a non-contiguousobject.");
287 return NULL;
288 }
289 bytes = PyBytes_FromStringAndSize(NULL, view->len);
290 if (bytes == NULL) {
291 Py_DECREF(mem);
292 return NULL;
293 }
294 dest = PyBytes_AS_STRING(bytes);
295 /* different copying strategy depending on whether
296 or not any pointer de-referencing is needed
297 */
298 /* strided or in-direct copy */
299 if (view->suboffsets==NULL) {
300 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
301 view->strides, view->itemsize, fort);
302 }
303 else {
304 if (_indirect_copy_nd(dest, view, fort) < 0) {
305 Py_DECREF(bytes);
306 Py_DECREF(mem);
307 return NULL;
308 }
309 }
310 if (buffertype == PyBUF_SHADOW) {
311 /* return a shadowed memory-view object */
312 view->buf = dest;
313 mem->base = PyTuple_Pack(2, obj, bytes);
314 Py_DECREF(bytes);
315 if (mem->base == NULL) {
316 Py_DECREF(mem);
317 return NULL;
318 }
319 }
320 else {
321 PyBuffer_Release(view); /* XXX ? */
322 /* steal the reference */
323 mem->base = bytes;
324 }
325 _PyObject_GC_TRACK(mem);
326 return (PyObject *)mem;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000327}
328
329
330static PyObject *
331memory_format_get(PyMemoryViewObject *self)
332{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000333 return PyUnicode_FromString(self->view.format);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000334}
335
336static PyObject *
337memory_itemsize_get(PyMemoryViewObject *self)
338{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000339 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000340}
341
342static PyObject *
343_IntTupleFromSsizet(int len, Py_ssize_t *vals)
344{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000345 int i;
346 PyObject *o;
347 PyObject *intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000348
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000349 if (vals == NULL) {
350 Py_INCREF(Py_None);
351 return Py_None;
352 }
353 intTuple = PyTuple_New(len);
354 if (!intTuple) return NULL;
355 for(i=0; i<len; i++) {
356 o = PyLong_FromSsize_t(vals[i]);
357 if (!o) {
358 Py_DECREF(intTuple);
359 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000360 }
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000361 PyTuple_SET_ITEM(intTuple, i, o);
362 }
363 return intTuple;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000364}
365
366static PyObject *
367memory_shape_get(PyMemoryViewObject *self)
368{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000369 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000370}
371
372static PyObject *
373memory_strides_get(PyMemoryViewObject *self)
374{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000375 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000376}
377
378static PyObject *
379memory_suboffsets_get(PyMemoryViewObject *self)
380{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000381 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000382}
383
384static PyObject *
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000385memory_readonly_get(PyMemoryViewObject *self)
386{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000387 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000388}
389
390static PyObject *
391memory_ndim_get(PyMemoryViewObject *self)
392{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000393 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000394}
395
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000396static PyGetSetDef memory_getsetlist[] ={
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000397 {"format", (getter)memory_format_get, NULL, NULL},
398 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
399 {"shape", (getter)memory_shape_get, NULL, NULL},
400 {"strides", (getter)memory_strides_get, NULL, NULL},
401 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
402 {"readonly", (getter)memory_readonly_get, NULL, NULL},
403 {"ndim", (getter)memory_ndim_get, NULL, NULL},
404 {NULL, NULL, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000405};
406
407
408static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000409memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000410{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000411 return PyObject_CallFunctionObjArgs(
412 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000413}
414
Antoine Pitrou616d2852008-08-19 22:09:34 +0000415/* TODO: rewrite this function using the struct module to unpack
416 each buffer item */
417
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000418static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000419memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000420{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000421 Py_buffer *view = &(mem->view);
422 Py_ssize_t i;
423 PyObject *res, *item;
424 char *buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000425
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000426 if (strcmp(view->format, "B") || view->itemsize != 1) {
427 PyErr_SetString(PyExc_NotImplementedError,
428 "tolist() only supports byte views");
429 return NULL;
430 }
431 if (view->ndim != 1) {
432 PyErr_SetString(PyExc_NotImplementedError,
433 "tolist() only supports one-dimensional objects");
434 return NULL;
435 }
436 res = PyList_New(view->len);
437 if (res == NULL)
438 return NULL;
439 buf = view->buf;
440 for (i = 0; i < view->len; i++) {
441 item = PyLong_FromUnsignedLong((unsigned char) *buf);
442 if (item == NULL) {
443 Py_DECREF(res);
444 return NULL;
445 }
446 PyList_SET_ITEM(res, i, item);
447 buf++;
448 }
449 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000450}
451
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000452static PyMethodDef memory_methods[] = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000453 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
454 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
455 {NULL, NULL} /* sentinel */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000456};
457
458
459static void
460memory_dealloc(PyMemoryViewObject *self)
461{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000462 _PyObject_GC_UNTRACK(self);
463 if (self->view.obj != NULL) {
464 if (self->base && PyTuple_Check(self->base)) {
465 /* Special case when first element is generic object
466 with buffer interface and the second element is a
467 contiguous "shadow" that must be copied back into
468 the data areay of the first tuple element before
469 releasing the buffer on the first element.
470 */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000471
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000472 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
473 PyTuple_GET_ITEM(self->base,1));
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000474
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000475 /* The view member should have readonly == -1 in
476 this instance indicating that the memory can
477 be "locked" and was locked and will be unlocked
478 again after this call.
479 */
480 PyBuffer_Release(&(self->view));
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000481 }
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000482 else {
483 PyBuffer_Release(&(self->view));
484 }
485 Py_CLEAR(self->base);
486 }
487 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000488}
489
490static PyObject *
491memory_repr(PyMemoryViewObject *self)
492{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000493 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000494}
495
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000496/* Sequence methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000497static Py_ssize_t
498memory_length(PyMemoryViewObject *self)
499{
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000500 return get_shape0(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000501}
502
Raymond Hettinger159eac92009-06-23 20:38:54 +0000503/* Alternate version of memory_subcript that only accepts indices.
504 Used by PySeqIter_New().
505*/
506static PyObject *
507memory_item(PyMemoryViewObject *self, Py_ssize_t result)
508{
509 Py_buffer *view = &(self->view);
510
511 if (view->ndim == 0) {
512 PyErr_SetString(PyExc_IndexError,
513 "invalid indexing of 0-dim memory");
514 return NULL;
515 }
516 if (view->ndim == 1) {
517 /* Return a bytes object */
518 char *ptr;
519 ptr = (char *)view->buf;
520 if (result < 0) {
521 result += get_shape0(view);
522 }
523 if ((result < 0) || (result >= get_shape0(view))) {
524 PyErr_SetString(PyExc_IndexError,
525 "index out of bounds");
526 return NULL;
527 }
528 if (view->strides == NULL)
529 ptr += view->itemsize * result;
530 else
531 ptr += view->strides[0] * result;
532 if (view->suboffsets != NULL &&
533 view->suboffsets[0] >= 0) {
534 ptr = *((char **)ptr) + view->suboffsets[0];
535 }
536 return PyBytes_FromStringAndSize(ptr, view->itemsize);
537 } else {
538 /* Return a new memory-view object */
539 Py_buffer newview;
540 memset(&newview, 0, sizeof(newview));
541 /* XXX: This needs to be fixed so it actually returns a sub-view */
542 return PyMemoryView_FromBuffer(&newview);
543 }
544}
545
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000546/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000547 mem[obj] returns a bytes object holding the data for one element if
548 obj fully indexes the memory view or another memory-view object
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000549 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000550
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000551 0-d memory-view objects can be referenced using ... or () but
552 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000553 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000554static PyObject *
555memory_subscript(PyMemoryViewObject *self, PyObject *key)
556{
Antoine Pitroubc420402008-12-07 20:14:49 +0000557 Py_buffer *view;
558 view = &(self->view);
559
560 if (view->ndim == 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000561 if (key == Py_Ellipsis ||
562 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
563 Py_INCREF(self);
564 return (PyObject *)self;
565 }
566 else {
567 PyErr_SetString(PyExc_IndexError,
568 "invalid indexing of 0-dim memory");
569 return NULL;
570 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000571 }
572 if (PyIndex_Check(key)) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000573 Py_ssize_t result;
574 result = PyNumber_AsSsize_t(key, NULL);
575 if (result == -1 && PyErr_Occurred())
576 return NULL;
Raymond Hettinger159eac92009-06-23 20:38:54 +0000577 return memory_item(self, result);
Antoine Pitroubc420402008-12-07 20:14:49 +0000578 }
579 else if (PySlice_Check(key)) {
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000580 Py_ssize_t start, stop, step, slicelength;
581
Antoine Pitroubc420402008-12-07 20:14:49 +0000582 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000583 &start, &stop, &step, &slicelength) < 0) {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000584 return NULL;
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000585 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000586
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000587 if (step == 1 && view->ndim == 1) {
588 Py_buffer newview;
589 void *newbuf = (char *) view->buf
590 + start * view->itemsize;
591 int newflags = view->readonly
592 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
Antoine Pitroubc420402008-12-07 20:14:49 +0000593
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000594 /* XXX There should be an API to create a subbuffer */
595 if (view->obj != NULL) {
596 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
597 return NULL;
598 }
599 else {
600 newview = *view;
601 }
602 newview.buf = newbuf;
603 newview.len = slicelength * newview.itemsize;
604 newview.format = view->format;
605 newview.shape = &(newview.smalltable[0]);
606 newview.shape[0] = slicelength;
607 newview.strides = &(newview.itemsize);
608 return PyMemoryView_FromBuffer(&newview);
609 }
610 PyErr_SetNone(PyExc_NotImplementedError);
611 return NULL;
Antoine Pitroubc420402008-12-07 20:14:49 +0000612 }
613 PyErr_Format(PyExc_TypeError,
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000614 "cannot index memory using \"%.200s\"",
615 key->ob_type->tp_name);
Antoine Pitroubc420402008-12-07 20:14:49 +0000616 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000617}
618
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000619
620/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000621static int
622memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
623{
Antoine Pitroudedbbe62010-07-11 12:15:03 +0000624 Py_ssize_t start, len, bytelen;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000625 Py_buffer srcview;
626 Py_buffer *view = &(self->view);
627 char *srcbuf, *destbuf;
628
629 if (view->readonly) {
630 PyErr_SetString(PyExc_TypeError,
631 "cannot modify read-only memory");
632 return -1;
633 }
Antoine Pitrouf43f65b2010-09-01 21:16:10 +0000634 if (value == NULL) {
635 PyErr_SetString(PyExc_TypeError,
636 "cannot delete memory");
637 return -1;
638 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000639 if (view->ndim != 1) {
640 PyErr_SetNone(PyExc_NotImplementedError);
641 return -1;
642 }
643 if (PyIndex_Check(key)) {
644 start = PyNumber_AsSsize_t(key, NULL);
645 if (start == -1 && PyErr_Occurred())
646 return -1;
647 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000648 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000649 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000650 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000651 PyErr_SetString(PyExc_IndexError,
652 "index out of bounds");
653 return -1;
654 }
655 len = 1;
656 }
657 else if (PySlice_Check(key)) {
658 Py_ssize_t stop, step;
659
Antoine Pitroubc420402008-12-07 20:14:49 +0000660 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000661 &start, &stop, &step, &len) < 0) {
662 return -1;
663 }
664 if (step != 1) {
665 PyErr_SetNone(PyExc_NotImplementedError);
666 return -1;
667 }
668 }
669 else {
670 PyErr_Format(PyExc_TypeError,
671 "cannot index memory using \"%.200s\"",
672 key->ob_type->tp_name);
673 return -1;
674 }
675 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
676 return -1;
677 }
678 /* XXX should we allow assignment of different item sizes
679 as long as the byte length is the same?
680 (e.g. assign 2 shorts to a 4-byte slice) */
681 if (srcview.itemsize != view->itemsize) {
682 PyErr_Format(PyExc_TypeError,
683 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
684 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
685 goto _error;
686 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000687 bytelen = len * view->itemsize;
688 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000689 PyErr_SetString(PyExc_ValueError,
690 "cannot modify size of memoryview object");
691 goto _error;
692 }
693 /* Do the actual copy */
694 destbuf = (char *) view->buf + start * view->itemsize;
695 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000696 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
697 /* No overlapping */
698 memcpy(destbuf, srcbuf, bytelen);
Antoine Pitroudedbbe62010-07-11 12:15:03 +0000699 else
700 memmove(destbuf, srcbuf, bytelen);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000701
702 PyBuffer_Release(&srcview);
703 return 0;
704
705_error:
706 PyBuffer_Release(&srcview);
707 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000708}
709
Antoine Pitrou616d2852008-08-19 22:09:34 +0000710static PyObject *
711memory_richcompare(PyObject *v, PyObject *w, int op)
712{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000713 Py_buffer vv, ww;
714 int equal = 0;
715 PyObject *res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000716
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000717 vv.obj = NULL;
718 ww.obj = NULL;
719 if (op != Py_EQ && op != Py_NE)
720 goto _notimpl;
721 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
722 PyErr_Clear();
723 goto _notimpl;
724 }
725 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
726 PyErr_Clear();
727 goto _notimpl;
728 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000729
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000730 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
731 goto _end;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000732
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000733 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000734
735_end:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000736 PyBuffer_Release(&vv);
737 PyBuffer_Release(&ww);
738 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
739 res = Py_True;
740 else
741 res = Py_False;
742 Py_INCREF(res);
743 return res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000744
745_notimpl:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000746 PyBuffer_Release(&vv);
747 PyBuffer_Release(&ww);
748 Py_INCREF(Py_NotImplemented);
749 return Py_NotImplemented;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000750}
751
752
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000753static int
754memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
755{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000756 if (self->base != NULL)
757 Py_VISIT(self->base);
758 if (self->view.obj != NULL)
759 Py_VISIT(self->view.obj);
760 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000761}
762
763static int
764memory_clear(PyMemoryViewObject *self)
765{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000766 Py_CLEAR(self->base);
767 PyBuffer_Release(&self->view);
768 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000769}
770
771
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000772/* As mapping */
773static PyMappingMethods memory_as_mapping = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000774 (lenfunc)memory_length, /* mp_length */
775 (binaryfunc)memory_subscript, /* mp_subscript */
776 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000777};
778
Raymond Hettinger159eac92009-06-23 20:38:54 +0000779static PySequenceMethods memory_as_sequence = {
780 0, /* sq_length */
781 0, /* sq_concat */
782 0, /* sq_repeat */
783 (ssizeargfunc)memory_item, /* sq_item */
784};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000785
786/* Buffer methods */
787
788static PyBufferProcs memory_as_buffer = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000789 (getbufferproc)memory_getbuf, /* bf_getbuffer */
790 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000791};
792
793
794PyTypeObject PyMemoryView_Type = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000795 PyVarObject_HEAD_INIT(&PyType_Type, 0)
796 "memoryview",
797 sizeof(PyMemoryViewObject),
798 0,
799 (destructor)memory_dealloc, /* tp_dealloc */
800 0, /* tp_print */
801 0, /* tp_getattr */
802 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000803 0, /* tp_reserved */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000804 (reprfunc)memory_repr, /* tp_repr */
805 0, /* tp_as_number */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000806 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000807 &memory_as_mapping, /* tp_as_mapping */
808 0, /* tp_hash */
809 0, /* tp_call */
Benjamin Peterson87618552009-02-08 15:00:52 +0000810 0, /* tp_str */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000811 PyObject_GenericGetAttr, /* tp_getattro */
812 0, /* tp_setattro */
813 &memory_as_buffer, /* tp_as_buffer */
814 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
815 memory_doc, /* tp_doc */
816 (traverseproc)memory_traverse, /* tp_traverse */
817 (inquiry)memory_clear, /* tp_clear */
818 memory_richcompare, /* tp_richcompare */
819 0, /* tp_weaklistoffset */
820 0, /* tp_iter */
821 0, /* tp_iternext */
822 memory_methods, /* tp_methods */
823 0, /* tp_members */
824 memory_getsetlist, /* tp_getset */
825 0, /* tp_base */
826 0, /* tp_dict */
827 0, /* tp_descr_get */
828 0, /* tp_descr_set */
829 0, /* tp_dictoffset */
830 0, /* tp_init */
831 0, /* tp_alloc */
832 memory_new, /* tp_new */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000833};