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