memoryobject.c 23.5 KB
Newer Older
1 2 3 4 5

/* Memoryview object implementation */

#include "Python.h"

6 7 8 9 10
static Py_ssize_t
get_shape0(Py_buffer *buf)
{
    if (buf->shape != NULL)
        return buf->shape[0];
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
    if (buf->ndim == 0)
        return 1;
    PyErr_SetString(PyExc_TypeError,
        "exported buffer does not have any shape information associated "
        "to it");
    return -1;
}

static void
dup_buffer(Py_buffer *dest, Py_buffer *src)
{
    *dest = *src;
    if (src->ndim == 1 && src->shape != NULL) {
        dest->shape = &(dest->smalltable[0]);
        dest->shape[0] = get_shape0(src);
    }
    if (src->ndim == 1 && src->strides != NULL) {
        dest->strides = &(dest->smalltable[1]);
        dest->strides[0] = src->strides[0];
    }
31 32
}

33
static int
34
memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
35
{
36 37 38 39 40 41 42 43 44
    int res = 0;
    /* XXX for whatever reason fixing the flags seems necessary */
    if (self->view.readonly)
        flags &= ~PyBUF_WRITABLE;
    if (self->view.obj != NULL)
        res = PyObject_GetBuffer(self->view.obj, view, flags);
    if (view)
        dup_buffer(view, &self->view);
    return res;
45 46 47
}

static void
48
memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
49
{
50
    PyBuffer_Release(view);
51 52 53 54 55 56 57 58
}

PyDoc_STRVAR(memory_doc,
"memoryview(object)\n\
\n\
Create a new memoryview object which references the given object.");

PyObject *
59
PyMemoryView_FromBuffer(Py_buffer *info)
60
{
61 62 63 64 65 66 67 68 69 70 71 72
    PyMemoryViewObject *mview;

    mview = (PyMemoryViewObject *)
        PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
    if (mview == NULL)
        return NULL;
    mview->base = NULL;
    dup_buffer(&mview->view, info);
    /* NOTE: mview->view.obj should already have been incref'ed as
       part of PyBuffer_FillInfo(). */
    _PyObject_GC_TRACK(mview);
    return (PyObject *)mview;
73 74 75 76 77
}

PyObject *
PyMemoryView_FromObject(PyObject *base)
{
78
    PyMemoryViewObject *mview;
79

80 81 82 83 84 85
    if (!PyObject_CheckBuffer(base)) {
        PyErr_SetString(PyExc_TypeError,
            "cannot make memory view because object does "
            "not have the buffer interface");
        return NULL;
    }
86

87 88 89 90
    mview = (PyMemoryViewObject *)
        PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
    if (mview == NULL)
        return NULL;
91

92 93 94 95 96
    mview->base = NULL;
    if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL_RO) < 0) {
        Py_DECREF(mview);
        return NULL;
    }
97

98 99 100 101
    mview->base = base;
    Py_INCREF(base);
    _PyObject_GC_TRACK(mview);
    return (PyObject *)mview;
102 103 104 105 106
}

static PyObject *
memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
{
107 108
    PyObject *obj;
    static char *kwlist[] = {"object", 0};
109

110 111 112 113
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
                                     &obj)) {
        return NULL;
    }
114

115
    return PyMemoryView_FromObject(obj);
116 117 118 119
}


static void
120
_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
121
                 Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
122
{
123 124
    int k;
    Py_ssize_t outstride;
125

126 127 128 129 130 131 132 133
    if (nd==0) {
        memcpy(dest, src, itemsize);
    }
    else if (nd == 1) {
        for (k = 0; k<shape[0]; k++) {
            memcpy(dest, src, itemsize);
            dest += itemsize;
            src += strides[0];
134
        }
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    }
    else {
        if (fort == 'F') {
            /* Copy first dimension first,
               second dimension second, etc...
               Set up the recursive loop backwards so that final
               dimension is actually copied last.
            */
            outstride = itemsize;
            for (k=1; k<nd-1;k++) {
                outstride *= shape[k];
            }
            for (k=0; k<shape[nd-1]; k++) {
                _strided_copy_nd(dest, src, nd-1, shape,
                                 strides, itemsize, fort);
                dest += outstride;
                src += strides[nd-1];
            }
153
        }
154

155
        else {
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
            /* Copy last dimension first,
               second-to-last dimension second, etc.
               Set up the recursion so that the
               first dimension is copied last
            */
            outstride = itemsize;
            for (k=1; k < nd; k++) {
                outstride *= shape[k];
            }
            for (k=0; k<shape[0]; k++) {
                _strided_copy_nd(dest, src, nd-1, shape+1,
                                 strides+1, itemsize,
                                 fort);
                dest += outstride;
                src += strides[0];
            }
172
        }
173 174
    }
    return;
175 176 177 178 179 180
}

void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);

static int
181
_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
182
{
183 184 185 186 187 188 189 190 191 192
    Py_ssize_t *indices;
    int k;
    Py_ssize_t elements;
    char *ptr;
    void (*func)(int, Py_ssize_t *, Py_ssize_t *);

    if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
        PyErr_NoMemory();
        return -1;
    }
193

194 195 196 197 198 199 200 201
    indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
    if (indices == NULL) {
        PyErr_NoMemory();
        return -1;
    }
    for (k=0; k<view->ndim;k++) {
        indices[k] = 0;
    }
202

203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
    elements = 1;
    for (k=0; k<view->ndim; k++) {
        elements *= view->shape[k];
    }
    if (fort == 'F') {
        func = _add_one_to_index_F;
    }
    else {
        func = _add_one_to_index_C;
    }
    while (elements--) {
        func(view->ndim, indices, view->shape);
        ptr = PyBuffer_GetPointer(view, indices);
        memcpy(dest, ptr, view->itemsize);
        dest += view->itemsize;
    }
219

220 221
    PyMem_Free(indices);
    return 0;
222 223
}

224
/*
225 226 227 228 229
   Get a the data from an object as a contiguous chunk of memory (in
   either 'C' or 'F'ortran order) even if it means copying it into a
   separate memory area.

   Returns a new reference to a Memory view object.  If no copy is needed,
230
   the memory view object points to the original memory and holds a
231
   lock on the original.  If a copy is needed, then the memory view object
232
   points to a brand-new Bytes object (and holds a memory lock on it).
233 234 235 236

   buffertype

   PyBUF_READ  buffer only needs to be read-only
237
   PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
238
   PyBUF_SHADOW buffer needs to be writable so shadow it with
239 240 241
                a contiguous buffer if it is not. The view will point to
                the shadow buffer which can be written to and then
                will be copied back into the other buffer when the memory
242
                view is de-allocated.  While the shadow buffer is
243 244
                being used, it will have an exclusive write lock on
                the original buffer.
245 246 247 248 249
 */

PyObject *
PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
{
250 251 252 253 254
    PyMemoryViewObject *mem;
    PyObject *bytes;
    Py_buffer *view;
    int flags;
    char *dest;
255

256 257 258 259 260
    if (!PyObject_CheckBuffer(obj)) {
        PyErr_SetString(PyExc_TypeError,
                        "object does not have the buffer interface");
        return NULL;
    }
261

262 263 264
    mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
    if (mem == NULL)
        return NULL;
265

266 267 268 269 270 271 272
    view = &mem->view;
    flags = PyBUF_FULL_RO;
    switch(buffertype) {
    case PyBUF_WRITE:
        flags = PyBUF_FULL;
        break;
    }
273

274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
    if (PyObject_GetBuffer(obj, view, flags) != 0) {
        Py_DECREF(mem);
        return NULL;
    }

    if (PyBuffer_IsContiguous(view, fort)) {
        /* no copy needed */
        Py_INCREF(obj);
        mem->base = obj;
        _PyObject_GC_TRACK(mem);
        return (PyObject *)mem;
    }
    /* otherwise a copy is needed */
    if (buffertype == PyBUF_WRITE) {
        Py_DECREF(mem);
        PyErr_SetString(PyExc_BufferError,
                        "writable contiguous buffer requested "
                        "for a non-contiguousobject.");
        return NULL;
    }
    bytes = PyBytes_FromStringAndSize(NULL, view->len);
    if (bytes == NULL) {
        Py_DECREF(mem);
        return NULL;
    }
    dest = PyBytes_AS_STRING(bytes);
    /* different copying strategy depending on whether
       or not any pointer de-referencing is needed
    */
    /* strided or in-direct copy */
    if (view->suboffsets==NULL) {
        _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
                         view->strides, view->itemsize, fort);
    }
    else {
        if (_indirect_copy_nd(dest, view, fort) < 0) {
            Py_DECREF(bytes);
            Py_DECREF(mem);
            return NULL;
313
        }
314 315 316 317 318 319 320 321 322
    }
    if (buffertype == PyBUF_SHADOW) {
        /* return a shadowed memory-view object */
        view->buf = dest;
        mem->base = PyTuple_Pack(2, obj, bytes);
        Py_DECREF(bytes);
        if (mem->base == NULL) {
            Py_DECREF(mem);
            return NULL;
323
        }
324 325 326 327 328 329 330 331
    }
    else {
        PyBuffer_Release(view);  /* XXX ? */
        /* steal the reference */
        mem->base = bytes;
    }
    _PyObject_GC_TRACK(mem);
    return (PyObject *)mem;
332 333 334 335 336 337
}


static PyObject *
memory_format_get(PyMemoryViewObject *self)
{
338
    return PyUnicode_FromString(self->view.format);
339 340 341 342 343
}

static PyObject *
memory_itemsize_get(PyMemoryViewObject *self)
{
344
    return PyLong_FromSsize_t(self->view.itemsize);
345 346 347 348 349
}

static PyObject *
_IntTupleFromSsizet(int len, Py_ssize_t *vals)
{
350 351 352
    int i;
    PyObject *o;
    PyObject *intTuple;
353

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
    if (vals == NULL) {
        Py_INCREF(Py_None);
        return Py_None;
    }
    intTuple = PyTuple_New(len);
    if (!intTuple) return NULL;
    for(i=0; i<len; i++) {
        o = PyLong_FromSsize_t(vals[i]);
        if (!o) {
            Py_DECREF(intTuple);
            return NULL;
        }
        PyTuple_SET_ITEM(intTuple, i, o);
    }
    return intTuple;
369 370 371 372 373
}

static PyObject *
memory_shape_get(PyMemoryViewObject *self)
{
374
    return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
375 376 377 378 379
}

static PyObject *
memory_strides_get(PyMemoryViewObject *self)
{
380
    return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
381 382 383 384 385
}

static PyObject *
memory_suboffsets_get(PyMemoryViewObject *self)
{
386
    return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
387 388 389 390 391
}

static PyObject *
memory_readonly_get(PyMemoryViewObject *self)
{
392
    return PyBool_FromLong(self->view.readonly);
393 394 395 396 397
}

static PyObject *
memory_ndim_get(PyMemoryViewObject *self)
{
398
    return PyLong_FromLong(self->view.ndim);
399 400
}

401
static PyGetSetDef memory_getsetlist[] ={
402 403 404 405 406 407 408 409
    {"format",                (getter)memory_format_get,      NULL, NULL},
    {"itemsize",        (getter)memory_itemsize_get,    NULL, NULL},
    {"shape",           (getter)memory_shape_get,       NULL, NULL},
    {"strides",         (getter)memory_strides_get,     NULL, NULL},
    {"suboffsets",      (getter)memory_suboffsets_get,  NULL, NULL},
    {"readonly",        (getter)memory_readonly_get,    NULL, NULL},
    {"ndim",            (getter)memory_ndim_get,        NULL, NULL},
    {NULL, NULL, NULL, NULL},
410 411 412 413
};


static PyObject *
414
memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
415
{
416 417
    return PyObject_CallFunctionObjArgs(
            (PyObject *) &PyBytes_Type, mem, NULL);
418 419
}

420 421 422
/* TODO: rewrite this function using the struct module to unpack
   each buffer item */

423
static PyObject *
424
memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
425
{
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
    Py_buffer *view = &(mem->view);
    Py_ssize_t i;
    PyObject *res, *item;
    char *buf;

    if (strcmp(view->format, "B") || view->itemsize != 1) {
        PyErr_SetString(PyExc_NotImplementedError, 
                "tolist() only supports byte views");
        return NULL;
    }
    if (view->ndim != 1) {
        PyErr_SetString(PyExc_NotImplementedError, 
                "tolist() only supports one-dimensional objects");
        return NULL;
    }
    res = PyList_New(view->len);
    if (res == NULL)
        return NULL;
    buf = view->buf;
    for (i = 0; i < view->len; i++) {
        item = PyLong_FromUnsignedLong((unsigned char) *buf);
        if (item == NULL) {
            Py_DECREF(res);
            return NULL;
        }
        PyList_SET_ITEM(res, i, item);
        buf++;
    }
    return res;
455 456 457
}

static PyMethodDef memory_methods[] = {
458 459 460
    {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
    {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
    {NULL,          NULL}           /* sentinel */
461 462 463 464 465 466
};


static void
memory_dealloc(PyMemoryViewObject *self)
{
467 468 469 470 471 472 473 474 475 476 477 478
    _PyObject_GC_UNTRACK(self);
    if (self->view.obj != NULL) {
        if (self->base && PyTuple_Check(self->base)) {
            /* Special case when first element is generic object
               with buffer interface and the second element is a
               contiguous "shadow" that must be copied back into
               the data areay of the first tuple element before
               releasing the buffer on the first element.
            */

            PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
                              PyTuple_GET_ITEM(self->base,1));
479

480 481 482 483 484 485
            /* The view member should have readonly == -1 in
               this instance indicating that the memory can
               be "locked" and was locked and will be unlocked
               again after this call.
            */
            PyBuffer_Release(&(self->view));
486
        }
487 488 489 490 491 492
        else {
            PyBuffer_Release(&(self->view));
        }
        Py_CLEAR(self->base);
    }
    PyObject_GC_Del(self);
493 494 495 496 497
}

static PyObject *
memory_repr(PyMemoryViewObject *self)
{
498
    return PyUnicode_FromFormat("<memory at %p>", self);
499 500 501 502 503 504
}

/* Sequence methods */
static Py_ssize_t
memory_length(PyMemoryViewObject *self)
{
505
    return get_shape0(&self->view);
506 507
}

508
/*
509 510
  mem[obj] returns a bytes object holding the data for one element if
           obj fully indexes the memory view or another memory-view object
511
           if it does not.
512

513 514
           0-d memory-view objects can be referenced using ... or () but
           not with anything else.
515
 */
516 517 518
static PyObject *
memory_subscript(PyMemoryViewObject *self, PyObject *key)
{
519 520 521 522
    Py_buffer *view;
    view = &(self->view);
    
    if (view->ndim == 0) {
523 524 525 526 527 528 529 530 531 532
        if (key == Py_Ellipsis ||
            (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
            Py_INCREF(self);
            return (PyObject *)self;
        }
        else {
            PyErr_SetString(PyExc_IndexError,
                                "invalid indexing of 0-dim memory");
            return NULL;
        }
533 534
    }
    if (PyIndex_Check(key)) {
535 536 537 538 539 540 541 542 543
        Py_ssize_t result;
        result = PyNumber_AsSsize_t(key, NULL);
        if (result == -1 && PyErr_Occurred())
                return NULL;
        if (view->ndim == 1) {
            /* Return a bytes object */
            char *ptr;
            ptr = (char *)view->buf;
            if (result < 0) {
544
                result += get_shape0(view);
545
            }
546
            if ((result < 0) || (result >= get_shape0(view))) {
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
                PyErr_SetString(PyExc_IndexError,
                                "index out of bounds");
                return NULL;
            }
            if (view->strides == NULL)
                ptr += view->itemsize * result;
            else
                ptr += view->strides[0] * result;
            if (view->suboffsets != NULL &&
                view->suboffsets[0] >= 0) {
                ptr = *((char **)ptr) + view->suboffsets[0];
            }
            return PyBytes_FromStringAndSize(ptr, view->itemsize);
        }
        else {
            /* Return a new memory-view object */
            Py_buffer newview;
            memset(&newview, 0, sizeof(newview));
            /* XXX:  This needs to be fixed so it
                         actually returns a sub-view
            */
            return PyMemoryView_FromBuffer(&newview);
        }
570 571
    }
    else if (PySlice_Check(key)) {
572 573
        Py_ssize_t start, stop, step, slicelength;

574
        if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
575
                                 &start, &stop, &step, &slicelength) < 0) {
576
            return NULL;
577
        }
578
    
579 580 581 582 583 584
        if (step == 1 && view->ndim == 1) {
            Py_buffer newview;
            void *newbuf = (char *) view->buf
                                    + start * view->itemsize;
            int newflags = view->readonly
                    ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
585
    
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
            /* XXX There should be an API to create a subbuffer */
            if (view->obj != NULL) {
                if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
                    return NULL;
            }
            else {
                newview = *view;
            }
            newview.buf = newbuf;
            newview.len = slicelength * newview.itemsize;
            newview.format = view->format;
            newview.shape = &(newview.smalltable[0]);
            newview.shape[0] = slicelength;
            newview.strides = &(newview.itemsize);
            return PyMemoryView_FromBuffer(&newview);
        }
        PyErr_SetNone(PyExc_NotImplementedError);
        return NULL;
604 605
    }
    PyErr_Format(PyExc_TypeError,
606 607
        "cannot index memory using \"%.200s\"", 
        key->ob_type->tp_name);
608
    return NULL;
609 610
}

