Fix field name conflicts for named tuples.
[python.git] / Objects / memoryobject.c
blob1828cef330857d1347e6c81104e9fc44541b8b13
2 /* Memoryview object implementation */
4 #include "Python.h"
6 static Py_ssize_t
7 get_shape0(Py_buffer *buf)
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;
19 static void
20 dup_buffer(Py_buffer *dest, Py_buffer *src)
22 *dest = *src;
23 if (src->ndim == 1 && src->shape != NULL) {
24 dest->shape = &(dest->smalltable[0]);
25 dest->shape[0] = get_shape0(src);
27 if (src->ndim == 1 && src->strides != NULL) {
28 dest->strides = &(dest->smalltable[1]);
29 dest->strides[0] = src->strides[0];
33 static int
34 memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
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;
47 static void
48 memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
50 PyBuffer_Release(view);
53 PyDoc_STRVAR(memory_doc,
54 "memoryview(object)\n\
55 \n\
56 Create a new memoryview object which references the given object.");
58 PyObject *
59 PyMemoryView_FromBuffer(Py_buffer *info)
61 PyMemoryViewObject *mview;
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;
75 PyObject *
76 PyMemoryView_FromObject(PyObject *base)
78 PyMemoryViewObject *mview;
80 if (!PyObject_CheckBuffer(base)) {
81 PyErr_SetString(PyExc_TypeError,
82 "cannot make memory view because object does "
83 "not have the buffer interface");
84 return NULL;
87 mview = (PyMemoryViewObject *)
88 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
89 if (mview == NULL)
90 return NULL;
92 mview->base = NULL;
93 if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL_RO) < 0) {
94 Py_DECREF(mview);
95 return NULL;
98 mview->base = base;
99 Py_INCREF(base);
100 _PyObject_GC_TRACK(mview);
101 return (PyObject *)mview;
104 static PyObject *
105 memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
107 PyObject *obj;
108 static char *kwlist[] = {"object", 0};
110 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
111 &obj)) {
112 return NULL;
115 return PyMemoryView_FromObject(obj);
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)
123 int k;
124 Py_ssize_t outstride;
126 if (nd==0) {
127 memcpy(dest, src, itemsize);
129 else if (nd == 1) {
130 for (k = 0; k<shape[0]; k++) {
131 memcpy(dest, src, itemsize);
132 dest += itemsize;
133 src += strides[0];
136 else {
137 if (fort == 'F') {
138 /* Copy first dimension first,
139 second dimension second, etc...
140 Set up the recursive loop backwards so that final
141 dimension is actually copied last.
143 outstride = itemsize;
144 for (k=1; k<nd-1;k++) {
145 outstride *= shape[k];
147 for (k=0; k<shape[nd-1]; k++) {
148 _strided_copy_nd(dest, src, nd-1, shape,
149 strides, itemsize, fort);
150 dest += outstride;
151 src += strides[nd-1];
155 else {
156 /* Copy last dimension first,
157 second-to-last dimension second, etc.
158 Set up the recursion so that the
159 first dimension is copied last
161 outstride = itemsize;
162 for (k=1; k < nd; k++) {
163 outstride *= shape[k];
165 for (k=0; k<shape[0]; k++) {
166 _strided_copy_nd(dest, src, nd-1, shape+1,
167 strides+1, itemsize,
168 fort);
169 dest += outstride;
170 src += strides[0];
174 return;
177 void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
178 void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
180 static int
181 _indirect_copy_nd(char *dest, Py_buffer *view, char fort)
183 Py_ssize_t *indices;
184 int k;
185 Py_ssize_t elements;
186 char *ptr;
187 void (*func)(int, Py_ssize_t *, Py_ssize_t *);
189 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
190 PyErr_NoMemory();
191 return -1;
194 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
195 if (indices == NULL) {
196 PyErr_NoMemory();
197 return -1;
199 for (k=0; k<view->ndim;k++) {
200 indices[k] = 0;
203 elements = 1;
204 for (k=0; k<view->ndim; k++) {
205 elements *= view->shape[k];
207 if (fort == 'F') {
208 func = _add_one_to_index_F;
210 else {
211 func = _add_one_to_index_C;
213 while (elements--) {
214 func(view->ndim, indices, view->shape);
215 ptr = PyBuffer_GetPointer(view, indices);
216 memcpy(dest, ptr, view->itemsize);
217 dest += view->itemsize;
220 PyMem_Free(indices);
221 return 0;
225 Get a the data from an object as a contiguous chunk of memory (in
226 either 'C' or 'F'ortran order) even if it means copying it into a
227 separate memory area.
229 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).
234 buffertype
236 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 a contiguous buffer if it is not. The view will point to
240 the shadow buffer which can be written to and then
241 will be copied back into the other buffer when the memory
242 view is de-allocated. While the shadow buffer is
243 being used, it will have an exclusive write lock on
244 the original buffer.
247 PyObject *
248 PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
250 PyMemoryViewObject *mem;
251 PyObject *bytes;
252 Py_buffer *view;
253 int flags;
254 char *dest;
256 if (!PyObject_CheckBuffer(obj)) {
257 PyErr_SetString(PyExc_TypeError,
258 "object does not have the buffer interface");
259 return NULL;
262 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
263 if (mem == NULL)
264 return NULL;
266 view = &mem->view;
267 flags = PyBUF_FULL_RO;
268 switch(buffertype) {
269 case PyBUF_WRITE:
270 flags = PyBUF_FULL;
271 break;
274 if (PyObject_GetBuffer(obj, view, flags) != 0) {
275 Py_DECREF(mem);
276 return NULL;
279 if (PyBuffer_IsContiguous(view, fort)) {
280 /* no copy needed */
281 Py_INCREF(obj);
282 mem->base = obj;
283 _PyObject_GC_TRACK(mem);
284 return (PyObject *)mem;
286 /* otherwise a copy is needed */
287 if (buffertype == PyBUF_WRITE) {
288 Py_DECREF(mem);
289 PyErr_SetString(PyExc_BufferError,
290 "writable contiguous buffer requested "
291 "for a non-contiguousobject.");
292 return NULL;
294 bytes = PyBytes_FromStringAndSize(NULL, view->len);
295 if (bytes == NULL) {
296 Py_DECREF(mem);
297 return NULL;
299 dest = PyBytes_AS_STRING(bytes);
300 /* different copying strategy depending on whether
301 or not any pointer de-referencing is needed
303 /* strided or in-direct copy */
304 if (view->suboffsets==NULL) {
305 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
306 view->strides, view->itemsize, fort);
308 else {
309 if (_indirect_copy_nd(dest, view, fort) < 0) {
310 Py_DECREF(bytes);
311 Py_DECREF(mem);
312 return NULL;
315 if (buffertype == PyBUF_SHADOW) {
316 /* return a shadowed memory-view object */
317 view->buf = dest;
318 mem->base = PyTuple_Pack(2, obj, bytes);
319 Py_DECREF(bytes);
320 if (mem->base == NULL) {
321 Py_DECREF(mem);
322 return NULL;
325 else {
326 PyBuffer_Release(view); /* XXX ? */
327 /* steal the reference */
328 mem->base = bytes;
330 _PyObject_GC_TRACK(mem);
331 return (PyObject *)mem;
335 static PyObject *
336 memory_format_get(PyMemoryViewObject *self)
338 return PyUnicode_FromString(self->view.format);
341 static PyObject *
342 memory_itemsize_get(PyMemoryViewObject *self)
344 return PyLong_FromSsize_t(self->view.itemsize);
347 static PyObject *
348 _IntTupleFromSsizet(int len, Py_ssize_t *vals)
350 int i;
351 PyObject *o;
352 PyObject *intTuple;
354 if (vals == NULL) {
355 Py_INCREF(Py_None);
356 return Py_None;
358 intTuple = PyTuple_New(len);
359 if (!intTuple) return NULL;
360 for(i=0; i<len; i++) {
361 o = PyLong_FromSsize_t(vals[i]);
362 if (!o) {
363 Py_DECREF(intTuple);
364 return NULL;
366 PyTuple_SET_ITEM(intTuple, i, o);
368 return intTuple;
371 static PyObject *
372 memory_shape_get(PyMemoryViewObject *self)
374 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
377 static PyObject *
378 memory_strides_get(PyMemoryViewObject *self)
380 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
383 static PyObject *
384 memory_suboffsets_get(PyMemoryViewObject *self)
386 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
389 static PyObject *
390 memory_readonly_get(PyMemoryViewObject *self)
392 return PyBool_FromLong(self->view.readonly);
395 static PyObject *
396 memory_ndim_get(PyMemoryViewObject *self)
398 return PyLong_FromLong(self->view.ndim);
401 static PyGetSetDef memory_getsetlist[] ={
402 {"format", (getter)memory_format_get, NULL, NULL},
403 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
404 {"shape", (getter)memory_shape_get, NULL, NULL},
405 {"strides", (getter)memory_strides_get, NULL, NULL},
406 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
407 {"readonly", (getter)memory_readonly_get, NULL, NULL},
408 {"ndim", (getter)memory_ndim_get, NULL, NULL},
409 {NULL, NULL, NULL, NULL},
413 static PyObject *
414 memory_tobytes(PyMemoryViewObject *self, PyObject *noargs)
416 Py_buffer view;
417 PyObject *res;
419 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
420 return NULL;
422 res = PyBytes_FromStringAndSize(NULL, view.len);
423 PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
424 PyBuffer_Release(&view);
425 return res;
428 /* TODO: rewrite this function using the struct module to unpack
429 each buffer item */
431 static PyObject *
432 memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
434 Py_buffer *view = &(mem->view);
435 Py_ssize_t i;
436 PyObject *res, *item;
437 char *buf;
439 if (strcmp(view->format, "B") || view->itemsize != 1) {
440 PyErr_SetString(PyExc_NotImplementedError,
441 "tolist() only supports byte views");
442 return NULL;
444 if (view->ndim != 1) {
445 PyErr_SetString(PyExc_NotImplementedError,
446 "tolist() only supports one-dimensional objects");
447 return NULL;
449 res = PyList_New(view->len);
450 if (res == NULL)
451 return NULL;
452 buf = view->buf;
453 for (i = 0; i < view->len; i++) {
454 item = PyInt_FromLong((unsigned char) *buf);
455 if (item == NULL) {
456 Py_DECREF(res);
457 return NULL;
459 PyList_SET_ITEM(res, i, item);
460 buf++;
462 return res;
465 static PyMethodDef memory_methods[] = {
466 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
467 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
468 {NULL, NULL} /* sentinel */
472 static void
473 memory_dealloc(PyMemoryViewObject *self)
475 _PyObject_GC_UNTRACK(self);
476 if (self->view.obj != NULL) {
477 if (self->base && PyTuple_Check(self->base)) {
478 /* Special case when first element is generic object
479 with buffer interface and the second element is a
480 contiguous "shadow" that must be copied back into
481 the data areay of the first tuple element before
482 releasing the buffer on the first element.
485 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
486 PyTuple_GET_ITEM(self->base,1));
488 /* The view member should have readonly == -1 in
489 this instance indicating that the memory can
490 be "locked" and was locked and will be unlocked
491 again after this call.
493 PyBuffer_Release(&(self->view));
495 else {
496 PyBuffer_Release(&(self->view));
498 Py_CLEAR(self->base);
500 PyObject_GC_Del(self);
503 static PyObject *
504 memory_repr(PyMemoryViewObject *self)
506 return PyUnicode_FromFormat("<memory at %p>", self);
509 /* Sequence methods */
510 static Py_ssize_t
511 memory_length(PyMemoryViewObject *self)
513 return get_shape0(&self->view);
517 mem[obj] returns a bytes object holding the data for one element if
518 obj fully indexes the memory view or another memory-view object
519 if it does not.
521 0-d memory-view objects can be referenced using ... or () but
522 not with anything else.
524 static PyObject *
525 memory_subscript(PyMemoryViewObject *self, PyObject *key)
527 Py_buffer *view;
528 view = &(self->view);
530 if (view->ndim == 0) {
531 if (key == Py_Ellipsis ||
532 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
533 Py_INCREF(self);
534 return (PyObject *)self;
536 else {
537 PyErr_SetString(PyExc_IndexError,
538 "invalid indexing of 0-dim memory");
539 return NULL;
542 if (PyIndex_Check(key)) {
543 Py_ssize_t result;
544 result = PyNumber_AsSsize_t(key, NULL);
545 if (result == -1 && PyErr_Occurred())
546 return NULL;
547 if (view->ndim == 1) {
548 /* Return a bytes object */
549 char *ptr;
550 ptr = (char *)view->buf;
551 if (result < 0) {
552 result += get_shape0(view);
554 if ((result < 0) || (result >= get_shape0(view))) {
555 PyErr_SetString(PyExc_IndexError,
556 "index out of bounds");
557 return NULL;
559 if (view->strides == NULL)
560 ptr += view->itemsize * result;
561 else
562 ptr += view->strides[0] * result;
563 if (view->suboffsets != NULL &&
564 view->suboffsets[0] >= 0) {
565 ptr = *((char **)ptr) + view->suboffsets[0];
567 return PyBytes_FromStringAndSize(ptr, view->itemsize);
569 else {
570 /* Return a new memory-view object */
571 Py_buffer newview;
572 memset(&newview, 0, sizeof(newview));
573 /* XXX: This needs to be fixed so it
574 actually returns a sub-view
576 return PyMemoryView_FromBuffer(&newview);
579 else if (PySlice_Check(key)) {
580 Py_ssize_t start, stop, step, slicelength;
582 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
583 &start, &stop, &step, &slicelength) < 0) {
584 return NULL;
587 if (step == 1 && view->ndim == 1) {
588 Py_buffer newview;
589 void *newbuf = (char *) view->buf
590 + start * view->itemsize;
591 int newflags = view->readonly
592 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
594 /* XXX There should be an API to create a subbuffer */
595 if (view->obj != NULL) {
596 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
597 return NULL;
599 else {
600 newview = *view;
602 newview.buf = newbuf;
603 newview.len = slicelength * newview.itemsize;
604 newview.format = view->format;
605 newview.shape = &(newview.smalltable[0]);
606 newview.shape[0] = slicelength;
607 newview.strides = &(newview.itemsize);
608 return PyMemoryView_FromBuffer(&newview);
610 PyErr_SetNone(PyExc_NotImplementedError);
611 return NULL;
613 PyErr_Format(PyExc_TypeError,
614 "cannot index memory using \"%.200s\"",
615 key->ob_type->tp_name);
616 return NULL;
620 /* Need to support assigning memory if we can */
621 static int
622 memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
624 Py_ssize_t start, len, bytelen, i;
625 Py_buffer srcview;
626 Py_buffer *view = &(self->view);
627 char *srcbuf, *destbuf;
629 if (view->readonly) {
630 PyErr_SetString(PyExc_TypeError,
631 "cannot modify read-only memory");
632 return -1;
634 if (view->ndim != 1) {
635 PyErr_SetNone(PyExc_NotImplementedError);
636 return -1;
638 if (PyIndex_Check(key)) {
639 start = PyNumber_AsSsize_t(key, NULL);
640 if (start == -1 && PyErr_Occurred())
641 return -1;
642 if (start < 0) {
643 start += get_shape0(view);
645 if ((start < 0) || (start >= get_shape0(view))) {
646 PyErr_SetString(PyExc_IndexError,
647 "index out of bounds");
648 return -1;
650 len = 1;
652 else if (PySlice_Check(key)) {
653 Py_ssize_t stop, step;
655 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
656 &start, &stop, &step, &len) < 0) {
657 return -1;
659 if (step != 1) {
660 PyErr_SetNone(PyExc_NotImplementedError);
661 return -1;
664 else {
665 PyErr_Format(PyExc_TypeError,
666 "cannot index memory using \"%.200s\"",
667 key->ob_type->tp_name);
668 return -1;
670 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
671 return -1;
673 /* XXX should we allow assignment of different item sizes
674 as long as the byte length is the same?
675 (e.g. assign 2 shorts to a 4-byte slice) */
676 if (srcview.itemsize != view->itemsize) {
677 PyErr_Format(PyExc_TypeError,
678 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
679 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
680 goto _error;
682 bytelen = len * view->itemsize;
683 if (bytelen != srcview.len) {
684 PyErr_SetString(PyExc_ValueError,
685 "cannot modify size of memoryview object");
686 goto _error;
688 /* Do the actual copy */
689 destbuf = (char *) view->buf + start * view->itemsize;
690 srcbuf = (char *) srcview.buf;
691 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
692 /* No overlapping */
693 memcpy(destbuf, srcbuf, bytelen);
694 else if (destbuf < srcbuf) {
695 /* Copy in ascending order */
696 for (i = 0; i < bytelen; i++)
697 destbuf[i] = srcbuf[i];
699 else {
700 /* Copy in descencing order */
701 for (i = bytelen - 1; i >= 0; i--)
702 destbuf[i] = srcbuf[i];
705 PyBuffer_Release(&srcview);
706 return 0;
708 _error:
709 PyBuffer_Release(&srcview);
710 return -1;
713 static PyObject *
714 memory_richcompare(PyObject *v, PyObject *w, int op)
716 Py_buffer vv, ww;
717 int equal = 0;
718 PyObject *res;
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;
728 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
729 PyErr_Clear();
730 goto _notimpl;
733 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
734 goto _end;
736 equal = !memcmp(vv.buf, ww.buf, vv.len);
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;
748 _notimpl:
749 PyBuffer_Release(&vv);
750 PyBuffer_Release(&ww);
751 Py_INCREF(Py_NotImplemented);
752 return Py_NotImplemented;
756 static int
757 memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
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;
766 static int
767 memory_clear(PyMemoryViewObject *self)
769 Py_CLEAR(self->base);
770 PyBuffer_Release(&self->view);
771 return 0;
775 /* As mapping */
776 static PyMappingMethods memory_as_mapping = {
777 (lenfunc)memory_length, /* mp_length */
778 (binaryfunc)memory_subscript, /* mp_subscript */
779 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
783 /* Buffer methods */
784 static PyBufferProcs memory_as_buffer = {
785 0, /* bf_getreadbuffer */
786 0, /* bf_getwritebuffer */
787 0, /* bf_getsegcount */
788 0, /* bf_getcharbuffer */
789 (getbufferproc)memory_getbuf, /* bf_getbuffer */
790 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
794 PyTypeObject PyMemoryView_Type = {
795 PyVarObject_HEAD_INIT(&PyType_Type, 0)
796 "memoryview",
797 sizeof(PyMemoryViewObject),
799 (destructor)memory_dealloc, /* tp_dealloc */
800 0, /* tp_print */
801 0, /* tp_getattr */
802 0, /* tp_setattr */
803 0, /* tp_compare */
804 (reprfunc)memory_repr, /* tp_repr */
805 0, /* tp_as_number */
806 0, /* tp_as_sequence */
807 &memory_as_mapping, /* tp_as_mapping */
808 0, /* tp_hash */
809 0, /* tp_call */
810 0, /* tp_str */
811 PyObject_GenericGetAttr, /* tp_getattro */
812 0, /* tp_setattro */
813 &memory_as_buffer, /* tp_as_buffer */
814 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
815 Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */
816 memory_doc, /* tp_doc */
817 (traverseproc)memory_traverse, /* tp_traverse */
818 (inquiry)memory_clear, /* tp_clear */
819 memory_richcompare, /* tp_richcompare */
820 0, /* tp_weaklistoffset */
821 0, /* tp_iter */
822 0, /* tp_iternext */
823 memory_methods, /* tp_methods */
824 0, /* tp_members */
825 memory_getsetlist, /* tp_getset */
826 0, /* tp_base */
827 0, /* tp_dict */
828 0, /* tp_descr_get */
829 0, /* tp_descr_set */
830 0, /* tp_dictoffset */
831 0, /* tp_init */
832 0, /* tp_alloc */
833 memory_new, /* tp_new */