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