611 612

/* Need to support assigning memory if we can */
613 614 615
static int
memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
{
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
    Py_ssize_t start, len, bytelen, i;
    Py_buffer srcview;
    Py_buffer *view = &(self->view);
    char *srcbuf, *destbuf;

    if (view->readonly) {
        PyErr_SetString(PyExc_TypeError,
            "cannot modify read-only memory");
        return -1;
    }
    if (view->ndim != 1) {
        PyErr_SetNone(PyExc_NotImplementedError);
        return -1;
    }
    if (PyIndex_Check(key)) {
        start = PyNumber_AsSsize_t(key, NULL);
        if (start == -1 && PyErr_Occurred())
            return -1;
        if (start < 0) {
635
            start += get_shape0(view);
636
        }
637
        if ((start < 0) || (start >= get_shape0(view))) {
638 639 640 641 642 643 644 645 646
            PyErr_SetString(PyExc_IndexError,
                            "index out of bounds");
            return -1;
        }
        len = 1;
    }
    else if (PySlice_Check(key)) {
        Py_ssize_t stop, step;

647
        if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
                         &start, &stop, &step, &len) < 0) {
            return -1;
        }
        if (step != 1) {
            PyErr_SetNone(PyExc_NotImplementedError);
            return -1;
        }
    }
    else {
        PyErr_Format(PyExc_TypeError,
            "cannot index memory using \"%.200s\"", 
            key->ob_type->tp_name);
        return -1;
    }
    if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
        return -1;
    }
    /* XXX should we allow assignment of different item sizes
       as long as the byte length is the same?
       (e.g. assign 2 shorts to a 4-byte slice) */
    if (srcview.itemsize != view->itemsize) {
        PyErr_Format(PyExc_TypeError,
            "mismatching item sizes for \"%.200s\" and \"%.200s\"", 
            view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
        goto _error;
    }
674 675
    bytelen = len * view->itemsize;
    if (bytelen != srcview.len) {
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
        PyErr_SetString(PyExc_ValueError,
            "cannot modify size of memoryview object");
        goto _error;
    }
    /* Do the actual copy */
    destbuf = (char *) view->buf + start * view->itemsize;
    srcbuf = (char *) srcview.buf;
    if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
        /* No overlapping */
        memcpy(destbuf, srcbuf, bytelen);
    else if (destbuf < srcbuf) {
        /* Copy in ascending order */
        for (i = 0; i < bytelen; i++)
            destbuf[i] = srcbuf[i];
    }
    else {
        /* Copy in descencing order */
        for (i = bytelen - 1; i >= 0; i--)
            destbuf[i] = srcbuf[i];
    }

    PyBuffer_Release(&srcview);
    return 0;

_error:
    PyBuffer_Release(&srcview);
    return -1;
703 704
}

