Home | History | Annotate | Download | only in Objects
      1 
      2 /* Memoryview object implementation */
      3 
      4 #include "Python.h"
      5 
      6 static Py_ssize_t
      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
     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
     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
     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 *
     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 *
     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 *
    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
    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
    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 *
    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 *
    328 memory_format_get(PyMemoryViewObject *self)
    329 {
    330     return PyString_FromString(self->view.format);
    331 }
    332 
    333 static PyObject *
    334 memory_itemsize_get(PyMemoryViewObject *self)
    335 {
    336     return PyLong_FromSsize_t(self->view.itemsize);
    337 }
    338 
    339 static PyObject *
    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 *
    364 memory_shape_get(PyMemoryViewObject *self)
    365 {
    366     return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
    367 }
    368 
    369 static PyObject *
    370 memory_strides_get(PyMemoryViewObject *self)
    371 {
    372     return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
    373 }
    374 
    375 static PyObject *
    376 memory_suboffsets_get(PyMemoryViewObject *self)
    377 {
    378     return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
    379 }
    380 
    381 static PyObject *
    382 memory_readonly_get(PyMemoryViewObject *self)
    383 {
    384     return PyBool_FromLong(self->view.readonly);
    385 }
    386 
    387 static PyObject *
    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 *
    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 *
    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
    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 *
    496 memory_repr(PyMemoryViewObject *self)
    497 {
    498     return PyString_FromFormat("<memory at %p>", self);
    499 }
    500 
    501 /* Sequence methods */
    502 static Py_ssize_t
    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 *
    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 *
    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
    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 *
    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
    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
    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