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