blob: f0a70532973f26833638096bc65a550b67f947a8 [file] [log] [blame]
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001
2/* Memoryview object implementation */
3
4#include "Python.h"
5
6static int
7memory_getbuf(PyMemoryViewObject *self, PyBuffer *view, int flags)
8{
9 if (view != NULL)
10 memcpy(view, &(self->view), sizeof(PyBuffer));
11 return self->base->ob_type->tp_as_buffer->bf_getbuffer(self->base,
12 NULL, PyBUF_FULL);
13}
14
15static void
16memory_releasebuf(PyMemoryViewObject *self, PyBuffer *view)
17{
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 *
27PyMemoryView_FromMemory(PyBuffer *info)
28{
Neal Norwitzfaa54a32007-08-19 04:23:20 +000029 /* XXX(nnorwitz): need to implement something here? */
Neal Norwitz666bb412007-08-19 18:38:46 +000030 PyErr_SetString(PyExc_NotImplementedError, "need to implement");
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000031 return NULL;
32}
33
34PyObject *
35PyMemoryView_FromObject(PyObject *base)
36{
37 PyMemoryViewObject *mview;
38
39 if (!PyObject_CheckBuffer(base)) {
40 PyErr_SetString(PyExc_TypeError,
41 "cannot make memory view because object does "\
42 "not have the buffer interface");
43 return NULL;
44 }
45
46 mview = (PyMemoryViewObject *)PyObject_New(PyMemoryViewObject,
47 &PyMemoryView_Type);
48 if (mview == NULL) return NULL;
49
Neal Norwitz666bb412007-08-19 18:38:46 +000050 mview->base = NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000051 if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL) < 0) {
Neal Norwitz666bb412007-08-19 18:38:46 +000052 Py_DECREF(mview);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000053 return NULL;
54 }
55
56 mview->base = base;
57 Py_INCREF(base);
58 return (PyObject *)mview;
59}
60
61static PyObject *
62memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
63{
64 PyObject *obj;
Neal Norwitzfaa54a32007-08-19 04:23:20 +000065 if (!PyArg_UnpackTuple(args, "memoryview", 1, 1, &obj)) return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000066
67 return PyMemoryView_FromObject(obj);
68}
69
70
71static void
72_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
73 Py_ssize_t *strides, int itemsize, char fort)
74{
75 int k;
76 Py_ssize_t outstride;
77
78 if (nd==0) {
79 memcpy(dest, src, itemsize);
80 }
81 else if (nd == 1) {
82 for (k = 0; k<shape[0]; k++) {
83 memcpy(dest, src, itemsize);
84 dest += itemsize;
85 src += strides[0];
86 }
87 }
88 else {
89 if (fort == 'F') {
90 /* Copy first dimension first,
91 second dimension second, etc...
92 Set up the recursive loop backwards so that final
93 dimension is actually copied last.
94 */
95 outstride = itemsize;
96 for (k=1; k<nd-1;k++) {
97 outstride *= shape[k];
98 }
99 for (k=0; k<shape[nd-1]; k++) {
100 _strided_copy_nd(dest, src, nd-1, shape,
101 strides, itemsize, fort);
102 dest += outstride;
103 src += strides[nd-1];
104 }
105 }
106
107 else {
108 /* Copy last dimension first,
109 second-to-last dimension second, etc.
110 Set up the recursion so that the
111 first dimension is copied last
112 */
113 outstride = itemsize;
114 for (k=1; k < nd; k++) {
115 outstride *= shape[k];
116 }
117 for (k=0; k<shape[0]; k++) {
118 _strided_copy_nd(dest, src, nd-1, shape+1,
119 strides+1, itemsize,
120 fort);
121 dest += outstride;
122 src += strides[0];
123 }
124 }
125 }
126 return;
127}
128
129void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
130void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
131
132static int
133_indirect_copy_nd(char *dest, PyBuffer *view, char fort)
134{
135 Py_ssize_t *indices;
136 int k;
137 Py_ssize_t elements;
138 char *ptr;
139 void (*func)(int, Py_ssize_t *, Py_ssize_t *);
140
141
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000142 /* XXX(nnorwitz): need to check for overflow! */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000143 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
144 if (indices == NULL) {
145 PyErr_NoMemory();
146 return -1;
147 }
148 for (k=0; k<view->ndim;k++) {
149 indices[k] = 0;
150 }
151
152 elements = 1;
153 for (k=0; k<view->ndim; k++) {
154 elements *= view->shape[k];
155 }
156 if (fort == 'F') {
157 func = _add_one_to_index_F;
158 }
159 else {
160 func = _add_one_to_index_C;
161 }
162 while (elements--) {
163 func(view->ndim, indices, view->shape);
164 ptr = PyBuffer_GetPointer(view, indices);
165 memcpy(dest, ptr, view->itemsize);
166 dest += view->itemsize;
167 }
168
169 PyMem_Free(indices);
170 return 0;
171}
172
173/*
174 Get a the data from an object as a contiguous chunk of memory (in
175 either 'C' or 'F'ortran order) even if it means copying it into a
176 separate memory area.
177
178 Returns a new reference to a Memory view object. If no copy is needed,
179 the memory view object points to the original memory and holds a
180 lock on the original. If a copy is needed, then the memory view object
181 points to a brand-new Bytes object (and holds a memory lock on it).
182
183 buffertype
184
185 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000186 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
187 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000188 a contiguous buffer if it is not. The view will point to
189 the shadow buffer which can be written to and then
190 will be copied back into the other buffer when the memory
191 view is de-allocated.
192 */
193
194PyObject *
195PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
196{
197 PyMemoryViewObject *mem;
198 PyObject *bytes;
199 PyBuffer *view;
200 int flags;
201 char *dest;
202
203 if (!PyObject_CheckBuffer(obj)) {
204 PyErr_SetString(PyExc_TypeError,
205 "object does not have the buffer interface");
206 return NULL;
207 }
208
209 mem = PyObject_New(PyMemoryViewObject, &PyMemoryView_Type);
210 if (mem == NULL) return NULL;
211
212 view = &PyMemoryView(mem);
213 flags = PyBUF_FULL_RO;
214 switch(buffertype) {
215 case PyBUF_WRITE:
216 flags = PyBUF_FULL;
217 break;
218 case PyBUF_SHADOW:
219 flags = PyBUF_FULL_LCK;
220 break;
221 }
222
223 if (PyObject_GetBuffer(obj, view, flags) != 0) {
224 PyObject_DEL(mem);
225 return NULL;
226 }
227
228 if (PyBuffer_IsContiguous(view, fort)) {
229 /* no copy needed */
230 Py_INCREF(obj);
231 mem->base = obj;
232 return (PyObject *)mem;
233 }
234 /* otherwise a copy is needed */
235 if (buffertype == PyBUF_WRITE) {
236 PyObject_DEL(mem);
237 PyErr_SetString(PyExc_BufferError,
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000238 "writable contiguous buffer requested for a non-contiguous" \
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000239 "object.");
240 return NULL;
241 }
242 bytes = PyBytes_FromStringAndSize(NULL, view->len);
243 if (bytes == NULL) {
244 PyObject_ReleaseBuffer(obj, view);
245 return NULL;
246 }
247 dest = PyBytes_AS_STRING(bytes);
248 /* different copying strategy depending on whether
249 or not any pointer de-referencing is needed
250 */
251 /* strided or in-direct copy */
252 if (view->suboffsets==NULL) {
253 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
254 view->strides, view->itemsize, fort);
255 }
256 else {
257 if (_indirect_copy_nd(dest, view, fort) < 0) {
258 Py_DECREF(bytes);
259 PyObject_ReleaseBuffer(obj, view);
260 return NULL;
261 }
262 }
263 if (buffertype == PyBUF_SHADOW) {
264 /* return a shadowed memory-view object */
265 view->buf = dest;
266 mem->base = PyTuple_Pack(2, obj, bytes);
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000267 /* XXX(nnorwitz): need to verify alloc was successful. */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000268 Py_DECREF(bytes);
269 }
270 else {
271 PyObject_ReleaseBuffer(obj, view);
272 /* steal the reference */
273 mem->base = bytes;
274 }
275 return (PyObject *)mem;
276}
277
278
279static PyObject *
280memory_format_get(PyMemoryViewObject *self)
281{
282 return PyUnicode_FromString(self->view.format);
283}
284
285static PyObject *
286memory_itemsize_get(PyMemoryViewObject *self)
287{
288 return PyInt_FromLong(self->view.itemsize);
289}
290
291static PyObject *
292_IntTupleFromSsizet(int len, Py_ssize_t *vals)
293{
294 int i;
295 PyObject *o;
296 PyObject *intTuple;
297
298 if (vals == NULL) {
299 Py_INCREF(Py_None);
300 return Py_None;
301 }
302 intTuple = PyTuple_New(len);
303 if (!intTuple) return NULL;
304 for(i=0; i<len; i++) {
305 o = PyInt_FromSsize_t(vals[i]);
306 if (!o) {
307 Py_DECREF(intTuple);
308 return NULL;
309 }
310 PyTuple_SET_ITEM(intTuple, i, o);
311 }
312 return intTuple;
313}
314
315static PyObject *
316memory_shape_get(PyMemoryViewObject *self)
317{
318 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
319}
320
321static PyObject *
322memory_strides_get(PyMemoryViewObject *self)
323{
324 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
325}
326
327static PyObject *
328memory_suboffsets_get(PyMemoryViewObject *self)
329{
330 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
331}
332
333static PyObject *
334memory_size_get(PyMemoryViewObject *self)
335{
336 return PyInt_FromSsize_t(self->view.len);
337}
338
339static PyObject *
340memory_readonly_get(PyMemoryViewObject *self)
341{
Neal Norwitz666bb412007-08-19 18:38:46 +0000342 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000343}
344
345static PyObject *
346memory_ndim_get(PyMemoryViewObject *self)
347{
348 return PyInt_FromLong(self->view.ndim);
349}
350
351static PyGetSetDef memory_getsetlist[] ={
Neal Norwitz666bb412007-08-19 18:38:46 +0000352 {"format", (getter)memory_format_get, NULL, NULL},
353 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
354 {"shape", (getter)memory_shape_get, NULL, NULL},
355 {"strides", (getter)memory_strides_get, NULL, NULL},
356 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
357 {"size", (getter)memory_size_get, NULL, NULL},
358 {"readonly", (getter)memory_readonly_get, NULL, NULL},
359 {"ndim", (getter)memory_ndim_get, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000360 {NULL, NULL, NULL, NULL},
361};
362
363
364static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000365memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000366{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000367 /* Create new Bytes object for data */
368 return PyBytes_FromObject((PyObject *)mem);
369}
370
371static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000372memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000373{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000374 Py_INCREF(Py_NotImplemented);
375 return Py_NotImplemented;
376}
377
378
379
380static PyMethodDef memory_methods[] = {
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000381 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
382 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000383 {NULL, NULL} /* sentinel */
384};
385
386
387static void
388memory_dealloc(PyMemoryViewObject *self)
389{
Neal Norwitz666bb412007-08-19 18:38:46 +0000390 if (self->base != NULL) {
391 if (PyTuple_Check(self->base)) {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000392 /* Special case when first element is generic object
393 with buffer interface and the second element is a
394 contiguous "shadow" that must be copied back into
395 the data areay of the first tuple element before
396 releasing the buffer on the first element.
397 */
398
399 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
400 PyTuple_GET_ITEM(self->base,1));
401
402 /* The view member should have readonly == -1 in
403 this instance indicating that the memory can
404 be "locked" and was locked and will be unlocked
405 again after this call.
406 */
407 PyObject_ReleaseBuffer(PyTuple_GET_ITEM(self->base,0),
408 &(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000409 }
410 else {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000411 PyObject_ReleaseBuffer(self->base, &(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000412 }
413 Py_CLEAR(self->base);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000414 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000415 PyObject_DEL(self);
416}
417
418static PyObject *
419memory_repr(PyMemoryViewObject *self)
420{
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000421 /* XXX(nnorwitz): the code should be different or remove condition. */
422 if (self->base == NULL)
423 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000424 else
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000425 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000426}
427
428
429static PyObject *
430memory_str(PyMemoryViewObject *self)
431{
432 PyBuffer view;
433 PyObject *res;
434
435 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
436 return NULL;
437
438 res = PyBytes_FromStringAndSize(NULL, view.len);
439 PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
440 PyObject_ReleaseBuffer((PyObject *)self, &view);
441 return res;
442}
443
444/* Sequence methods */
445
446static Py_ssize_t
447memory_length(PyMemoryViewObject *self)
448{
449 PyBuffer view;
450
451 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
452 return -1;
453 PyObject_ReleaseBuffer((PyObject *)self, &view);
454 return view.len;
455}
456
457static PyObject *
458memory_subscript(PyMemoryViewObject *self, PyObject *key)
459{
460 Py_INCREF(Py_NotImplemented);
461 return Py_NotImplemented;
462}
463
464static int
465memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
466{
467 return 0;
468}
469
470/* As mapping */
471static PyMappingMethods memory_as_mapping = {
472 (lenfunc)memory_length, /*mp_length*/
473 (binaryfunc)memory_subscript, /*mp_subscript*/
474 (objobjargproc)memory_ass_sub, /*mp_ass_subscript*/
475};
476
477
478/* Buffer methods */
479
480static PyBufferProcs memory_as_buffer = {
481 (getbufferproc)memory_getbuf, /* bf_getbuffer */
482 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
483};
484
485
486PyTypeObject PyMemoryView_Type = {
487 PyVarObject_HEAD_INIT(&PyType_Type, 0)
488 "memoryview",
489 sizeof(PyMemoryViewObject),
490 0,
491 (destructor)memory_dealloc, /* tp_dealloc */
492 0, /* tp_print */
493 0, /* tp_getattr */
494 0, /* tp_setattr */
495 0, /* tp_compare */
496 (reprfunc)memory_repr, /* tp_repr */
497 0, /* tp_as_number */
498 0, /* tp_as_sequence */
499 &memory_as_mapping, /* tp_as_mapping */
500 0, /* tp_hash */
501 0, /* tp_call */
502 (reprfunc)memory_str, /* tp_str */
503 PyObject_GenericGetAttr, /* tp_getattro */
504 0, /* tp_setattro */
505 &memory_as_buffer, /* tp_as_buffer */
506 Py_TPFLAGS_DEFAULT, /* tp_flags */
507 memory_doc, /* tp_doc */
508 0, /* tp_traverse */
509 0, /* tp_clear */
510 0, /* tp_richcompare */
511 0, /* tp_weaklistoffset */
512 0, /* tp_iter */
513 0, /* tp_iternext */
514 memory_methods, /* tp_methods */
515 0, /* tp_members */
516 memory_getsetlist, /* tp_getset */
517 0, /* tp_base */
518 0, /* tp_dict */
519 0, /* tp_descr_get */
520 0, /* tp_descr_set */
521 0, /* tp_dictoffset */
522 0, /* tp_init */
523 0, /* tp_alloc */
524 memory_new, /* tp_new */
525};