blob: 9a62dd84bd67c40e80957d89277b1066b24da327 [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
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;
182 void (*func)(int, Py_ssize_t *, 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 Pitrouf68c2a72010-09-01 12:58:21 +0000203 func = _Py_add_one_to_index_F;
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000204 }
205 else {
Antoine Pitrouf68c2a72010-09-01 12:58:21 +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 Brandl61b96dc2009-08-04 20:29:27 +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 Pitrou1ac745b2010-07-11 12:12:00 +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 }
634 if (view->ndim != 1) {
635 PyErr_SetNone(PyExc_NotImplementedError);
636 return -1;
637 }
638 if (PyIndex_Check(key)) {
639 start = PyNumber_AsSsize_t(key, NULL);
640 if (start == -1 && PyErr_Occurred())
641 return -1;
642 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000643 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000644 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000645 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000646 PyErr_SetString(PyExc_IndexError,
647 "index out of bounds");
648 return -1;
649 }
650 len = 1;
651 }
652 else if (PySlice_Check(key)) {
653 Py_ssize_t stop, step;
654
Antoine Pitroubc420402008-12-07 20:14:49 +0000655 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000656 &start, &stop, &step, &len) < 0) {
657 return -1;
658 }
659 if (step != 1) {
660 PyErr_SetNone(PyExc_NotImplementedError);
661 return -1;
662 }
663 }
664 else {
665 PyErr_Format(PyExc_TypeError,
666 "cannot index memory using \"%.200s\"",
667 key->ob_type->tp_name);
668 return -1;
669 }
670 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
671 return -1;
672 }
673 /* XXX should we allow assignment of different item sizes
674 as long as the byte length is the same?
675 (e.g. assign 2 shorts to a 4-byte slice) */
676 if (srcview.itemsize != view->itemsize) {
677 PyErr_Format(PyExc_TypeError,
678 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
679 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
680 goto _error;
681 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000682 bytelen = len * view->itemsize;
683 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000684 PyErr_SetString(PyExc_ValueError,
685 "cannot modify size of memoryview object");
686 goto _error;
687 }
688 /* Do the actual copy */
689 destbuf = (char *) view->buf + start * view->itemsize;
690 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000691 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
692 /* No overlapping */
693 memcpy(destbuf, srcbuf, bytelen);
Antoine Pitrou1ac745b2010-07-11 12:12:00 +0000694 else
695 memmove(destbuf, srcbuf, bytelen);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000696
697 PyBuffer_Release(&srcview);
698 return 0;
699
700_error:
701 PyBuffer_Release(&srcview);
702 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000703}
704
Antoine Pitrou616d2852008-08-19 22:09:34 +0000705static PyObject *
706memory_richcompare(PyObject *v, PyObject *w, int op)
707{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000708 Py_buffer vv, ww;
709 int equal = 0;
710 PyObject *res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000711
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000712 vv.obj = NULL;
713 ww.obj = NULL;
714 if (op != Py_EQ && op != Py_NE)
715 goto _notimpl;
716 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
717 PyErr_Clear();
718 goto _notimpl;
719 }
720 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
721 PyErr_Clear();
722 goto _notimpl;
723 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000724
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000725 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
726 goto _end;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000727
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000728 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000729
730_end:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000731 PyBuffer_Release(&vv);
732 PyBuffer_Release(&ww);
733 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
734 res = Py_True;
735 else
736 res = Py_False;
737 Py_INCREF(res);
738 return res;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000739
740_notimpl:
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000741 PyBuffer_Release(&vv);
742 PyBuffer_Release(&ww);
743 Py_INCREF(Py_NotImplemented);
744 return Py_NotImplemented;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000745}
746
747
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000748static int
749memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
750{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000751 if (self->base != NULL)
752 Py_VISIT(self->base);
753 if (self->view.obj != NULL)
754 Py_VISIT(self->view.obj);
755 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000756}
757
758static int
759memory_clear(PyMemoryViewObject *self)
760{
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000761 Py_CLEAR(self->base);
762 PyBuffer_Release(&self->view);
763 return 0;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000764}
765
766
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000767/* As mapping */
768static PyMappingMethods memory_as_mapping = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000769 (lenfunc)memory_length, /* mp_length */
770 (binaryfunc)memory_subscript, /* mp_subscript */
771 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000772};
773
Raymond Hettinger159eac92009-06-23 20:38:54 +0000774static PySequenceMethods memory_as_sequence = {
Alexander Belopolskyf0f45142010-08-11 17:31:17 +0000775 0, /* sq_length */
776 0, /* sq_concat */
777 0, /* sq_repeat */
778 (ssizeargfunc)memory_item, /* sq_item */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000779};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000780
781/* Buffer methods */
782
783static PyBufferProcs memory_as_buffer = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000784 (getbufferproc)memory_getbuf, /* bf_getbuffer */
785 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000786};
787
788
789PyTypeObject PyMemoryView_Type = {
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000790 PyVarObject_HEAD_INIT(&PyType_Type, 0)
791 "memoryview",
792 sizeof(PyMemoryViewObject),
793 0,
794 (destructor)memory_dealloc, /* tp_dealloc */
795 0, /* tp_print */
796 0, /* tp_getattr */
797 0, /* tp_setattr */
Mark Dickinsone94c6792009-02-02 20:36:42 +0000798 0, /* tp_reserved */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000799 (reprfunc)memory_repr, /* tp_repr */
800 0, /* tp_as_number */
Raymond Hettinger159eac92009-06-23 20:38:54 +0000801 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000802 &memory_as_mapping, /* tp_as_mapping */
803 0, /* tp_hash */
804 0, /* tp_call */
Benjamin Peterson87618552009-02-08 15:00:52 +0000805 0, /* tp_str */
Antoine Pitrou35b7e832009-01-03 19:20:36 +0000806 PyObject_GenericGetAttr, /* tp_getattro */
807 0, /* tp_setattro */
808 &memory_as_buffer, /* tp_as_buffer */
809 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
810 memory_doc, /* tp_doc */
811 (traverseproc)memory_traverse, /* tp_traverse */
812 (inquiry)memory_clear, /* tp_clear */
813 memory_richcompare, /* tp_richcompare */
814 0, /* tp_weaklistoffset */
815 0, /* tp_iter */
816 0, /* tp_iternext */
817 memory_methods, /* tp_methods */
818 0, /* tp_members */
819 memory_getsetlist, /* tp_getset */
820 0, /* tp_base */
821 0, /* tp_dict */
822 0, /* tp_descr_get */
823 0, /* tp_descr_set */
824 0, /* tp_dictoffset */
825 0, /* tp_init */
826 0, /* tp_alloc */
827 memory_new, /* tp_new */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000828};