blob: 4997fcc6c965e4bec45ddf90db59142498438cec [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;
Antoine Pitrou9cf85f12010-09-01 21:17:34 +0000182 void (*func)(int, Py_ssize_t *, const Py_ssize_t *);
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000183
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 }
Antoine Pitrou9cf85f12010-09-01 21:17:34 +0000642 if (value == NULL) {
643 PyErr_SetString(PyExc_TypeError,
644 "cannot delete memory");
645 return -1;
646 }
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000647 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);
Antoine Pitrou32669782010-07-11 12:14:05 +0000707 else
708 memmove(destbuf, srcbuf, bytelen);
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000709
710 PyBuffer_Release(&srcview);
711 return 0;
712
713_error:
714 PyBuffer_Release(&srcview);
715 return -1;
716}
717
718static PyObject *
719memory_richcompare(PyObject *v, PyObject *w, int op)
720{
721 Py_buffer vv, ww;
722 int equal = 0;
723 PyObject *res;
724
725 vv.obj = NULL;
726 ww.obj = NULL;
727 if (op != Py_EQ && op != Py_NE)
728 goto _notimpl;
729 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
730 PyErr_Clear();
731 goto _notimpl;
732 }
733 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
734 PyErr_Clear();
735 goto _notimpl;
736 }
737
738 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
739 goto _end;
740
741 equal = !memcmp(vv.buf, ww.buf, vv.len);
742
743_end:
744 PyBuffer_Release(&vv);
745 PyBuffer_Release(&ww);
746 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
747 res = Py_True;
748 else
749 res = Py_False;
750 Py_INCREF(res);
751 return res;
752
753_notimpl:
754 PyBuffer_Release(&vv);
755 PyBuffer_Release(&ww);
756 Py_INCREF(Py_NotImplemented);
757 return Py_NotImplemented;
758}
759
760
761static int
762memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
763{
764 if (self->base != NULL)
765 Py_VISIT(self->base);
766 if (self->view.obj != NULL)
767 Py_VISIT(self->view.obj);
768 return 0;
769}
770
771static int
772memory_clear(PyMemoryViewObject *self)
773{
774 Py_CLEAR(self->base);
775 PyBuffer_Release(&self->view);
776 return 0;
777}
778
779
780/* As mapping */
781static PyMappingMethods memory_as_mapping = {
782 (lenfunc)memory_length, /* mp_length */
783 (binaryfunc)memory_subscript, /* mp_subscript */
784 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
785};
786
Raymond Hettinger62641e92009-06-23 20:59:43 +0000787static PySequenceMethods memory_as_sequence = {
788 0, /* sq_length */
789 0, /* sq_concat */
790 0, /* sq_repeat */
791 (ssizeargfunc)memory_item, /* sq_item */
792};
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000793
794/* Buffer methods */
795static PyBufferProcs memory_as_buffer = {
796 0, /* bf_getreadbuffer */
797 0, /* bf_getwritebuffer */
798 0, /* bf_getsegcount */
799 0, /* bf_getcharbuffer */
800 (getbufferproc)memory_getbuf, /* bf_getbuffer */
801 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
802};
803
804
805PyTypeObject PyMemoryView_Type = {
806 PyVarObject_HEAD_INIT(&PyType_Type, 0)
807 "memoryview",
808 sizeof(PyMemoryViewObject),
809 0,
810 (destructor)memory_dealloc, /* tp_dealloc */
811 0, /* tp_print */
812 0, /* tp_getattr */
813 0, /* tp_setattr */
814 0, /* tp_compare */
815 (reprfunc)memory_repr, /* tp_repr */
816 0, /* tp_as_number */
Raymond Hettinger62641e92009-06-23 20:59:43 +0000817 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000818 &memory_as_mapping, /* tp_as_mapping */
819 0, /* tp_hash */
820 0, /* tp_call */
821 0, /* tp_str */
822 PyObject_GenericGetAttr, /* tp_getattro */
823 0, /* tp_setattro */
824 &memory_as_buffer, /* tp_as_buffer */
825 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
826 Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */
827 memory_doc, /* tp_doc */
828 (traverseproc)memory_traverse, /* tp_traverse */
829 (inquiry)memory_clear, /* tp_clear */
830 memory_richcompare, /* tp_richcompare */
831 0, /* tp_weaklistoffset */
832 0, /* tp_iter */
833 0, /* tp_iternext */
834 memory_methods, /* tp_methods */
835 0, /* tp_members */
836 memory_getsetlist, /* tp_getset */
837 0, /* tp_base */
838 0, /* tp_dict */
839 0, /* tp_descr_get */
840 0, /* tp_descr_set */
841 0, /* tp_dictoffset */
842 0, /* tp_init */
843 0, /* tp_alloc */
844 memory_new, /* tp_new */
845};