blob: 32e5c4473878b1286bd8b678df9b872d863218ff [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
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000016static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000017memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000018{
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000019 int res = 0;
20 /* XXX for whatever reason fixing the flags seems necessary */
21 if (self->view.readonly)
22 flags &= ~PyBUF_WRITABLE;
23 if (self->view.obj != NULL)
24 res = PyObject_GetBuffer(self->view.obj, view, flags);
25 if (view)
26 dup_buffer(view, &self->view);
27 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000028}
29
30static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000031memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000032{
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000033 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000034}
35
36PyDoc_STRVAR(memory_doc,
37"memoryview(object)\n\
38\n\
39Create a new memoryview object which references the given object.");
40
41PyObject *
Antoine Pitrouee58fa42008-08-19 18:22:14 +000042PyMemoryView_FromBuffer(Py_buffer *info)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000043{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000044 PyMemoryViewObject *mview;
45
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000046 mview = (PyMemoryViewObject *)
47 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
48 if (mview == NULL)
49 return NULL;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000050 mview->base = NULL;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000051 dup_buffer(&mview->view, info);
Antoine Pitrou616d2852008-08-19 22:09:34 +000052 /* NOTE: mview->view.obj should already have been incref'ed as
53 part of PyBuffer_FillInfo(). */
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000054 _PyObject_GC_TRACK(mview);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000055 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000056}
57
58PyObject *
59PyMemoryView_FromObject(PyObject *base)
60{
61 PyMemoryViewObject *mview;
62
63 if (!PyObject_CheckBuffer(base)) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +000064 PyErr_SetString(PyExc_TypeError,
65 "cannot make memory view because object does "
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000066 "not have the buffer interface");
Guido van Rossum5dde61d2007-09-25 22:10:05 +000067 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000068 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +000069
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000070 mview = (PyMemoryViewObject *)
71 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
72 if (mview == NULL)
73 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +000074
Neal Norwitz666bb412007-08-19 18:38:46 +000075 mview->base = NULL;
Antoine Pitrou2f89aa62008-08-02 21:02:48 +000076 if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL_RO) < 0) {
Neal Norwitz666bb412007-08-19 18:38:46 +000077 Py_DECREF(mview);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000078 return NULL;
79 }
80
81 mview->base = base;
82 Py_INCREF(base);
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +000083 _PyObject_GC_TRACK(mview);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000084 return (PyObject *)mview;
85}
86
87static PyObject *
88memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
89{
Christian Heimes7b6fc8e2007-11-08 02:28:11 +000090 PyObject *obj;
91 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000092
Christian Heimes7b6fc8e2007-11-08 02:28:11 +000093 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
94 &obj)) {
95 return NULL;
96 }
97
98 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000099}
100
101
102static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000103_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +0000104 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000105{
106 int k;
107 Py_ssize_t outstride;
108
109 if (nd==0) {
110 memcpy(dest, src, itemsize);
111 }
112 else if (nd == 1) {
113 for (k = 0; k<shape[0]; k++) {
114 memcpy(dest, src, itemsize);
115 dest += itemsize;
116 src += strides[0];
117 }
118 }
119 else {
120 if (fort == 'F') {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000121 /* Copy first dimension first,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000122 second dimension second, etc...
123 Set up the recursive loop backwards so that final
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000124 dimension is actually copied last.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000125 */
126 outstride = itemsize;
127 for (k=1; k<nd-1;k++) {
128 outstride *= shape[k];
129 }
130 for (k=0; k<shape[nd-1]; k++) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000131 _strided_copy_nd(dest, src, nd-1, shape,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000132 strides, itemsize, fort);
133 dest += outstride;
134 src += strides[nd-1];
135 }
136 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000137
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000138 else {
139 /* Copy last dimension first,
140 second-to-last dimension second, etc.
141 Set up the recursion so that the
142 first dimension is copied last
143 */
144 outstride = itemsize;
145 for (k=1; k < nd; k++) {
146 outstride *= shape[k];
147 }
148 for (k=0; k<shape[0]; k++) {
149 _strided_copy_nd(dest, src, nd-1, shape+1,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000150 strides+1, itemsize,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000151 fort);
152 dest += outstride;
153 src += strides[0];
154 }
155 }
156 }
157 return;
158}
159
160void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
161void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
162
163static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000164_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000165{
166 Py_ssize_t *indices;
167 int k;
168 Py_ssize_t elements;
169 char *ptr;
170 void (*func)(int, Py_ssize_t *, Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000171
Amaury Forgeot d'Arc9c74b142008-06-18 00:47:36 +0000172 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
173 PyErr_NoMemory();
174 return -1;
175 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000176
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000177 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
178 if (indices == NULL) {
179 PyErr_NoMemory();
180 return -1;
181 }
182 for (k=0; k<view->ndim;k++) {
183 indices[k] = 0;
184 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000185
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000186 elements = 1;
187 for (k=0; k<view->ndim; k++) {
188 elements *= view->shape[k];
189 }
190 if (fort == 'F') {
191 func = _add_one_to_index_F;
192 }
193 else {
194 func = _add_one_to_index_C;
195 }
196 while (elements--) {
197 func(view->ndim, indices, view->shape);
198 ptr = PyBuffer_GetPointer(view, indices);
199 memcpy(dest, ptr, view->itemsize);
200 dest += view->itemsize;
201 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000202
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000203 PyMem_Free(indices);
204 return 0;
205}
206
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000207/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000208 Get a the data from an object as a contiguous chunk of memory (in
209 either 'C' or 'F'ortran order) even if it means copying it into a
210 separate memory area.
211
212 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000213 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000214 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000215 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000216
217 buffertype
218
219 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000220 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000221 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000222 a contiguous buffer if it is not. The view will point to
223 the shadow buffer which can be written to and then
224 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000225 view is de-allocated. While the shadow buffer is
226 being used, it will have an exclusive write lock on
227 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000228 */
229
230PyObject *
231PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
232{
233 PyMemoryViewObject *mem;
234 PyObject *bytes;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000235 Py_buffer *view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000236 int flags;
237 char *dest;
238
239 if (!PyObject_CheckBuffer(obj)) {
240 PyErr_SetString(PyExc_TypeError,
241 "object does not have the buffer interface");
242 return NULL;
243 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000244
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000245 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
246 if (mem == NULL)
247 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000248
Antoine Pitrouee58fa42008-08-19 18:22:14 +0000249 view = &mem->view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000250 flags = PyBUF_FULL_RO;
251 switch(buffertype) {
252 case PyBUF_WRITE:
253 flags = PyBUF_FULL;
254 break;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000255 }
256
257 if (PyObject_GetBuffer(obj, view, flags) != 0) {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000258 Py_DECREF(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000259 return NULL;
260 }
261
262 if (PyBuffer_IsContiguous(view, fort)) {
263 /* no copy needed */
264 Py_INCREF(obj);
265 mem->base = obj;
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000266 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000267 return (PyObject *)mem;
268 }
269 /* otherwise a copy is needed */
270 if (buffertype == PyBUF_WRITE) {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000271 Py_DECREF(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000272 PyErr_SetString(PyExc_BufferError,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000273 "writable contiguous buffer requested "
274 "for a non-contiguousobject.");
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000275 return NULL;
276 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000277 bytes = PyBytes_FromStringAndSize(NULL, view->len);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000278 if (bytes == NULL) {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000279 Py_DECREF(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000280 return NULL;
281 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000282 dest = PyBytes_AS_STRING(bytes);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000283 /* different copying strategy depending on whether
284 or not any pointer de-referencing is needed
285 */
286 /* strided or in-direct copy */
287 if (view->suboffsets==NULL) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000288 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
289 view->strides, view->itemsize, fort);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000290 }
291 else {
292 if (_indirect_copy_nd(dest, view, fort) < 0) {
293 Py_DECREF(bytes);
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000294 Py_DECREF(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000295 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000296 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000297 }
298 if (buffertype == PyBUF_SHADOW) {
299 /* return a shadowed memory-view object */
300 view->buf = dest;
301 mem->base = PyTuple_Pack(2, obj, bytes);
302 Py_DECREF(bytes);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000303 if (mem->base == NULL) {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000304 Py_DECREF(mem);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000305 return NULL;
306 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000307 }
308 else {
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000309 PyBuffer_Release(view); /* XXX ? */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000310 /* steal the reference */
311 mem->base = bytes;
312 }
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000313 _PyObject_GC_TRACK(mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000314 return (PyObject *)mem;
315}
316
317
318static PyObject *
319memory_format_get(PyMemoryViewObject *self)
320{
321 return PyUnicode_FromString(self->view.format);
322}
323
324static PyObject *
325memory_itemsize_get(PyMemoryViewObject *self)
326{
Christian Heimes217cfd12007-12-02 14:31:20 +0000327 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000328}
329
330static PyObject *
331_IntTupleFromSsizet(int len, Py_ssize_t *vals)
332{
333 int i;
334 PyObject *o;
335 PyObject *intTuple;
336
337 if (vals == NULL) {
338 Py_INCREF(Py_None);
339 return Py_None;
340 }
341 intTuple = PyTuple_New(len);
342 if (!intTuple) return NULL;
343 for(i=0; i<len; i++) {
Christian Heimes217cfd12007-12-02 14:31:20 +0000344 o = PyLong_FromSsize_t(vals[i]);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000345 if (!o) {
346 Py_DECREF(intTuple);
347 return NULL;
348 }
349 PyTuple_SET_ITEM(intTuple, i, o);
350 }
351 return intTuple;
352}
353
354static PyObject *
355memory_shape_get(PyMemoryViewObject *self)
356{
357 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
358}
359
360static PyObject *
361memory_strides_get(PyMemoryViewObject *self)
362{
363 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
364}
365
366static PyObject *
367memory_suboffsets_get(PyMemoryViewObject *self)
368{
369 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
370}
371
372static PyObject *
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000373memory_readonly_get(PyMemoryViewObject *self)
374{
Neal Norwitz666bb412007-08-19 18:38:46 +0000375 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000376}
377
378static PyObject *
379memory_ndim_get(PyMemoryViewObject *self)
380{
Christian Heimes217cfd12007-12-02 14:31:20 +0000381 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000382}
383
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000384static PyGetSetDef memory_getsetlist[] ={
Neal Norwitz666bb412007-08-19 18:38:46 +0000385 {"format", (getter)memory_format_get, NULL, NULL},
386 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
387 {"shape", (getter)memory_shape_get, NULL, NULL},
388 {"strides", (getter)memory_strides_get, NULL, NULL},
389 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
Neal Norwitz666bb412007-08-19 18:38:46 +0000390 {"readonly", (getter)memory_readonly_get, NULL, NULL},
391 {"ndim", (getter)memory_ndim_get, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000392 {NULL, NULL, NULL, NULL},
393};
394
395
396static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000397memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000398{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000399 return PyObject_CallFunctionObjArgs(
400 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000401}
402
Antoine Pitrou616d2852008-08-19 22:09:34 +0000403/* TODO: rewrite this function using the struct module to unpack
404 each buffer item */
405
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000406static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000407memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000408{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000409 Py_buffer *view = &(mem->view);
410 Py_ssize_t i;
411 PyObject *res, *item;
412 char *buf;
413
414 if (strcmp(view->format, "B") || view->itemsize != 1) {
415 PyErr_SetString(PyExc_NotImplementedError,
416 "tolist() only supports byte views");
417 return NULL;
418 }
419 if (view->ndim != 1) {
420 PyErr_SetString(PyExc_NotImplementedError,
421 "tolist() only supports one-dimensional objects");
422 return NULL;
423 }
424 res = PyList_New(view->len);
425 if (res == NULL)
426 return NULL;
427 buf = view->buf;
428 for (i = 0; i < view->len; i++) {
429 item = PyLong_FromUnsignedLong((unsigned char) *buf);
430 if (item == NULL) {
431 Py_DECREF(res);
432 return NULL;
433 }
434 PyList_SET_ITEM(res, i, item);
435 buf++;
436 }
437 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000438}
439
440
441
442static PyMethodDef memory_methods[] = {
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000443 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
444 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000445 {NULL, NULL} /* sentinel */
446};
447
448
449static void
450memory_dealloc(PyMemoryViewObject *self)
451{
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000452 _PyObject_GC_UNTRACK(self);
Martin v. Löwis423be952008-08-13 15:53:07 +0000453 if (self->view.obj != NULL) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000454 if (self->base && PyTuple_Check(self->base)) {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000455 /* Special case when first element is generic object
456 with buffer interface and the second element is a
457 contiguous "shadow" that must be copied back into
458 the data areay of the first tuple element before
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000459 releasing the buffer on the first element.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000460 */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000461
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000462 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
463 PyTuple_GET_ITEM(self->base,1));
464
465 /* The view member should have readonly == -1 in
466 this instance indicating that the memory can
467 be "locked" and was locked and will be unlocked
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000468 again after this call.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000469 */
Martin v. Löwis423be952008-08-13 15:53:07 +0000470 PyBuffer_Release(&(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000471 }
472 else {
Martin v. Löwis423be952008-08-13 15:53:07 +0000473 PyBuffer_Release(&(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000474 }
475 Py_CLEAR(self->base);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000476 }
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000477 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000478}
479
480static PyObject *
481memory_repr(PyMemoryViewObject *self)
482{
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000483 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000484}
485
486
487static PyObject *
488memory_str(PyMemoryViewObject *self)
489{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000490 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000491 PyObject *res;
492
493 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
494 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000495
Antoine Pitrou616d2852008-08-19 22:09:34 +0000496 res = PyBytes_FromStringAndSize(NULL, view.len);
497 PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
Martin v. Löwis423be952008-08-13 15:53:07 +0000498 PyBuffer_Release(&view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000499 return res;
500}
501
502/* Sequence methods */
503
504static Py_ssize_t
505memory_length(PyMemoryViewObject *self)
506{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000507 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000508
509 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
510 return -1;
Martin v. Löwis423be952008-08-13 15:53:07 +0000511 PyBuffer_Release(&view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000512 return view.len;
513}
514
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000515/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000516 mem[obj] returns a bytes object holding the data for one element if
517 obj fully indexes the memory view or another memory-view object
518 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000519
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000520 0-d memory-view objects can be referenced using ... or () but
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000521 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000522 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000523static PyObject *
524memory_subscript(PyMemoryViewObject *self, PyObject *key)
525{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000526 Py_buffer *view;
527 view = &(self->view);
528
529 if (view->ndim == 0) {
530 if (key == Py_Ellipsis ||
531 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
532 Py_INCREF(self);
533 return (PyObject *)self;
534 }
535 else {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000536 PyErr_SetString(PyExc_IndexError,
537 "invalid indexing of 0-dim memory");
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000538 return NULL;
539 }
540 }
541 if (PyIndex_Check(key)) {
542 Py_ssize_t result;
543 result = PyNumber_AsSsize_t(key, NULL);
544 if (result == -1 && PyErr_Occurred())
545 return NULL;
546 if (view->ndim == 1) {
547 /* Return a bytes object */
548 char *ptr;
549 ptr = (char *)view->buf;
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000550 if (result < 0) {
551 result += view->shape[0];
552 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000553 if ((result < 0) || (result >= view->shape[0])) {
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000554 PyErr_SetString(PyExc_IndexError,
555 "index out of bounds");
556 return NULL;
557 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000558 if (view->strides == NULL)
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000559 ptr += view->itemsize * result;
560 else
561 ptr += view->strides[0] * result;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000562 if (view->suboffsets != NULL &&
563 view->suboffsets[0] >= 0)
564 {
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000565 ptr = *((char **)ptr) + view->suboffsets[0];
566 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000567 return PyBytes_FromStringAndSize(ptr, view->itemsize);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000568 }
569 else {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000570 /* Return a new memory-view object */
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000571 Py_buffer newview;
Neal Norwitzb35f1282007-10-07 19:26:50 +0000572 memset(&newview, 0, sizeof(newview));
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000573 /* XXX: This needs to be fixed so it
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000574 actually returns a sub-view
575 */
Antoine Pitrouee58fa42008-08-19 18:22:14 +0000576 return PyMemoryView_FromBuffer(&newview);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000577 }
578 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000579 else if (PySlice_Check(key)) {
580 Py_ssize_t start, stop, step, slicelength;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000581
Antoine Pitrou616d2852008-08-19 22:09:34 +0000582 if (PySlice_GetIndicesEx((PySliceObject*)key, view->len,
583 &start, &stop, &step, &slicelength) < 0) {
584 return NULL;
585 }
586
587 if (step == 1 && view->ndim == 1) {
588 Py_buffer newview;
589 void *newbuf = (char *) view->buf
590 + start * view->itemsize;
591 int newflags = view->readonly
592 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
593
594 /* XXX There should be an API to create a subbuffer */
595 if (view->obj != NULL) {
596 if (PyObject_GetBuffer(view->obj,
597 &newview, newflags) == -1)
598 return NULL;
599 }
600 else {
601 newview = *view;
602 }
603 newview.buf = newbuf;
604 newview.len = slicelength;
605 newview.format = view->format;
606 if (view->shape == &(view->len))
607 newview.shape = &(newview.len);
608 if (view->strides == &(view->itemsize))
609 newview.strides = &(newview.itemsize);
610 return PyMemoryView_FromBuffer(&newview);
611 }
612 PyErr_SetNone(PyExc_NotImplementedError);
613 return NULL;
614 }
615 PyErr_Format(PyExc_TypeError,
616 "cannot index memory using \"%.200s\"",
617 key->ob_type->tp_name);
618 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000619}
620
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000621
622/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000623static int
624memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
625{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000626 Py_ssize_t start, len, bytelen, i;
627 Py_buffer srcview;
628 Py_buffer *view = &(self->view);
629 char *srcbuf, *destbuf;
630
631 if (view->readonly) {
632 PyErr_SetString(PyExc_TypeError,
633 "cannot modify read-only memory");
634 return -1;
635 }
636 if (view->ndim != 1) {
637 PyErr_SetNone(PyExc_NotImplementedError);
638 return -1;
639 }
640 if (PyIndex_Check(key)) {
641 start = PyNumber_AsSsize_t(key, NULL);
642 if (start == -1 && PyErr_Occurred())
643 return -1;
644 if (start < 0) {
645 start += view->shape[0];
646 }
647 if ((start < 0) || (start >= view->shape[0])) {
648 PyErr_SetString(PyExc_IndexError,
649 "index out of bounds");
650 return -1;
651 }
652 len = 1;
653 }
654 else if (PySlice_Check(key)) {
655 Py_ssize_t stop, step;
656
657 if (PySlice_GetIndicesEx((PySliceObject*)key, view->len,
658 &start, &stop, &step, &len) < 0) {
659 return -1;
660 }
661 if (step != 1) {
662 PyErr_SetNone(PyExc_NotImplementedError);
663 return -1;
664 }
665 }
666 else {
667 PyErr_Format(PyExc_TypeError,
668 "cannot index memory using \"%.200s\"",
669 key->ob_type->tp_name);
670 return -1;
671 }
672 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
673 return -1;
674 }
675 /* XXX should we allow assignment of different item sizes
676 as long as the byte length is the same?
677 (e.g. assign 2 shorts to a 4-byte slice) */
678 if (srcview.itemsize != view->itemsize) {
679 PyErr_Format(PyExc_TypeError,
680 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
681 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
682 goto _error;
683 }
684 if (srcview.len != len) {
685 PyErr_SetString(PyExc_ValueError,
686 "cannot modify size of memoryview object");
687 goto _error;
688 }
689 /* Do the actual copy */
690 destbuf = (char *) view->buf + start * view->itemsize;
691 srcbuf = (char *) srcview.buf;
692 bytelen = len * view->itemsize;
693 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
694 /* No overlapping */
695 memcpy(destbuf, srcbuf, bytelen);
696 else if (destbuf < srcbuf) {
697 /* Copy in ascending order */
698 for (i = 0; i < bytelen; i++)
699 destbuf[i] = srcbuf[i];
700 }
701 else {
702 /* Copy in descencing order */
703 for (i = bytelen - 1; i >= 0; i--)
704 destbuf[i] = srcbuf[i];
705 }
706
707 PyBuffer_Release(&srcview);
708 return 0;
709
710_error:
711 PyBuffer_Release(&srcview);
712 return -1;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000713}
714
Antoine Pitrou616d2852008-08-19 22:09:34 +0000715static PyObject *
716memory_richcompare(PyObject *v, PyObject *w, int op)
717{
718 Py_buffer vv, ww;
719 int equal = 0;
720 PyObject *res;
721
722 vv.obj = NULL;
723 ww.obj = NULL;
724 if (op != Py_EQ && op != Py_NE)
725 goto _notimpl;
726 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
727 PyErr_Clear();
728 goto _notimpl;
729 }
730 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
731 PyErr_Clear();
732 goto _notimpl;
733 }
734
735 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
736 goto _end;
737
738 equal = !memcmp(vv.buf, ww.buf, vv.len * vv.itemsize);
739
740_end:
741 PyBuffer_Release(&vv);
742 PyBuffer_Release(&ww);
743 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
744 res = Py_True;
745 else
746 res = Py_False;
747 Py_INCREF(res);
748 return res;
749
750_notimpl:
751 PyBuffer_Release(&vv);
752 PyBuffer_Release(&ww);
753 Py_INCREF(Py_NotImplemented);
754 return Py_NotImplemented;
755}
756
757
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000758static int
759memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
760{
761 if (self->base != NULL)
762 Py_VISIT(self->base);
763 if (self->view.obj != NULL)
764 Py_VISIT(self->view.obj);
765 return 0;
766}
767
768static int
769memory_clear(PyMemoryViewObject *self)
770{
771 Py_CLEAR(self->base);
772 PyBuffer_Release(&self->view);
773 return 0;
774}
775
776
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000777/* As mapping */
778static PyMappingMethods memory_as_mapping = {
779 (lenfunc)memory_length, /*mp_length*/
780 (binaryfunc)memory_subscript, /*mp_subscript*/
781 (objobjargproc)memory_ass_sub, /*mp_ass_subscript*/
782};
783
784
785/* Buffer methods */
786
787static PyBufferProcs memory_as_buffer = {
788 (getbufferproc)memory_getbuf, /* bf_getbuffer */
789 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
790};
791
792
793PyTypeObject PyMemoryView_Type = {
794 PyVarObject_HEAD_INIT(&PyType_Type, 0)
795 "memoryview",
796 sizeof(PyMemoryViewObject),
797 0,
798 (destructor)memory_dealloc, /* tp_dealloc */
799 0, /* tp_print */
800 0, /* tp_getattr */
801 0, /* tp_setattr */
802 0, /* tp_compare */
803 (reprfunc)memory_repr, /* tp_repr */
804 0, /* tp_as_number */
805 0, /* tp_as_sequence */
806 &memory_as_mapping, /* tp_as_mapping */
807 0, /* tp_hash */
808 0, /* tp_call */
809 (reprfunc)memory_str, /* tp_str */
810 PyObject_GenericGetAttr, /* tp_getattro */
811 0, /* tp_setattro */
812 &memory_as_buffer, /* tp_as_buffer */
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000813 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000814 memory_doc, /* tp_doc */
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000815 (traverseproc)memory_traverse, /* tp_traverse */
816 (inquiry)memory_clear, /* tp_clear */
Antoine Pitrou616d2852008-08-19 22:09:34 +0000817 memory_richcompare, /* tp_richcompare */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000818 0, /* tp_weaklistoffset */
819 0, /* tp_iter */
820 0, /* tp_iternext */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000821 memory_methods, /* tp_methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000822 0, /* tp_members */
823 memory_getsetlist, /* tp_getset */
824 0, /* tp_base */
825 0, /* tp_dict */
826 0, /* tp_descr_get */
827 0, /* tp_descr_set */
828 0, /* tp_dictoffset */
829 0, /* tp_init */
830 0, /* tp_alloc */
831 memory_new, /* tp_new */
832};