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