From ec3c86e558adbae96f816943a1a24fd7366d5f27 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Mon, 10 Aug 2020 19:14:46 -0500 Subject: [PATCH 1/6] port _testbuffer to multi-phase --- Modules/_testbuffer.c | 59 ++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c index d8321768bc9729..9f14c2e86e08c3 100644 --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -2813,48 +2813,29 @@ static struct PyMethodDef _testbuffer_functions[] = { {NULL, NULL} }; -static struct PyModuleDef _testbuffermodule = { - PyModuleDef_HEAD_INIT, - "_testbuffer", - NULL, - -1, - _testbuffer_functions, - NULL, - NULL, - NULL, - NULL -}; - - -PyMODINIT_FUNC -PyInit__testbuffer(void) +static int +_testbuffer_exec(PyObject *m) { - PyObject *m; - - m = PyModule_Create(&_testbuffermodule); - if (m == NULL) - return NULL; - - Py_SET_TYPE(&NDArray_Type, &PyType_Type); - Py_INCREF(&NDArray_Type); - PyModule_AddObject(m, "ndarray", (PyObject *)&NDArray_Type); + if (PyModule_AddType(m, &NDArray_Type) < 0) { + return -1; + } - Py_SET_TYPE(&StaticArray_Type, &PyType_Type); - Py_INCREF(&StaticArray_Type); - PyModule_AddObject(m, "staticarray", (PyObject *)&StaticArray_Type); + if (PyModule_AddType(m, &StaticArray_Type) < 0) { + return -1; + } structmodule = PyImport_ImportModule("struct"); if (structmodule == NULL) - return NULL; + return -1; Struct = PyObject_GetAttrString(structmodule, "Struct"); calcsize = PyObject_GetAttrString(structmodule, "calcsize"); if (Struct == NULL || calcsize == NULL) - return NULL; + return -1; simple_format = PyUnicode_FromString(simple_fmt); if (simple_format == NULL) - return NULL; + return -1; PyModule_AddIntMacro(m, ND_MAX_NDIM); PyModule_AddIntMacro(m, ND_VAREXPORT); @@ -2887,8 +2868,24 @@ PyInit__testbuffer(void) PyModule_AddIntMacro(m, PyBUF_READ); PyModule_AddIntMacro(m, PyBUF_WRITE); - return m; + return 0; } +static PyModuleDef_Slot _testbuffer_slots[] = { + {Py_mod_exec, _testbuffer_exec}, + {0, NULL} +}; +static struct PyModuleDef _testbuffermodule = { + PyModuleDef_HEAD_INIT, + .m_name = "_testbuffer", + .m_size = 0, + .m_methods = _testbuffer_functions, + .m_slots = _testbuffer_slots +}; +PyMODINIT_FUNC +PyInit__testbuffer(void) +{ + return PyModuleDef_Init(&_testbuffermodule); +} \ No newline at end of file From 3542f6ae3a2599a5cb8b77f45544ce16d01ed9c3 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Tue, 1 Sep 2020 17:24:41 -0500 Subject: [PATCH 2/6] blurb --- .../2020-09-01-17-24-34.bpo-1635741.WTmuDL.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-09-01-17-24-34.bpo-1635741.WTmuDL.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-09-01-17-24-34.bpo-1635741.WTmuDL.rst b/Misc/NEWS.d/next/Core and Builtins/2020-09-01-17-24-34.bpo-1635741.WTmuDL.rst new file mode 100644 index 00000000000000..6b4d29ae118f68 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-09-01-17-24-34.bpo-1635741.WTmuDL.rst @@ -0,0 +1,2 @@ +Port the :mod:`_testbuffer` extension module to multi-phase initialization +(:pep:`489`). From 64d4c620dd05cb9293772077062e0d0c3d52028d Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Tue, 1 Sep 2020 20:42:01 -0500 Subject: [PATCH 3/6] test module state --- Modules/_testbuffer.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c index 9f14c2e86e08c3..e7420215ccccff 100644 --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -9,8 +9,6 @@ /* struct module */ static PyObject *structmodule = NULL; -static PyObject *Struct = NULL; -static PyObject *calcsize = NULL; /* cache simple format string */ static const char *simple_fmt = "B"; @@ -23,6 +21,19 @@ static PyObject *simple_format = NULL; /* NDArray Object */ /**************************************************************************/ +typedef struct { + PyObject *Struct; + PyObject *calcsize; +} _testbuffer_state; + +static inline _testbuffer_state* +_testbuffer_get_state(PyObject *module) +{ + void *state = PyModule_GetState(module); + assert(state != NULL); + return (_testbuffer_state *)state; +} + static PyTypeObject NDArray_Type; #define NDArray_Check(v) Py_IS_TYPE(v, &NDArray_Type) @@ -1279,6 +1290,7 @@ ndarray_push_base(NDArrayObject *nd, PyObject *items, static int ndarray_init(PyObject *self, PyObject *args, PyObject *kwds) { + PyObject *module; NDArrayObject *nd = (NDArrayObject *)self; static char *kwlist[] = { "obj", "shape", "strides", "offset", "format", "flags", "getbuf", NULL @@ -1338,7 +1350,7 @@ ndarray_init(PyObject *self, PyObject *args, PyObject *kwds) } /* Initialize and push the first base buffer onto the linked list. */ - return ndarray_push_base(nd, v, shape, strides, offset, format, flags); + return ndarray_push_base(module, nd, v, shape, strides, offset, format, flags); } /* Push an additional base onto the linked list. */ @@ -2825,13 +2837,17 @@ _testbuffer_exec(PyObject *m) } structmodule = PyImport_ImportModule("struct"); - if (structmodule == NULL) + if (structmodule == NULL) { return -1; + } - Struct = PyObject_GetAttrString(structmodule, "Struct"); - calcsize = PyObject_GetAttrString(structmodule, "calcsize"); - if (Struct == NULL || calcsize == NULL) + _testbuffer_state *st = _testbuffer_get_state(m); + + st->Struct = PyObject_GetAttrString(structmodule, "Struct"); + st->calcsize = PyObject_GetAttrString(structmodule, "calcsize"); + if (st->Struct == NULL || st->calcsize == NULL) { return -1; + } simple_format = PyUnicode_FromString(simple_fmt); if (simple_format == NULL) From a1db5b3437131233e28e2fe77c5d90ca77277933 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Sun, 6 Sep 2020 16:18:20 -0500 Subject: [PATCH 4/6] heap types --- Modules/_testbuffer.c | 517 ++++++++++++++++++++---------------------- 1 file changed, 251 insertions(+), 266 deletions(-) diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c index e7420215ccccff..cb74c12a513207 100644 --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -12,7 +12,6 @@ static PyObject *structmodule = NULL; /* cache simple format string */ static const char *simple_fmt = "B"; -static PyObject *simple_format = NULL; #define SIMPLE_FORMAT(fmt) (fmt == NULL || strcmp(fmt, "B") == 0) #define FIX_FORMAT(fmt) (fmt == NULL ? "B" : fmt) @@ -24,6 +23,9 @@ static PyObject *simple_format = NULL; typedef struct { PyObject *Struct; PyObject *calcsize; + PyTypeObject *ndarray_type; + PyTypeObject *staticarray_type; + PyObject *simple_format; } _testbuffer_state; static inline _testbuffer_state* @@ -34,9 +36,6 @@ _testbuffer_get_state(PyObject *module) return (_testbuffer_state *)state; } -static PyTypeObject NDArray_Type; -#define NDArray_Check(v) Py_IS_TYPE(v, &NDArray_Type) - #define CHECK_LIST_OR_TUPLE(v) \ if (!PyList_Check(v) && !PyTuple_Check(v)) { \ PyErr_SetString(PyExc_TypeError, \ @@ -94,8 +93,6 @@ static PyTypeObject NDArray_Type; /* 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 { struct ndbuf *next; @@ -218,11 +215,10 @@ ndbuf_pop(NDArrayObject *nd) static PyObject * ndarray_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - NDArrayObject *nd; - - nd = PyObject_New(NDArrayObject, &NDArray_Type); - if (nd == NULL) + NDArrayObject *nd = PyObject_New(NDArrayObject, type); + if (nd == NULL) { return NULL; + } nd->flags = 0; nd->head = NULL; @@ -309,43 +305,40 @@ get_nmemb(PyObject *s) in struct module syntax. For standard C types, a single item is an integer. For compound types, a single item is a tuple of integers. */ static int -pack_from_list(PyObject *obj, PyObject *items, PyObject *format, - Py_ssize_t itemsize) -{ - PyObject *structobj, *pack_into; - PyObject *args, *offset; - PyObject *item, *tmp; - Py_ssize_t nitems; /* number of items */ - Py_ssize_t nmemb; /* number of members in a single item */ - Py_ssize_t i, j; +pack_from_list(_testbuffer_state *state, PyObject *obj, PyObject *items, + PyObject *format, Py_ssize_t itemsize) +{ int ret = 0; assert(PyObject_CheckBuffer(obj)); assert(PyList_Check(items) || PyTuple_Check(items)); - structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL); - if (structobj == NULL) + PyObject *structobj; + structobj = PyObject_CallFunctionObjArgs(state->Struct, format, NULL); + if (structobj == NULL) { return -1; + } - nitems = PySequence_Fast_GET_SIZE(items); - nmemb = get_nmemb(structobj); + Py_ssize_t nitems = PySequence_Fast_GET_SIZE(items); // number of items + Py_ssize_t nmemb = get_nmemb(structobj); // number of members in a single item assert(nmemb >= 1); - pack_into = PyObject_GetAttrString(structobj, "pack_into"); + PyObject * pack_into = PyObject_GetAttrString(structobj, "pack_into"); if (pack_into == NULL) { Py_DECREF(structobj); return -1; } /* nmemb >= 1 */ - args = PyTuple_New(2 + nmemb); + PyObject *args = PyTuple_New(2 + nmemb); if (args == NULL) { Py_DECREF(pack_into); Py_DECREF(structobj); return -1; } - offset = NULL; + PyObject *offset = NULL; + Py_ssize_t i, j; for (i = 0; i < nitems; i++) { /* Loop invariant: args[j] are borrowed references or NULL. */ PyTuple_SET_ITEM(args, 0, obj); @@ -360,7 +353,7 @@ pack_from_list(PyObject *obj, PyObject *items, PyObject *format, } PyTuple_SET_ITEM(args, 1, offset); - item = PySequence_Fast_GET_ITEM(items, i); + PyObject *item = PySequence_Fast_GET_ITEM(items, i); if ((PyBytes_Check(item) || PyLong_Check(item) || PyFloat_Check(item)) && nmemb == 1) { PyTuple_SET_ITEM(args, 2, item); @@ -368,7 +361,7 @@ pack_from_list(PyObject *obj, PyObject *items, PyObject *format, else if ((PyList_Check(item) || PyTuple_Check(item)) && PySequence_Length(item) == nmemb) { for (j = 0; j < nmemb; j++) { - tmp = PySequence_Fast_GET_ITEM(item, j); + PyObject *tmp = PySequence_Fast_GET_ITEM(item, j); PyTuple_SET_ITEM(args, 2+j, tmp); } } @@ -379,7 +372,7 @@ pack_from_list(PyObject *obj, PyObject *items, PyObject *format, break; } - tmp = PyObject_CallObject(pack_into, args); + PyObject *tmp = PyObject_CallObject(pack_into, args); if (tmp == NULL) { ret = -1; break; @@ -390,7 +383,7 @@ pack_from_list(PyObject *obj, PyObject *items, PyObject *format, Py_INCREF(obj); /* args[0] */ /* args[1]: offset is either NULL or should be dealloc'd */ for (i = 2; i < 2+nmemb; i++) { - tmp = PyTuple_GET_ITEM(args, i); + PyObject *tmp = PyTuple_GET_ITEM(args, i); Py_XINCREF(tmp); } Py_DECREF(args); @@ -403,42 +396,46 @@ pack_from_list(PyObject *obj, PyObject *items, PyObject *format, /* Pack single element */ static int -pack_single(char *ptr, PyObject *item, const char *fmt, Py_ssize_t itemsize) +pack_single(_testbuffer_state *state, char *ptr, PyObject *item, const char *fmt, + Py_ssize_t itemsize) { + if (fmt == NULL) fmt = "B"; + PyObject *structobj = NULL, *pack_into = NULL, *args = NULL; PyObject *format = NULL, *mview = NULL, *zero = NULL; - Py_ssize_t i, nmemb; - int ret = -1; - PyObject *x; - - if (fmt == NULL) fmt = "B"; format = PyUnicode_FromString(fmt); - if (format == NULL) + if (format == NULL) { goto out; + } - structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL); - if (structobj == NULL) + structobj = PyObject_CallFunctionObjArgs(state->Struct, format, NULL); + if (structobj == NULL) { goto out; + } - nmemb = get_nmemb(structobj); + Py_ssize_t nmemb = get_nmemb(structobj); assert(nmemb >= 1); mview = PyMemoryView_FromMemory(ptr, itemsize, PyBUF_WRITE); - if (mview == NULL) + if (mview == NULL) { goto out; + } zero = PyLong_FromLong(0); - if (zero == NULL) + if (zero == NULL) { goto out; + } pack_into = PyObject_GetAttrString(structobj, "pack_into"); - if (pack_into == NULL) + if (pack_into == NULL) { goto out; + } args = PyTuple_New(2+nmemb); - if (args == NULL) + if (args == NULL) { goto out; + } PyTuple_SET_ITEM(args, 0, mview); PyTuple_SET_ITEM(args, 1, zero); @@ -449,8 +446,9 @@ pack_single(char *ptr, PyObject *item, const char *fmt, Py_ssize_t itemsize) } else if ((PyList_Check(item) || PyTuple_Check(item)) && PySequence_Length(item) == nmemb) { + Py_ssize_t i; for (i = 0; i < nmemb; i++) { - x = PySequence_Fast_GET_ITEM(item, i); + PyObject *x = PySequence_Fast_GET_ITEM(item, i); PyTuple_SET_ITEM(args, 2+i, x); } } @@ -460,7 +458,8 @@ pack_single(char *ptr, PyObject *item, const char *fmt, Py_ssize_t itemsize) goto args_out; } - x = PyObject_CallObject(pack_into, args); + int ret = -1; + PyObject *x = PyObject_CallObject(pack_into, args); if (x != NULL) { Py_DECREF(x); ret = 0; @@ -468,6 +467,7 @@ pack_single(char *ptr, PyObject *item, const char *fmt, Py_ssize_t itemsize) args_out: + Py_ssize_t i; for (i = 0; i < 2+nmemb; i++) Py_XINCREF(PyTuple_GET_ITEM(args, i)); Py_XDECREF(args); @@ -668,19 +668,21 @@ unpack_rec(PyObject *unpack_from, char *ptr, PyObject *mview, char *item, static PyObject * ndarray_as_list(NDArrayObject *nd) { + _testbuffer_state *state = PyType_GetModuleState(Py_TYPE(nd)); + if (state == NULL) { + return NULL; + } + PyObject *structobj = NULL, *unpack_from = NULL; PyObject *lst = NULL, *mview = NULL; + Py_buffer *base = &nd->head->base; Py_ssize_t *shape = base->shape; Py_ssize_t *strides = base->strides; Py_ssize_t simple_shape[1]; Py_ssize_t simple_strides[1]; - char *item = NULL; - PyObject *format; char *fmt = base->format; - base = &nd->head->base; - if (fmt == NULL) { PyErr_SetString(PyExc_ValueError, "ndarray: tolist() does not support format=NULL, use " @@ -699,32 +701,37 @@ ndarray_as_list(NDArrayObject *nd) else if (strides == NULL) { assert(ND_C_CONTIGUOUS(nd->head->flags)); strides = strides_from_shape(nd->head, 0); - if (strides == NULL) + if (strides == NULL) { return NULL; + } } - format = PyUnicode_FromString(fmt); - if (format == NULL) + PyObject *format = PyUnicode_FromString(fmt); + if (format == NULL) { goto out; + } - structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL); + structobj = PyObject_CallFunctionObjArgs(state->Struct, format, NULL); Py_DECREF(format); - if (structobj == NULL) + if (structobj == NULL) { goto out; + } unpack_from = PyObject_GetAttrString(structobj, "unpack_from"); - if (unpack_from == NULL) + if (unpack_from == NULL) { goto out; + } - item = PyMem_Malloc(base->itemsize); + char *item = PyMem_Malloc(base->itemsize); if (item == NULL) { PyErr_NoMemory(); goto out; } mview = PyMemoryView_FromMemory(item, base->itemsize, PyBUF_WRITE); - if (mview == NULL) + if (mview == NULL) { goto out; + } lst = unpack_rec(unpack_from, base->buf, mview, item, shape, strides, base->suboffsets, @@ -794,12 +801,12 @@ ndarray_as_list(NDArrayObject *nd) */ static Py_ssize_t -get_itemsize(PyObject *format) +get_itemsize(_testbuffer_state *state, PyObject *format) { PyObject *tmp; Py_ssize_t itemsize; - tmp = PyObject_CallFunctionObjArgs(calcsize, format, NULL); + tmp = PyObject_CallFunctionObjArgs(state->calcsize, format, NULL); if (tmp == NULL) return -1; itemsize = PyLong_AsSsize_t(tmp); @@ -830,27 +837,28 @@ get_format(PyObject *format) } static int -init_simple(ndbuf_t *ndbuf, PyObject *items, PyObject *format, - Py_ssize_t itemsize) +init_simple(_testbuffer_state *state, ndbuf_t *ndbuf, PyObject *items, + PyObject *format, Py_ssize_t itemsize) { - PyObject *mview; Py_buffer *base = &ndbuf->base; - int ret; - mview = PyMemoryView_FromBuffer(base); - if (mview == NULL) + PyObject *mview = PyMemoryView_FromBuffer(base); + if (mview == NULL) { return -1; + } - ret = pack_from_list(mview, items, format, itemsize); + int ret = pack_from_list(state, mview, items, format, itemsize); Py_DECREF(mview); - if (ret < 0) + if (ret < 0) { return -1; + } base->readonly = !(ndbuf->flags & ND_WRITABLE); base->itemsize = itemsize; base->format = get_format(format); - if (base->format == NULL) + if (base->format == NULL) { return -1; + } return 0; } @@ -1185,8 +1193,8 @@ init_structure(ndbuf_t *ndbuf, PyObject *shape, PyObject *strides, } static ndbuf_t * -init_ndbuf(PyObject *items, PyObject *shape, PyObject *strides, - Py_ssize_t offset, PyObject *format, int flags) +init_ndbuf(_testbuffer_state *state, PyObject *items, PyObject *shape, + PyObject *strides, Py_ssize_t offset, PyObject *format, int flags) { ndbuf_t *ndbuf; Py_ssize_t ndim; @@ -1220,7 +1228,7 @@ init_ndbuf(PyObject *items, PyObject *shape, PyObject *strides, } /* itemsize */ - itemsize = get_itemsize(format); + itemsize = get_itemsize(state, format); if (itemsize <= 0) { if (itemsize == 0) { PyErr_SetString(PyExc_ValueError, @@ -1256,7 +1264,7 @@ init_ndbuf(PyObject *items, PyObject *shape, PyObject *strides, } - if (init_simple(ndbuf, items, format, itemsize) < 0) + if (init_simple(state, ndbuf, items, format, itemsize) < 0) goto error; if (init_structure(ndbuf, shape, strides, ndim) < 0) goto error; @@ -1276,11 +1284,16 @@ ndarray_push_base(NDArrayObject *nd, PyObject *items, PyObject *shape, PyObject *strides, Py_ssize_t offset, PyObject *format, int flags) { - ndbuf_t *ndbuf; + _testbuffer_state *state = PyType_GetModuleState(Py_TYPE(nd)); + if (state == NULL) { + return -1; + } - ndbuf = init_ndbuf(items, shape, strides, offset, format, flags); - if (ndbuf == NULL) + ndbuf_t *ndbuf; + ndbuf = init_ndbuf(state, items, shape, strides, offset, format, flags); + if (ndbuf == NULL) { return -1; + } ndbuf_push(nd, ndbuf); return 0; @@ -1290,7 +1303,11 @@ ndarray_push_base(NDArrayObject *nd, PyObject *items, static int ndarray_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *module; + _testbuffer_state *state = PyType_GetModuleState(Py_TYPE(self)); + if (state == NULL) { + return -1; + } + NDArrayObject *nd = (NDArrayObject *)self; static char *kwlist[] = { "obj", "shape", "strides", "offset", "format", "flags", "getbuf", NULL @@ -1299,7 +1316,7 @@ ndarray_init(PyObject *self, PyObject *args, PyObject *kwds) 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 = state->simple_format; /* struct module specifier: "B" */ int flags = ND_DEFAULT; /* base buffer and ndarray flags */ int getbuf = PyBUF_UNUSED; /* re-exporter: getbuffer request flags */ @@ -1311,7 +1328,7 @@ ndarray_init(PyObject *self, PyObject *args, PyObject *kwds) /* NDArrayObject is re-exporter */ if (PyObject_CheckBuffer(v) && shape == NULL) { - if (strides || offset || format != simple_format || + if (strides || offset || format != state->simple_format || !(flags == ND_DEFAULT || flags == ND_REDIRECT)) { PyErr_SetString(PyExc_TypeError, "construction from exporter object only takes 'obj', 'getbuf' " @@ -1350,13 +1367,18 @@ ndarray_init(PyObject *self, PyObject *args, PyObject *kwds) } /* Initialize and push the first base buffer onto the linked list. */ - return ndarray_push_base(module, nd, v, shape, strides, offset, format, flags); + return ndarray_push_base(nd, v, shape, strides, offset, format, flags); } /* Push an additional base onto the linked list. */ static PyObject * ndarray_push(PyObject *self, PyObject *args, PyObject *kwds) { + _testbuffer_state *state = PyType_GetModuleState(Py_TYPE(self)); + if (state == NULL) { + return NULL; + } + NDArrayObject *nd = (NDArrayObject *)self; static char *kwlist[] = { "items", "shape", "strides", "offset", "format", "flags", NULL @@ -1364,7 +1386,7 @@ ndarray_push(PyObject *self, PyObject *args, PyObject *kwds) 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 = state->simple_format; /* struct module specifier: "B" */ Py_ssize_t offset = 0; /* buffer offset */ int flags = ND_DEFAULT; /* base buffer flags */ @@ -1553,12 +1575,6 @@ ndarray_releasebuf(NDArrayObject *self, Py_buffer *view) } } -static PyBufferProcs ndarray_as_buffer = { - (getbufferproc)ndarray_getbuf, /* bf_getbuffer */ - (releasebufferproc)ndarray_releasebuf /* bf_releasebuffer */ -}; - - /**************************************************************************/ /* indexing/slicing */ /**************************************************************************/ @@ -1601,14 +1617,13 @@ ndarray_item(NDArrayObject *self, Py_ssize_t index) { ndbuf_t *ndbuf = self->head; Py_buffer *base = &ndbuf->base; - char *ptr; if (base->ndim == 0) { PyErr_SetString(PyExc_TypeError, "invalid indexing of scalar"); return NULL; } - ptr = ptr_from_index(base, index); + char *ptr = ptr_from_index(base, index); if (ptr == NULL) return NULL; @@ -1617,18 +1632,23 @@ ndarray_item(NDArrayObject *self, Py_ssize_t index) } else { NDArrayObject *nd; - Py_buffer *subview; - nd = (NDArrayObject *)ndarray_new(&NDArray_Type, NULL, NULL); - if (nd == NULL) + _testbuffer_state *state = PyType_GetModuleState(Py_TYPE(self)); + if (state == NULL) { return NULL; + } + + nd = (NDArrayObject *)ndarray_new(state->ndarray_type, NULL, NULL); + if (nd == NULL) { + return NULL; + } if (ndarray_init_staticbuf((PyObject *)self, nd, PyBUF_FULL_RO) < 0) { Py_DECREF(nd); return NULL; } - subview = &nd->staticbuf.base; + Py_buffer *subview = &nd->staticbuf.base; subview->buf = ptr; subview->len /= subview->shape[0]; @@ -1791,8 +1811,11 @@ copy_structure(Py_buffer *base) static PyObject * ndarray_subscript(NDArrayObject *self, PyObject *key) { - NDArrayObject *nd; - ndbuf_t *ndbuf; + _testbuffer_state *state = PyType_GetModuleState(Py_TYPE(self)); + if (state == NULL) { + return NULL; + } + Py_buffer *base = &self->head->base; if (base->ndim == 0) { @@ -1815,9 +1838,11 @@ ndarray_subscript(NDArrayObject *self, PyObject *key) return ndarray_item(self, index); } - nd = (NDArrayObject *)ndarray_new(&NDArray_Type, NULL, NULL); - if (nd == NULL) + NDArrayObject *nd; + nd = (NDArrayObject *)ndarray_new(state->ndarray_type, NULL, NULL); + if (nd == NULL) { return NULL; + } /* new ndarray is a consumer */ if (ndarray_init_staticbuf((PyObject *)self, nd, PyBUF_FULL_RO) < 0) { @@ -1826,7 +1851,7 @@ ndarray_subscript(NDArrayObject *self, PyObject *key) } /* copy shape, strides and suboffsets */ - ndbuf = nd->head; + ndbuf_t *ndbuf = nd->head; base = &ndbuf->base; if (copy_structure(base) < 0) { Py_DECREF(nd); @@ -1876,13 +1901,12 @@ ndarray_subscript(NDArrayObject *self, PyObject *key) static int ndarray_ass_subscript(NDArrayObject *self, PyObject *key, PyObject *value) { - NDArrayObject *nd; - Py_buffer *dest = &self->head->base; - Py_buffer src; - char *ptr; - Py_ssize_t index; - int ret = -1; + _testbuffer_state *state = PyType_GetModuleState(Py_TYPE(self)); + if (state == NULL) { + return -1; + } + Py_buffer *dest = &self->head->base; if (dest->readonly) { PyErr_SetString(PyExc_TypeError, "ndarray is not writable"); return -1; @@ -1891,11 +1915,13 @@ ndarray_ass_subscript(NDArrayObject *self, PyObject *key, PyObject *value) PyErr_SetString(PyExc_TypeError, "ndarray data cannot be deleted"); return -1; } + + char *ptr; if (dest->ndim == 0) { if (key == Py_Ellipsis || (PyTuple_Check(key) && PyTuple_GET_SIZE(key) == 0)) { ptr = (char *)dest->buf; - return pack_single(ptr, value, dest->format, dest->itemsize); + return pack_single(state, ptr, value, dest->format, dest->itemsize); } else { PyErr_SetString(PyExc_TypeError, "invalid indexing of scalar"); @@ -1904,7 +1930,7 @@ ndarray_ass_subscript(NDArrayObject *self, PyObject *key, PyObject *value) } if (dest->ndim == 1 && PyIndex_Check(key)) { /* rvalue must be a single item */ - index = PyLong_AsSsize_t(key); + Py_ssize_t index = PyLong_AsSsize_t(key); if (index == -1 && PyErr_Occurred()) return -1; else { @@ -1912,14 +1938,16 @@ ndarray_ass_subscript(NDArrayObject *self, PyObject *key, PyObject *value) if (ptr == NULL) return -1; } - return pack_single(ptr, value, dest->format, dest->itemsize); + return pack_single(state, ptr, value, dest->format, dest->itemsize); } /* rvalue must be an exporter */ + Py_buffer src; if (PyObject_GetBuffer(value, &src, PyBUF_FULL_RO) == -1) return -1; - nd = (NDArrayObject *)ndarray_subscript(self, key); + int ret = -1; + NDArrayObject *nd = (NDArrayObject *)ndarray_subscript(self, key); if (nd != NULL) { dest = &nd->head->base; ret = copy_buffer(dest, &src); @@ -1968,21 +1996,6 @@ slice_indices(PyObject *self, PyObject *args) 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 */ /**************************************************************************/ @@ -2243,21 +2256,22 @@ static char *infobuf = NULL; static PyObject * ndarray_memoryview_from_buffer(PyObject *self, PyObject *dummy) { + _testbuffer_state *state = PyType_GetModuleState(Py_TYPE(self)); + if (state == NULL) { + return NULL; + } + const NDArrayObject *nd = (NDArrayObject *)self; const Py_buffer *view = &nd->head->base; const ndbuf_t *ndbuf; - static char format[ND_MAX_NDIM+1]; - static Py_ssize_t shape[ND_MAX_NDIM]; - static Py_ssize_t strides[ND_MAX_NDIM]; - static Py_ssize_t suboffsets[ND_MAX_NDIM]; - static Py_buffer info; - char *p; - - if (!ND_IS_CONSUMER(nd)) + + if (!ND_IS_CONSUMER(nd)) { ndbuf = nd->head; /* self is ndarray/original exporter */ - else if (NDArray_Check(view->obj) && !ND_IS_CONSUMER(view->obj)) + } + else if (Py_IS_TYPE(view->obj, state->ndarray_type) && !ND_IS_CONSUMER(view->obj)) { /* self is ndarray and consumer from ndarray/original exporter */ ndbuf = ((NDArrayObject *)view->obj)->head; + } else { PyErr_SetString(PyExc_TypeError, "memoryview_from_buffer(): ndarray must be original exporter or " @@ -2265,8 +2279,8 @@ ndarray_memoryview_from_buffer(PyObject *self, PyObject *dummy) return NULL; } - info = *view; - p = PyMem_Realloc(infobuf, ndbuf->len); + Py_buffer info = *view; + char *p = PyMem_Realloc(infobuf, ndbuf->len); if (p == NULL) { PyMem_Free(infobuf); PyErr_NoMemory(); @@ -2281,6 +2295,7 @@ ndarray_memoryview_from_buffer(PyObject *self, PyObject *dummy) info.buf = infobuf + ((char *)view->buf - ndbuf->data); if (view->format) { + static char format[ND_MAX_NDIM+1]; if (strlen(view->format) > ND_MAX_NDIM) { PyErr_Format(PyExc_TypeError, "memoryview_from_buffer: format is limited to %d characters", @@ -2295,15 +2310,21 @@ ndarray_memoryview_from_buffer(PyObject *self, PyObject *dummy) "memoryview_from_buffer: ndim is limited to %d", ND_MAX_NDIM); return NULL; } + if (view->shape) { + static Py_ssize_t shape[ND_MAX_NDIM]; memcpy(shape, view->shape, view->ndim * sizeof(Py_ssize_t)); info.shape = shape; } + if (view->strides) { + static Py_ssize_t strides[ND_MAX_NDIM]; memcpy(strides, view->strides, view->ndim * sizeof(Py_ssize_t)); info.strides = strides; } + if (view->suboffsets) { + static Py_ssize_t suboffsets[ND_MAX_NDIM]; memcpy(suboffsets, view->suboffsets, view->ndim * sizeof(Py_ssize_t)); info.suboffsets = suboffsets; } @@ -2580,25 +2601,29 @@ is_contiguous(PyObject *self, PyObject *args) { PyObject *obj; PyObject *order; - PyObject *ret = NULL; - Py_buffer view, *base; - char ord; if (!PyArg_ParseTuple(args, "OO", &obj, &order)) { return NULL; } - ord = get_ascii_order(order); + char ord = get_ascii_order(order); if (ord == CHAR_MAX) { return NULL; } - if (NDArray_Check(obj)) { + _testbuffer_state *state = _testbuffer_get_state(self); + if (state == NULL) { + return NULL; + } + + PyObject *ret = NULL; + if (Py_IS_TYPE(obj, state->ndarray_type)) { /* Skip the buffer protocol to check simple etc. buffers directly. */ - base = &((NDArrayObject *)obj)->head->base; + Py_buffer *base = &((NDArrayObject *)obj)->head->base; ret = PyBuffer_IsContiguous(base, ord) ? Py_True : Py_False; } else { + Py_buffer view; if (PyObject_GetBuffer(obj, &view, PyBUF_FULL_RO) < 0) { PyErr_SetString(PyExc_TypeError, "is_contiguous: object does not implement the buffer " @@ -2652,53 +2677,33 @@ static PyMethodDef ndarray_methods [] = {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_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 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 _testbuffer_ndarray_type_slots[] = { + {Py_tp_dealloc, ndarray_dealloc}, + {Py_tp_hash, 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}, + {Py_sq_item, ndarray_item}, + {Py_mp_subscript, ndarray_subscript}, + {Py_mp_ass_subscript, ndarray_ass_subscript}, + {Py_bf_getbuffer, ndarray_getbuf}, + {Py_bf_releasebuffer, ndarray_releasebuf}, + {0,0} +}; + +static PyType_Spec ndarray_type_spec = { + .name = "ndarray", + .basicsize = sizeof(NDArrayObject), + .flags = Py_TPFLAGS_DEFAULT, + .slots = _testbuffer_ndarray_type_slots }; /**************************************************************************/ /* StaticArray Object */ /**************************************************************************/ -static PyTypeObject StaticArray_Type; - typedef struct { PyObject_HEAD int legacy_mode; /* if true, use the view.obj==NULL hack */ @@ -2724,7 +2729,7 @@ static Py_buffer static_buffer = { static PyObject * staticarray_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - return (PyObject *)PyObject_New(StaticArrayObject, &StaticArray_Type); + return (PyObject *)PyObject_New(StaticArrayObject, type); } static int @@ -2767,52 +2772,20 @@ staticarray_getbuf(StaticArrayObject *self, Py_buffer *view, int flags) return 0; } -static PyBufferProcs staticarray_as_buffer = { - (getbufferproc)staticarray_getbuf, /* bf_getbuffer */ - 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_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 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 _testbuffer_staticarray_type_slots[] = { + {Py_tp_dealloc, staticarray_dealloc}, + {Py_tp_init, staticarray_init}, + {Py_tp_new, staticarray_new}, + {Py_bf_getbuffer, staticarray_getbuf}, + {0,0} }; +static PyType_Spec staticarray_type_spec = { + .name = "staticarray", + .basicsize = sizeof(StaticArrayObject), + .flags = Py_TPFLAGS_DEFAULT, + .slots = _testbuffer_staticarray_type_slots + }; static struct PyMethodDef _testbuffer_functions[] = { {"slice_indices", slice_indices, METH_VARARGS, NULL}, @@ -2826,13 +2799,19 @@ static struct PyMethodDef _testbuffer_functions[] = { }; static int -_testbuffer_exec(PyObject *m) +_testbuffer_exec(PyObject *mod) { - if (PyModule_AddType(m, &NDArray_Type) < 0) { + _testbuffer_state *state = _testbuffer_get_state(mod); + + state->ndarray_type = (PyTypeObject *)PyType_FromModuleAndSpec( + mod, &ndarray_type_spec, NULL); + if (PyModule_AddType(mod, state->ndarray_type) < 0) { return -1; } - if (PyModule_AddType(m, &StaticArray_Type) < 0) { + state->staticarray_type = (PyTypeObject *)PyType_FromModuleAndSpec( + mod, &staticarray_type_spec, NULL); + if (PyModule_AddType(mod, state->staticarray_type) < 0) { return -1; } @@ -2841,48 +2820,54 @@ _testbuffer_exec(PyObject *m) return -1; } - _testbuffer_state *st = _testbuffer_get_state(m); - - st->Struct = PyObject_GetAttrString(structmodule, "Struct"); - st->calcsize = PyObject_GetAttrString(structmodule, "calcsize"); - if (st->Struct == NULL || st->calcsize == NULL) { + state->Struct = PyObject_GetAttrString(structmodule, "Struct"); + state->calcsize = PyObject_GetAttrString(structmodule, "calcsize"); + if (state->Struct == NULL || state->calcsize == NULL) { return -1; } - simple_format = PyUnicode_FromString(simple_fmt); - if (simple_format == NULL) + state->simple_format = PyUnicode_FromString(simple_fmt); + if (state->simple_format == NULL) { return -1; + } - PyModule_AddIntMacro(m, ND_MAX_NDIM); - PyModule_AddIntMacro(m, ND_VAREXPORT); - PyModule_AddIntMacro(m, ND_WRITABLE); - PyModule_AddIntMacro(m, ND_FORTRAN); - PyModule_AddIntMacro(m, ND_SCALAR); - PyModule_AddIntMacro(m, ND_PIL); - PyModule_AddIntMacro(m, ND_GETBUF_FAIL); - PyModule_AddIntMacro(m, ND_GETBUF_UNDEFINED); - PyModule_AddIntMacro(m, ND_REDIRECT); - - PyModule_AddIntMacro(m, PyBUF_SIMPLE); - PyModule_AddIntMacro(m, PyBUF_WRITABLE); - PyModule_AddIntMacro(m, PyBUF_FORMAT); - PyModule_AddIntMacro(m, PyBUF_ND); - PyModule_AddIntMacro(m, PyBUF_STRIDES); - PyModule_AddIntMacro(m, PyBUF_INDIRECT); - PyModule_AddIntMacro(m, PyBUF_C_CONTIGUOUS); - PyModule_AddIntMacro(m, PyBUF_F_CONTIGUOUS); - PyModule_AddIntMacro(m, PyBUF_ANY_CONTIGUOUS); - PyModule_AddIntMacro(m, PyBUF_FULL); - PyModule_AddIntMacro(m, PyBUF_FULL_RO); - PyModule_AddIntMacro(m, PyBUF_RECORDS); - PyModule_AddIntMacro(m, PyBUF_RECORDS_RO); - PyModule_AddIntMacro(m, PyBUF_STRIDED); - PyModule_AddIntMacro(m, PyBUF_STRIDED_RO); - PyModule_AddIntMacro(m, PyBUF_CONTIG); - PyModule_AddIntMacro(m, PyBUF_CONTIG_RO); - - PyModule_AddIntMacro(m, PyBUF_READ); - PyModule_AddIntMacro(m, PyBUF_WRITE); +#define TESTBUFFER_ADD_INT_MACRO(mod, c) \ + do { \ + if ((PyModule_AddIntConstant(mod, #c, c)) < 0) { \ + return -1; \ + } \ + } while(0) + + TESTBUFFER_ADD_INT_MACRO(mod, ND_MAX_NDIM); + TESTBUFFER_ADD_INT_MACRO(mod, ND_VAREXPORT); + TESTBUFFER_ADD_INT_MACRO(mod, ND_WRITABLE); + TESTBUFFER_ADD_INT_MACRO(mod, ND_FORTRAN); + TESTBUFFER_ADD_INT_MACRO(mod, ND_SCALAR); + TESTBUFFER_ADD_INT_MACRO(mod, ND_PIL); + TESTBUFFER_ADD_INT_MACRO(mod, ND_GETBUF_FAIL); + TESTBUFFER_ADD_INT_MACRO(mod, ND_GETBUF_UNDEFINED); + TESTBUFFER_ADD_INT_MACRO(mod, ND_REDIRECT); + + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_SIMPLE); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_WRITABLE); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_FORMAT); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_ND); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_STRIDES); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_INDIRECT); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_C_CONTIGUOUS); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_F_CONTIGUOUS); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_ANY_CONTIGUOUS); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_FULL); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_FULL_RO); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_RECORDS); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_RECORDS_RO); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_STRIDED); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_STRIDED_RO); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_CONTIG); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_CONTIG_RO); + + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_READ); + TESTBUFFER_ADD_INT_MACRO(mod, PyBUF_WRITE); return 0; } From f269a43b6642ed5e08bb6c8eb1af6399f8255307 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Sun, 6 Sep 2020 18:32:12 -0500 Subject: [PATCH 5/6] really switch to heap types --- Modules/_testbuffer.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c index cb74c12a513207..37368d40b6240f 100644 --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -243,7 +243,9 @@ ndarray_dealloc(NDArrayObject *self) ndbuf_pop(self); } } + PyTypeObject *tp = Py_TYPE(self); PyObject_Del(self); + Py_DECREF(tp); } static int @@ -403,6 +405,7 @@ pack_single(_testbuffer_state *state, char *ptr, PyObject *item, const char *fmt PyObject *structobj = NULL, *pack_into = NULL, *args = NULL; PyObject *format = NULL, *mview = NULL, *zero = NULL; + Py_ssize_t i; format = PyUnicode_FromString(fmt); if (format == NULL) { @@ -446,7 +449,6 @@ pack_single(_testbuffer_state *state, char *ptr, PyObject *item, const char *fmt } else if ((PyList_Check(item) || PyTuple_Check(item)) && PySequence_Length(item) == nmemb) { - Py_ssize_t i; for (i = 0; i < nmemb; i++) { PyObject *x = PySequence_Fast_GET_ITEM(item, i); PyTuple_SET_ITEM(args, 2+i, x); @@ -465,9 +467,7 @@ pack_single(_testbuffer_state *state, char *ptr, PyObject *item, const char *fmt ret = 0; } - args_out: - Py_ssize_t i; for (i = 0; i < 2+nmemb; i++) Py_XINCREF(PyTuple_GET_ITEM(args, i)); Py_XDECREF(args); @@ -2751,7 +2751,9 @@ staticarray_init(PyObject *self, PyObject *args, PyObject *kwds) static void staticarray_dealloc(StaticArrayObject *self) { + PyTypeObject *tp = Py_TYPE(self); PyObject_Del(self); + Py_DECREF(tp); } /* Return a buffer for a PyBUF_FULL_RO request. Flags are not checked, @@ -2798,6 +2800,30 @@ static struct PyMethodDef _testbuffer_functions[] = { {NULL, NULL} }; +static int +_testbuffer_traverse(PyObject *module, visitproc visit, void *arg) +{ + _testbuffer_state *state = _testbuffer_get_state(module); + Py_VISIT(state->ndarray_type); + Py_VISIT(state->staticarray_type); + return 0; +} + +static int +_testbuffer_clear(PyObject *module) +{ + _testbuffer_state *state = _testbuffer_get_state(module); + Py_CLEAR(state->ndarray_type); + Py_CLEAR(state->staticarray_type); + return 0; +} + +static void +_testbuffer_free(void *module) +{ + _testbuffer_clear((PyObject *)module); +} + static int _testbuffer_exec(PyObject *mod) { @@ -2882,7 +2908,10 @@ static struct PyModuleDef _testbuffermodule = { .m_name = "_testbuffer", .m_size = 0, .m_methods = _testbuffer_functions, - .m_slots = _testbuffer_slots + .m_slots = _testbuffer_slots, + .m_traverse = _testbuffer_traverse, + .m_clear = _testbuffer_clear, + .m_free = _testbuffer_free }; PyMODINIT_FUNC From 282a4164348c33148813791e260ee94f0586d74c Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Mon, 7 Sep 2020 08:14:48 -0500 Subject: [PATCH 6/6] fix issue --- Modules/_testbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c index 37368d40b6240f..79a52e6bc3ddec 100644 --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -2906,7 +2906,7 @@ static PyModuleDef_Slot _testbuffer_slots[] = { static struct PyModuleDef _testbuffermodule = { PyModuleDef_HEAD_INIT, .m_name = "_testbuffer", - .m_size = 0, + .m_size = sizeof(_testbuffer_state), .m_methods = _testbuffer_functions, .m_slots = _testbuffer_slots, .m_traverse = _testbuffer_traverse, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy