blob: 3d7e42ec6737e2fe0014be577fe67b884e78345f [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{
9 if (view != NULL)
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000010 *view = self->view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000011 return self->base->ob_type->tp_as_buffer->bf_getbuffer(self->base,
12 NULL, PyBUF_FULL);
13}
14
15static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000016memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000017{
18 PyObject_ReleaseBuffer(self->base, NULL);
19}
20
21PyDoc_STRVAR(memory_doc,
22"memoryview(object)\n\
23\n\
24Create a new memoryview object which references the given object.");
25
26PyObject *
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000027PyMemoryView_FromMemory(Py_buffer *info)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000028{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000029 PyMemoryViewObject *mview;
30
31 mview = (PyMemoryViewObject *)PyObject_New(PyMemoryViewObject,
32 &PyMemoryView_Type);
33 if (mview == NULL) return NULL;
34 mview->base = NULL;
35 mview->view = *info;
36 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000037}
38
39PyObject *
40PyMemoryView_FromObject(PyObject *base)
41{
42 PyMemoryViewObject *mview;
43
44 if (!PyObject_CheckBuffer(base)) {
45 PyErr_SetString(PyExc_TypeError,
46 "cannot make memory view because object does "\
47 "not have the buffer interface");
48 return NULL;
49 }
50
51 mview = (PyMemoryViewObject *)PyObject_New(PyMemoryViewObject,
52 &PyMemoryView_Type);
53 if (mview == NULL) return NULL;
54
Neal Norwitz666bb412007-08-19 18:38:46 +000055 mview->base = NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000056 if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL) < 0) {
Neal Norwitz666bb412007-08-19 18:38:46 +000057 Py_DECREF(mview);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000058 return NULL;
59 }
60
61 mview->base = base;
62 Py_INCREF(base);
63 return (PyObject *)mview;
64}
65
66static PyObject *
67memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
68{
69 PyObject *obj;
Neal Norwitzfaa54a32007-08-19 04:23:20 +000070 if (!PyArg_UnpackTuple(args, "memoryview", 1, 1, &obj)) return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000071
72 return PyMemoryView_FromObject(obj);
73}
74
75
76static void
77_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
78 Py_ssize_t *strides, int itemsize, char fort)
79{
80 int k;
81 Py_ssize_t outstride;
82
83 if (nd==0) {
84 memcpy(dest, src, itemsize);
85 }
86 else if (nd == 1) {
87 for (k = 0; k<shape[0]; k++) {
88 memcpy(dest, src, itemsize);
89 dest += itemsize;
90 src += strides[0];
91 }
92 }
93 else {
94 if (fort == 'F') {
95 /* Copy first dimension first,
96 second dimension second, etc...
97 Set up the recursive loop backwards so that final
98 dimension is actually copied last.
99 */
100 outstride = itemsize;
101 for (k=1; k<nd-1;k++) {
102 outstride *= shape[k];
103 }
104 for (k=0; k<shape[nd-1]; k++) {
105 _strided_copy_nd(dest, src, nd-1, shape,
106 strides, itemsize, fort);
107 dest += outstride;
108 src += strides[nd-1];
109 }
110 }
111
112 else {
113 /* Copy last dimension first,
114 second-to-last dimension second, etc.
115 Set up the recursion so that the
116 first dimension is copied last
117 */
118 outstride = itemsize;
119 for (k=1; k < nd; k++) {
120 outstride *= shape[k];
121 }
122 for (k=0; k<shape[0]; k++) {
123 _strided_copy_nd(dest, src, nd-1, shape+1,
124 strides+1, itemsize,
125 fort);
126 dest += outstride;
127 src += strides[0];
128 }
129 }
130 }
131 return;
132}
133
134void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
135void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
136
137static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000138_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000139{
140 Py_ssize_t *indices;
141 int k;
142 Py_ssize_t elements;
143 char *ptr;
144 void (*func)(int, Py_ssize_t *, Py_ssize_t *);
145
146
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000147 /* XXX(nnorwitz): need to check for overflow! */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000148 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
149 if (indices == NULL) {
150 PyErr_NoMemory();
151 return -1;
152 }
153 for (k=0; k<view->ndim;k++) {
154 indices[k] = 0;
155 }
156
157 elements = 1;
158 for (k=0; k<view->ndim; k++) {
159 elements *= view->shape[k];
160 }
161 if (fort == 'F') {
162 func = _add_one_to_index_F;
163 }
164 else {
165 func = _add_one_to_index_C;
166 }
167 while (elements--) {
168 func(view->ndim, indices, view->shape);
169 ptr = PyBuffer_GetPointer(view, indices);
170 memcpy(dest, ptr, view->itemsize);
171 dest += view->itemsize;
172 }
173
174 PyMem_Free(indices);
175 return 0;
176}
177
178/*
179 Get a the data from an object as a contiguous chunk of memory (in
180 either 'C' or 'F'ortran order) even if it means copying it into a
181 separate memory area.
182
183 Returns a new reference to a Memory view object. If no copy is needed,
184 the memory view object points to the original memory and holds a
185 lock on the original. If a copy is needed, then the memory view object
186 points to a brand-new Bytes object (and holds a memory lock on it).
187
188 buffertype
189
190 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000191 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
192 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000193 a contiguous buffer if it is not. The view will point to
194 the shadow buffer which can be written to and then
195 will be copied back into the other buffer when the memory
196 view is de-allocated.
197 */
198
199PyObject *
200PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
201{
202 PyMemoryViewObject *mem;
203 PyObject *bytes;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000204 Py_buffer *view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000205 int flags;
206 char *dest;
207
208 if (!PyObject_CheckBuffer(obj)) {
209 PyErr_SetString(PyExc_TypeError,
210 "object does not have the buffer interface");
211 return NULL;
212 }
213
214 mem = PyObject_New(PyMemoryViewObject, &PyMemoryView_Type);
215 if (mem == NULL) return NULL;
216
217 view = &PyMemoryView(mem);
218 flags = PyBUF_FULL_RO;
219 switch(buffertype) {
220 case PyBUF_WRITE:
221 flags = PyBUF_FULL;
222 break;
223 case PyBUF_SHADOW:
224 flags = PyBUF_FULL_LCK;
225 break;
226 }
227
228 if (PyObject_GetBuffer(obj, view, flags) != 0) {
229 PyObject_DEL(mem);
230 return NULL;
231 }
232
233 if (PyBuffer_IsContiguous(view, fort)) {
234 /* no copy needed */
235 Py_INCREF(obj);
236 mem->base = obj;
237 return (PyObject *)mem;
238 }
239 /* otherwise a copy is needed */
240 if (buffertype == PyBUF_WRITE) {
241 PyObject_DEL(mem);
242 PyErr_SetString(PyExc_BufferError,
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000243 "writable contiguous buffer requested for a non-contiguous" \
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000244 "object.");
245 return NULL;
246 }
247 bytes = PyBytes_FromStringAndSize(NULL, view->len);
248 if (bytes == NULL) {
249 PyObject_ReleaseBuffer(obj, view);
250 return NULL;
251 }
252 dest = PyBytes_AS_STRING(bytes);
253 /* different copying strategy depending on whether
254 or not any pointer de-referencing is needed
255 */
256 /* strided or in-direct copy */
257 if (view->suboffsets==NULL) {
258 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
259 view->strides, view->itemsize, fort);
260 }
261 else {
262 if (_indirect_copy_nd(dest, view, fort) < 0) {
263 Py_DECREF(bytes);
264 PyObject_ReleaseBuffer(obj, view);
265 return NULL;
266 }
267 }
268 if (buffertype == PyBUF_SHADOW) {
269 /* return a shadowed memory-view object */
270 view->buf = dest;
271 mem->base = PyTuple_Pack(2, obj, bytes);
272 Py_DECREF(bytes);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000273 if (mem->base == NULL) {
274 PyObject_ReleaseBuffer(obj, view);
275 return NULL;
276 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000277 }
278 else {
279 PyObject_ReleaseBuffer(obj, view);
280 /* steal the reference */
281 mem->base = bytes;
282 }
283 return (PyObject *)mem;
284}
285
286
287static PyObject *
288memory_format_get(PyMemoryViewObject *self)
289{
290 return PyUnicode_FromString(self->view.format);
291}
292
293static PyObject *
294memory_itemsize_get(PyMemoryViewObject *self)
295{
296 return PyInt_FromLong(self->view.itemsize);
297}
298
299static PyObject *
300_IntTupleFromSsizet(int len, Py_ssize_t *vals)
301{
302 int i;
303 PyObject *o;
304 PyObject *intTuple;
305
306 if (vals == NULL) {
307 Py_INCREF(Py_None);
308 return Py_None;
309 }
310 intTuple = PyTuple_New(len);
311 if (!intTuple) return NULL;
312 for(i=0; i<len; i++) {
313 o = PyInt_FromSsize_t(vals[i]);
314 if (!o) {
315 Py_DECREF(intTuple);
316 return NULL;
317 }
318 PyTuple_SET_ITEM(intTuple, i, o);
319 }
320 return intTuple;
321}
322
323static PyObject *
324memory_shape_get(PyMemoryViewObject *self)
325{
326 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
327}
328
329static PyObject *
330memory_strides_get(PyMemoryViewObject *self)
331{
332 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
333}
334
335static PyObject *
336memory_suboffsets_get(PyMemoryViewObject *self)
337{
338 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
339}
340
341static PyObject *
342memory_size_get(PyMemoryViewObject *self)
343{
344 return PyInt_FromSsize_t(self->view.len);
345}
346
347static PyObject *
348memory_readonly_get(PyMemoryViewObject *self)
349{
Neal Norwitz666bb412007-08-19 18:38:46 +0000350 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000351}
352
353static PyObject *
354memory_ndim_get(PyMemoryViewObject *self)
355{
356 return PyInt_FromLong(self->view.ndim);
357}
358
359static PyGetSetDef memory_getsetlist[] ={
Neal Norwitz666bb412007-08-19 18:38:46 +0000360 {"format", (getter)memory_format_get, NULL, NULL},
361 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
362 {"shape", (getter)memory_shape_get, NULL, NULL},
363 {"strides", (getter)memory_strides_get, NULL, NULL},
364 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
365 {"size", (getter)memory_size_get, NULL, NULL},
366 {"readonly", (getter)memory_readonly_get, NULL, NULL},
367 {"ndim", (getter)memory_ndim_get, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000368 {NULL, NULL, NULL, NULL},
369};
370
371
372static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000373memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000374{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000375 return PyBytes_FromObject((PyObject *)mem);
376}
377
378static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000379memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000380{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000381 /* This should construct a (nested) list of unpacked objects
382 possibly using the struct module.
383 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000384 Py_INCREF(Py_NotImplemented);
385 return Py_NotImplemented;
386}
387
388
389
390static PyMethodDef memory_methods[] = {
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000391 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
392 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000393 {NULL, NULL} /* sentinel */
394};
395
396
397static void
398memory_dealloc(PyMemoryViewObject *self)
399{
Neal Norwitz666bb412007-08-19 18:38:46 +0000400 if (self->base != NULL) {
401 if (PyTuple_Check(self->base)) {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000402 /* Special case when first element is generic object
403 with buffer interface and the second element is a
404 contiguous "shadow" that must be copied back into
405 the data areay of the first tuple element before
406 releasing the buffer on the first element.
407 */
408
409 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
410 PyTuple_GET_ITEM(self->base,1));
411
412 /* The view member should have readonly == -1 in
413 this instance indicating that the memory can
414 be "locked" and was locked and will be unlocked
415 again after this call.
416 */
417 PyObject_ReleaseBuffer(PyTuple_GET_ITEM(self->base,0),
418 &(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000419 }
420 else {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000421 PyObject_ReleaseBuffer(self->base, &(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000422 }
423 Py_CLEAR(self->base);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000424 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000425 PyObject_DEL(self);
426}
427
428static PyObject *
429memory_repr(PyMemoryViewObject *self)
430{
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000431 /* XXX(nnorwitz): the code should be different or remove condition. */
432 if (self->base == NULL)
433 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000434 else
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000435 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000436}
437
438
439static PyObject *
440memory_str(PyMemoryViewObject *self)
441{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000442 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000443 PyObject *res;
444
445 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
446 return NULL;
447
448 res = PyBytes_FromStringAndSize(NULL, view.len);
449 PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
450 PyObject_ReleaseBuffer((PyObject *)self, &view);
451 return res;
452}
453
454/* Sequence methods */
455
456static Py_ssize_t
457memory_length(PyMemoryViewObject *self)
458{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000459 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000460
461 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
462 return -1;
463 PyObject_ReleaseBuffer((PyObject *)self, &view);
464 return view.len;
465}
466
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000467/*
468 mem[obj] returns a bytes object holding the data for one element if
469 obj fully indexes the memory view or another memory-view object
470 if it does not.
471
472 0-d memory-view objects can be referenced using ... or () but
473 not with anything else.
474 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000475static PyObject *
476memory_subscript(PyMemoryViewObject *self, PyObject *key)
477{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000478 Py_buffer *view;
479 view = &(self->view);
480
481 if (view->ndim == 0) {
482 if (key == Py_Ellipsis ||
483 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
484 Py_INCREF(self);
485 return (PyObject *)self;
486 }
487 else {
488 PyErr_SetString(PyExc_IndexError, "invalid indexing of 0-dim memory");
489 return NULL;
490 }
491 }
492 if (PyIndex_Check(key)) {
493 Py_ssize_t result;
494 result = PyNumber_AsSsize_t(key, NULL);
495 if (result == -1 && PyErr_Occurred())
496 return NULL;
497 if (view->ndim == 1) {
498 /* Return a bytes object */
499 char *ptr;
500 ptr = (char *)view->buf;
501 if (view->strides == NULL)
502 ptr += view->itemsize * result;
503 else
504 ptr += view->strides[0] * result;
505 if (view->suboffsets != NULL && view->suboffsets[0] >= 0) {
506 ptr = *((char **)ptr) + view->suboffsets[0];
507 }
508 return PyBytes_FromStringAndSize(ptr, view->itemsize);
509 }
510 else {
511 /* Return a new memory-view object */
512 Py_buffer newview;
513 PyMemoryView_FromMemory(&newview);
514 }
515 }
516
517
518
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000519 Py_INCREF(Py_NotImplemented);
520 return Py_NotImplemented;
521}
522
523static int
524memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
525{
526 return 0;
527}
528
529/* As mapping */
530static PyMappingMethods memory_as_mapping = {
531 (lenfunc)memory_length, /*mp_length*/
532 (binaryfunc)memory_subscript, /*mp_subscript*/
533 (objobjargproc)memory_ass_sub, /*mp_ass_subscript*/
534};
535
536
537/* Buffer methods */
538
539static PyBufferProcs memory_as_buffer = {
540 (getbufferproc)memory_getbuf, /* bf_getbuffer */
541 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
542};
543
544
545PyTypeObject PyMemoryView_Type = {
546 PyVarObject_HEAD_INIT(&PyType_Type, 0)
547 "memoryview",
548 sizeof(PyMemoryViewObject),
549 0,
550 (destructor)memory_dealloc, /* tp_dealloc */
551 0, /* tp_print */
552 0, /* tp_getattr */
553 0, /* tp_setattr */
554 0, /* tp_compare */
555 (reprfunc)memory_repr, /* tp_repr */
556 0, /* tp_as_number */
557 0, /* tp_as_sequence */
558 &memory_as_mapping, /* tp_as_mapping */
559 0, /* tp_hash */
560 0, /* tp_call */
561 (reprfunc)memory_str, /* tp_str */
562 PyObject_GenericGetAttr, /* tp_getattro */
563 0, /* tp_setattro */
564 &memory_as_buffer, /* tp_as_buffer */
565 Py_TPFLAGS_DEFAULT, /* tp_flags */
566 memory_doc, /* tp_doc */
567 0, /* tp_traverse */
568 0, /* tp_clear */
569 0, /* tp_richcompare */
570 0, /* tp_weaklistoffset */
571 0, /* tp_iter */
572 0, /* tp_iternext */
573 memory_methods, /* tp_methods */
574 0, /* tp_members */
575 memory_getsetlist, /* tp_getset */
576 0, /* tp_base */
577 0, /* tp_dict */
578 0, /* tp_descr_get */
579 0, /* tp_descr_set */
580 0, /* tp_dictoffset */
581 0, /* tp_init */
582 0, /* tp_alloc */
583 memory_new, /* tp_new */
584};