blob: bd5820f0f085f1c6b1fda18d9081a0eb140087f3 [file] [log] [blame]
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001
2/* Memoryview object implementation */
3
4#include "Python.h"
5
6static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +00007memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00008{
Martin v. Löwis423be952008-08-13 15:53:07 +00009 if (view != NULL) {
10 if (self->view.obj)
11 Py_INCREF(self->view.obj);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000012 *view = self->view;
Martin v. Löwis423be952008-08-13 15:53:07 +000013 }
14 if (self->view.obj == NULL)
Guido van Rossumbe801ac2007-10-08 03:32:34 +000015 return 0;
Antoine Pitrou616d2852008-08-19 22:09:34 +000016 return self->view.obj->ob_type->tp_as_buffer->bf_getbuffer(
17 self->view.obj, NULL, PyBUF_FULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000018}
19
20static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000021memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000022{
Martin v. Löwis423be952008-08-13 15:53:07 +000023 PyBuffer_Release(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000024}
25
26PyDoc_STRVAR(memory_doc,
27"memoryview(object)\n\
28\n\
29Create a new memoryview object which references the given object.");
30
31PyObject *
Antoine Pitrouee58fa42008-08-19 18:22:14 +000032PyMemoryView_FromBuffer(Py_buffer *info)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000033{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000034 PyMemoryViewObject *mview;
35
36 mview = (PyMemoryViewObject *)PyObject_New(PyMemoryViewObject,
37 &PyMemoryView_Type);
38 if (mview == NULL) return NULL;
39 mview->base = NULL;
Antoine Pitrou616d2852008-08-19 22:09:34 +000040 /* XXX there should be an API to duplicate a buffer object */
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000041 mview->view = *info;
Antoine Pitrou616d2852008-08-19 22:09:34 +000042 if (info->shape == &(info->len))
43 mview->view.shape = &(mview->view.len);
44 if (info->strides == &(info->itemsize))
45 mview->view.strides = &(mview->view.itemsize);
46 /* NOTE: mview->view.obj should already have been incref'ed as
47 part of PyBuffer_FillInfo(). */
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000048 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000049}
50
51PyObject *
52PyMemoryView_FromObject(PyObject *base)
53{
54 PyMemoryViewObject *mview;
55
56 if (!PyObject_CheckBuffer(base)) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +000057 PyErr_SetString(PyExc_TypeError,
58 "cannot make memory view because object does "
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000059 "not have the buffer interface");
Guido van Rossum5dde61d2007-09-25 22:10:05 +000060 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000061 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +000062
63 mview = (PyMemoryViewObject *)PyObject_New(PyMemoryViewObject,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000064 &PyMemoryView_Type);
65 if (mview == NULL) return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +000066
Neal Norwitz666bb412007-08-19 18:38:46 +000067 mview->base = NULL;
Antoine Pitrou2f89aa62008-08-02 21:02:48 +000068 if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL_RO) < 0) {
Neal Norwitz666bb412007-08-19 18:38:46 +000069 Py_DECREF(mview);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000070 return NULL;
71 }
72
73 mview->base = base;
74 Py_INCREF(base);
75 return (PyObject *)mview;
76}
77
78static PyObject *
79memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
80{
Christian Heimes7b6fc8e2007-11-08 02:28:11 +000081 PyObject *obj;
82 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000083
Christian Heimes7b6fc8e2007-11-08 02:28:11 +000084 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
85 &obj)) {
86 return NULL;
87 }
88
89 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000090}
91
92
93static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000094_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +000095 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000096{
97 int k;
98 Py_ssize_t outstride;
99
100 if (nd==0) {
101 memcpy(dest, src, itemsize);
102 }
103 else if (nd == 1) {
104 for (k = 0; k<shape[0]; k++) {
105 memcpy(dest, src, itemsize);
106 dest += itemsize;
107 src += strides[0];
108 }
109 }
110 else {
111 if (fort == 'F') {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000112 /* Copy first dimension first,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000113 second dimension second, etc...
114 Set up the recursive loop backwards so that final
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000115 dimension is actually copied last.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000116 */
117 outstride = itemsize;
118 for (k=1; k<nd-1;k++) {
119 outstride *= shape[k];
120 }
121 for (k=0; k<shape[nd-1]; k++) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000122 _strided_copy_nd(dest, src, nd-1, shape,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000123 strides, itemsize, fort);
124 dest += outstride;
125 src += strides[nd-1];
126 }
127 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000128
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000129 else {
130 /* Copy last dimension first,
131 second-to-last dimension second, etc.
132 Set up the recursion so that the
133 first dimension is copied last
134 */
135 outstride = itemsize;
136 for (k=1; k < nd; k++) {
137 outstride *= shape[k];
138 }
139 for (k=0; k<shape[0]; k++) {
140 _strided_copy_nd(dest, src, nd-1, shape+1,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000141 strides+1, itemsize,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000142 fort);
143 dest += outstride;
144 src += strides[0];
145 }
146 }
147 }
148 return;
149}
150
151void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
152void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
153
154static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000155_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000156{
157 Py_ssize_t *indices;
158 int k;
159 Py_ssize_t elements;
160 char *ptr;
161 void (*func)(int, Py_ssize_t *, Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000162
Amaury Forgeot d'Arc9c74b142008-06-18 00:47:36 +0000163 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
164 PyErr_NoMemory();
165 return -1;
166 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000167
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000168 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
169 if (indices == NULL) {
170 PyErr_NoMemory();
171 return -1;
172 }
173 for (k=0; k<view->ndim;k++) {
174 indices[k] = 0;
175 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000176
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000177 elements = 1;
178 for (k=0; k<view->ndim; k++) {
179 elements *= view->shape[k];
180 }
181 if (fort == 'F') {
182 func = _add_one_to_index_F;
183 }
184 else {
185 func = _add_one_to_index_C;
186 }
187 while (elements--) {
188 func(view->ndim, indices, view->shape);
189 ptr = PyBuffer_GetPointer(view, indices);
190 memcpy(dest, ptr, view->itemsize);
191 dest += view->itemsize;
192 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000193
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000194 PyMem_Free(indices);
195 return 0;
196}
197
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000198/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000199 Get a the data from an object as a contiguous chunk of memory (in
200 either 'C' or 'F'ortran order) even if it means copying it into a
201 separate memory area.
202
203 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000204 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000205 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000206 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000207
208 buffertype
209
210 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000211 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000212 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000213 a contiguous buffer if it is not. The view will point to
214 the shadow buffer which can be written to and then
215 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000216 view is de-allocated. While the shadow buffer is
217 being used, it will have an exclusive write lock on
218 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000219 */
220
221PyObject *
222PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
223{
224 PyMemoryViewObject *mem;
225 PyObject *bytes;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000226 Py_buffer *view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000227 int flags;
228 char *dest;
229
230 if (!PyObject_CheckBuffer(obj)) {
231 PyErr_SetString(PyExc_TypeError,
232 "object does not have the buffer interface");
233 return NULL;
234 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000235
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000236 mem = PyObject_New(PyMemoryViewObject, &PyMemoryView_Type);
237 if (mem == NULL) return NULL;
238
Antoine Pitrouee58fa42008-08-19 18:22:14 +0000239 view = &mem->view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000240 flags = PyBUF_FULL_RO;
241 switch(buffertype) {
242 case PyBUF_WRITE:
243 flags = PyBUF_FULL;
244 break;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000245 }
246
247 if (PyObject_GetBuffer(obj, view, flags) != 0) {
248 PyObject_DEL(mem);
249 return NULL;
250 }
251
252 if (PyBuffer_IsContiguous(view, fort)) {
253 /* no copy needed */
254 Py_INCREF(obj);
255 mem->base = obj;
256 return (PyObject *)mem;
257 }
258 /* otherwise a copy is needed */
259 if (buffertype == PyBUF_WRITE) {
260 PyObject_DEL(mem);
261 PyErr_SetString(PyExc_BufferError,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000262 "writable contiguous buffer requested "
263 "for a non-contiguousobject.");
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000264 return NULL;
265 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000266 bytes = PyBytes_FromStringAndSize(NULL, view->len);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000267 if (bytes == NULL) {
Martin v. Löwis423be952008-08-13 15:53:07 +0000268 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000269 return NULL;
270 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000271 dest = PyBytes_AS_STRING(bytes);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000272 /* different copying strategy depending on whether
273 or not any pointer de-referencing is needed
274 */
275 /* strided or in-direct copy */
276 if (view->suboffsets==NULL) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000277 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
278 view->strides, view->itemsize, fort);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000279 }
280 else {
281 if (_indirect_copy_nd(dest, view, fort) < 0) {
282 Py_DECREF(bytes);
Martin v. Löwis423be952008-08-13 15:53:07 +0000283 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000284 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000285 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000286 }
287 if (buffertype == PyBUF_SHADOW) {
288 /* return a shadowed memory-view object */
289 view->buf = dest;
290 mem->base = PyTuple_Pack(2, obj, bytes);
291 Py_DECREF(bytes);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000292 if (mem->base == NULL) {
Martin v. Löwis423be952008-08-13 15:53:07 +0000293 PyBuffer_Release(view);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000294 return NULL;
295 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000296 }
297 else {
Martin v. Löwis423be952008-08-13 15:53:07 +0000298 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000299 /* steal the reference */
300 mem->base = bytes;
301 }
302 return (PyObject *)mem;
303}
304
305
306static PyObject *
307memory_format_get(PyMemoryViewObject *self)
308{
309 return PyUnicode_FromString(self->view.format);
310}
311
312static PyObject *
313memory_itemsize_get(PyMemoryViewObject *self)
314{
Christian Heimes217cfd12007-12-02 14:31:20 +0000315 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000316}
317
318static PyObject *
319_IntTupleFromSsizet(int len, Py_ssize_t *vals)
320{
321 int i;
322 PyObject *o;
323 PyObject *intTuple;
324
325 if (vals == NULL) {
326 Py_INCREF(Py_None);
327 return Py_None;
328 }
329 intTuple = PyTuple_New(len);
330 if (!intTuple) return NULL;
331 for(i=0; i<len; i++) {
Christian Heimes217cfd12007-12-02 14:31:20 +0000332 o = PyLong_FromSsize_t(vals[i]);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000333 if (!o) {
334 Py_DECREF(intTuple);
335 return NULL;
336 }
337 PyTuple_SET_ITEM(intTuple, i, o);
338 }
339 return intTuple;
340}
341
342static PyObject *
343memory_shape_get(PyMemoryViewObject *self)
344{
345 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
346}
347
348static PyObject *
349memory_strides_get(PyMemoryViewObject *self)
350{
351 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
352}
353
354static PyObject *
355memory_suboffsets_get(PyMemoryViewObject *self)
356{
357 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
358}
359
360static PyObject *
361memory_size_get(PyMemoryViewObject *self)
362{
Christian Heimes217cfd12007-12-02 14:31:20 +0000363 return PyLong_FromSsize_t(self->view.len);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000364}
365
366static PyObject *
367memory_readonly_get(PyMemoryViewObject *self)
368{
Neal Norwitz666bb412007-08-19 18:38:46 +0000369 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000370}
371
372static PyObject *
373memory_ndim_get(PyMemoryViewObject *self)
374{
Christian Heimes217cfd12007-12-02 14:31:20 +0000375 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000376}
377
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000378static PyGetSetDef memory_getsetlist[] ={
Neal Norwitz666bb412007-08-19 18:38:46 +0000379 {"format", (getter)memory_format_get, NULL, NULL},
380 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
381 {"shape", (getter)memory_shape_get, NULL, NULL},
382 {"strides", (getter)memory_strides_get, NULL, NULL},
383 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
384 {"size", (getter)memory_size_get, NULL, NULL},
385 {"readonly", (getter)memory_readonly_get, NULL, NULL},
386 {"ndim", (getter)memory_ndim_get, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000387 {NULL, NULL, NULL, NULL},
388};
389
390
391static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000392memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000393{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000394 return PyObject_CallFunctionObjArgs(
395 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000396}
397
Antoine Pitrou616d2852008-08-19 22:09:34 +0000398/* TODO: rewrite this function using the struct module to unpack
399 each buffer item */
400
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000401static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000402memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000403{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000404 Py_buffer *view = &(mem->view);
405 Py_ssize_t i;
406 PyObject *res, *item;
407 char *buf;
408
409 if (strcmp(view->format, "B") || view->itemsize != 1) {
410 PyErr_SetString(PyExc_NotImplementedError,
411 "tolist() only supports byte views");
412 return NULL;
413 }
414 if (view->ndim != 1) {
415 PyErr_SetString(PyExc_NotImplementedError,
416 "tolist() only supports one-dimensional objects");
417 return NULL;
418 }
419 res = PyList_New(view->len);
420 if (res == NULL)
421 return NULL;
422 buf = view->buf;
423 for (i = 0; i < view->len; i++) {
424 item = PyLong_FromUnsignedLong((unsigned char) *buf);
425 if (item == NULL) {
426 Py_DECREF(res);
427 return NULL;
428 }
429 PyList_SET_ITEM(res, i, item);
430 buf++;
431 }
432 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000433}
434
435
436
437static PyMethodDef memory_methods[] = {
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000438 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
439 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000440 {NULL, NULL} /* sentinel */
441};
442
443
444static void
445memory_dealloc(PyMemoryViewObject *self)
446{
Martin v. Löwis423be952008-08-13 15:53:07 +0000447 if (self->view.obj != NULL) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000448 if (self->base && PyTuple_Check(self->base)) {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000449 /* Special case when first element is generic object
450 with buffer interface and the second element is a
451 contiguous "shadow" that must be copied back into
452 the data areay of the first tuple element before
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000453 releasing the buffer on the first element.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000454 */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000455
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000456 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
457 PyTuple_GET_ITEM(self->base,1));
458
459 /* The view member should have readonly == -1 in
460 this instance indicating that the memory can
461 be "locked" and was locked and will be unlocked
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000462 again after this call.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000463 */
Martin v. Löwis423be952008-08-13 15:53:07 +0000464 PyBuffer_Release(&(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000465 }
466 else {
Martin v. Löwis423be952008-08-13 15:53:07 +0000467 PyBuffer_Release(&(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000468 }
469 Py_CLEAR(self->base);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000470 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000471 PyObject_DEL(self);
472}
473
474static PyObject *
475memory_repr(PyMemoryViewObject *self)
476{
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000477 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000478}
479
480
481static PyObject *
482memory_str(PyMemoryViewObject *self)
483{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000484 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000485 PyObject *res;
486
487 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
488 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000489
Antoine Pitrou616d2852008-08-19 22:09:34 +0000490 res = PyBytes_FromStringAndSize(NULL, view.len);
491 PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
Martin v. Löwis423be952008-08-13 15:53:07 +0000492 PyBuffer_Release(&view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000493 return res;
494}
495
496/* Sequence methods */
497
498static Py_ssize_t
499memory_length(PyMemoryViewObject *self)
500{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000501 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000502
503 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
504 return -1;
Martin v. Löwis423be952008-08-13 15:53:07 +0000505 PyBuffer_Release(&view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000506 return view.len;
507}
508
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000509/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000510 mem[obj] returns a bytes object holding the data for one element if
511 obj fully indexes the memory view or another memory-view object
512 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000513
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000514 0-d memory-view objects can be referenced using ... or () but
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000515 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000516 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000517static PyObject *
518memory_subscript(PyMemoryViewObject *self, PyObject *key)
519{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000520 Py_buffer *view;
521 view = &(self->view);
522
523 if (view->ndim == 0) {
524 if (key == Py_Ellipsis ||
525 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
526 Py_INCREF(self);
527 return (PyObject *)self;
528 }
529 else {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000530 PyErr_SetString(PyExc_IndexError,
531 "invalid indexing of 0-dim memory");
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000532 return NULL;
533 }
534 }
535 if (PyIndex_Check(key)) {
536 Py_ssize_t result;
537 result = PyNumber_AsSsize_t(key, NULL);
538 if (result == -1 && PyErr_Occurred())
539 return NULL;
540 if (view->ndim == 1) {
541 /* Return a bytes object */
542 char *ptr;
543 ptr = (char *)view->buf;
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000544 if (result < 0) {
545 result += view->shape[0];
546 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000547 if ((result < 0) || (result >= view->shape[0])) {
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000548 PyErr_SetString(PyExc_IndexError,
549 "index out of bounds");
550 return NULL;
551 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000552 if (view->strides == NULL)
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000553 ptr += view->itemsize * result;
554 else
555 ptr += view->strides[0] * result;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000556 if (view->suboffsets != NULL &&
557 view->suboffsets[0] >= 0)
558 {
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000559 ptr = *((char **)ptr) + view->suboffsets[0];
560 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000561 return PyBytes_FromStringAndSize(ptr, view->itemsize);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000562 }
563 else {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000564 /* Return a new memory-view object */
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000565 Py_buffer newview;
Neal Norwitzb35f1282007-10-07 19:26:50 +0000566 memset(&newview, 0, sizeof(newview));
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000567 /* XXX: This needs to be fixed so it
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000568 actually returns a sub-view
569 */
Antoine Pitrouee58fa42008-08-19 18:22:14 +0000570 return PyMemoryView_FromBuffer(&newview);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000571 }
572 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000573 else if (PySlice_Check(key)) {
574 Py_ssize_t start, stop, step, slicelength;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000575
Antoine Pitrou616d2852008-08-19 22:09:34 +0000576 if (PySlice_GetIndicesEx((PySliceObject*)key, view->len,
577 &start, &stop, &step, &slicelength) < 0) {
578 return NULL;
579 }
580
581 if (step == 1 && view->ndim == 1) {
582 Py_buffer newview;
583 void *newbuf = (char *) view->buf
584 + start * view->itemsize;
585 int newflags = view->readonly
586 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
587
588 /* XXX There should be an API to create a subbuffer */
589 if (view->obj != NULL) {
590 if (PyObject_GetBuffer(view->obj,
591 &newview, newflags) == -1)
592 return NULL;
593 }
594 else {
595 newview = *view;
596 }
597 newview.buf = newbuf;
598 newview.len = slicelength;
599 newview.format = view->format;
600 if (view->shape == &(view->len))
601 newview.shape = &(newview.len);
602 if (view->strides == &(view->itemsize))
603 newview.strides = &(newview.itemsize);
604 return PyMemoryView_FromBuffer(&newview);
605 }
606 PyErr_SetNone(PyExc_NotImplementedError);
607 return NULL;
608 }
609 PyErr_Format(PyExc_TypeError,
610 "cannot index memory using \"%.200s\"",
611 key->ob_type->tp_name);
612 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000613}
614
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000615
616/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000617static int
618memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
619{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000620 Py_ssize_t start, len, bytelen, i;
621 Py_buffer srcview;
622 Py_buffer *view = &(self->view);
623 char *srcbuf, *destbuf;
624
625 if (view->readonly) {
626 PyErr_SetString(PyExc_TypeError,
627 "cannot modify read-only memory");
628 return -1;
629 }
630 if (view->ndim != 1) {
631 PyErr_SetNone(PyExc_NotImplementedError);
632 return -1;
633 }
634 if (PyIndex_Check(key)) {
635 start = PyNumber_AsSsize_t(key, NULL);
636 if (start == -1 && PyErr_Occurred())
637 return -1;
638 if (start < 0) {
639 start += view->shape[0];
640 }
641 if ((start < 0) || (start >= view->shape[0])) {
642 PyErr_SetString(PyExc_IndexError,
643 "index out of bounds");
644 return -1;
645 }
646 len = 1;
647 }
648 else if (PySlice_Check(key)) {
649 Py_ssize_t stop, step;
650
651 if (PySlice_GetIndicesEx((PySliceObject*)key, view->len,
652 &start, &stop, &step, &len) < 0) {
653 return -1;
654 }
655 if (step != 1) {
656 PyErr_SetNone(PyExc_NotImplementedError);
657 return -1;
658 }
659 }
660 else {
661 PyErr_Format(PyExc_TypeError,
662 "cannot index memory using \"%.200s\"",
663 key->ob_type->tp_name);
664 return -1;
665 }
666 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
667 return -1;
668 }
669 /* XXX should we allow assignment of different item sizes
670 as long as the byte length is the same?
671 (e.g. assign 2 shorts to a 4-byte slice) */
672 if (srcview.itemsize != view->itemsize) {
673 PyErr_Format(PyExc_TypeError,
674 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
675 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
676 goto _error;
677 }
678 if (srcview.len != len) {
679 PyErr_SetString(PyExc_ValueError,
680 "cannot modify size of memoryview object");
681 goto _error;
682 }
683 /* Do the actual copy */
684 destbuf = (char *) view->buf + start * view->itemsize;
685 srcbuf = (char *) srcview.buf;
686 bytelen = len * view->itemsize;
687 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
688 /* No overlapping */
689 memcpy(destbuf, srcbuf, bytelen);
690 else if (destbuf < srcbuf) {
691 /* Copy in ascending order */
692 for (i = 0; i < bytelen; i++)
693 destbuf[i] = srcbuf[i];
694 }
695 else {
696 /* Copy in descencing order */
697 for (i = bytelen - 1; i >= 0; i--)
698 destbuf[i] = srcbuf[i];
699 }
700
701 PyBuffer_Release(&srcview);
702 return 0;
703
704_error:
705 PyBuffer_Release(&srcview);
706 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000707}
708
Antoine Pitrou616d2852008-08-19 22:09:34 +0000709static PyObject *
710memory_richcompare(PyObject *v, PyObject *w, int op)
711{
712 Py_buffer vv, ww;
713 int equal = 0;
714 PyObject *res;
715
716 vv.obj = NULL;
717 ww.obj = NULL;
718 if (op != Py_EQ && op != Py_NE)
719 goto _notimpl;
720 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
721 PyErr_Clear();
722 goto _notimpl;
723 }
724 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
725 PyErr_Clear();
726 goto _notimpl;
727 }
728
729 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
730 goto _end;
731
732 equal = !memcmp(vv.buf, ww.buf, vv.len * vv.itemsize);
733
734_end:
735 PyBuffer_Release(&vv);
736 PyBuffer_Release(&ww);
737 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
738 res = Py_True;
739 else
740 res = Py_False;
741 Py_INCREF(res);
742 return res;
743
744_notimpl:
745 PyBuffer_Release(&vv);
746 PyBuffer_Release(&ww);
747 Py_INCREF(Py_NotImplemented);
748 return Py_NotImplemented;
749}
750
751
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000752/* As mapping */
753static PyMappingMethods memory_as_mapping = {
754 (lenfunc)memory_length, /*mp_length*/
755 (binaryfunc)memory_subscript, /*mp_subscript*/
756 (objobjargproc)memory_ass_sub, /*mp_ass_subscript*/
757};
758
759
760/* Buffer methods */
761
762static PyBufferProcs memory_as_buffer = {
763 (getbufferproc)memory_getbuf, /* bf_getbuffer */
764 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
765};
766
767
768PyTypeObject PyMemoryView_Type = {
769 PyVarObject_HEAD_INIT(&PyType_Type, 0)
770 "memoryview",
771 sizeof(PyMemoryViewObject),
772 0,
773 (destructor)memory_dealloc, /* tp_dealloc */
774 0, /* tp_print */
775 0, /* tp_getattr */
776 0, /* tp_setattr */
777 0, /* tp_compare */
778 (reprfunc)memory_repr, /* tp_repr */
779 0, /* tp_as_number */
780 0, /* tp_as_sequence */
781 &memory_as_mapping, /* tp_as_mapping */
782 0, /* tp_hash */
783 0, /* tp_call */
784 (reprfunc)memory_str, /* tp_str */
785 PyObject_GenericGetAttr, /* tp_getattro */
786 0, /* tp_setattro */
787 &memory_as_buffer, /* tp_as_buffer */
788 Py_TPFLAGS_DEFAULT, /* tp_flags */
789 memory_doc, /* tp_doc */
790 0, /* tp_traverse */
791 0, /* tp_clear */
Antoine Pitrou616d2852008-08-19 22:09:34 +0000792 memory_richcompare, /* tp_richcompare */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000793 0, /* tp_weaklistoffset */
794 0, /* tp_iter */
795 0, /* tp_iternext */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000796 memory_methods, /* tp_methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000797 0, /* tp_members */
798 memory_getsetlist, /* tp_getset */
799 0, /* tp_base */
800 0, /* tp_dict */
801 0, /* tp_descr_get */
802 0, /* tp_descr_set */
803 0, /* tp_dictoffset */
804 0, /* tp_init */
805 0, /* tp_alloc */
806 memory_new, /* tp_new */
807};