Python-2.7.3/Objects/memoryobject.c

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 };