blob: b36c3a7ade599c2ae383ef3b71adfd036de5807e [file] [log] [blame]
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001
2/* Memoryview object implementation */
3
4#include "Python.h"
5
6static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +00007memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00008{
Martin v. Löwis423be952008-08-13 15:53:07 +00009 if (view != NULL) {
10 if (self->view.obj)
11 Py_INCREF(self->view.obj);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000012 *view = self->view;
Martin v. Löwis423be952008-08-13 15:53:07 +000013 }
14 if (self->view.obj == NULL)
Guido van Rossumbe801ac2007-10-08 03:32:34 +000015 return 0;
Martin v. Löwis423be952008-08-13 15:53:07 +000016 return self->view.obj->ob_type->tp_as_buffer->bf_getbuffer(self->base, NULL,
Guido van Rossum5dde61d2007-09-25 22:10:05 +000017 PyBUF_FULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000018}
19
20static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000021memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000022{
Martin v. Löwis423be952008-08-13 15:53:07 +000023 PyBuffer_Release(&self->view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000024}
25
26PyDoc_STRVAR(memory_doc,
27"memoryview(object)\n\
28\n\
29Create a new memoryview object which references the given object.");
30
31PyObject *
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000032PyMemoryView_FromMemory(Py_buffer *info)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000033{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000034 PyMemoryViewObject *mview;
35
36 mview = (PyMemoryViewObject *)PyObject_New(PyMemoryViewObject,
37 &PyMemoryView_Type);
38 if (mview == NULL) return NULL;
39 mview->base = NULL;
40 mview->view = *info;
Martin v. Löwis423be952008-08-13 15:53:07 +000041 if (info->obj)
42 Py_INCREF(mview->view.obj);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000043 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000044}
45
46PyObject *
47PyMemoryView_FromObject(PyObject *base)
48{
49 PyMemoryViewObject *mview;
50
51 if (!PyObject_CheckBuffer(base)) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +000052 PyErr_SetString(PyExc_TypeError,
53 "cannot make memory view because object does "
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000054 "not have the buffer interface");
Guido van Rossum5dde61d2007-09-25 22:10:05 +000055 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000056 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +000057
58 mview = (PyMemoryViewObject *)PyObject_New(PyMemoryViewObject,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000059 &PyMemoryView_Type);
60 if (mview == NULL) return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +000061
Neal Norwitz666bb412007-08-19 18:38:46 +000062 mview->base = NULL;
Antoine Pitrou2f89aa62008-08-02 21:02:48 +000063 if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL_RO) < 0) {
Neal Norwitz666bb412007-08-19 18:38:46 +000064 Py_DECREF(mview);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000065 return NULL;
66 }
67
68 mview->base = base;
69 Py_INCREF(base);
70 return (PyObject *)mview;
71}
72
73static PyObject *
74memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
75{
Christian Heimes7b6fc8e2007-11-08 02:28:11 +000076 PyObject *obj;
77 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000078
Christian Heimes7b6fc8e2007-11-08 02:28:11 +000079 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
80 &obj)) {
81 return NULL;
82 }
83
84 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000085}
86
87
88static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000089_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +000090 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000091{
92 int k;
93 Py_ssize_t outstride;
94
95 if (nd==0) {
96 memcpy(dest, src, itemsize);
97 }
98 else if (nd == 1) {
99 for (k = 0; k<shape[0]; k++) {
100 memcpy(dest, src, itemsize);
101 dest += itemsize;
102 src += strides[0];
103 }
104 }
105 else {
106 if (fort == 'F') {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000107 /* Copy first dimension first,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000108 second dimension second, etc...
109 Set up the recursive loop backwards so that final
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000110 dimension is actually copied last.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000111 */
112 outstride = itemsize;
113 for (k=1; k<nd-1;k++) {
114 outstride *= shape[k];
115 }
116 for (k=0; k<shape[nd-1]; k++) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000117 _strided_copy_nd(dest, src, nd-1, shape,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000118 strides, itemsize, fort);
119 dest += outstride;
120 src += strides[nd-1];
121 }
122 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000123
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000124 else {
125 /* Copy last dimension first,
126 second-to-last dimension second, etc.
127 Set up the recursion so that the
128 first dimension is copied last
129 */
130 outstride = itemsize;
131 for (k=1; k < nd; k++) {
132 outstride *= shape[k];
133 }
134 for (k=0; k<shape[0]; k++) {
135 _strided_copy_nd(dest, src, nd-1, shape+1,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000136 strides+1, itemsize,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000137 fort);
138 dest += outstride;
139 src += strides[0];
140 }
141 }
142 }
143 return;
144}
145
146void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
147void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
148
149static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000150_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000151{
152 Py_ssize_t *indices;
153 int k;
154 Py_ssize_t elements;
155 char *ptr;
156 void (*func)(int, Py_ssize_t *, Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000157
Amaury Forgeot d'Arc9c74b142008-06-18 00:47:36 +0000158 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
159 PyErr_NoMemory();
160 return -1;
161 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000162
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000163 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
164 if (indices == NULL) {
165 PyErr_NoMemory();
166 return -1;
167 }
168 for (k=0; k<view->ndim;k++) {
169 indices[k] = 0;
170 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000171
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000172 elements = 1;
173 for (k=0; k<view->ndim; k++) {
174 elements *= view->shape[k];
175 }
176 if (fort == 'F') {
177 func = _add_one_to_index_F;
178 }
179 else {
180 func = _add_one_to_index_C;
181 }
182 while (elements--) {
183 func(view->ndim, indices, view->shape);
184 ptr = PyBuffer_GetPointer(view, indices);
185 memcpy(dest, ptr, view->itemsize);
186 dest += view->itemsize;
187 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000188
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000189 PyMem_Free(indices);
190 return 0;
191}
192
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000193/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000194 Get a the data from an object as a contiguous chunk of memory (in
195 either 'C' or 'F'ortran order) even if it means copying it into a
196 separate memory area.
197
198 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000199 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000200 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000201 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000202
203 buffertype
204
205 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000206 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000207 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000208 a contiguous buffer if it is not. The view will point to
209 the shadow buffer which can be written to and then
210 will be copied back into the other buffer when the memory
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000211 view is de-allocated. While the shadow buffer is
212 being used, it will have an exclusive write lock on
213 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000214 */
215
216PyObject *
217PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
218{
219 PyMemoryViewObject *mem;
220 PyObject *bytes;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000221 Py_buffer *view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000222 int flags;
223 char *dest;
224
225 if (!PyObject_CheckBuffer(obj)) {
226 PyErr_SetString(PyExc_TypeError,
227 "object does not have the buffer interface");
228 return NULL;
229 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000230
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000231 mem = PyObject_New(PyMemoryViewObject, &PyMemoryView_Type);
232 if (mem == NULL) return NULL;
233
234 view = &PyMemoryView(mem);
235 flags = PyBUF_FULL_RO;
236 switch(buffertype) {
237 case PyBUF_WRITE:
238 flags = PyBUF_FULL;
239 break;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000240 }
241
242 if (PyObject_GetBuffer(obj, view, flags) != 0) {
243 PyObject_DEL(mem);
244 return NULL;
245 }
246
247 if (PyBuffer_IsContiguous(view, fort)) {
248 /* no copy needed */
249 Py_INCREF(obj);
250 mem->base = obj;
251 return (PyObject *)mem;
252 }
253 /* otherwise a copy is needed */
254 if (buffertype == PyBUF_WRITE) {
255 PyObject_DEL(mem);
256 PyErr_SetString(PyExc_BufferError,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000257 "writable contiguous buffer requested "
258 "for a non-contiguousobject.");
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000259 return NULL;
260 }
Christian Heimes9c4756e2008-05-26 13:22:05 +0000261 bytes = PyByteArray_FromStringAndSize(NULL, view->len);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000262 if (bytes == NULL) {
Martin v. Löwis423be952008-08-13 15:53:07 +0000263 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000264 return NULL;
265 }
Christian Heimes9c4756e2008-05-26 13:22:05 +0000266 dest = PyByteArray_AS_STRING(bytes);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000267 /* different copying strategy depending on whether
268 or not any pointer de-referencing is needed
269 */
270 /* strided or in-direct copy */
271 if (view->suboffsets==NULL) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000272 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
273 view->strides, view->itemsize, fort);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000274 }
275 else {
276 if (_indirect_copy_nd(dest, view, fort) < 0) {
277 Py_DECREF(bytes);
Martin v. Löwis423be952008-08-13 15:53:07 +0000278 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000279 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000280 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000281 }
282 if (buffertype == PyBUF_SHADOW) {
283 /* return a shadowed memory-view object */
284 view->buf = dest;
285 mem->base = PyTuple_Pack(2, obj, bytes);
286 Py_DECREF(bytes);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000287 if (mem->base == NULL) {
Martin v. Löwis423be952008-08-13 15:53:07 +0000288 PyBuffer_Release(view);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000289 return NULL;
290 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000291 }
292 else {
Martin v. Löwis423be952008-08-13 15:53:07 +0000293 PyBuffer_Release(view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000294 /* steal the reference */
295 mem->base = bytes;
296 }
297 return (PyObject *)mem;
298}
299
300
301static PyObject *
302memory_format_get(PyMemoryViewObject *self)
303{
304 return PyUnicode_FromString(self->view.format);
305}
306
307static PyObject *
308memory_itemsize_get(PyMemoryViewObject *self)
309{
Christian Heimes217cfd12007-12-02 14:31:20 +0000310 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000311}
312
313static PyObject *
314_IntTupleFromSsizet(int len, Py_ssize_t *vals)
315{
316 int i;
317 PyObject *o;
318 PyObject *intTuple;
319
320 if (vals == NULL) {
321 Py_INCREF(Py_None);
322 return Py_None;
323 }
324 intTuple = PyTuple_New(len);
325 if (!intTuple) return NULL;
326 for(i=0; i<len; i++) {
Christian Heimes217cfd12007-12-02 14:31:20 +0000327 o = PyLong_FromSsize_t(vals[i]);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000328 if (!o) {
329 Py_DECREF(intTuple);
330 return NULL;
331 }
332 PyTuple_SET_ITEM(intTuple, i, o);
333 }
334 return intTuple;
335}
336
337static PyObject *
338memory_shape_get(PyMemoryViewObject *self)
339{
340 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
341}
342
343static PyObject *
344memory_strides_get(PyMemoryViewObject *self)
345{
346 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
347}
348
349static PyObject *
350memory_suboffsets_get(PyMemoryViewObject *self)
351{
352 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
353}
354
355static PyObject *
356memory_size_get(PyMemoryViewObject *self)
357{
Christian Heimes217cfd12007-12-02 14:31:20 +0000358 return PyLong_FromSsize_t(self->view.len);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000359}
360
361static PyObject *
362memory_readonly_get(PyMemoryViewObject *self)
363{
Neal Norwitz666bb412007-08-19 18:38:46 +0000364 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000365}
366
367static PyObject *
368memory_ndim_get(PyMemoryViewObject *self)
369{
Christian Heimes217cfd12007-12-02 14:31:20 +0000370 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000371}
372
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000373static PyGetSetDef memory_getsetlist[] ={
Neal Norwitz666bb412007-08-19 18:38:46 +0000374 {"format", (getter)memory_format_get, NULL, NULL},
375 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
376 {"shape", (getter)memory_shape_get, NULL, NULL},
377 {"strides", (getter)memory_strides_get, NULL, NULL},
378 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
379 {"size", (getter)memory_size_get, NULL, NULL},
380 {"readonly", (getter)memory_readonly_get, NULL, NULL},
381 {"ndim", (getter)memory_ndim_get, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000382 {NULL, NULL, NULL, NULL},
383};
384
385
386static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000387memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000388{
Christian Heimes9c4756e2008-05-26 13:22:05 +0000389 return PyByteArray_FromObject((PyObject *)mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000390}
391
392static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000393memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000394{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000395 /* This should construct a (nested) list of unpacked objects
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000396 possibly using the struct module.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000397 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000398 Py_INCREF(Py_NotImplemented);
399 return Py_NotImplemented;
400}
401
402
403
404static PyMethodDef memory_methods[] = {
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000405 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
406 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000407 {NULL, NULL} /* sentinel */
408};
409
410
411static void
412memory_dealloc(PyMemoryViewObject *self)
413{
Martin v. Löwis423be952008-08-13 15:53:07 +0000414 if (self->view.obj != NULL) {
Neal Norwitz666bb412007-08-19 18:38:46 +0000415 if (PyTuple_Check(self->base)) {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000416 /* Special case when first element is generic object
417 with buffer interface and the second element is a
418 contiguous "shadow" that must be copied back into
419 the data areay of the first tuple element before
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000420 releasing the buffer on the first element.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000421 */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000422
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000423 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
424 PyTuple_GET_ITEM(self->base,1));
425
426 /* The view member should have readonly == -1 in
427 this instance indicating that the memory can
428 be "locked" and was locked and will be unlocked
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000429 again after this call.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000430 */
Martin v. Löwis423be952008-08-13 15:53:07 +0000431 PyBuffer_Release(&(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000432 }
433 else {
Martin v. Löwis423be952008-08-13 15:53:07 +0000434 PyBuffer_Release(&(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000435 }
436 Py_CLEAR(self->base);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000437 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000438 PyObject_DEL(self);
439}
440
441static PyObject *
442memory_repr(PyMemoryViewObject *self)
443{
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000444 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000445}
446
447
448static PyObject *
449memory_str(PyMemoryViewObject *self)
450{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000451 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000452 PyObject *res;
453
454 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
455 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000456
Christian Heimes9c4756e2008-05-26 13:22:05 +0000457 res = PyByteArray_FromStringAndSize(NULL, view.len);
458 PyBuffer_ToContiguous(PyByteArray_AS_STRING(res), &view, view.len, 'C');
Martin v. Löwis423be952008-08-13 15:53:07 +0000459 PyBuffer_Release(&view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000460 return res;
461}
462
463/* Sequence methods */
464
465static Py_ssize_t
466memory_length(PyMemoryViewObject *self)
467{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000468 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000469
470 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
471 return -1;
Martin v. Löwis423be952008-08-13 15:53:07 +0000472 PyBuffer_Release(&view);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000473 return view.len;
474}
475
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000476/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000477 mem[obj] returns a bytes object holding the data for one element if
478 obj fully indexes the memory view or another memory-view object
479 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000480
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000481 0-d memory-view objects can be referenced using ... or () but
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000482 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000483 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000484static PyObject *
485memory_subscript(PyMemoryViewObject *self, PyObject *key)
486{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000487 Py_buffer *view;
488 view = &(self->view);
489
490 if (view->ndim == 0) {
491 if (key == Py_Ellipsis ||
492 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
493 Py_INCREF(self);
494 return (PyObject *)self;
495 }
496 else {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000497 PyErr_SetString(PyExc_IndexError,
498 "invalid indexing of 0-dim memory");
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000499 return NULL;
500 }
501 }
502 if (PyIndex_Check(key)) {
503 Py_ssize_t result;
504 result = PyNumber_AsSsize_t(key, NULL);
505 if (result == -1 && PyErr_Occurred())
506 return NULL;
507 if (view->ndim == 1) {
508 /* Return a bytes object */
509 char *ptr;
510 ptr = (char *)view->buf;
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000511 if (result < 0) {
512 result += view->shape[0];
513 }
514 if ((result < 0) || (result > view->shape[0])) {
515 PyErr_SetString(PyExc_IndexError,
516 "index out of bounds");
517 return NULL;
518 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000519 if (view->strides == NULL)
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000520 ptr += view->itemsize * result;
521 else
522 ptr += view->strides[0] * result;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000523 if (view->suboffsets != NULL &&
524 view->suboffsets[0] >= 0)
525 {
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000526 ptr = *((char **)ptr) + view->suboffsets[0];
527 }
Christian Heimes9c4756e2008-05-26 13:22:05 +0000528 return PyByteArray_FromStringAndSize(ptr, view->itemsize);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000529 }
530 else {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000531 /* Return a new memory-view object */
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000532 Py_buffer newview;
Neal Norwitzb35f1282007-10-07 19:26:50 +0000533 memset(&newview, 0, sizeof(newview));
Antoine Pitrou2f89aa62008-08-02 21:02:48 +0000534 /* XXX: This needs to be fixed so it
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000535 actually returns a sub-view
536 */
Neal Norwitzb35f1282007-10-07 19:26:50 +0000537 return PyMemoryView_FromMemory(&newview);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000538 }
539 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000540
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000541 /* Need to support getting a sliced view */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000542 Py_INCREF(Py_NotImplemented);
543 return Py_NotImplemented;
544}
545
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000546
547/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000548static int
549memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
550{
551 return 0;
552}
553
554/* As mapping */
555static PyMappingMethods memory_as_mapping = {
556 (lenfunc)memory_length, /*mp_length*/
557 (binaryfunc)memory_subscript, /*mp_subscript*/
558 (objobjargproc)memory_ass_sub, /*mp_ass_subscript*/
559};
560
561
562/* Buffer methods */
563
564static PyBufferProcs memory_as_buffer = {
565 (getbufferproc)memory_getbuf, /* bf_getbuffer */
566 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
567};
568
569
570PyTypeObject PyMemoryView_Type = {
571 PyVarObject_HEAD_INIT(&PyType_Type, 0)
572 "memoryview",
573 sizeof(PyMemoryViewObject),
574 0,
575 (destructor)memory_dealloc, /* tp_dealloc */
576 0, /* tp_print */
577 0, /* tp_getattr */
578 0, /* tp_setattr */
579 0, /* tp_compare */
580 (reprfunc)memory_repr, /* tp_repr */
581 0, /* tp_as_number */
582 0, /* tp_as_sequence */
583 &memory_as_mapping, /* tp_as_mapping */
584 0, /* tp_hash */
585 0, /* tp_call */
586 (reprfunc)memory_str, /* tp_str */
587 PyObject_GenericGetAttr, /* tp_getattro */
588 0, /* tp_setattro */
589 &memory_as_buffer, /* tp_as_buffer */
590 Py_TPFLAGS_DEFAULT, /* tp_flags */
591 memory_doc, /* tp_doc */
592 0, /* tp_traverse */
593 0, /* tp_clear */
594 0, /* tp_richcompare */
595 0, /* tp_weaklistoffset */
596 0, /* tp_iter */
597 0, /* tp_iternext */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000598 memory_methods, /* tp_methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000599 0, /* tp_members */
600 memory_getsetlist, /* tp_getset */
601 0, /* tp_base */
602 0, /* tp_dict */
603 0, /* tp_descr_get */
604 0, /* tp_descr_set */
605 0, /* tp_dictoffset */
606 0, /* tp_init */
607 0, /* tp_alloc */
608 memory_new, /* tp_new */
609};