blob: 9427522c36d39675270ad17ab5ea4d025a309f83 [file] [log] [blame]
Antoine Pitrou789be0c2009-04-02 21:18:34 +00001
2/* Memoryview object implementation */
3
4#include "Python.h"
5
6static Py_ssize_t
7get_shape0(Py_buffer *buf)
8{
9 if (buf->shape != NULL)
10 return buf->shape[0];
11 if (buf->ndim == 0)
12 return 1;
13 PyErr_SetString(PyExc_TypeError,
14 "exported buffer does not have any shape information associated "
15 "to it");
16 return -1;
17}
18
19static void
20dup_buffer(Py_buffer *dest, Py_buffer *src)
21{
22 *dest = *src;
23 if (src->ndim == 1 && src->shape != NULL) {
24 dest->shape = &(dest->smalltable[0]);
25 dest->shape[0] = get_shape0(src);
26 }
27 if (src->ndim == 1 && src->strides != NULL) {
28 dest->strides = &(dest->smalltable[1]);
29 dest->strides[0] = src->strides[0];
30 }
31}
32
33static int
34memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
35{
36 int res = 0;
37 /* XXX for whatever reason fixing the flags seems necessary */
38 if (self->view.readonly)
39 flags &= ~PyBUF_WRITABLE;
40 if (self->view.obj != NULL)
41 res = PyObject_GetBuffer(self->view.obj, view, flags);
42 if (view)
43 dup_buffer(view, &self->view);
44 return res;
45}
46
47static void
48memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
49{
50 PyBuffer_Release(view);
51}
52
53PyDoc_STRVAR(memory_doc,
54"memoryview(object)\n\
55\n\
56Create a new memoryview object which references the given object.");
57
58PyObject *
59PyMemoryView_FromBuffer(Py_buffer *info)
60{
61 PyMemoryViewObject *mview;
62
63 mview = (PyMemoryViewObject *)
64 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
65 if (mview == NULL)
66 return NULL;
67 mview->base = NULL;
68 dup_buffer(&mview->view, info);
69 /* NOTE: mview->view.obj should already have been incref'ed as
70 part of PyBuffer_FillInfo(). */
71 _PyObject_GC_TRACK(mview);
72 return (PyObject *)mview;
73}
74
75PyObject *
76PyMemoryView_FromObject(PyObject *base)
77{
78 PyMemoryViewObject *mview;
79
80 if (!PyObject_CheckBuffer(base)) {
81 PyErr_SetString(PyExc_TypeError,
82 "cannot make memory view because object does "
83 "not have the buffer interface");
84 return NULL;
85 }
86
87 mview = (PyMemoryViewObject *)
88 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
89 if (mview == NULL)
90 return NULL;
91
92 mview->base = NULL;
93 if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL_RO) < 0) {
94 Py_DECREF(mview);
95 return NULL;
96 }
97
98 mview->base = base;
99 Py_INCREF(base);
100 _PyObject_GC_TRACK(mview);
101 return (PyObject *)mview;
102}
103
104static PyObject *
105memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
106{
107 PyObject *obj;
108 static char *kwlist[] = {"object", 0};
109
110 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
111 &obj)) {
112 return NULL;
113 }
114
115 return PyMemoryView_FromObject(obj);
116}
117
118
119static void
120_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
121 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
122{
123 int k;
124 Py_ssize_t outstride;
125
126 if (nd==0) {
127 memcpy(dest, src, itemsize);
128 }
129 else if (nd == 1) {
130 for (k = 0; k<shape[0]; k++) {
131 memcpy(dest, src, itemsize);
132 dest += itemsize;
133 src += strides[0];
134 }
135 }
136 else {
137 if (fort == 'F') {
138 /* Copy first dimension first,
139 second dimension second, etc...
140 Set up the recursive loop backwards so that final
141 dimension is actually copied last.
142 */
143 outstride = itemsize;
144 for (k=1; k<nd-1;k++) {
145 outstride *= shape[k];
146 }
147 for (k=0; k<shape[nd-1]; k++) {
148 _strided_copy_nd(dest, src, nd-1, shape,
149 strides, itemsize, fort);
150 dest += outstride;
151 src += strides[nd-1];
152 }
153 }
154
155 else {
156 /* Copy last dimension first,
157 second-to-last dimension second, etc.
158 Set up the recursion so that the
159 first dimension is copied last
160 */
161 outstride = itemsize;
162 for (k=1; k < nd; k++) {
163 outstride *= shape[k];
164 }
165 for (k=0; k<shape[0]; k++) {
166 _strided_copy_nd(dest, src, nd-1, shape+1,
167 strides+1, itemsize,
168 fort);
169 dest += outstride;
170 src += strides[0];
171 }
172 }
173 }
174 return;
175}
176
177void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
178void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
179
180static int
181_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
182{
183 Py_ssize_t *indices;
184 int k;
185 Py_ssize_t elements;
186 char *ptr;
187 void (*func)(int, Py_ssize_t *, Py_ssize_t *);
188
189 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
190 PyErr_NoMemory();
191 return -1;
192 }
193
194 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
195 if (indices == NULL) {
196 PyErr_NoMemory();
197 return -1;
198 }
199 for (k=0; k<view->ndim;k++) {
200 indices[k] = 0;
201 }
202
203 elements = 1;
204 for (k=0; k<view->ndim; k++) {
205 elements *= view->shape[k];
206 }
207 if (fort == 'F') {
208 func = _add_one_to_index_F;
209 }
210 else {
211 func = _add_one_to_index_C;
212 }
213 while (elements--) {
214 func(view->ndim, indices, view->shape);
215 ptr = PyBuffer_GetPointer(view, indices);
216 memcpy(dest, ptr, view->itemsize);
217 dest += view->itemsize;
218 }
219
220 PyMem_Free(indices);
221 return 0;
222}
223
224/*
225 Get a the data from an object as a contiguous chunk of memory (in
226 either 'C' or 'F'ortran order) even if it means copying it into a
227 separate memory area.
228
229 Returns a new reference to a Memory view object. If no copy is needed,
230 the memory view object points to the original memory and holds a
231 lock on the original. If a copy is needed, then the memory view object
232 points to a brand-new Bytes object (and holds a memory lock on it).
233
234 buffertype
235
236 PyBUF_READ buffer only needs to be read-only
237 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
238 PyBUF_SHADOW buffer needs to be writable so shadow it with
239 a contiguous buffer if it is not. The view will point to
240 the shadow buffer which can be written to and then
241 will be copied back into the other buffer when the memory
242 view is de-allocated. While the shadow buffer is
243 being used, it will have an exclusive write lock on
244 the original buffer.
245 */
246
247PyObject *
248PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
249{
250 PyMemoryViewObject *mem;
251 PyObject *bytes;
252 Py_buffer *view;
253 int flags;
254 char *dest;
255
256 if (!PyObject_CheckBuffer(obj)) {
257 PyErr_SetString(PyExc_TypeError,
258 "object does not have the buffer interface");
259 return NULL;
260 }
261
262 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
263 if (mem == NULL)
264 return NULL;
265
266 view = &mem->view;
267 flags = PyBUF_FULL_RO;
268 switch(buffertype) {
269 case PyBUF_WRITE:
270 flags = PyBUF_FULL;
271 break;
272 }
273
274 if (PyObject_GetBuffer(obj, view, flags) != 0) {
275 Py_DECREF(mem);
276 return NULL;
277 }
278
279 if (PyBuffer_IsContiguous(view, fort)) {
280 /* no copy needed */
281 Py_INCREF(obj);
282 mem->base = obj;
283 _PyObject_GC_TRACK(mem);
284 return (PyObject *)mem;
285 }
286 /* otherwise a copy is needed */
287 if (buffertype == PyBUF_WRITE) {
288 Py_DECREF(mem);
289 PyErr_SetString(PyExc_BufferError,
290 "writable contiguous buffer requested "
291 "for a non-contiguousobject.");
292 return NULL;
293 }
294 bytes = PyBytes_FromStringAndSize(NULL, view->len);
295 if (bytes == NULL) {
296 Py_DECREF(mem);
297 return NULL;
298 }
299 dest = PyBytes_AS_STRING(bytes);
300 /* different copying strategy depending on whether
301 or not any pointer de-referencing is needed
302 */
303 /* strided or in-direct copy */
304 if (view->suboffsets==NULL) {
305 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
306 view->strides, view->itemsize, fort);
307 }
308 else {
309 if (_indirect_copy_nd(dest, view, fort) < 0) {
310 Py_DECREF(bytes);
311 Py_DECREF(mem);
312 return NULL;
313 }
314 }
315 if (buffertype == PyBUF_SHADOW) {
316 /* return a shadowed memory-view object */
317 view->buf = dest;
318 mem->base = PyTuple_Pack(2, obj, bytes);
319 Py_DECREF(bytes);
320 if (mem->base == NULL) {
321 Py_DECREF(mem);
322 return NULL;
323 }
324 }
325 else {
326 PyBuffer_Release(view); /* XXX ? */
327 /* steal the reference */
328 mem->base = bytes;
329 }
330 _PyObject_GC_TRACK(mem);
331 return (PyObject *)mem;
332}
333
334
335static PyObject *
336memory_format_get(PyMemoryViewObject *self)
337{
338 return PyUnicode_FromString(self->view.format);
339}
340
341static PyObject *
342memory_itemsize_get(PyMemoryViewObject *self)
343{
344 return PyLong_FromSsize_t(self->view.itemsize);
345}
346
347static PyObject *
348_IntTupleFromSsizet(int len, Py_ssize_t *vals)
349{
350 int i;
351 PyObject *o;
352 PyObject *intTuple;
353
354 if (vals == NULL) {
355 Py_INCREF(Py_None);
356 return Py_None;
357 }
358 intTuple = PyTuple_New(len);
359 if (!intTuple) return NULL;
360 for(i=0; i<len; i++) {
361 o = PyLong_FromSsize_t(vals[i]);
362 if (!o) {
363 Py_DECREF(intTuple);
364 return NULL;
365 }
366 PyTuple_SET_ITEM(intTuple, i, o);
367 }
368 return intTuple;
369}
370
371static PyObject *
372memory_shape_get(PyMemoryViewObject *self)
373{
374 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
375}
376
377static PyObject *
378memory_strides_get(PyMemoryViewObject *self)
379{
380 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
381}
382
383static PyObject *
384memory_suboffsets_get(PyMemoryViewObject *self)
385{
386 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
387}
388
389static PyObject *
390memory_readonly_get(PyMemoryViewObject *self)
391{
392 return PyBool_FromLong(self->view.readonly);
393}
394
395static PyObject *
396memory_ndim_get(PyMemoryViewObject *self)
397{
398 return PyLong_FromLong(self->view.ndim);
399}
400
401static PyGetSetDef memory_getsetlist[] ={
402 {"format", (getter)memory_format_get, NULL, NULL},
403 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
404 {"shape", (getter)memory_shape_get, NULL, NULL},
405 {"strides", (getter)memory_strides_get, NULL, NULL},
406 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
407 {"readonly", (getter)memory_readonly_get, NULL, NULL},
408 {"ndim", (getter)memory_ndim_get, NULL, NULL},
409 {NULL, NULL, NULL, NULL},
410};
411
412
413static PyObject *
414memory_tobytes(PyMemoryViewObject *self, PyObject *noargs)
415{
416 Py_buffer view;
417 PyObject *res;
418
419 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
420 return NULL;
421
422 res = PyBytes_FromStringAndSize(NULL, view.len);
423 PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
424 PyBuffer_Release(&view);
425 return res;
426}
427
428/* TODO: rewrite this function using the struct module to unpack
429 each buffer item */
430
431static PyObject *
432memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
433{
434 Py_buffer *view = &(mem->view);
435 Py_ssize_t i;
436 PyObject *res, *item;
437 char *buf;
438
439 if (strcmp(view->format, "B") || view->itemsize != 1) {
440 PyErr_SetString(PyExc_NotImplementedError,
441 "tolist() only supports byte views");
442 return NULL;
443 }
444 if (view->ndim != 1) {
445 PyErr_SetString(PyExc_NotImplementedError,
446 "tolist() only supports one-dimensional objects");
447 return NULL;
448 }
449 res = PyList_New(view->len);
450 if (res == NULL)
451 return NULL;
452 buf = view->buf;
453 for (i = 0; i < view->len; i++) {
454 item = PyInt_FromLong((unsigned char) *buf);
455 if (item == NULL) {
456 Py_DECREF(res);
457 return NULL;
458 }
459 PyList_SET_ITEM(res, i, item);
460 buf++;
461 }
462 return res;
463}
464
465static PyMethodDef memory_methods[] = {
466 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
467 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
468 {NULL, NULL} /* sentinel */
469};
470
471
472static void
473memory_dealloc(PyMemoryViewObject *self)
474{
475 _PyObject_GC_UNTRACK(self);
476 if (self->view.obj != NULL) {
477 if (self->base && PyTuple_Check(self->base)) {
478 /* Special case when first element is generic object
479 with buffer interface and the second element is a
480 contiguous "shadow" that must be copied back into
481 the data areay of the first tuple element before
482 releasing the buffer on the first element.
483 */
484
485 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
486 PyTuple_GET_ITEM(self->base,1));
487
488 /* The view member should have readonly == -1 in
489 this instance indicating that the memory can
490 be "locked" and was locked and will be unlocked
491 again after this call.
492 */
493 PyBuffer_Release(&(self->view));
494 }
495 else {
496 PyBuffer_Release(&(self->view));
497 }
498 Py_CLEAR(self->base);
499 }
500 PyObject_GC_Del(self);
501}
502
503static PyObject *
504memory_repr(PyMemoryViewObject *self)
505{
506 return PyUnicode_FromFormat("<memory at %p>", self);
507}
508
509/* Sequence methods */
510static Py_ssize_t
511memory_length(PyMemoryViewObject *self)
512{
513 return get_shape0(&self->view);
514}
515
Raymond Hettinger62641e92009-06-23 20:59:43 +0000516/* Alternate version of memory_subcript that only accepts indices.
517 Used by PySeqIter_New().
518*/
519static PyObject *
520memory_item(PyMemoryViewObject *self, Py_ssize_t result)
521{
522 Py_buffer *view = &(self->view);
523
524 if (view->ndim == 0) {
525 PyErr_SetString(PyExc_IndexError,
526 "invalid indexing of 0-dim memory");
527 return NULL;
528 }
529 if (view->ndim == 1) {
530 /* Return a bytes object */
531 char *ptr;
532 ptr = (char *)view->buf;
533 if (result < 0) {
534 result += get_shape0(view);
535 }
536 if ((result < 0) || (result >= get_shape0(view))) {
537 PyErr_SetString(PyExc_IndexError,
538 "index out of bounds");
539 return NULL;
540 }
541 if (view->strides == NULL)
542 ptr += view->itemsize * result;
543 else
544 ptr += view->strides[0] * result;
545 if (view->suboffsets != NULL &&
546 view->suboffsets[0] >= 0) {
547 ptr = *((char **)ptr) + view->suboffsets[0];
548 }
549 return PyBytes_FromStringAndSize(ptr, view->itemsize);
550 } else {
551 /* Return a new memory-view object */
552 Py_buffer newview;
553 memset(&newview, 0, sizeof(newview));
554 /* XXX: This needs to be fixed so it actually returns a sub-view */
555 return PyMemoryView_FromBuffer(&newview);
556 }
557}
558
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000559/*
560 mem[obj] returns a bytes object holding the data for one element if
561 obj fully indexes the memory view or another memory-view object
562 if it does not.
563
564 0-d memory-view objects can be referenced using ... or () but
565 not with anything else.
566 */
567static PyObject *
568memory_subscript(PyMemoryViewObject *self, PyObject *key)
569{
570 Py_buffer *view;
571 view = &(self->view);
572
573 if (view->ndim == 0) {
574 if (key == Py_Ellipsis ||
575 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
576 Py_INCREF(self);
577 return (PyObject *)self;
578 }
579 else {
580 PyErr_SetString(PyExc_IndexError,
581 "invalid indexing of 0-dim memory");
582 return NULL;
583 }
584 }
585 if (PyIndex_Check(key)) {
586 Py_ssize_t result;
587 result = PyNumber_AsSsize_t(key, NULL);
588 if (result == -1 && PyErr_Occurred())
589 return NULL;
Raymond Hettinger62641e92009-06-23 20:59:43 +0000590 return memory_item(self, result);
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000591 }
592 else if (PySlice_Check(key)) {
593 Py_ssize_t start, stop, step, slicelength;
594
595 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
596 &start, &stop, &step, &slicelength) < 0) {
597 return NULL;
598 }
599
600 if (step == 1 && view->ndim == 1) {
601 Py_buffer newview;
602 void *newbuf = (char *) view->buf
603 + start * view->itemsize;
604 int newflags = view->readonly
605 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
606
607 /* XXX There should be an API to create a subbuffer */
608 if (view->obj != NULL) {
609 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
610 return NULL;
611 }
612 else {
613 newview = *view;
614 }
615 newview.buf = newbuf;
616 newview.len = slicelength * newview.itemsize;
617 newview.format = view->format;
618 newview.shape = &(newview.smalltable[0]);
619 newview.shape[0] = slicelength;
620 newview.strides = &(newview.itemsize);
621 return PyMemoryView_FromBuffer(&newview);
622 }
623 PyErr_SetNone(PyExc_NotImplementedError);
624 return NULL;
625 }
626 PyErr_Format(PyExc_TypeError,
627 "cannot index memory using \"%.200s\"",
628 key->ob_type->tp_name);
629 return NULL;
630}
631
632
633/* Need to support assigning memory if we can */
634static int
635memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
636{
637 Py_ssize_t start, len, bytelen, i;
638 Py_buffer srcview;
639 Py_buffer *view = &(self->view);
640 char *srcbuf, *destbuf;
641
642 if (view->readonly) {
643 PyErr_SetString(PyExc_TypeError,
644 "cannot modify read-only memory");
645 return -1;
646 }
647 if (view->ndim != 1) {
648 PyErr_SetNone(PyExc_NotImplementedError);
649 return -1;
650 }
651 if (PyIndex_Check(key)) {
652 start = PyNumber_AsSsize_t(key, NULL);
653 if (start == -1 && PyErr_Occurred())
654 return -1;
655 if (start < 0) {
656 start += get_shape0(view);
657 }
658 if ((start < 0) || (start >= get_shape0(view))) {
659 PyErr_SetString(PyExc_IndexError,
660 "index out of bounds");
661 return -1;
662 }
663 len = 1;
664 }
665 else if (PySlice_Check(key)) {
666 Py_ssize_t stop, step;
667
668 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
669 &start, &stop, &step, &len) < 0) {
670 return -1;
671 }
672 if (step != 1) {
673 PyErr_SetNone(PyExc_NotImplementedError);
674 return -1;
675 }
676 }
677 else {
678 PyErr_Format(PyExc_TypeError,
679 "cannot index memory using \"%.200s\"",
680 key->ob_type->tp_name);
681 return -1;
682 }
683 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
684 return -1;
685 }
686 /* XXX should we allow assignment of different item sizes
687 as long as the byte length is the same?
688 (e.g. assign 2 shorts to a 4-byte slice) */
689 if (srcview.itemsize != view->itemsize) {
690 PyErr_Format(PyExc_TypeError,
691 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
692 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
693 goto _error;
694 }
695 bytelen = len * view->itemsize;
696 if (bytelen != srcview.len) {
697 PyErr_SetString(PyExc_ValueError,
698 "cannot modify size of memoryview object");
699 goto _error;
700 }
701 /* Do the actual copy */
702 destbuf = (char *) view->buf + start * view->itemsize;
703 srcbuf = (char *) srcview.buf;
704 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
705 /* No overlapping */
706 memcpy(destbuf, srcbuf, bytelen);
707 else if (destbuf < srcbuf) {
708 /* Copy in ascending order */
709 for (i = 0; i < bytelen; i++)
710 destbuf[i] = srcbuf[i];
711 }
712 else {
713 /* Copy in descencing order */
714 for (i = bytelen - 1; i >= 0; i--)
715 destbuf[i] = srcbuf[i];
716 }
717
718 PyBuffer_Release(&srcview);
719 return 0;
720
721_error:
722 PyBuffer_Release(&srcview);
723 return -1;
724}
725
726static PyObject *
727memory_richcompare(PyObject *v, PyObject *w, int op)
728{
729 Py_buffer vv, ww;
730 int equal = 0;
731 PyObject *res;
732
733 vv.obj = NULL;
734 ww.obj = NULL;
735 if (op != Py_EQ && op != Py_NE)
736 goto _notimpl;
737 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
738 PyErr_Clear();
739 goto _notimpl;
740 }
741 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
742 PyErr_Clear();
743 goto _notimpl;
744 }
745
746 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
747 goto _end;
748
749 equal = !memcmp(vv.buf, ww.buf, vv.len);
750
751_end:
752 PyBuffer_Release(&vv);
753 PyBuffer_Release(&ww);
754 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
755 res = Py_True;
756 else
757 res = Py_False;
758 Py_INCREF(res);
759 return res;
760
761_notimpl:
762 PyBuffer_Release(&vv);
763 PyBuffer_Release(&ww);
764 Py_INCREF(Py_NotImplemented);
765 return Py_NotImplemented;
766}
767
768
769static int
770memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
771{
772 if (self->base != NULL)
773 Py_VISIT(self->base);
774 if (self->view.obj != NULL)
775 Py_VISIT(self->view.obj);
776 return 0;
777}
778
779static int
780memory_clear(PyMemoryViewObject *self)
781{
782 Py_CLEAR(self->base);
783 PyBuffer_Release(&self->view);
784 return 0;
785}
786
787
788/* As mapping */
789static PyMappingMethods memory_as_mapping = {
790 (lenfunc)memory_length, /* mp_length */
791 (binaryfunc)memory_subscript, /* mp_subscript */
792 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
793};
794
Raymond Hettinger62641e92009-06-23 20:59:43 +0000795static PySequenceMethods memory_as_sequence = {
796 0, /* sq_length */
797 0, /* sq_concat */
798 0, /* sq_repeat */
799 (ssizeargfunc)memory_item, /* sq_item */
800};
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000801
802/* Buffer methods */
803static PyBufferProcs memory_as_buffer = {
804 0, /* bf_getreadbuffer */
805 0, /* bf_getwritebuffer */
806 0, /* bf_getsegcount */
807 0, /* bf_getcharbuffer */
808 (getbufferproc)memory_getbuf, /* bf_getbuffer */
809 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
810};
811
812
813PyTypeObject PyMemoryView_Type = {
814 PyVarObject_HEAD_INIT(&PyType_Type, 0)
815 "memoryview",
816 sizeof(PyMemoryViewObject),
817 0,
818 (destructor)memory_dealloc, /* tp_dealloc */
819 0, /* tp_print */
820 0, /* tp_getattr */
821 0, /* tp_setattr */
822 0, /* tp_compare */
823 (reprfunc)memory_repr, /* tp_repr */
824 0, /* tp_as_number */
Raymond Hettinger62641e92009-06-23 20:59:43 +0000825 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000826 &memory_as_mapping, /* tp_as_mapping */
827 0, /* tp_hash */
828 0, /* tp_call */
829 0, /* tp_str */
830 PyObject_GenericGetAttr, /* tp_getattro */
831 0, /* tp_setattro */
832 &memory_as_buffer, /* tp_as_buffer */
833 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
834 Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */
835 memory_doc, /* tp_doc */
836 (traverseproc)memory_traverse, /* tp_traverse */
837 (inquiry)memory_clear, /* tp_clear */
838 memory_richcompare, /* tp_richcompare */
839 0, /* tp_weaklistoffset */
840 0, /* tp_iter */
841 0, /* tp_iternext */
842 memory_methods, /* tp_methods */
843 0, /* tp_members */
844 memory_getsetlist, /* tp_getset */
845 0, /* tp_base */
846 0, /* tp_dict */
847 0, /* tp_descr_get */
848 0, /* tp_descr_set */
849 0, /* tp_dictoffset */
850 0, /* tp_init */
851 0, /* tp_alloc */
852 memory_new, /* tp_new */
853};