blob: 9bb16971d6a37fba1dac3b7e0bbd4eec878bb0e8 [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{
Guido van Rossum5dde61d2007-09-25 22:10:05 +00009 if (view != NULL)
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000010 *view = self->view;
Guido van Rossumbe801ac2007-10-08 03:32:34 +000011 if (self->base == NULL)
12 return 0;
Guido van Rossum5dde61d2007-09-25 22:10:05 +000013 return self->base->ob_type->tp_as_buffer->bf_getbuffer(self->base, NULL,
14 PyBUF_FULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000015}
16
17static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000018memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000019{
Guido van Rossumbe801ac2007-10-08 03:32:34 +000020 if (self->base != NULL)
21 PyObject_ReleaseBuffer(self->base, NULL);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000022}
23
24PyDoc_STRVAR(memory_doc,
25"memoryview(object)\n\
26\n\
27Create a new memoryview object which references the given object.");
28
29PyObject *
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000030PyMemoryView_FromMemory(Py_buffer *info)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000031{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +000032 PyMemoryViewObject *mview;
33
34 mview = (PyMemoryViewObject *)PyObject_New(PyMemoryViewObject,
35 &PyMemoryView_Type);
36 if (mview == NULL) return NULL;
37 mview->base = NULL;
38 mview->view = *info;
39 return (PyObject *)mview;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000040}
41
42PyObject *
43PyMemoryView_FromObject(PyObject *base)
44{
45 PyMemoryViewObject *mview;
46
47 if (!PyObject_CheckBuffer(base)) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +000048 PyErr_SetString(PyExc_TypeError,
49 "cannot make memory view because object does "
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000050 "not have the buffer interface");
Guido van Rossum5dde61d2007-09-25 22:10:05 +000051 return NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000052 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +000053
54 mview = (PyMemoryViewObject *)PyObject_New(PyMemoryViewObject,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000055 &PyMemoryView_Type);
56 if (mview == NULL) return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +000057
Neal Norwitz666bb412007-08-19 18:38:46 +000058 mview->base = NULL;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000059 if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL) < 0) {
Neal Norwitz666bb412007-08-19 18:38:46 +000060 Py_DECREF(mview);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000061 return NULL;
62 }
63
64 mview->base = base;
65 Py_INCREF(base);
66 return (PyObject *)mview;
67}
68
69static PyObject *
70memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
71{
Christian Heimes7b6fc8e2007-11-08 02:28:11 +000072 PyObject *obj;
73 static char *kwlist[] = {"object", 0};
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000074
Christian Heimes7b6fc8e2007-11-08 02:28:11 +000075 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
76 &obj)) {
77 return NULL;
78 }
79
80 return PyMemoryView_FromObject(obj);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000081}
82
83
84static void
Guido van Rossum5dde61d2007-09-25 22:10:05 +000085_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Neal Norwitz61ec0d32007-10-26 06:44:10 +000086 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000087{
88 int k;
89 Py_ssize_t outstride;
90
91 if (nd==0) {
92 memcpy(dest, src, itemsize);
93 }
94 else if (nd == 1) {
95 for (k = 0; k<shape[0]; k++) {
96 memcpy(dest, src, itemsize);
97 dest += itemsize;
98 src += strides[0];
99 }
100 }
101 else {
102 if (fort == 'F') {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000103 /* Copy first dimension first,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000104 second dimension second, etc...
105 Set up the recursive loop backwards so that final
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000106 dimension is actually copied last.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000107 */
108 outstride = itemsize;
109 for (k=1; k<nd-1;k++) {
110 outstride *= shape[k];
111 }
112 for (k=0; k<shape[nd-1]; k++) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000113 _strided_copy_nd(dest, src, nd-1, shape,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000114 strides, itemsize, fort);
115 dest += outstride;
116 src += strides[nd-1];
117 }
118 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000119
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000120 else {
121 /* Copy last dimension first,
122 second-to-last dimension second, etc.
123 Set up the recursion so that the
124 first dimension is copied last
125 */
126 outstride = itemsize;
127 for (k=1; k < nd; k++) {
128 outstride *= shape[k];
129 }
130 for (k=0; k<shape[0]; k++) {
131 _strided_copy_nd(dest, src, nd-1, shape+1,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000132 strides+1, itemsize,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000133 fort);
134 dest += outstride;
135 src += strides[0];
136 }
137 }
138 }
139 return;
140}
141
142void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
143void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
144
145static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000146_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000147{
148 Py_ssize_t *indices;
149 int k;
150 Py_ssize_t elements;
151 char *ptr;
152 void (*func)(int, Py_ssize_t *, Py_ssize_t *);
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000153
154
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000155 /* XXX(nnorwitz): need to check for overflow! */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000156 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
157 if (indices == NULL) {
158 PyErr_NoMemory();
159 return -1;
160 }
161 for (k=0; k<view->ndim;k++) {
162 indices[k] = 0;
163 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000164
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000165 elements = 1;
166 for (k=0; k<view->ndim; k++) {
167 elements *= view->shape[k];
168 }
169 if (fort == 'F') {
170 func = _add_one_to_index_F;
171 }
172 else {
173 func = _add_one_to_index_C;
174 }
175 while (elements--) {
176 func(view->ndim, indices, view->shape);
177 ptr = PyBuffer_GetPointer(view, indices);
178 memcpy(dest, ptr, view->itemsize);
179 dest += view->itemsize;
180 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000181
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000182 PyMem_Free(indices);
183 return 0;
184}
185
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000186/*
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000187 Get a the data from an object as a contiguous chunk of memory (in
188 either 'C' or 'F'ortran order) even if it means copying it into a
189 separate memory area.
190
191 Returns a new reference to a Memory view object. If no copy is needed,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000192 the memory view object points to the original memory and holds a
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000193 lock on the original. If a copy is needed, then the memory view object
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000194 points to a brand-new Bytes object (and holds a memory lock on it).
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000195
196 buffertype
197
198 PyBUF_READ buffer only needs to be read-only
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000199 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000200 PyBUF_SHADOW buffer needs to be writable so shadow it with
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000201 a contiguous buffer if it is not. The view will point to
202 the shadow buffer which can be written to and then
203 will be copied back into the other buffer when the memory
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000204 view is de-allocated. While the shadow buffer is
205 being used, it will have an exclusive write lock on
206 the original buffer.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000207 */
208
209PyObject *
210PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
211{
212 PyMemoryViewObject *mem;
213 PyObject *bytes;
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000214 Py_buffer *view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000215 int flags;
216 char *dest;
217
218 if (!PyObject_CheckBuffer(obj)) {
219 PyErr_SetString(PyExc_TypeError,
220 "object does not have the buffer interface");
221 return NULL;
222 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000223
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000224 mem = PyObject_New(PyMemoryViewObject, &PyMemoryView_Type);
225 if (mem == NULL) return NULL;
226
227 view = &PyMemoryView(mem);
228 flags = PyBUF_FULL_RO;
229 switch(buffertype) {
230 case PyBUF_WRITE:
231 flags = PyBUF_FULL;
232 break;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000233 }
234
235 if (PyObject_GetBuffer(obj, view, flags) != 0) {
236 PyObject_DEL(mem);
237 return NULL;
238 }
239
240 if (PyBuffer_IsContiguous(view, fort)) {
241 /* no copy needed */
242 Py_INCREF(obj);
243 mem->base = obj;
244 return (PyObject *)mem;
245 }
246 /* otherwise a copy is needed */
247 if (buffertype == PyBUF_WRITE) {
248 PyObject_DEL(mem);
249 PyErr_SetString(PyExc_BufferError,
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000250 "writable contiguous buffer requested "
251 "for a non-contiguousobject.");
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000252 return NULL;
253 }
Christian Heimes9c4756e2008-05-26 13:22:05 +0000254 bytes = PyByteArray_FromStringAndSize(NULL, view->len);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000255 if (bytes == NULL) {
256 PyObject_ReleaseBuffer(obj, view);
257 return NULL;
258 }
Christian Heimes9c4756e2008-05-26 13:22:05 +0000259 dest = PyByteArray_AS_STRING(bytes);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000260 /* different copying strategy depending on whether
261 or not any pointer de-referencing is needed
262 */
263 /* strided or in-direct copy */
264 if (view->suboffsets==NULL) {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000265 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
266 view->strides, view->itemsize, fort);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000267 }
268 else {
269 if (_indirect_copy_nd(dest, view, fort) < 0) {
270 Py_DECREF(bytes);
271 PyObject_ReleaseBuffer(obj, view);
272 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000273 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000274 }
275 if (buffertype == PyBUF_SHADOW) {
276 /* return a shadowed memory-view object */
277 view->buf = dest;
278 mem->base = PyTuple_Pack(2, obj, bytes);
279 Py_DECREF(bytes);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000280 if (mem->base == NULL) {
281 PyObject_ReleaseBuffer(obj, view);
282 return NULL;
283 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000284 }
285 else {
286 PyObject_ReleaseBuffer(obj, view);
287 /* steal the reference */
288 mem->base = bytes;
289 }
290 return (PyObject *)mem;
291}
292
293
294static PyObject *
295memory_format_get(PyMemoryViewObject *self)
296{
297 return PyUnicode_FromString(self->view.format);
298}
299
300static PyObject *
301memory_itemsize_get(PyMemoryViewObject *self)
302{
Christian Heimes217cfd12007-12-02 14:31:20 +0000303 return PyLong_FromSsize_t(self->view.itemsize);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000304}
305
306static PyObject *
307_IntTupleFromSsizet(int len, Py_ssize_t *vals)
308{
309 int i;
310 PyObject *o;
311 PyObject *intTuple;
312
313 if (vals == NULL) {
314 Py_INCREF(Py_None);
315 return Py_None;
316 }
317 intTuple = PyTuple_New(len);
318 if (!intTuple) return NULL;
319 for(i=0; i<len; i++) {
Christian Heimes217cfd12007-12-02 14:31:20 +0000320 o = PyLong_FromSsize_t(vals[i]);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000321 if (!o) {
322 Py_DECREF(intTuple);
323 return NULL;
324 }
325 PyTuple_SET_ITEM(intTuple, i, o);
326 }
327 return intTuple;
328}
329
330static PyObject *
331memory_shape_get(PyMemoryViewObject *self)
332{
333 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
334}
335
336static PyObject *
337memory_strides_get(PyMemoryViewObject *self)
338{
339 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
340}
341
342static PyObject *
343memory_suboffsets_get(PyMemoryViewObject *self)
344{
345 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
346}
347
348static PyObject *
349memory_size_get(PyMemoryViewObject *self)
350{
Christian Heimes217cfd12007-12-02 14:31:20 +0000351 return PyLong_FromSsize_t(self->view.len);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000352}
353
354static PyObject *
355memory_readonly_get(PyMemoryViewObject *self)
356{
Neal Norwitz666bb412007-08-19 18:38:46 +0000357 return PyBool_FromLong(self->view.readonly);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000358}
359
360static PyObject *
361memory_ndim_get(PyMemoryViewObject *self)
362{
Christian Heimes217cfd12007-12-02 14:31:20 +0000363 return PyLong_FromLong(self->view.ndim);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000364}
365
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000366static PyGetSetDef memory_getsetlist[] ={
Neal Norwitz666bb412007-08-19 18:38:46 +0000367 {"format", (getter)memory_format_get, NULL, NULL},
368 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
369 {"shape", (getter)memory_shape_get, NULL, NULL},
370 {"strides", (getter)memory_strides_get, NULL, NULL},
371 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
372 {"size", (getter)memory_size_get, NULL, NULL},
373 {"readonly", (getter)memory_readonly_get, NULL, NULL},
374 {"ndim", (getter)memory_ndim_get, NULL, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000375 {NULL, NULL, NULL, NULL},
376};
377
378
379static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000380memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000381{
Christian Heimes9c4756e2008-05-26 13:22:05 +0000382 return PyByteArray_FromObject((PyObject *)mem);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000383}
384
385static PyObject *
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000386memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000387{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000388 /* This should construct a (nested) list of unpacked objects
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000389 possibly using the struct module.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000390 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000391 Py_INCREF(Py_NotImplemented);
392 return Py_NotImplemented;
393}
394
395
396
397static PyMethodDef memory_methods[] = {
Neal Norwitzfaa54a32007-08-19 04:23:20 +0000398 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
399 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000400 {NULL, NULL} /* sentinel */
401};
402
403
404static void
405memory_dealloc(PyMemoryViewObject *self)
406{
Neal Norwitz666bb412007-08-19 18:38:46 +0000407 if (self->base != NULL) {
408 if (PyTuple_Check(self->base)) {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000409 /* Special case when first element is generic object
410 with buffer interface and the second element is a
411 contiguous "shadow" that must be copied back into
412 the data areay of the first tuple element before
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000413 releasing the buffer on the first element.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000414 */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000415
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000416 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
417 PyTuple_GET_ITEM(self->base,1));
418
419 /* The view member should have readonly == -1 in
420 this instance indicating that the memory can
421 be "locked" and was locked and will be unlocked
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000422 again after this call.
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000423 */
424 PyObject_ReleaseBuffer(PyTuple_GET_ITEM(self->base,0),
425 &(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000426 }
427 else {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000428 PyObject_ReleaseBuffer(self->base, &(self->view));
Neal Norwitz666bb412007-08-19 18:38:46 +0000429 }
430 Py_CLEAR(self->base);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000431 }
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000432 PyObject_DEL(self);
433}
434
435static PyObject *
436memory_repr(PyMemoryViewObject *self)
437{
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000438 return PyUnicode_FromFormat("<memory at %p>", self);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000439}
440
441
442static PyObject *
443memory_str(PyMemoryViewObject *self)
444{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000445 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000446 PyObject *res;
447
448 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
449 return NULL;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000450
Christian Heimes9c4756e2008-05-26 13:22:05 +0000451 res = PyByteArray_FromStringAndSize(NULL, view.len);
452 PyBuffer_ToContiguous(PyByteArray_AS_STRING(res), &view, view.len, 'C');
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000453 PyObject_ReleaseBuffer((PyObject *)self, &view);
454 return res;
455}
456
457/* Sequence methods */
458
459static Py_ssize_t
460memory_length(PyMemoryViewObject *self)
461{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000462 Py_buffer view;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000463
464 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
465 return -1;
466 PyObject_ReleaseBuffer((PyObject *)self, &view);
467 return view.len;
468}
469
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000470/*
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000471 mem[obj] returns a bytes object holding the data for one element if
472 obj fully indexes the memory view or another memory-view object
473 if it does not.
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000474
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000475 0-d memory-view objects can be referenced using ... or () but
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000476 not with anything else.
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000477 */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000478static PyObject *
479memory_subscript(PyMemoryViewObject *self, PyObject *key)
480{
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000481 Py_buffer *view;
482 view = &(self->view);
483
484 if (view->ndim == 0) {
485 if (key == Py_Ellipsis ||
486 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
487 Py_INCREF(self);
488 return (PyObject *)self;
489 }
490 else {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000491 PyErr_SetString(PyExc_IndexError,
492 "invalid indexing of 0-dim memory");
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000493 return NULL;
494 }
495 }
496 if (PyIndex_Check(key)) {
497 Py_ssize_t result;
498 result = PyNumber_AsSsize_t(key, NULL);
499 if (result == -1 && PyErr_Occurred())
500 return NULL;
501 if (view->ndim == 1) {
502 /* Return a bytes object */
503 char *ptr;
504 ptr = (char *)view->buf;
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000505 if (result < 0) {
506 result += view->shape[0];
507 }
508 if ((result < 0) || (result > view->shape[0])) {
509 PyErr_SetString(PyExc_IndexError,
510 "index out of bounds");
511 return NULL;
512 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000513 if (view->strides == NULL)
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000514 ptr += view->itemsize * result;
515 else
516 ptr += view->strides[0] * result;
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000517 if (view->suboffsets != NULL &&
518 view->suboffsets[0] >= 0)
519 {
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000520 ptr = *((char **)ptr) + view->suboffsets[0];
521 }
Christian Heimes9c4756e2008-05-26 13:22:05 +0000522 return PyByteArray_FromStringAndSize(ptr, view->itemsize);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000523 }
524 else {
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000525 /* Return a new memory-view object */
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000526 Py_buffer newview;
Neal Norwitzb35f1282007-10-07 19:26:50 +0000527 memset(&newview, 0, sizeof(newview));
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000528 /* XXX: This needs to be fixed so it
529 actually returns a sub-view
530 */
Neal Norwitzb35f1282007-10-07 19:26:50 +0000531 return PyMemoryView_FromMemory(&newview);
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000532 }
533 }
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000534
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000535 /* Need to support getting a sliced view */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000536 Py_INCREF(Py_NotImplemented);
537 return Py_NotImplemented;
538}
539
Travis E. Oliphantfe9bed02007-10-12 23:27:53 +0000540
541/* Need to support assigning memory if we can */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000542static int
543memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
544{
545 return 0;
546}
547
548/* As mapping */
549static PyMappingMethods memory_as_mapping = {
550 (lenfunc)memory_length, /*mp_length*/
551 (binaryfunc)memory_subscript, /*mp_subscript*/
552 (objobjargproc)memory_ass_sub, /*mp_ass_subscript*/
553};
554
555
556/* Buffer methods */
557
558static PyBufferProcs memory_as_buffer = {
559 (getbufferproc)memory_getbuf, /* bf_getbuffer */
560 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
561};
562
563
564PyTypeObject PyMemoryView_Type = {
565 PyVarObject_HEAD_INIT(&PyType_Type, 0)
566 "memoryview",
567 sizeof(PyMemoryViewObject),
568 0,
569 (destructor)memory_dealloc, /* tp_dealloc */
570 0, /* tp_print */
571 0, /* tp_getattr */
572 0, /* tp_setattr */
573 0, /* tp_compare */
574 (reprfunc)memory_repr, /* tp_repr */
575 0, /* tp_as_number */
576 0, /* tp_as_sequence */
577 &memory_as_mapping, /* tp_as_mapping */
578 0, /* tp_hash */
579 0, /* tp_call */
580 (reprfunc)memory_str, /* tp_str */
581 PyObject_GenericGetAttr, /* tp_getattro */
582 0, /* tp_setattro */
583 &memory_as_buffer, /* tp_as_buffer */
584 Py_TPFLAGS_DEFAULT, /* tp_flags */
585 memory_doc, /* tp_doc */
586 0, /* tp_traverse */
587 0, /* tp_clear */
588 0, /* tp_richcompare */
589 0, /* tp_weaklistoffset */
590 0, /* tp_iter */
591 0, /* tp_iternext */
Guido van Rossum5dde61d2007-09-25 22:10:05 +0000592 memory_methods, /* tp_methods */
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000593 0, /* tp_members */
594 memory_getsetlist, /* tp_getset */
595 0, /* tp_base */
596 0, /* tp_dict */
597 0, /* tp_descr_get */
598 0, /* tp_descr_set */
599 0, /* tp_dictoffset */
600 0, /* tp_init */
601 0, /* tp_alloc */
602 memory_new, /* tp_new */
603};