705 706 707
static PyObject *
memory_richcompare(PyObject *v, PyObject *w, int op)
{
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
    Py_buffer vv, ww;
    int equal = 0;
    PyObject *res;

    vv.obj = NULL;
    ww.obj = NULL;
    if (op != Py_EQ && op != Py_NE)
        goto _notimpl;
    if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
        PyErr_Clear();
        goto _notimpl;
    }
    if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
        PyErr_Clear();
        goto _notimpl;
    }

    if (vv.itemsize != ww.itemsize || vv.len != ww.len)
        goto _end;

    equal = !memcmp(vv.buf, ww.buf, vv.len);
729 730

_end:
731 732 733 734 735 736 737 738
    PyBuffer_Release(&vv);
    PyBuffer_Release(&ww);
    if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
        res = Py_True;
    else
        res = Py_False;
    Py_INCREF(res);
    return res;
739 740

_notimpl:
741 742 743 744
    PyBuffer_Release(&vv);
    PyBuffer_Release(&ww);
    Py_INCREF(Py_NotImplemented);
    return Py_NotImplemented;
745 746 747
}


748 749 750
static int
memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
{
751 752 753 754 755
    if (self->base != NULL)
        Py_VISIT(self->base);
    if (self->view.obj != NULL)
        Py_VISIT(self->view.obj);
    return 0;
756 757 758 759 760
}

static int
memory_clear(PyMemoryViewObject *self)
{
761 762 763
    Py_CLEAR(self->base);
    PyBuffer_Release(&self->view);
    return 0;
764 765 766
}


767 768
/* As mapping */
static PyMappingMethods memory_as_mapping = {
769 770 771
    (lenfunc)memory_length,               /* mp_length */
    (binaryfunc)memory_subscript,         /* mp_subscript */
    (objobjargproc)memory_ass_sub,        /* mp_ass_subscript */
772 773 774 775 776 777
};


/* Buffer methods */

static PyBufferProcs memory_as_buffer = {
778 779
    (getbufferproc)memory_getbuf,         /* bf_getbuffer */
    (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
780 781 782 783
};


PyTypeObject PyMemoryView_Type = {
784 785 786 787 788 789 790 791
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "memoryview",
    sizeof(PyMemoryViewObject),
    0,
    (destructor)memory_dealloc,               /* tp_dealloc */
    0,                                        /* tp_print */
    0,                                        /* tp_getattr */
    0,                                        /* tp_setattr */
792
    0,                                        /* tp_reserved */
793 794 795 796 797 798
    (reprfunc)memory_repr,                    /* tp_repr */
    0,                                        /* tp_as_number */
    0,                                        /* tp_as_sequence */
    &memory_as_mapping,                       /* tp_as_mapping */
    0,                                        /* tp_hash */
    0,                                        /* tp_call */
799
    0,                                        /* tp_str */
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
    PyObject_GenericGetAttr,                  /* tp_getattro */
    0,                                        /* tp_setattro */
    &memory_as_buffer,                        /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,  /* tp_flags */
    memory_doc,                               /* tp_doc */
    (traverseproc)memory_traverse,            /* tp_traverse */
    (inquiry)memory_clear,                    /* tp_clear */
    memory_richcompare,                       /* tp_richcompare */
    0,                                        /* tp_weaklistoffset */
    0,                                        /* tp_iter */
    0,                                        /* tp_iternext */
    memory_methods,                           /* tp_methods */
    0,                                        /* tp_members */
    memory_getsetlist,                        /* tp_getset */
    0,                                        /* tp_base */
    0,                                        /* tp_dict */
    0,                                        /* tp_descr_get */
    0,                                        /* tp_descr_set */
    0,                                        /* tp_dictoffset */
    0,                                        /* tp_init */
    0,                                        /* tp_alloc */
    memory_new,                               /* tp_new */
822
};