Merged revisions 78818 via svnmerge from
[python/dscho.git] / Objects / memoryobject.c
blobe92a771dfd26968a258b20f6032c94c040b3a2ce
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;
79 Py_buffer view;
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;
88 if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)
89 return NULL;
91 mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);
92 if (mview == NULL) {
93 PyBuffer_Release(&view);
94 return NULL;
97 mview->base = base;
98 Py_INCREF(base);
99 return (PyObject *)mview;
102 static PyObject *
103 memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
105 PyObject *obj;
106 static char *kwlist[] = {"object", 0};
108 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
109 &obj)) {
110 return NULL;
113 return PyMemoryView_FromObject(obj);
117 static 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)
121 int k;
122 Py_ssize_t outstride;
124 if (nd==0) {
125 memcpy(dest, src, itemsize);
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];
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.
141 outstride = itemsize;
142 for (k=1; k<nd-1;k++) {
143 outstride *= shape[k];
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];
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
159 outstride = itemsize;
160 for (k=1; k < nd; k++) {
161 outstride *= shape[k];
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];
172 return;
175 void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
176 void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
178 static int
179 _indirect_copy_nd(char *dest, Py_buffer *view, char fort)
181 Py_ssize_t *indices;
182 int k;
183 Py_ssize_t elements;
184 char *ptr;
185 void (*func)(int, Py_ssize_t *, Py_ssize_t *);
187 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
188 PyErr_NoMemory();
189 return -1;
192 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
193 if (indices == NULL) {
194 PyErr_NoMemory();
195 return -1;
197 for (k=0; k<view->ndim;k++) {
198 indices[k] = 0;
201 elements = 1;
202 for (k=0; k<view->ndim; k++) {
203 elements *= view->shape[k];
205 if (fort == 'F') {
206 func = _add_one_to_index_F;
208 else {
209 func = _add_one_to_index_C;
211 while (elements--) {
212 func(view->ndim, indices, view->shape);
213 ptr = PyBuffer_GetPointer(view, indices);
214 memcpy(dest, ptr, view->itemsize);
215 dest += view->itemsize;
218 PyMem_Free(indices);
219 return 0;
223 Get a the data from an object as a contiguous chunk of memory (in
224 either 'C' or 'F'ortran order) even if it means copying it into a
225 separate memory area.
227 Returns a new reference to a Memory view object. If no copy is needed,
228 the memory view object points to the original memory and holds a
229 lock on the original. If a copy is needed, then the memory view object
230 points to a brand-new Bytes object (and holds a memory lock on it).
232 buffertype
234 PyBUF_READ buffer only needs to be read-only
235 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
236 PyBUF_SHADOW buffer needs to be writable so shadow it with
237 a contiguous buffer if it is not. The view will point to
238 the shadow buffer which can be written to and then
239 will be copied back into the other buffer when the memory
240 view is de-allocated. While the shadow buffer is
241 being used, it will have an exclusive write lock on
242 the original buffer.
245 PyObject *
246 PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
248 PyMemoryViewObject *mem;
249 PyObject *bytes;
250 Py_buffer *view;
251 int flags;
252 char *dest;
254 if (!PyObject_CheckBuffer(obj)) {
255 PyErr_SetString(PyExc_TypeError,
256 "object does not support the buffer interface");
257 return NULL;
260 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
261 if (mem == NULL)
262 return NULL;
264 view = &mem->view;
265 flags = PyBUF_FULL_RO;
266 switch(buffertype) {
267 case PyBUF_WRITE:
268 flags = PyBUF_FULL;
269 break;
272 if (PyObject_GetBuffer(obj, view, flags) != 0) {
273 Py_DECREF(mem);
274 return NULL;
277 if (PyBuffer_IsContiguous(view, fort)) {
278 /* no copy needed */
279 Py_INCREF(obj);
280 mem->base = obj;
281 _PyObject_GC_TRACK(mem);
282 return (PyObject *)mem;
284 /* otherwise a copy is needed */
285 if (buffertype == PyBUF_WRITE) {
286 Py_DECREF(mem);
287 PyErr_SetString(PyExc_BufferError,
288 "writable contiguous buffer requested "
289 "for a non-contiguousobject.");
290 return NULL;
292 bytes = PyBytes_FromStringAndSize(NULL, view->len);
293 if (bytes == NULL) {
294 Py_DECREF(mem);
295 return NULL;
297 dest = PyBytes_AS_STRING(bytes);
298 /* different copying strategy depending on whether
299 or not any pointer de-referencing is needed
301 /* strided or in-direct copy */
302 if (view->suboffsets==NULL) {
303 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
304 view->strides, view->itemsize, fort);
306 else {
307 if (_indirect_copy_nd(dest, view, fort) < 0) {
308 Py_DECREF(bytes);
309 Py_DECREF(mem);
310 return NULL;
313 if (buffertype == PyBUF_SHADOW) {
314 /* return a shadowed memory-view object */
315 view->buf = dest;
316 mem->base = PyTuple_Pack(2, obj, bytes);
317 Py_DECREF(bytes);
318 if (mem->base == NULL) {
319 Py_DECREF(mem);
320 return NULL;
323 else {
324 PyBuffer_Release(view); /* XXX ? */
325 /* steal the reference */
326 mem->base = bytes;
328 _PyObject_GC_TRACK(mem);
329 return (PyObject *)mem;
333 static PyObject *
334 memory_format_get(PyMemoryViewObject *self)
336 return PyUnicode_FromString(self->view.format);
339 static PyObject *
340 memory_itemsize_get(PyMemoryViewObject *self)
342 return PyLong_FromSsize_t(self->view.itemsize);
345 static PyObject *
346 _IntTupleFromSsizet(int len, Py_ssize_t *vals)
348 int i;
349 PyObject *o;
350 PyObject *intTuple;
352 if (vals == NULL) {
353 Py_INCREF(Py_None);
354 return Py_None;
356 intTuple = PyTuple_New(len);
357 if (!intTuple) return NULL;
358 for(i=0; i<len; i++) {
359 o = PyLong_FromSsize_t(vals[i]);
360 if (!o) {
361 Py_DECREF(intTuple);
362 return NULL;
364 PyTuple_SET_ITEM(intTuple, i, o);
366 return intTuple;
369 static PyObject *
370 memory_shape_get(PyMemoryViewObject *self)
372 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
375 static PyObject *
376 memory_strides_get(PyMemoryViewObject *self)
378 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
381 static PyObject *
382 memory_suboffsets_get(PyMemoryViewObject *self)
384 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
387 static PyObject *
388 memory_readonly_get(PyMemoryViewObject *self)
390 return PyBool_FromLong(self->view.readonly);
393 static PyObject *
394 memory_ndim_get(PyMemoryViewObject *self)
396 return PyLong_FromLong(self->view.ndim);
399 static PyGetSetDef memory_getsetlist[] ={
400 {"format", (getter)memory_format_get, NULL, NULL},
401 {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
402 {"shape", (getter)memory_shape_get, NULL, NULL},
403 {"strides", (getter)memory_strides_get, NULL, NULL},
404 {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
405 {"readonly", (getter)memory_readonly_get, NULL, NULL},
406 {"ndim", (getter)memory_ndim_get, NULL, NULL},
407 {NULL, NULL, NULL, NULL},
411 static PyObject *
412 memory_tobytes(PyMemoryViewObject *mem, PyObject *noargs)
414 return PyObject_CallFunctionObjArgs(
415 (PyObject *) &PyBytes_Type, mem, NULL);
418 /* TODO: rewrite this function using the struct module to unpack
419 each buffer item */
421 static PyObject *
422 memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
424 Py_buffer *view = &(mem->view);
425 Py_ssize_t i;
426 PyObject *res, *item;
427 char *buf;
429 if (strcmp(view->format, "B") || view->itemsize != 1) {
430 PyErr_SetString(PyExc_NotImplementedError,
431 "tolist() only supports byte views");
432 return NULL;
434 if (view->ndim != 1) {
435 PyErr_SetString(PyExc_NotImplementedError,
436 "tolist() only supports one-dimensional objects");
437 return NULL;
439 res = PyList_New(view->len);
440 if (res == NULL)
441 return NULL;
442 buf = view->buf;
443 for (i = 0; i < view->len; i++) {
444 item = PyLong_FromUnsignedLong((unsigned char) *buf);
445 if (item == NULL) {
446 Py_DECREF(res);
447 return NULL;
449 PyList_SET_ITEM(res, i, item);
450 buf++;
452 return res;
455 static PyMethodDef memory_methods[] = {
456 {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
457 {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
458 {NULL, NULL} /* sentinel */
462 static void
463 memory_dealloc(PyMemoryViewObject *self)
465 _PyObject_GC_UNTRACK(self);
466 if (self->view.obj != NULL) {
467 if (self->base && PyTuple_Check(self->base)) {
468 /* Special case when first element is generic object
469 with buffer interface and the second element is a
470 contiguous "shadow" that must be copied back into
471 the data areay of the first tuple element before
472 releasing the buffer on the first element.
475 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
476 PyTuple_GET_ITEM(self->base,1));
478 /* The view member should have readonly == -1 in
479 this instance indicating that the memory can
480 be "locked" and was locked and will be unlocked
481 again after this call.
483 PyBuffer_Release(&(self->view));
485 else {
486 PyBuffer_Release(&(self->view));
488 Py_CLEAR(self->base);
490 PyObject_GC_Del(self);
493 static PyObject *
494 memory_repr(PyMemoryViewObject *self)
496 return PyUnicode_FromFormat("<memory at %p>", self);
499 /* Sequence methods */
500 static Py_ssize_t
501 memory_length(PyMemoryViewObject *self)
503 return get_shape0(&self->view);
506 /* Alternate version of memory_subcript that only accepts indices.
507 Used by PySeqIter_New().
509 static PyObject *
510 memory_item(PyMemoryViewObject *self, Py_ssize_t result)
512 Py_buffer *view = &(self->view);
514 if (view->ndim == 0) {
515 PyErr_SetString(PyExc_IndexError,
516 "invalid indexing of 0-dim memory");
517 return NULL;
519 if (view->ndim == 1) {
520 /* Return a bytes object */
521 char *ptr;
522 ptr = (char *)view->buf;
523 if (result < 0) {
524 result += get_shape0(view);
526 if ((result < 0) || (result >= get_shape0(view))) {
527 PyErr_SetString(PyExc_IndexError,
528 "index out of bounds");
529 return NULL;
531 if (view->strides == NULL)
532 ptr += view->itemsize * result;
533 else
534 ptr += view->strides[0] * result;
535 if (view->suboffsets != NULL &&
536 view->suboffsets[0] >= 0) {
537 ptr = *((char **)ptr) + view->suboffsets[0];
539 return PyBytes_FromStringAndSize(ptr, view->itemsize);
540 } else {
541 /* Return a new memory-view object */
542 Py_buffer newview;
543 memset(&newview, 0, sizeof(newview));
544 /* XXX: This needs to be fixed so it actually returns a sub-view */
545 return PyMemoryView_FromBuffer(&newview);
550 mem[obj] returns a bytes object holding the data for one element if
551 obj fully indexes the memory view or another memory-view object
552 if it does not.
554 0-d memory-view objects can be referenced using ... or () but
555 not with anything else.
557 static PyObject *
558 memory_subscript(PyMemoryViewObject *self, PyObject *key)
560 Py_buffer *view;
561 view = &(self->view);
563 if (view->ndim == 0) {
564 if (key == Py_Ellipsis ||
565 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
566 Py_INCREF(self);
567 return (PyObject *)self;
569 else {
570 PyErr_SetString(PyExc_IndexError,
571 "invalid indexing of 0-dim memory");
572 return NULL;
575 if (PyIndex_Check(key)) {
576 Py_ssize_t result;
577 result = PyNumber_AsSsize_t(key, NULL);
578 if (result == -1 && PyErr_Occurred())
579 return NULL;
580 return memory_item(self, result);
582 else if (PySlice_Check(key)) {
583 Py_ssize_t start, stop, step, slicelength;
585 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
586 &start, &stop, &step, &slicelength) < 0) {
587 return NULL;
590 if (step == 1 && view->ndim == 1) {
591 Py_buffer newview;
592 void *newbuf = (char *) view->buf
593 + start * view->itemsize;
594 int newflags = view->readonly
595 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
597 /* XXX There should be an API to create a subbuffer */
598 if (view->obj != NULL) {
599 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
600 return NULL;
602 else {
603 newview = *view;
605 newview.buf = newbuf;
606 newview.len = slicelength * newview.itemsize;
607 newview.format = view->format;
608 newview.shape = &(newview.smalltable[0]);
609 newview.shape[0] = slicelength;
610 newview.strides = &(newview.itemsize);
611 return PyMemoryView_FromBuffer(&newview);
613 PyErr_SetNone(PyExc_NotImplementedError);
614 return NULL;
616 PyErr_Format(PyExc_TypeError,
617 "cannot index memory using \"%.200s\"",
618 key->ob_type->tp_name);
619 return NULL;
623 /* Need to support assigning memory if we can */
624 static int
625 memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
627 Py_ssize_t start, len, bytelen, i;
628 Py_buffer srcview;
629 Py_buffer *view = &(self->view);
630 char *srcbuf, *destbuf;
632 if (view->readonly) {
633 PyErr_SetString(PyExc_TypeError,
634 "cannot modify read-only memory");
635 return -1;
637 if (view->ndim != 1) {
638 PyErr_SetNone(PyExc_NotImplementedError);
639 return -1;
641 if (PyIndex_Check(key)) {
642 start = PyNumber_AsSsize_t(key, NULL);
643 if (start == -1 && PyErr_Occurred())
644 return -1;
645 if (start < 0) {
646 start += get_shape0(view);
648 if ((start < 0) || (start >= get_shape0(view))) {
649 PyErr_SetString(PyExc_IndexError,
650 "index out of bounds");
651 return -1;
653 len = 1;
655 else if (PySlice_Check(key)) {
656 Py_ssize_t stop, step;
658 if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
659 &start, &stop, &step, &len) < 0) {
660 return -1;
662 if (step != 1) {
663 PyErr_SetNone(PyExc_NotImplementedError);
664 return -1;
667 else {
668 PyErr_Format(PyExc_TypeError,
669 "cannot index memory using \"%.200s\"",
670 key->ob_type->tp_name);
671 return -1;
673 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
674 return -1;
676 /* XXX should we allow assignment of different item sizes
677 as long as the byte length is the same?
678 (e.g. assign 2 shorts to a 4-byte slice) */
679 if (srcview.itemsize != view->itemsize) {
680 PyErr_Format(PyExc_TypeError,
681 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
682 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
683 goto _error;
685 bytelen = len * view->itemsize;
686 if (bytelen != srcview.len) {
687 PyErr_SetString(PyExc_ValueError,
688 "cannot modify size of memoryview object");
689 goto _error;
691 /* Do the actual copy */
692 destbuf = (char *) view->buf + start * view->itemsize;
693 srcbuf = (char *) srcview.buf;
694 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
695 /* No overlapping */
696 memcpy(destbuf, srcbuf, bytelen);
697 else if (destbuf < srcbuf) {
698 /* Copy in ascending order */
699 for (i = 0; i < bytelen; i++)
700 destbuf[i] = srcbuf[i];
702 else {
703 /* Copy in descencing order */
704 for (i = bytelen - 1; i >= 0; i--)
705 destbuf[i] = srcbuf[i];
708 PyBuffer_Release(&srcview);
709 return 0;
711 _error:
712 PyBuffer_Release(&srcview);
713 return -1;
716 static PyObject *
717 memory_richcompare(PyObject *v, PyObject *w, int op)
719 Py_buffer vv, ww;
720 int equal = 0;
721 PyObject *res;
723 vv.obj = NULL;
724 ww.obj = NULL;
725 if (op != Py_EQ && op != Py_NE)
726 goto _notimpl;
727 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
728 PyErr_Clear();
729 goto _notimpl;
731 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
732 PyErr_Clear();
733 goto _notimpl;
736 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
737 goto _end;
739 equal = !memcmp(vv.buf, ww.buf, vv.len);
741 _end:
742 PyBuffer_Release(&vv);
743 PyBuffer_Release(&ww);
744 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
745 res = Py_True;
746 else
747 res = Py_False;
748 Py_INCREF(res);
749 return res;
751 _notimpl:
752 PyBuffer_Release(&vv);
753 PyBuffer_Release(&ww);
754 Py_INCREF(Py_NotImplemented);
755 return Py_NotImplemented;
759 static int
760 memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
762 if (self->base != NULL)
763 Py_VISIT(self->base);
764 if (self->view.obj != NULL)
765 Py_VISIT(self->view.obj);
766 return 0;
769 static int
770 memory_clear(PyMemoryViewObject *self)
772 Py_CLEAR(self->base);
773 PyBuffer_Release(&self->view);
774 return 0;
778 /* As mapping */
779 static PyMappingMethods memory_as_mapping = {
780 (lenfunc)memory_length, /* mp_length */
781 (binaryfunc)memory_subscript, /* mp_subscript */
782 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
785 static PySequenceMethods memory_as_sequence = {
786 0, /* sq_length */
787 0, /* sq_concat */
788 0, /* sq_repeat */
789 (ssizeargfunc)memory_item, /* sq_item */
792 /* Buffer methods */
794 static PyBufferProcs memory_as_buffer = {
795 (getbufferproc)memory_getbuf, /* bf_getbuffer */
796 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
800 PyTypeObject PyMemoryView_Type = {
801 PyVarObject_HEAD_INIT(&PyType_Type, 0)
802 "memoryview",
803 sizeof(PyMemoryViewObject),
805 (destructor)memory_dealloc, /* tp_dealloc */
806 0, /* tp_print */
807 0, /* tp_getattr */
808 0, /* tp_setattr */
809 0, /* tp_reserved */
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, /* tp_flags */
821 memory_doc, /* tp_doc */
822 (traverseproc)memory_traverse, /* tp_traverse */
823 (inquiry)memory_clear, /* tp_clear */
824 memory_richcompare, /* tp_richcompare */
825 0, /* tp_weaklistoffset */
826 0, /* tp_iter */
827 0, /* tp_iternext */
828 memory_methods, /* tp_methods */
829 0, /* tp_members */
830 memory_getsetlist, /* tp_getset */
831 0, /* tp_base */
832 0, /* tp_dict */
833 0, /* tp_descr_get */
834 0, /* tp_descr_set */
835 0, /* tp_dictoffset */
836 0, /* tp_init */
837 0, /* tp_alloc */
838 memory_new, /* tp_new */