blob: fbb1af65d6bd98f1741a3b3b72a9cdb6bfa86fb8 [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 *
373memory_size_get(PyMemoryViewObject *self)
374{
Christian Heimes217cfd12007-12-02 14:31:20 +0000375 return PyLong_FromSsize_t(self->view.len);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000376}
377
378static PyObject *
379memory_readonly_get(PyMemoryViewObject *self)
380{
Neal Norwitz666bb412007-08-19 18:38:46 +0000381 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000382}
383
384static PyObject *
385memory_ndim_get(PyMemoryViewObject *self)
386{
Christian Heimes217cfd12007-12-02 14:31:20 +0000387 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000388}
389
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000390static PyGetSetDef memory_getsetlist[] ={
Neal Norwitz666bb412007-08-19 18:38:46 +0000391 {"format", (getter)memory_format_get, NULL, NULL},
392 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
393 {"shape", (getter)memory_shape_get, NULL, NULL},
394 {"strides", (getter)memory_strides_get, NULL, NULL},
395 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
396 {"size", (getter)memory_size_get, NULL, NULL},
397 {"readonly", (getter)memory_readonly_get, NULL, NULL},
398 {"ndim", (getter)memory_ndim_get, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000399 {NULL, NULL, NULL, NULL},
400};
401
402
403static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000404memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000405{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000406 return PyObject_CallFunctionObjArgs(
407 (PyObject *) &PyBytes_Type, mem, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000408}
409
Antoine Pitrou616d2852008-08-19 22:09:34 +0000410/* TODO: rewrite this function using the struct module to unpack
411 each buffer item */
412
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000413static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000414memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000415{
Antoine Pitrou616d2852008-08-19 22:09:34 +0000416 Py_buffer *view = &(mem->view);
417 Py_ssize_t i;
418 PyObject *res, *item;
419 char *buf;
420
421 if (strcmp(view->format, "B") || view->itemsize != 1) {
422 PyErr_SetString(PyExc_NotImplementedError,
423 "tolist() only supports byte views");
424 return NULL;
425 }
426 if (view->ndim != 1) {
427 PyErr_SetString(PyExc_NotImplementedError,
428 "tolist() only supports one-dimensional objects");
429 return NULL;
430 }
431 res = PyList_New(view->len);
432 if (res == NULL)
433 return NULL;
434 buf = view->buf;
435 for (i = 0; i < view->len; i++) {
436 item = PyLong_FromUnsignedLong((unsigned char) *buf);
437 if (item == NULL) {
438 Py_DECREF(res);
439 return NULL;
440 }
441 PyList_SET_ITEM(res, i, item);
442 buf++;
443 }
444 return res;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000445}
446
447
448
449static PyMethodDef memory_methods[] = {
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000450 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
451 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000452 {NULL, NULL} /* sentinel */
453};
454
455
456static void
457memory_dealloc(PyMemoryViewObject *self)
458{
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000459 _PyObject_GC_UNTRACK(self);
Martin v. Löwis423be952008-08-13 15:53:07 +0000460 if (self->view.obj != NULL) {
Antoine Pitrou616d2852008-08-19 22:09:34 +0000461 if (self->base && PyTuple_Check(self->base)) {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000462 /* Special case when first element is generic object
463 with buffer interface and the second element is a
464 contiguous "shadow" that must be copied back into
465 the data areay of the first tuple element before
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000466 releasing the buffer on the first element.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000467 */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000468
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000469 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
470 PyTuple_GET_ITEM(self->base,1));
471
472 /* The view member should have readonly == -1 in
473 this instance indicating that the memory can
474 be "locked" and was locked and will be unlocked
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000475 again after this call.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000476 */
Martin v. Löwis423be952008-08-13 15:53:07 +0000477 PyBuffer_Release(&(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000478 }
479 else {
Martin v. Löwis423be952008-08-13 15:53:07 +0000480 PyBuffer_Release(&(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000481 }
482 Py_CLEAR(self->base);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000483 }
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000484 PyObject_GC_Del(self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000485}
486
487static PyObject *
488memory_repr(PyMemoryViewObject *self)
489{
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000490 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000491}
492
493
494static PyObject *
495memory_str(PyMemoryViewObject *self)
496{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000497 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000498 PyObject *res;
499
500 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
501 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000502
Antoine Pitrou616d2852008-08-19 22:09:34 +0000503 res = PyBytes_FromStringAndSize(NULL, view.len);
504 PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
Martin v. Löwis423be952008-08-13 15:53:07 +0000505 PyBuffer_Release(&view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000506 return res;
507}
508
509/* Sequence methods */
510
511static Py_ssize_t
512memory_length(PyMemoryViewObject *self)
513{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000514 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000515
516 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
517 return -1;
Martin v. Löwis423be952008-08-13 15:53:07 +0000518 PyBuffer_Release(&view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000519 return view.len;
520}
521
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000522/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000523 mem[obj] returns a bytes object holding the data for one element if
524 obj fully indexes the memory view or another memory-view object
525 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000526
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000527 0-d memory-view objects can be referenced using ... or () but
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000528 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000529 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000530static PyObject *
531memory_subscript(PyMemoryViewObject *self, PyObject *key)
532{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000533 Py_buffer *view;
534 view = &(self->view);
535
536 if (view->ndim == 0) {
537 if (key == Py_Ellipsis ||
538 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
539 Py_INCREF(self);
540 return (PyObject *)self;
541 }
542 else {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000543 PyErr_SetString(PyExc_IndexError,
544 "invalid indexing of 0-dim memory");
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000545 return NULL;
546 }
547 }
548 if (PyIndex_Check(key)) {
549 Py_ssize_t result;
550 result = PyNumber_AsSsize_t(key, NULL);
551 if (result == -1 && PyErr_Occurred())
552 return NULL;
553 if (view->ndim == 1) {
554 /* Return a bytes object */
555 char *ptr;
556 ptr = (char *)view->buf;
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000557 if (result < 0) {
558 result += view->shape[0];
559 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000560 if ((result < 0) || (result >= view->shape[0])) {
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000561 PyErr_SetString(PyExc_IndexError,
562 "index out of bounds");
563 return NULL;
564 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000565 if (view->strides == NULL)
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000566 ptr += view->itemsize * result;
567 else
568 ptr += view->strides[0] * result;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000569 if (view->suboffsets != NULL &&
570 view->suboffsets[0] >= 0)
571 {
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000572 ptr = *((char **)ptr) + view->suboffsets[0];
573 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000574 return PyBytes_FromStringAndSize(ptr, view->itemsize);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000575 }
576 else {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000577 /* Return a new memory-view object */
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000578 Py_buffer newview;
Neal Norwitzb35f1282007-10-07 19:26:50 +0000579 memset(&newview, 0, sizeof(newview));
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000580 /* XXX: This needs to be fixed so it
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000581 actually returns a sub-view
582 */
Antoine Pitrouee58fa42008-08-19 18:22:14 +0000583 return PyMemoryView_FromBuffer(&newview);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000584 }
585 }
Antoine Pitrou616d2852008-08-19 22:09:34 +0000586 else if (PySlice_Check(key)) {
587 Py_ssize_t start, stop, step, slicelength;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000588
Antoine Pitrou616d2852008-08-19 22:09:34 +0000589 if (PySlice_GetIndicesEx((PySliceObject*)key, view->len,
590 &start, &stop, &step, &slicelength) < 0) {
591 return NULL;
592 }
593
594 if (step == 1 && view->ndim == 1) {
595 Py_buffer newview;
596 void *newbuf = (char *) view->buf
597 + start * view->itemsize;
598 int newflags = view->readonly
599 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
600
601 /* XXX There should be an API to create a subbuffer */
602 if (view->obj != NULL) {
603 if (PyObject_GetBuffer(view->obj,
604 &newview, newflags) == -1)
605 return NULL;
606 }
607 else {
608 newview = *view;
609 }
610 newview.buf = newbuf;
611 newview.len = slicelength;
612 newview.format = view->format;
613 if (view->shape == &(view->len))
614 newview.shape = &(newview.len);
615 if (view->strides == &(view->itemsize))
616 newview.strides = &(newview.itemsize);
617 return PyMemoryView_FromBuffer(&newview);
618 }
619 PyErr_SetNone(PyExc_NotImplementedError);
620 return NULL;
621 }
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) {
652 start += view->shape[0];
653 }
654 if ((start < 0) || (start >= view->shape[0])) {
655 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
664 if (PySlice_GetIndicesEx((PySliceObject*)key, view->len,
665 &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 }
691 if (srcview.len != len) {
692 PyErr_SetString(PyExc_ValueError,
693 "cannot modify size of memoryview object");
694 goto _error;
695 }
696 /* Do the actual copy */
697 destbuf = (char *) view->buf + start * view->itemsize;
698 srcbuf = (char *) srcview.buf;
699 bytelen = len * view->itemsize;
700 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
745 equal = !memcmp(vv.buf, ww.buf, vv.len * vv.itemsize);
746
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};