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