blob: df893132852f829f99e48fc3db74f827e9ed70c8 [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 Pitrouc6b09eb2008-09-01 15:10:14 +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 Pitrouc6b09eb2008-09-01 15:10:14 +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{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000061 PyMemoryViewObject *mview;
62
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000063 mview = (PyMemoryViewObject *)
64 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
65 if (mview == NULL)
66 return NULL;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000067 mview->base = NULL;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000068 dup_buffer(&mview->view, info);
Antoine Pitrou616d2852008-08-19 22:09:34 +000069 /* NOTE: mview->view.obj should already have been incref'ed as
70 part of PyBuffer_FillInfo(). */
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000071 _PyObject_GC_TRACK(mview);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000072 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000073}
74
75PyObject *
76PyMemoryView_FromObject(PyObject *base)
77{
78 PyMemoryViewObject *mview;
79
80 if (!PyObject_CheckBuffer(base)) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +000081 PyErr_SetString(PyExc_TypeError,
82 "cannot make memory view because object does "
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000083 "not have the buffer interface");
Guido van Rossum5dde61d2007-09-25 22:10:05 +000084 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000085 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +000086
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000087 mview = (PyMemoryViewObject *)
88 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
89 if (mview == NULL)
90 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +000091
Neal Norwitz666bb412007-08-19 18:38:46 +000092 mview->base = NULL;
Antoine Pitrou2f89aa62008-08-02 21:02:48 +000093 if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL_RO) < 0) {
Neal Norwitz666bb412007-08-19 18:38:46 +000094 Py_DECREF(mview);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000095 return NULL;
96 }
97
98 mview->base = base;
99 Py_INCREF(base);
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000100 _PyObject_GC_TRACK(mview);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000101 return (PyObject *)mview;
102}
103
104static PyObject *
105memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
106{
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000107 PyObject *obj;
108 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000109
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000110 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
111 &obj)) {
112 return NULL;
113 }
114
115 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000116}
117
118
119static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000120_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +0000121 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000122{
123 int k;
124 Py_ssize_t outstride;
125
126 if (nd==0) {
127 memcpy(dest, src, itemsize);
128 }
129 else if (nd == 1) {
130 for (k = 0; k<shape[0]; k++) {
131 memcpy(dest, src, itemsize);
132 dest += itemsize;
133 src += strides[0];
134 }
135 }
136 else {
137 if (fort == 'F') {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000138 /* Copy first dimension first,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000139 second dimension second, etc...
140 Set up the recursive loop backwards so that final
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000141 dimension is actually copied last.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000142 */
143 outstride = itemsize;
144 for (k=1; k<nd-1;k++) {
145 outstride *= shape[k];
146 }
147 for (k=0; k<shape[nd-1]; k++) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000148 _strided_copy_nd(dest, src, nd-1, shape,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000149 strides, itemsize, fort);
150 dest += outstride;
151 src += strides[nd-1];
152 }
153 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000154
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000155 else {
156 /* Copy last dimension first,
157 second-to-last dimension second, etc.
158 Set up the recursion so that the
159 first dimension is copied last
160 */
161 outstride = itemsize;
162 for (k=1; k < nd; k++) {
163 outstride *= shape[k];
164 }
165 for (k=0; k<shape[0]; k++) {
166 _strided_copy_nd(dest, src, nd-1, shape+1,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000167 strides+1, itemsize,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000168 fort);
169 dest += outstride;
170 src += strides[0];
171 }
172 }
173 }
174 return;
175}
176
177void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
178void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
179
180static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000181_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000182{
183 Py_ssize_t *indices;
184 int k;
185 Py_ssize_t elements;
186 char *ptr;
187 void (*func)(int, Py_ssize_t *, Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000188
Amaury Forgeot d'Arc9c74b142008-06-18 00:47:36 +0000189 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
190 PyErr_NoMemory();
191 return -1;
192 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000193
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000194 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
195 if (indices == NULL) {
196 PyErr_NoMemory();
197 return -1;
198 }
199 for (k=0; k<view->ndim;k++) {
200 indices[k] = 0;
201 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000202
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000203 elements = 1;
204 for (k=0; k<view->ndim; k++) {
205 elements *= view->shape[k];
206 }
207 if (fort == 'F') {
208 func = _add_one_to_index_F;
209 }
210 else {
211 func = _add_one_to_index_C;
212 }
213 while (elements--) {
214 func(view->ndim, indices, view->shape);
215 ptr = PyBuffer_GetPointer(view, indices);
216 memcpy(dest, ptr, view->itemsize);
217 dest += view->itemsize;
218 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000219
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000220 PyMem_Free(indices);
221 return 0;
222}
223
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000224/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000225 Get a the data from an object as a contiguous chunk of memory (in
226 either 'C' or 'F'ortran order) even if it means copying it into a
227 separate memory area.
228
229 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000230 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000231 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000232 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000233
234 buffertype
235
236 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000237 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000238 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000239 a contiguous buffer if it is not. The view will point to
240 the shadow buffer which can be written to and then
241 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000242 view is de-allocated. While the shadow buffer is
243 being used, it will have an exclusive write lock on
244 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000245 */
246
247PyObject *
248PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
249{
250 PyMemoryViewObject *mem;
251 PyObject *bytes;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000252 Py_buffer *view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000253 int flags;
254 char *dest;
255
256 if (!PyObject_CheckBuffer(obj)) {
257 PyErr_SetString(PyExc_TypeError,
258 "object does not have the buffer interface");
259 return NULL;
260 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000261
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000262 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
263 if (mem == NULL)
264 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000265
Antoine Pitrouee58fa42008-08-19 18:22:14 +0000266 view = &mem->view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000267 flags = PyBUF_FULL_RO;
268 switch(buffertype) {
269 case PyBUF_WRITE:
270 flags = PyBUF_FULL;
271 break;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000272 }
273
274 if (PyObject_GetBuffer(obj, view, flags) != 0) {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000275 Py_DECREF(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000276 return NULL;
277 }
278
279 if (PyBuffer_IsContiguous(view, fort)) {
280 /* no copy needed */
281 Py_INCREF(obj);
282 mem->base = obj;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000283 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000284 return (PyObject *)mem;
285 }
286 /* otherwise a copy is needed */
287 if (buffertype == PyBUF_WRITE) {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000288 Py_DECREF(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000289 PyErr_SetString(PyExc_BufferError,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000290 "writable contiguous buffer requested "
291 "for a non-contiguousobject.");
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000292 return NULL;
293 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000294 bytes = PyBytes_FromStringAndSize(NULL, view->len);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000295 if (bytes == NULL) {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000296 Py_DECREF(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000297 return NULL;
298 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000299 dest = PyBytes_AS_STRING(bytes);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000300 /* different copying strategy depending on whether
301 or not any pointer de-referencing is needed
302 */
303 /* strided or in-direct copy */
304 if (view->suboffsets==NULL) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000305 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
306 view->strides, view->itemsize, fort);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000307 }
308 else {
309 if (_indirect_copy_nd(dest, view, fort) < 0) {
310 Py_DECREF(bytes);
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000311 Py_DECREF(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000312 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000313 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000314 }
315 if (buffertype == PyBUF_SHADOW) {
316 /* return a shadowed memory-view object */
317 view->buf = dest;
318 mem->base = PyTuple_Pack(2, obj, bytes);
319 Py_DECREF(bytes);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000320 if (mem->base == NULL) {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000321 Py_DECREF(mem);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000322 return NULL;
323 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000324 }
325 else {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000326 PyBuffer_Release(view); /* XXX ? */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000327 /* steal the reference */
328 mem->base = bytes;
329 }
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000330 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000331 return (PyObject *)mem;
332}
333
334
335static PyObject *
336memory_format_get(PyMemoryViewObject *self)
337{
338 return PyUnicode_FromString(self->view.format);
339}
340
341static PyObject *
342memory_itemsize_get(PyMemoryViewObject *self)
343{
Christian Heimes217cfd12007-12-02 14:31:20 +0000344 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000345}
346
347static PyObject *
348_IntTupleFromSsizet(int len, Py_ssize_t *vals)
349{
350 int i;
351 PyObject *o;
352 PyObject *intTuple;
353
354 if (vals == NULL) {
355 Py_INCREF(Py_None);
356 return Py_None;
357 }
358 intTuple = PyTuple_New(len);
359 if (!intTuple) return NULL;
360 for(i=0; i<len; i++) {
Christian Heimes217cfd12007-12-02 14:31:20 +0000361 o = PyLong_FromSsize_t(vals[i]);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000362 if (!o) {
363 Py_DECREF(intTuple);
364 return NULL;
365 }
366 PyTuple_SET_ITEM(intTuple, i, o);
367 }
368 return intTuple;
369}
370
371static PyObject *
372memory_shape_get(PyMemoryViewObject *self)
373{
374 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
375}
376
377static PyObject *
378memory_strides_get(PyMemoryViewObject *self)
379{
380 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
381}
382
383static PyObject *
384memory_suboffsets_get(PyMemoryViewObject *self)
385{
386 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
387}
388
389static PyObject *
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000390memory_readonly_get(PyMemoryViewObject *self)
391{
Neal Norwitz666bb412007-08-19 18:38:46 +0000392 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000393}
394
395static PyObject *
396memory_ndim_get(PyMemoryViewObject *self)
397{
Christian Heimes217cfd12007-12-02 14:31:20 +0000398 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000399}
400
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000401static PyGetSetDef memory_getsetlist[] ={
Neal Norwitz666bb412007-08-19 18:38:46 +0000402 {"format", (getter)memory_format_get, NULL, NULL},
403 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
404 {"shape", (getter)memory_shape_get, NULL, NULL},
405 {"strides", (getter)memory_strides_get, NULL, NULL},
406 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
Neal Norwitz666bb412007-08-19 18:38:46 +0000407 {"readonly", (getter)memory_readonly_get, NULL, NULL},
408 {"ndim", (getter)memory_ndim_get, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000409 {NULL, NULL, NULL, NULL},
410};
411
412
413static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000414memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000415{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000416 return PyObject_CallFunctionObjArgs(
417 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000418}
419
Antoine Pitrou616d2852008-08-19 22:09:34 +0000420/* TODO: rewrite this function using the struct module to unpack
421 each buffer item */
422
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000423static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000424memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000425{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000426 Py_buffer *view = &(mem->view);
427 Py_ssize_t i;
428 PyObject *res, *item;
429 char *buf;
430
431 if (strcmp(view->format, "B") || view->itemsize != 1) {
432 PyErr_SetString(PyExc_NotImplementedError,
433 "tolist() only supports byte views");
434 return NULL;
435 }
436 if (view->ndim != 1) {
437 PyErr_SetString(PyExc_NotImplementedError,
438 "tolist() only supports one-dimensional objects");
439 return NULL;
440 }
441 res = PyList_New(view->len);
442 if (res == NULL)
443 return NULL;
444 buf = view->buf;
445 for (i = 0; i < view->len; i++) {
446 item = PyLong_FromUnsignedLong((unsigned char) *buf);
447 if (item == NULL) {
448 Py_DECREF(res);
449 return NULL;
450 }
451 PyList_SET_ITEM(res, i, item);
452 buf++;
453 }
454 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000455}
456
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000457static PyMethodDef memory_methods[] = {
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000458 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
459 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000460 {NULL, NULL} /* sentinel */
461};
462
463
464static void
465memory_dealloc(PyMemoryViewObject *self)
466{
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000467 _PyObject_GC_UNTRACK(self);
Martin v. Löwis423be952008-08-13 15:53:07 +0000468 if (self->view.obj != NULL) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000469 if (self->base && PyTuple_Check(self->base)) {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000470 /* Special case when first element is generic object
471 with buffer interface and the second element is a
472 contiguous "shadow" that must be copied back into
473 the data areay of the first tuple element before
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000474 releasing the buffer on the first element.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000475 */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000476
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000477 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
478 PyTuple_GET_ITEM(self->base,1));
479
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000480 /* The view member should have readonly == -1 in
481 this instance indicating that the memory can
482 be "locked" and was locked and will be unlocked
483 again after this call.
484 */
485 PyBuffer_Release(&(self->view));
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000486 }
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000487 else {
488 PyBuffer_Release(&(self->view));
489 }
490 Py_CLEAR(self->base);
491 }
492 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000493}
494
495static PyObject *
496memory_repr(PyMemoryViewObject *self)
497{
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000498 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000499}
500
501
502static PyObject *
503memory_str(PyMemoryViewObject *self)
504{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000505 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000506 PyObject *res;
507
508 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
509 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000510
Antoine Pitrou616d2852008-08-19 22:09:34 +0000511 res = PyBytes_FromStringAndSize(NULL, view.len);
512 PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
Martin v. Löwis423be952008-08-13 15:53:07 +0000513 PyBuffer_Release(&view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000514 return res;
515}
516
517/* Sequence methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000518static Py_ssize_t
519memory_length(PyMemoryViewObject *self)
520{
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000521 return get_shape0(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000522}
523
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000524/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000525 mem[obj] returns a bytes object holding the data for one element if
526 obj fully indexes the memory view or another memory-view object
527 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000528
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000529 0-d memory-view objects can be referenced using ... or () but
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000530 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000531 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000532static PyObject *
533memory_subscript(PyMemoryViewObject *self, PyObject *key)
534{
Antoine Pitroubc420402008-12-07 20:14:49 +0000535 Py_buffer *view;
536 view = &(self->view);
537
538 if (view->ndim == 0) {
539 if (key == Py_Ellipsis ||
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000540 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000541 Py_INCREF(self);
542 return (PyObject *)self;
543 }
544 else {
545 PyErr_SetString(PyExc_IndexError,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000546 "invalid indexing of 0-dim memory");
Antoine Pitroubc420402008-12-07 20:14:49 +0000547 return NULL;
548 }
549 }
550 if (PyIndex_Check(key)) {
551 Py_ssize_t result;
552 result = PyNumber_AsSsize_t(key, NULL);
553 if (result == -1 && PyErr_Occurred())
554 return NULL;
555 if (view->ndim == 1) {
556 /* Return a bytes object */
557 char *ptr;
558 ptr = (char *)view->buf;
559 if (result < 0) {
560 result += get_shape0(view);
561 }
562 if ((result < 0) || (result >= get_shape0(view))) {
563 PyErr_SetString(PyExc_IndexError,
564 "index out of bounds");
565 return NULL;
566 }
567 if (view->strides == NULL)
568 ptr += view->itemsize * result;
569 else
570 ptr += view->strides[0] * result;
571 if (view->suboffsets != NULL &&
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000572 view->suboffsets[0] >= 0)
573 {
Antoine Pitroubc420402008-12-07 20:14:49 +0000574 ptr = *((char **)ptr) + view->suboffsets[0];
575 }
576 return PyBytes_FromStringAndSize(ptr, view->itemsize);
577 }
578 else {
579 /* Return a new memory-view object */
580 Py_buffer newview;
581 memset(&newview, 0, sizeof(newview));
582 /* XXX: This needs to be fixed so it
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000583 actually returns a sub-view
Antoine Pitroubc420402008-12-07 20:14:49 +0000584 */
585 return PyMemoryView_FromBuffer(&newview);
586 }
587 }
588 else if (PySlice_Check(key)) {
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000589 Py_ssize_t start, stop, step, slicelength;
590
Antoine Pitroubc420402008-12-07 20:14:49 +0000591 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000592 &start, &stop, &step, &slicelength) < 0) {
593 return NULL;
594 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000595
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000596 if (step == 1 && view->ndim == 1) {
597 Py_buffer newview;
598 void *newbuf = (char *) view->buf
599 + start * view->itemsize;
600 int newflags = view->readonly
601 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
Antoine Pitroubc420402008-12-07 20:14:49 +0000602
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000603 /* XXX There should be an API to create a subbuffer */
604 if (view->obj != NULL) {
605 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
606 return NULL;
607 }
608 else {
609 newview = *view;
610 }
611 newview.buf = newbuf;
612 newview.len = slicelength * newview.itemsize;
613 newview.format = view->format;
614 newview.shape = &(newview.smalltable[0]);
615 newview.shape[0] = slicelength;
616 newview.strides = &(newview.itemsize);
617 return PyMemoryView_FromBuffer(&newview);
618 }
619 PyErr_SetNone(PyExc_NotImplementedError);
620 return NULL;
Antoine Pitroubc420402008-12-07 20:14:49 +0000621 }
622 PyErr_Format(PyExc_TypeError,
623 "cannot index memory using \"%.200s\"",
624 key->ob_type->tp_name);
625 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000626}
627
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000628
629/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000630static int
631memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
632{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000633 Py_ssize_t start, len, bytelen, i;
634 Py_buffer srcview;
635 Py_buffer *view = &(self->view);
636 char *srcbuf, *destbuf;
637
638 if (view->readonly) {
639 PyErr_SetString(PyExc_TypeError,
640 "cannot modify read-only memory");
641 return -1;
642 }
643 if (view->ndim != 1) {
644 PyErr_SetNone(PyExc_NotImplementedError);
645 return -1;
646 }
647 if (PyIndex_Check(key)) {
648 start = PyNumber_AsSsize_t(key, NULL);
649 if (start == -1 && PyErr_Occurred())
650 return -1;
651 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000652 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000653 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000654 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000655 PyErr_SetString(PyExc_IndexError,
656 "index out of bounds");
657 return -1;
658 }
659 len = 1;
660 }
661 else if (PySlice_Check(key)) {
662 Py_ssize_t stop, step;
663
Antoine Pitroubc420402008-12-07 20:14:49 +0000664 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000665 &start, &stop, &step, &len) < 0) {
666 return -1;
667 }
668 if (step != 1) {
669 PyErr_SetNone(PyExc_NotImplementedError);
670 return -1;
671 }
672 }
673 else {
674 PyErr_Format(PyExc_TypeError,
675 "cannot index memory using \"%.200s\"",
676 key->ob_type->tp_name);
677 return -1;
678 }
679 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
680 return -1;
681 }
682 /* XXX should we allow assignment of different item sizes
683 as long as the byte length is the same?
684 (e.g. assign 2 shorts to a 4-byte slice) */
685 if (srcview.itemsize != view->itemsize) {
686 PyErr_Format(PyExc_TypeError,
687 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
688 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
689 goto _error;
690 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000691 bytelen = len * view->itemsize;
692 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000693 PyErr_SetString(PyExc_ValueError,
694 "cannot modify size of memoryview object");
695 goto _error;
696 }
697 /* Do the actual copy */
698 destbuf = (char *) view->buf + start * view->itemsize;
699 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000700 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
701 /* No overlapping */
702 memcpy(destbuf, srcbuf, bytelen);
703 else if (destbuf < srcbuf) {
704 /* Copy in ascending order */
705 for (i = 0; i < bytelen; i++)
706 destbuf[i] = srcbuf[i];
707 }
708 else {
709 /* Copy in descencing order */
710 for (i = bytelen - 1; i >= 0; i--)
711 destbuf[i] = srcbuf[i];
712 }
713
714 PyBuffer_Release(&srcview);
715 return 0;
716
717_error:
718 PyBuffer_Release(&srcview);
719 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000720}
721
Antoine Pitrou616d2852008-08-19 22:09:34 +0000722static PyObject *
723memory_richcompare(PyObject *v, PyObject *w, int op)
724{
725 Py_buffer vv, ww;
726 int equal = 0;
727 PyObject *res;
728
729 vv.obj = NULL;
730 ww.obj = NULL;
731 if (op != Py_EQ && op != Py_NE)
732 goto _notimpl;
733 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
734 PyErr_Clear();
735 goto _notimpl;
736 }
737 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
738 PyErr_Clear();
739 goto _notimpl;
740 }
741
742 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
743 goto _end;
744
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000745 equal = !memcmp(vv.buf, ww.buf, vv.len);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000746
747_end:
748 PyBuffer_Release(&vv);
749 PyBuffer_Release(&ww);
750 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
751 res = Py_True;
752 else
753 res = Py_False;
754 Py_INCREF(res);
755 return res;
756
757_notimpl:
758 PyBuffer_Release(&vv);
759 PyBuffer_Release(&ww);
760 Py_INCREF(Py_NotImplemented);
761 return Py_NotImplemented;
762}
763
764
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000765static int
766memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
767{
768 if (self->base != NULL)
769 Py_VISIT(self->base);
770 if (self->view.obj != NULL)
771 Py_VISIT(self->view.obj);
772 return 0;
773}
774
775static int
776memory_clear(PyMemoryViewObject *self)
777{
778 Py_CLEAR(self->base);
779 PyBuffer_Release(&self->view);
780 return 0;
781}
782
783
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000784/* As mapping */
785static PyMappingMethods memory_as_mapping = {
786 (lenfunc)memory_length, /*mp_length*/
787 (binaryfunc)memory_subscript, /*mp_subscript*/
788 (objobjargproc)memory_ass_sub, /*mp_ass_subscript*/
789};
790
791
792/* Buffer methods */
793
794static PyBufferProcs memory_as_buffer = {
795 (getbufferproc)memory_getbuf, /* bf_getbuffer */
796 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
797};
798
799
800PyTypeObject PyMemoryView_Type = {
801 PyVarObject_HEAD_INIT(&PyType_Type, 0)
802 "memoryview",
803 sizeof(PyMemoryViewObject),
804 0,
805 (destructor)memory_dealloc, /* tp_dealloc */
806 0, /* tp_print */
807 0, /* tp_getattr */
808 0, /* tp_setattr */
809 0, /* tp_compare */
810 (reprfunc)memory_repr, /* tp_repr */
811 0, /* tp_as_number */
812 0, /* tp_as_sequence */
813 &memory_as_mapping, /* tp_as_mapping */
814 0, /* tp_hash */
815 0, /* tp_call */
816 (reprfunc)memory_str, /* tp_str */
817 PyObject_GenericGetAttr, /* tp_getattro */
818 0, /* tp_setattro */
819 &memory_as_buffer, /* tp_as_buffer */
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000820 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000821 memory_doc, /* tp_doc */
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000822 (traverseproc)memory_traverse, /* tp_traverse */
823 (inquiry)memory_clear, /* tp_clear */
Antoine Pitrou616d2852008-08-19 22:09:34 +0000824 memory_richcompare, /* tp_richcompare */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000825 0, /* tp_weaklistoffset */
826 0, /* tp_iter */
827 0, /* tp_iternext */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000828 memory_methods, /* tp_methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000829 0, /* tp_members */
830 memory_getsetlist, /* tp_getset */
831 0, /* tp_base */
832 0, /* tp_dict */
833 0, /* tp_descr_get */
834 0, /* tp_descr_set */
835 0, /* tp_dictoffset */
836 0, /* tp_init */
837 0, /* tp_alloc */
838 memory_new, /* tp_new */
839};