diff -r 28d17b3f3074 Modules/_testbuffer.c --- a/Modules/_testbuffer.c Wed Aug 15 16:36:17 2012 +0200 +++ b/Modules/_testbuffer.c Wed Aug 15 16:49:32 2012 +0200 @@ -6,15 +6,61 @@ #include "Python.h" - -/* struct module */ -PyObject *structmodule = NULL; -PyObject *Struct = NULL; -PyObject *calcsize = NULL; +typedef struct { + /* struct module */ + PyObject *structmodule; + PyObject *Struct; + PyObject *calcsize; + PyObject *simple_format; + PyObject *NDArray_Type; + PyObject *StaticArray_Type; +} _testbufferstate; + + +#define _testbuffer_state(o) ((_testbufferstate *)PyModule_GetState(o)) + +static int +_testbuffer_clear(PyObject *m) +{ + _testbufferstate *state = _testbuffer_state(m); + Py_CLEAR(state->structmodule); + Py_CLEAR(state->Struct); + Py_CLEAR(state->calcsize); + Py_CLEAR(state->simple_format); + Py_CLEAR(state->NDArray_Type); + Py_CLEAR(state->StaticArray_Type); + return 0; +} + +static int +_testbuffer_traverse(PyObject *m, visitproc visit, void *arg) +{ + _testbufferstate *state = _testbuffer_state(m); + Py_VISIT(state->structmodule); + Py_VISIT(state->Struct); + Py_VISIT(state->calcsize); + Py_VISIT(state->simple_format); + Py_VISIT(state->NDArray_Type); + Py_VISIT(state->StaticArray_Type); + return 0; +} + +static void +_testbuffer_free(void *m) +{ + _testbuffer_clear((PyObject *)m); +} + +static PyModuleDef _testbuffermodule; + +#define _testbufferstate_global ((_testbufferstate *)PyModule_GetState(PyState_FindModule(&_testbuffermodule))) + + + /* cache simple format string */ static const char *simple_fmt = "B"; -PyObject *simple_format = NULL; + #define SIMPLE_FORMAT(fmt) (fmt == NULL || strcmp(fmt, "B") == 0) @@ -22,8 +68,8 @@ /* NDArray Object */ /**************************************************************************/ -static PyTypeObject NDArray_Type; -#define NDArray_Check(v) (Py_TYPE(v) == &NDArray_Type) + +#define NDArray_Check(v) (Py_TYPE(v) == (PyTypeObject *)_testbufferstate_global->NDArray_Type) #define CHECK_LIST_OR_TUPLE(v) \ if (!PyList_Check(v) && !PyTuple_Check(v)) { \ @@ -82,7 +128,6 @@ /* Single node of a list of base buffers. The list is needed to implement changes in memory layout while exported buffers are active. */ -static PyTypeObject NDArray_Type; struct ndbuf; typedef struct ndbuf { @@ -208,9 +253,10 @@ { NDArrayObject *nd; - nd = PyObject_New(NDArrayObject, &NDArray_Type); + nd = PyObject_New(NDArrayObject, (PyTypeObject *)_testbufferstate_global->NDArray_Type); if (nd == NULL) return NULL; + Py_INCREF(_testbufferstate_global->NDArray_Type); nd->flags = 0; nd->head = NULL; @@ -220,6 +266,7 @@ static void ndarray_dealloc(NDArrayObject *self) { + PyTypeObject *type = Py_TYPE(self); if (self->head) { if (ND_IS_CONSUMER(self)) { Py_buffer *base = &self->head->base; @@ -235,6 +282,9 @@ ndbuf_pop(self); } } + if((void *)type->tp_dealloc == (void *)ndarray_dealloc) { + Py_DECREF(type); + } PyObject_Del(self); } @@ -311,7 +361,7 @@ assert(PyObject_CheckBuffer(obj)); assert(PyList_Check(items) || PyTuple_Check(items)); - structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL); + structobj = PyObject_CallFunctionObjArgs(_testbufferstate_global->Struct, format, NULL); if (structobj == NULL) return -1; @@ -405,7 +455,7 @@ if (format == NULL) goto out; - structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL); + structobj = PyObject_CallFunctionObjArgs(_testbufferstate_global->Struct, format, NULL); if (structobj == NULL) goto out; @@ -579,7 +629,7 @@ itemsize = 1; } - unpack_from = PyObject_GetAttrString(structmodule, "unpack_from"); + unpack_from = PyObject_GetAttrString(_testbufferstate_global->structmodule, "unpack_from"); if (unpack_from == NULL) return NULL; @@ -697,7 +747,7 @@ if (format == NULL) goto out; - structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL); + structobj = PyObject_CallFunctionObjArgs(_testbufferstate_global->Struct, format, NULL); Py_DECREF(format); if (structobj == NULL) goto out; @@ -789,7 +839,7 @@ PyObject *tmp; Py_ssize_t itemsize; - tmp = PyObject_CallFunctionObjArgs(calcsize, format, NULL); + tmp = PyObject_CallFunctionObjArgs(_testbufferstate_global->calcsize, format, NULL); if (tmp == NULL) return -1; itemsize = PyLong_AsSsize_t(tmp); @@ -1287,7 +1337,7 @@ PyObject *shape = NULL; /* size of each dimension */ PyObject *strides = NULL; /* number of bytes to the next elt in each dim */ Py_ssize_t offset = 0; /* buffer offset */ - PyObject *format = simple_format; /* struct module specifier: "B" */ + PyObject *format = _testbufferstate_global->simple_format; /* struct module specifier: "B" */ int flags = ND_DEFAULT; /* base buffer and ndarray flags */ int getbuf = PyBUF_UNUSED; /* re-exporter: getbuffer request flags */ @@ -1299,7 +1349,7 @@ /* NDArrayObject is re-exporter */ if (PyObject_CheckBuffer(v) && shape == NULL) { - if (strides || offset || format != simple_format || + if (strides || offset || format != _testbufferstate_global->simple_format || !(flags == ND_DEFAULT || flags == ND_REDIRECT)) { PyErr_SetString(PyExc_TypeError, "construction from exporter object only takes 'obj', 'getbuf' " @@ -1352,7 +1402,7 @@ PyObject *items = NULL; /* initializer: scalar, list or tuple */ PyObject *shape = NULL; /* size of each dimension */ PyObject *strides = NULL; /* number of bytes to the next elt in each dim */ - PyObject *format = simple_format; /* struct module specifier: "B" */ + PyObject *format = _testbufferstate_global->simple_format; /* struct module specifier: "B" */ Py_ssize_t offset = 0; /* buffer offset */ int flags = ND_DEFAULT; /* base buffer flags */ @@ -1596,7 +1646,7 @@ NDArrayObject *nd; Py_buffer *subview; - nd = (NDArrayObject *)ndarray_new(&NDArray_Type, NULL, NULL); + nd = (NDArrayObject *)ndarray_new((PyTypeObject *)_testbufferstate_global->NDArray_Type, NULL, NULL); if (nd == NULL) return NULL; @@ -1792,7 +1842,7 @@ return ndarray_item(self, index); } - nd = (NDArrayObject *)ndarray_new(&NDArray_Type, NULL, NULL); + nd = (NDArrayObject *)ndarray_new((PyTypeObject *)_testbufferstate_global->NDArray_Type, NULL, NULL); if (nd == NULL) return NULL; @@ -1944,21 +1994,6 @@ return NULL; } - -static PyMappingMethods ndarray_as_mapping = { - NULL, /* mp_length */ - (binaryfunc)ndarray_subscript, /* mp_subscript */ - (objobjargproc)ndarray_ass_subscript /* mp_ass_subscript */ -}; - -static PySequenceMethods ndarray_as_sequence = { - 0, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - (ssizeargfunc)ndarray_item, /* sq_item */ -}; - - /**************************************************************************/ /* getters */ /**************************************************************************/ @@ -2610,52 +2645,35 @@ {NULL} }; -static PyTypeObject NDArray_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "ndarray", /* Name of this type */ - sizeof(NDArrayObject), /* Basic object size */ - 0, /* Item size for varobject */ - (destructor)ndarray_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - &ndarray_as_sequence, /* tp_as_sequence */ - &ndarray_as_mapping, /* tp_as_mapping */ - (hashfunc)ndarray_hash, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - &ndarray_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - ndarray_methods, /* tp_methods */ - 0, /* tp_members */ - ndarray_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - ndarray_init, /* tp_init */ - 0, /* tp_alloc */ - ndarray_new, /* tp_new */ +static PyType_Slot NDArray_Type_slots[] = { + {Py_tp_dealloc, (destructor)ndarray_dealloc}, + {Py_sq_item, (ssizeargfunc)ndarray_item}, + //{Py_was_sq_slice, }, + {Py_mp_length, NULL}, + {Py_mp_subscript, (binaryfunc)ndarray_subscript}, + {Py_mp_ass_subscript, (objobjargproc)ndarray_ass_subscript}, + {Py_tp_hash, (hashfunc)ndarray_hash}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_methods, ndarray_methods}, + {Py_tp_getset, ndarray_getset}, + {Py_tp_init, ndarray_init}, + {Py_tp_new, ndarray_new}, + {0, 0} }; +static PyType_Spec NDArray_Type_spec = { + "ndarray", + sizeof(NDArrayObject), + 0, + Py_TPFLAGS_DEFAULT, + NDArray_Type_slots, +}; + + /**************************************************************************/ /* StaticArray Object */ /**************************************************************************/ -static PyTypeObject StaticArray_Type; typedef struct { PyObject_HEAD @@ -2682,7 +2700,9 @@ static PyObject * staticarray_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return (PyObject *)PyObject_New(StaticArrayObject, &StaticArray_Type); + Py_INCREF(_testbufferstate_global->StaticArray_Type); + return (PyObject *)PyObject_New(StaticArrayObject, + (PyTypeObject *)_testbufferstate_global->StaticArray_Type); } static int @@ -2704,6 +2724,10 @@ static void staticarray_dealloc(StaticArrayObject *self) { + PyTypeObject *type = Py_TYPE(self); + if((void *)type->tp_dealloc == (void *)staticarray_dealloc) { + Py_DECREF(type); + } PyObject_Del(self); } @@ -2730,47 +2754,25 @@ NULL, /* bf_releasebuffer */ }; -static PyTypeObject StaticArray_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "staticarray", /* Name of this type */ - sizeof(StaticArrayObject), /* Basic object size */ - 0, /* Item size for varobject */ - (destructor)staticarray_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - &staticarray_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - staticarray_init, /* tp_init */ - 0, /* tp_alloc */ - staticarray_new, /* tp_new */ + + + +static PyType_Slot StaticArray_Type_slots[] = { + {Py_tp_dealloc, (destructor)staticarray_dealloc}, + {Py_tp_init, staticarray_init}, + {Py_tp_new, staticarray_new}, + {0, 0} }; +static PyType_Spec StaticArray_Type_spec = { + "staticarray", + sizeof(StaticArrayObject), + 0, + Py_TPFLAGS_DEFAULT, + StaticArray_Type_slots, +}; + + static struct PyMethodDef _testbuffer_functions[] = { {"slice_indices", slice_indices, METH_VARARGS, NULL}, @@ -2787,12 +2789,12 @@ PyModuleDef_HEAD_INIT, "_testbuffer", NULL, - -1, + sizeof(_testbufferstate), _testbuffer_functions, NULL, - NULL, - NULL, - NULL + _testbuffer_traverse, + _testbuffer_clear, + _testbuffer_free }; @@ -2800,30 +2802,48 @@ PyInit__testbuffer(void) { PyObject *m; + _testbufferstate *state; m = PyModule_Create(&_testbuffermodule); if (m == NULL) return NULL; - Py_TYPE(&NDArray_Type) = &PyType_Type; - Py_INCREF(&NDArray_Type); - PyModule_AddObject(m, "ndarray", (PyObject *)&NDArray_Type); - - Py_TYPE(&StaticArray_Type) = &PyType_Type; - Py_INCREF(&StaticArray_Type); - PyModule_AddObject(m, "staticarray", (PyObject *)&StaticArray_Type); - - structmodule = PyImport_ImportModule("struct"); - if (structmodule == NULL) + state = _testbuffer_state(m); + + state->NDArray_Type = PyType_FromSpec(&NDArray_Type_spec); + if(state->NDArray_Type == NULL) return NULL; - Struct = PyObject_GetAttrString(structmodule, "Struct"); - calcsize = PyObject_GetAttrString(structmodule, "calcsize"); - if (Struct == NULL || calcsize == NULL) + ((PyTypeObject *)state->NDArray_Type)->tp_as_buffer = &ndarray_as_buffer; + Py_INCREF(state->NDArray_Type); + PyModule_AddObject(m, "ndarray", state->NDArray_Type); + + state->StaticArray_Type = PyType_FromSpec(&StaticArray_Type_spec); + if(state->StaticArray_Type == NULL) return NULL; - simple_format = PyUnicode_FromString(simple_fmt); - if (simple_format == NULL) + ((PyTypeObject *)state->StaticArray_Type)->tp_as_buffer = &staticarray_as_buffer; + Py_INCREF(state->StaticArray_Type); + PyModule_AddObject(m, "staticarray", state->StaticArray_Type); + + state->structmodule = PyImport_ImportModule("struct"); + if (state->structmodule == NULL) + return NULL; + + state->Struct = PyObject_GetAttrString( + state->structmodule, + "Struct" + ); + state->calcsize = PyObject_GetAttrString( + state->structmodule, + "calcsize" + ); + if (state->Struct == NULL + || state->calcsize == NULL) + return NULL; + + state->simple_format = PyUnicode_FromString(simple_fmt); + if (state->simple_format == NULL) return NULL; PyModule_AddIntConstant(m, "ND_MAX_NDIM", ND_MAX_NDIM);