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_Unpack(key, &start, &stop, &step) < 0) {
588 return NULL;
589 }
590 slicelength = _PySlice_AdjustIndices(get_shape0(view), &start, &stop,
591 step);
592
593 if (step == 1 && view->ndim == 1) {
594 Py_buffer newview;
595 void *newbuf = (char *) view->buf
596 + start * view->itemsize;
597 int newflags = view->readonly
598 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
599
600 /* XXX There should be an API to create a subbuffer */
601 if (view->obj != NULL) {
602 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
603 return NULL;
604 }
605 else {
606 newview = *view;
607 }
608 newview.buf = newbuf;
609 newview.len = slicelength * newview.itemsize;
610 newview.format = view->format;
611 newview.shape = &(newview.smalltable[0]);
612 newview.shape[0] = slicelength;
613 newview.strides = &(newview.itemsize);
614 return PyMemoryView_FromBuffer(&newview);
615 }
616 PyErr_SetNone(PyExc_NotImplementedError);
617 return NULL;
618 }
619 PyErr_Format(PyExc_TypeError,
620 "cannot index memory using \"%.200s\"",
621 key->ob_type->tp_name);
622 return NULL;
623 }
624
625
626 /* Need to support assigning memory if we can */
627 static int
memory_ass_sub(PyMemoryViewObject * self,PyObject * key,PyObject * value)628 memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
629 {
630 Py_ssize_t start, len, bytelen;
631 Py_buffer srcview;
632 Py_buffer *view = &(self->view);
633 char *srcbuf, *destbuf;
634
635 if (view->readonly) {
636 PyErr_SetString(PyExc_TypeError,
637 "cannot modify read-only memory");
638 return -1;
639 }
640 if (value == NULL) {
641 PyErr_SetString(PyExc_TypeError,
642 "cannot delete 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_Unpack(key, &start, &stop, &step) < 0) {
667 return -1;
668 }
669 len = _PySlice_AdjustIndices(get_shape0(view), &start, &stop, step);
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
706 memmove(destbuf, srcbuf, bytelen);
707
708 PyBuffer_Release(&srcview);
709 return 0;
710
711 _error:
712 PyBuffer_Release(&srcview);
713 return -1;
714 }
715
716 static PyObject *
memory_richcompare(PyObject * v,PyObject * w,int op)717 memory_richcompare(PyObject *v, PyObject *w, int op)
718 {
719 Py_buffer vv, ww;
720 int equal = 0;
721 PyObject *res;
722
723 vv.obj = NULL;
724 ww.obj = NULL;
725 if (op != Py_EQ && op != Py_NE)
726 goto _notimpl;
727 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
728 PyErr_Clear();
729 goto _notimpl;
730 }
731 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
732 PyErr_Clear();
733 goto _notimpl;
734 }
735
736 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
737 goto _end;
738
739 equal = !memcmp(vv.buf, ww.buf, vv.len);
740
741 _end:
742 PyBuffer_Release(&vv);
743 PyBuffer_Release(&ww);
744 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
745 res = Py_True;
746 else
747 res = Py_False;
748 Py_INCREF(res);
749 return res;
750
751 _notimpl:
752 PyBuffer_Release(&vv);
753 PyBuffer_Release(&ww);
754 Py_INCREF(Py_NotImplemented);
755 return Py_NotImplemented;
756 }
757
758
759 static int
memory_traverse(PyMemoryViewObject * self,visitproc visit,void * arg)760 memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
761 {
762 if (self->base != NULL)
763 Py_VISIT(self->base);
764 if (self->view.obj != NULL)
765 Py_VISIT(self->view.obj);
766 return 0;
767 }
768
769 static int
memory_clear(PyMemoryViewObject * self)770 memory_clear(PyMemoryViewObject *self)
771 {
772 Py_CLEAR(self->base);
773 PyBuffer_Release(&self->view);
774 return 0;
775 }
776
777
778 /* As mapping */
779 static PyMappingMethods memory_as_mapping = {
780 (lenfunc)memory_length, /* mp_length */
781 (binaryfunc)memory_subscript, /* mp_subscript */
782 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
783 };
784
785 static PySequenceMethods memory_as_sequence = {
786 0, /* sq_length */
787 0, /* sq_concat */
788 0, /* sq_repeat */
789 (ssizeargfunc)memory_item, /* sq_item */
790 };
791
792 /* Buffer methods */
793 static PyBufferProcs memory_as_buffer = {
794 0, /* bf_getreadbuffer */
795 0, /* bf_getwritebuffer */
796 0, /* bf_getsegcount */
797 0, /* bf_getcharbuffer */
798 (getbufferproc)memory_getbuf, /* bf_getbuffer */
799 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
800 };
801
802
803 PyTypeObject PyMemoryView_Type = {
804 PyVarObject_HEAD_INIT(&PyType_Type, 0)
805 "memoryview",
806 sizeof(PyMemoryViewObject),
807 0,
808 (destructor)memory_dealloc, /* tp_dealloc */
809 0, /* tp_print */
810 0, /* tp_getattr */
811 0, /* tp_setattr */
812 0, /* tp_compare */
813 (reprfunc)memory_repr, /* tp_repr */
814 0, /* tp_as_number */
815 &memory_as_sequence, /* tp_as_sequence */
816 &memory_as_mapping, /* tp_as_mapping */
817 0, /* tp_hash */
818 0, /* tp_call */
819 0, /* tp_str */
820 PyObject_GenericGetAttr, /* tp_getattro */
821 0, /* tp_setattro */
822 &memory_as_buffer, /* tp_as_buffer */
823 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
824 Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */
825 memory_doc, /* tp_doc */
826 (traverseproc)memory_traverse, /* tp_traverse */
827 (inquiry)memory_clear, /* tp_clear */
828 memory_richcompare, /* tp_richcompare */
829 0, /* tp_weaklistoffset */
830 0, /* tp_iter */
831 0, /* tp_iternext */
832 memory_methods, /* tp_methods */
833 0, /* tp_members */
834 memory_getsetlist, /* tp_getset */
835 0, /* tp_base */
836 0, /* tp_dict */
837 0, /* tp_descr_get */
838 0, /* tp_descr_set */
839 0, /* tp_dictoffset */
840 0, /* tp_init */
841 0, /* tp_alloc */
842 memory_new, /* tp_new */
843 };
844