blob: f96fcbe88123f3fbdd8f6f251f10765f55657edb [file] [log] [blame]
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001
2/* Memoryview object implementation */
3
4#include "Python.h"
5
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +00006static void
7dup_buffer(Py_buffer *dest, Py_buffer *src)
8{
9 *dest = *src;
10 if (src->shape == &(src->len))
11 dest->shape = &(dest->len);
12 if (src->strides == &(src->itemsize))
13 dest->strides = &(dest->itemsize);
14}
15
Antoine Pitroubc420402008-12-07 20:14:49 +000016/* XXX The buffer API should mandate that the shape array be non-NULL, but
17 it would complicate some code since the (de)allocation semantics of shape
18 are not specified. */
19static Py_ssize_t
20get_shape0(Py_buffer *buf)
21{
22 if (buf->shape != NULL)
23 return buf->shape[0];
24 assert(buf->ndim == 1 && buf->itemsize > 0);
25 return buf->len / buf->itemsize;
26}
27
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000028static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000029memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000030{
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000031 int res = 0;
32 /* XXX for whatever reason fixing the flags seems necessary */
33 if (self->view.readonly)
34 flags &= ~PyBUF_WRITABLE;
35 if (self->view.obj != NULL)
36 res = PyObject_GetBuffer(self->view.obj, view, flags);
37 if (view)
38 dup_buffer(view, &self->view);
39 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000040}
41
42static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000043memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000044{
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000045 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000046}
47
48PyDoc_STRVAR(memory_doc,
49"memoryview(object)\n\
50\n\
51Create a new memoryview object which references the given object.");
52
53PyObject *
Antoine Pitrouee58fa42008-08-19 18:22:14 +000054PyMemoryView_FromBuffer(Py_buffer *info)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000055{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000056 PyMemoryViewObject *mview;
57
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000058 mview = (PyMemoryViewObject *)
59 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
60 if (mview == NULL)
61 return NULL;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000062 mview->base = NULL;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000063 dup_buffer(&mview->view, info);
Antoine Pitrou616d2852008-08-19 22:09:34 +000064 /* NOTE: mview->view.obj should already have been incref'ed as
65 part of PyBuffer_FillInfo(). */
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000066 _PyObject_GC_TRACK(mview);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000067 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000068}
69
70PyObject *
71PyMemoryView_FromObject(PyObject *base)
72{
73 PyMemoryViewObject *mview;
74
75 if (!PyObject_CheckBuffer(base)) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +000076 PyErr_SetString(PyExc_TypeError,
77 "cannot make memory view because object does "
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000078 "not have the buffer interface");
Guido van Rossum5dde61d2007-09-25 22:10:05 +000079 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000080 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +000081
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000082 mview = (PyMemoryViewObject *)
83 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
84 if (mview == NULL)
85 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +000086
Neal Norwitz666bb412007-08-19 18:38:46 +000087 mview->base = NULL;
Antoine Pitrou2f89aa62008-08-02 21:02:48 +000088 if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL_RO) < 0) {
Neal Norwitz666bb412007-08-19 18:38:46 +000089 Py_DECREF(mview);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000090 return NULL;
91 }
92
93 mview->base = base;
94 Py_INCREF(base);
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000095 _PyObject_GC_TRACK(mview);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000096 return (PyObject *)mview;
97}
98
99static PyObject *
100memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
101{
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000102 PyObject *obj;
103 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000104
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000105 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
106 &obj)) {
107 return NULL;
108 }
109
110 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000111}
112
113
114static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000115_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +0000116 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000117{
118 int k;
119 Py_ssize_t outstride;
120
121 if (nd==0) {
122 memcpy(dest, src, itemsize);
123 }
124 else if (nd == 1) {
125 for (k = 0; k<shape[0]; k++) {
126 memcpy(dest, src, itemsize);
127 dest += itemsize;
128 src += strides[0];
129 }
130 }
131 else {
132 if (fort == 'F') {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000133 /* Copy first dimension first,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000134 second dimension second, etc...
135 Set up the recursive loop backwards so that final
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000136 dimension is actually copied last.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000137 */
138 outstride = itemsize;
139 for (k=1; k<nd-1;k++) {
140 outstride *= shape[k];
141 }
142 for (k=0; k<shape[nd-1]; k++) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000143 _strided_copy_nd(dest, src, nd-1, shape,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000144 strides, itemsize, fort);
145 dest += outstride;
146 src += strides[nd-1];
147 }
148 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000149
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000150 else {
151 /* Copy last dimension first,
152 second-to-last dimension second, etc.
153 Set up the recursion so that the
154 first dimension is copied last
155 */
156 outstride = itemsize;
157 for (k=1; k < nd; k++) {
158 outstride *= shape[k];
159 }
160 for (k=0; k<shape[0]; k++) {
161 _strided_copy_nd(dest, src, nd-1, shape+1,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000162 strides+1, itemsize,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000163 fort);
164 dest += outstride;
165 src += strides[0];
166 }
167 }
168 }
169 return;
170}
171
172void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
173void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
174
175static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000176_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000177{
178 Py_ssize_t *indices;
179 int k;
180 Py_ssize_t elements;
181 char *ptr;
182 void (*func)(int, Py_ssize_t *, Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000183
Amaury Forgeot d'Arc9c74b142008-06-18 00:47:36 +0000184 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
185 PyErr_NoMemory();
186 return -1;
187 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000188
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000189 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
190 if (indices == NULL) {
191 PyErr_NoMemory();
192 return -1;
193 }
194 for (k=0; k<view->ndim;k++) {
195 indices[k] = 0;
196 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000197
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000198 elements = 1;
199 for (k=0; k<view->ndim; k++) {
200 elements *= view->shape[k];
201 }
202 if (fort == 'F') {
203 func = _add_one_to_index_F;
204 }
205 else {
206 func = _add_one_to_index_C;
207 }
208 while (elements--) {
209 func(view->ndim, indices, view->shape);
210 ptr = PyBuffer_GetPointer(view, indices);
211 memcpy(dest, ptr, view->itemsize);
212 dest += view->itemsize;
213 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000214
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000215 PyMem_Free(indices);
216 return 0;
217}
218
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000219/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000220 Get a the data from an object as a contiguous chunk of memory (in
221 either 'C' or 'F'ortran order) even if it means copying it into a
222 separate memory area.
223
224 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000225 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000226 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000227 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000228
229 buffertype
230
231 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000232 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000233 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000234 a contiguous buffer if it is not. The view will point to
235 the shadow buffer which can be written to and then
236 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000237 view is de-allocated. While the shadow buffer is
238 being used, it will have an exclusive write lock on
239 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000240 */
241
242PyObject *
243PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
244{
245 PyMemoryViewObject *mem;
246 PyObject *bytes;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000247 Py_buffer *view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000248 int flags;
249 char *dest;
250
251 if (!PyObject_CheckBuffer(obj)) {
252 PyErr_SetString(PyExc_TypeError,
253 "object does not have the buffer interface");
254 return NULL;
255 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000256
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000257 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
258 if (mem == NULL)
259 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000260
Antoine Pitrouee58fa42008-08-19 18:22:14 +0000261 view = &mem->view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000262 flags = PyBUF_FULL_RO;
263 switch(buffertype) {
264 case PyBUF_WRITE:
265 flags = PyBUF_FULL;
266 break;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000267 }
268
269 if (PyObject_GetBuffer(obj, view, flags) != 0) {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000270 Py_DECREF(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000271 return NULL;
272 }
273
274 if (PyBuffer_IsContiguous(view, fort)) {
275 /* no copy needed */
276 Py_INCREF(obj);
277 mem->base = obj;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000278 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000279 return (PyObject *)mem;
280 }
281 /* otherwise a copy is needed */
282 if (buffertype == PyBUF_WRITE) {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000283 Py_DECREF(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000284 PyErr_SetString(PyExc_BufferError,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000285 "writable contiguous buffer requested "
286 "for a non-contiguousobject.");
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000287 return NULL;
288 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000289 bytes = PyBytes_FromStringAndSize(NULL, view->len);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000290 if (bytes == NULL) {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000291 Py_DECREF(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000292 return NULL;
293 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000294 dest = PyBytes_AS_STRING(bytes);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000295 /* different copying strategy depending on whether
296 or not any pointer de-referencing is needed
297 */
298 /* strided or in-direct copy */
299 if (view->suboffsets==NULL) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000300 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
301 view->strides, view->itemsize, fort);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000302 }
303 else {
304 if (_indirect_copy_nd(dest, view, fort) < 0) {
305 Py_DECREF(bytes);
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000306 Py_DECREF(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000307 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000308 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000309 }
310 if (buffertype == PyBUF_SHADOW) {
311 /* return a shadowed memory-view object */
312 view->buf = dest;
313 mem->base = PyTuple_Pack(2, obj, bytes);
314 Py_DECREF(bytes);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000315 if (mem->base == NULL) {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000316 Py_DECREF(mem);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000317 return NULL;
318 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000319 }
320 else {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000321 PyBuffer_Release(view); /* XXX ? */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000322 /* steal the reference */
323 mem->base = bytes;
324 }
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000325 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000326 return (PyObject *)mem;
327}
328
329
330static PyObject *
331memory_format_get(PyMemoryViewObject *self)
332{
333 return PyUnicode_FromString(self->view.format);
334}
335
336static PyObject *
337memory_itemsize_get(PyMemoryViewObject *self)
338{
Christian Heimes217cfd12007-12-02 14:31:20 +0000339 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000340}
341
342static PyObject *
343_IntTupleFromSsizet(int len, Py_ssize_t *vals)
344{
345 int i;
346 PyObject *o;
347 PyObject *intTuple;
348
349 if (vals == NULL) {
350 Py_INCREF(Py_None);
351 return Py_None;
352 }
353 intTuple = PyTuple_New(len);
354 if (!intTuple) return NULL;
355 for(i=0; i<len; i++) {
Christian Heimes217cfd12007-12-02 14:31:20 +0000356 o = PyLong_FromSsize_t(vals[i]);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000357 if (!o) {
358 Py_DECREF(intTuple);
359 return NULL;
360 }
361 PyTuple_SET_ITEM(intTuple, i, o);
362 }
363 return intTuple;
364}
365
366static PyObject *
367memory_shape_get(PyMemoryViewObject *self)
368{
369 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
370}
371
372static PyObject *
373memory_strides_get(PyMemoryViewObject *self)
374{
375 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
376}
377
378static PyObject *
379memory_suboffsets_get(PyMemoryViewObject *self)
380{
381 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
382}
383
384static PyObject *
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000385memory_readonly_get(PyMemoryViewObject *self)
386{
Neal Norwitz666bb412007-08-19 18:38:46 +0000387 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000388}
389
390static PyObject *
391memory_ndim_get(PyMemoryViewObject *self)
392{
Christian Heimes217cfd12007-12-02 14:31:20 +0000393 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000394}
395
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000396static PyGetSetDef memory_getsetlist[] ={
Neal Norwitz666bb412007-08-19 18:38:46 +0000397 {"format", (getter)memory_format_get, NULL, NULL},
398 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
399 {"shape", (getter)memory_shape_get, NULL, NULL},
400 {"strides", (getter)memory_strides_get, NULL, NULL},
401 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
Neal Norwitz666bb412007-08-19 18:38:46 +0000402 {"readonly", (getter)memory_readonly_get, NULL, NULL},
403 {"ndim", (getter)memory_ndim_get, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000404 {NULL, NULL, NULL, NULL},
405};
406
407
408static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000409memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000410{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000411 return PyObject_CallFunctionObjArgs(
412 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000413}
414
Antoine Pitrou616d2852008-08-19 22:09:34 +0000415/* TODO: rewrite this function using the struct module to unpack
416 each buffer item */
417
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000418static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000419memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000420{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000421 Py_buffer *view = &(mem->view);
422 Py_ssize_t i;
423 PyObject *res, *item;
424 char *buf;
425
426 if (strcmp(view->format, "B") || view->itemsize != 1) {
427 PyErr_SetString(PyExc_NotImplementedError,
428 "tolist() only supports byte views");
429 return NULL;
430 }
431 if (view->ndim != 1) {
432 PyErr_SetString(PyExc_NotImplementedError,
433 "tolist() only supports one-dimensional objects");
434 return NULL;
435 }
436 res = PyList_New(view->len);
437 if (res == NULL)
438 return NULL;
439 buf = view->buf;
440 for (i = 0; i < view->len; i++) {
441 item = PyLong_FromUnsignedLong((unsigned char) *buf);
442 if (item == NULL) {
443 Py_DECREF(res);
444 return NULL;
445 }
446 PyList_SET_ITEM(res, i, item);
447 buf++;
448 }
449 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000450}
451
452
453
454static PyMethodDef memory_methods[] = {
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000455 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
456 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000457 {NULL, NULL} /* sentinel */
458};
459
460
461static void
462memory_dealloc(PyMemoryViewObject *self)
463{
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000464 _PyObject_GC_UNTRACK(self);
Martin v. Löwis423be952008-08-13 15:53:07 +0000465 if (self->view.obj != NULL) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000466 if (self->base && PyTuple_Check(self->base)) {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000467 /* Special case when first element is generic object
468 with buffer interface and the second element is a
469 contiguous "shadow" that must be copied back into
470 the data areay of the first tuple element before
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000471 releasing the buffer on the first element.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000472 */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000473
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000474 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
475 PyTuple_GET_ITEM(self->base,1));
476
477 /* The view member should have readonly == -1 in
478 this instance indicating that the memory can
479 be "locked" and was locked and will be unlocked
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000480 again after this call.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000481 */
Martin v. Löwis423be952008-08-13 15:53:07 +0000482 PyBuffer_Release(&(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000483 }
484 else {
Martin v. Löwis423be952008-08-13 15:53:07 +0000485 PyBuffer_Release(&(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000486 }
487 Py_CLEAR(self->base);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000488 }
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000489 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000490}
491
492static PyObject *
493memory_repr(PyMemoryViewObject *self)
494{
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000495 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000496}
497
498
499static PyObject *
500memory_str(PyMemoryViewObject *self)
501{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000502 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000503 PyObject *res;
504
505 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
506 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000507
Antoine Pitrou616d2852008-08-19 22:09:34 +0000508 res = PyBytes_FromStringAndSize(NULL, view.len);
509 PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
Martin v. Löwis423be952008-08-13 15:53:07 +0000510 PyBuffer_Release(&view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000511 return res;
512}
513
514/* Sequence methods */
515
516static Py_ssize_t
517memory_length(PyMemoryViewObject *self)
518{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000519 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000520
521 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
522 return -1;
Martin v. Löwis423be952008-08-13 15:53:07 +0000523 PyBuffer_Release(&view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000524 return view.len;
525}
526
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000527/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000528 mem[obj] returns a bytes object holding the data for one element if
529 obj fully indexes the memory view or another memory-view object
530 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000531
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000532 0-d memory-view objects can be referenced using ... or () but
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000533 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000534 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000535static PyObject *
536memory_subscript(PyMemoryViewObject *self, PyObject *key)
537{
Antoine Pitroubc420402008-12-07 20:14:49 +0000538 Py_buffer *view;
539 view = &(self->view);
540
541 if (view->ndim == 0) {
542 if (key == Py_Ellipsis ||
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000543 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000544 Py_INCREF(self);
545 return (PyObject *)self;
546 }
547 else {
548 PyErr_SetString(PyExc_IndexError,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000549 "invalid indexing of 0-dim memory");
Antoine Pitroubc420402008-12-07 20:14:49 +0000550 return NULL;
551 }
552 }
553 if (PyIndex_Check(key)) {
554 Py_ssize_t result;
555 result = PyNumber_AsSsize_t(key, NULL);
556 if (result == -1 && PyErr_Occurred())
557 return NULL;
558 if (view->ndim == 1) {
559 /* Return a bytes object */
560 char *ptr;
561 ptr = (char *)view->buf;
562 if (result < 0) {
563 result += get_shape0(view);
564 }
565 if ((result < 0) || (result >= get_shape0(view))) {
566 PyErr_SetString(PyExc_IndexError,
567 "index out of bounds");
568 return NULL;
569 }
570 if (view->strides == NULL)
571 ptr += view->itemsize * result;
572 else
573 ptr += view->strides[0] * result;
574 if (view->suboffsets != NULL &&
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000575 view->suboffsets[0] >= 0)
576 {
Antoine Pitroubc420402008-12-07 20:14:49 +0000577 ptr = *((char **)ptr) + view->suboffsets[0];
578 }
579 return PyBytes_FromStringAndSize(ptr, view->itemsize);
580 }
581 else {
582 /* Return a new memory-view object */
583 Py_buffer newview;
584 memset(&newview, 0, sizeof(newview));
585 /* XXX: This needs to be fixed so it
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000586 actually returns a sub-view
Antoine Pitroubc420402008-12-07 20:14:49 +0000587 */
588 return PyMemoryView_FromBuffer(&newview);
589 }
590 }
591 else if (PySlice_Check(key)) {
592 Py_ssize_t start, stop, step, slicelength;
593
594 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
595 &start, &stop, &step, &slicelength) < 0) {
596 return NULL;
597 }
598
599 if (step == 1 && view->ndim == 1) {
600 Py_buffer newview;
601 void *newbuf = (char *) view->buf
602 + start * view->itemsize;
603 int newflags = view->readonly
604 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
605
606 /* XXX There should be an API to create a subbuffer */
607 if (view->obj != NULL) {
608 if (PyObject_GetBuffer(view->obj,
609 &newview, newflags) == -1)
610 return NULL;
611 }
612 else {
613 newview = *view;
614 }
615 newview.buf = newbuf;
616 newview.len = slicelength;
617 newview.format = view->format;
618 if (view->shape == &(view->len))
619 newview.shape = &(newview.len);
620 if (view->strides == &(view->itemsize))
621 newview.strides = &(newview.itemsize);
622 return PyMemoryView_FromBuffer(&newview);
623 }
624 PyErr_SetNone(PyExc_NotImplementedError);
625 return NULL;
626 }
627 PyErr_Format(PyExc_TypeError,
628 "cannot index memory using \"%.200s\"",
629 key->ob_type->tp_name);
630 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000631}
632
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000633
634/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000635static int
636memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
637{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000638 Py_ssize_t start, len, bytelen, i;
639 Py_buffer srcview;
640 Py_buffer *view = &(self->view);
641 char *srcbuf, *destbuf;
642
643 if (view->readonly) {
644 PyErr_SetString(PyExc_TypeError,
645 "cannot modify read-only memory");
646 return -1;
647 }
648 if (view->ndim != 1) {
649 PyErr_SetNone(PyExc_NotImplementedError);
650 return -1;
651 }
652 if (PyIndex_Check(key)) {
653 start = PyNumber_AsSsize_t(key, NULL);
654 if (start == -1 && PyErr_Occurred())
655 return -1;
656 if (start < 0) {
Antoine Pitroubc420402008-12-07 20:14:49 +0000657 start += get_shape0(view);
Antoine Pitrou616d2852008-08-19 22:09:34 +0000658 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000659 if ((start < 0) || (start >= get_shape0(view))) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000660 PyErr_SetString(PyExc_IndexError,
661 "index out of bounds");
662 return -1;
663 }
664 len = 1;
665 }
666 else if (PySlice_Check(key)) {
667 Py_ssize_t stop, step;
668
Antoine Pitroubc420402008-12-07 20:14:49 +0000669 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
Antoine Pitrou616d2852008-08-19 22:09:34 +0000670 &start, &stop, &step, &len) < 0) {
671 return -1;
672 }
673 if (step != 1) {
674 PyErr_SetNone(PyExc_NotImplementedError);
675 return -1;
676 }
677 }
678 else {
679 PyErr_Format(PyExc_TypeError,
680 "cannot index memory using \"%.200s\"",
681 key->ob_type->tp_name);
682 return -1;
683 }
684 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
685 return -1;
686 }
687 /* XXX should we allow assignment of different item sizes
688 as long as the byte length is the same?
689 (e.g. assign 2 shorts to a 4-byte slice) */
690 if (srcview.itemsize != view->itemsize) {
691 PyErr_Format(PyExc_TypeError,
692 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
693 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
694 goto _error;
695 }
Antoine Pitroubc420402008-12-07 20:14:49 +0000696 bytelen = len * view->itemsize;
697 if (bytelen != srcview.len) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000698 PyErr_SetString(PyExc_ValueError,
699 "cannot modify size of memoryview object");
700 goto _error;
701 }
702 /* Do the actual copy */
703 destbuf = (char *) view->buf + start * view->itemsize;
704 srcbuf = (char *) srcview.buf;
Antoine Pitrou616d2852008-08-19 22:09:34 +0000705 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
706 /* No overlapping */
707 memcpy(destbuf, srcbuf, bytelen);
708 else if (destbuf < srcbuf) {
709 /* Copy in ascending order */
710 for (i = 0; i < bytelen; i++)
711 destbuf[i] = srcbuf[i];
712 }
713 else {
714 /* Copy in descencing order */
715 for (i = bytelen - 1; i >= 0; i--)
716 destbuf[i] = srcbuf[i];
717 }
718
719 PyBuffer_Release(&srcview);
720 return 0;
721
722_error:
723 PyBuffer_Release(&srcview);
724 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000725}
726
Antoine Pitrou616d2852008-08-19 22:09:34 +0000727static PyObject *
728memory_richcompare(PyObject *v, PyObject *w, int op)
729{
730 Py_buffer vv, ww;
731 int equal = 0;
732 PyObject *res;
733
734 vv.obj = NULL;
735 ww.obj = NULL;
736 if (op != Py_EQ && op != Py_NE)
737 goto _notimpl;
738 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
739 PyErr_Clear();
740 goto _notimpl;
741 }
742 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
743 PyErr_Clear();
744 goto _notimpl;
745 }
746
747 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
748 goto _end;
749
750 equal = !memcmp(vv.buf, ww.buf, vv.len * vv.itemsize);
751
752_end:
753 PyBuffer_Release(&vv);
754 PyBuffer_Release(&ww);
755 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
756 res = Py_True;
757 else
758 res = Py_False;
759 Py_INCREF(res);
760 return res;
761
762_notimpl:
763 PyBuffer_Release(&vv);
764 PyBuffer_Release(&ww);
765 Py_INCREF(Py_NotImplemented);
766 return Py_NotImplemented;
767}
768
769
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000770static int
771memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
772{
773 if (self->base != NULL)
774 Py_VISIT(self->base);
775 if (self->view.obj != NULL)
776 Py_VISIT(self->view.obj);
777 return 0;
778}
779
780static int
781memory_clear(PyMemoryViewObject *self)
782{
783 Py_CLEAR(self->base);
784 PyBuffer_Release(&self->view);
785 return 0;
786}
787
788
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000789/* As mapping */
790static PyMappingMethods memory_as_mapping = {
791 (lenfunc)memory_length, /*mp_length*/
792 (binaryfunc)memory_subscript, /*mp_subscript*/
793 (objobjargproc)memory_ass_sub, /*mp_ass_subscript*/
794};
795
796
797/* Buffer methods */
798
799static PyBufferProcs memory_as_buffer = {
800 (getbufferproc)memory_getbuf, /* bf_getbuffer */
801 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
802};
803
804
805PyTypeObject PyMemoryView_Type = {
806 PyVarObject_HEAD_INIT(&PyType_Type, 0)
807 "memoryview",
808 sizeof(PyMemoryViewObject),
809 0,
810 (destructor)memory_dealloc, /* tp_dealloc */
811 0, /* tp_print */
812 0, /* tp_getattr */
813 0, /* tp_setattr */
814 0, /* tp_compare */
815 (reprfunc)memory_repr, /* tp_repr */
816 0, /* tp_as_number */
817 0, /* tp_as_sequence */
818 &memory_as_mapping, /* tp_as_mapping */
819 0, /* tp_hash */
820 0, /* tp_call */
821 (reprfunc)memory_str, /* tp_str */
822 PyObject_GenericGetAttr, /* tp_getattro */
823 0, /* tp_setattro */
824 &memory_as_buffer, /* tp_as_buffer */
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000825 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000826 memory_doc, /* tp_doc */
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000827 (traverseproc)memory_traverse, /* tp_traverse */
828 (inquiry)memory_clear, /* tp_clear */
Antoine Pitrou616d2852008-08-19 22:09:34 +0000829 memory_richcompare, /* tp_richcompare */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000830 0, /* tp_weaklistoffset */
831 0, /* tp_iter */
832 0, /* tp_iternext */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000833 memory_methods, /* tp_methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000834 0, /* tp_members */
835 memory_getsetlist, /* tp_getset */
836 0, /* tp_base */
837 0, /* tp_dict */
838 0, /* tp_descr_get */
839 0, /* tp_descr_set */
840 0, /* tp_dictoffset */
841 0, /* tp_init */
842 0, /* tp_alloc */
843 memory_new, /* tp_new */
844};