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