From 9a4b14c075388ae764141a346fc028bbc99215f5 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 24 Jan 2023 23:34:59 +0100 Subject: [PATCH 01/22] gh-101277: Add repeat type to module state --- Modules/itertoolsmodule.c | 73 +++++++++++++++------------------------ 1 file changed, 27 insertions(+), 46 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index ce8720d0fd9228..e6855e0d61ca78 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -25,6 +25,7 @@ typedef struct { PyTypeObject *pairwise_type; PyTypeObject *permutations_type; PyTypeObject *product_type; + PyTypeObject *repeat_type; PyTypeObject *starmap_type; PyTypeObject *takewhile_type; PyTypeObject *ziplongest_type; @@ -4261,8 +4262,6 @@ typedef struct { Py_ssize_t cnt; } repeatobject; -static PyTypeObject repeat_type; - static PyObject * repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { @@ -4292,14 +4291,17 @@ repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwds) static void repeat_dealloc(repeatobject *ro) { + PyTypeObject *tp = Py_TYPE(ro); PyObject_GC_UnTrack(ro); Py_XDECREF(ro->element); - Py_TYPE(ro)->tp_free(ro); + tp->tp_free(ro); + Py_DECREF(tp); } static int repeat_traverse(repeatobject *ro, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(ro)); Py_VISIT(ro->element); return 0; } @@ -4361,48 +4363,25 @@ PyDoc_STRVAR(repeat_doc, for the specified number of times. If not specified, returns the object\n\ endlessly."); -static PyTypeObject repeat_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "itertools.repeat", /* tp_name */ - sizeof(repeatobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)repeat_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)repeat_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - repeat_doc, /* tp_doc */ - (traverseproc)repeat_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)repeat_next, /* tp_iternext */ - repeat_methods, /* 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 */ - 0, /* tp_init */ - 0, /* tp_alloc */ - repeat_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot repeat_slots[] = { + {Py_tp_dealloc, repeat_dealloc}, + {Py_tp_repr, repeat_repr}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)repeat_doc}, + {Py_tp_traverse, repeat_traverse}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, repeat_next}, + {Py_tp_methods, repeat_methods}, + {Py_tp_new, repeat_new}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec repeat_spec = { + .name = "itertools.repeat", + .basicsize = sizeof(repeatobject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + .slots = repeat_slots, }; @@ -4707,6 +4686,7 @@ itertoolsmodule_traverse(PyObject *mod, visitproc visit, void *arg) Py_VISIT(state->pairwise_type); Py_VISIT(state->permutations_type); Py_VISIT(state->product_type); + Py_VISIT(state->repeat_type); Py_VISIT(state->starmap_type); Py_VISIT(state->takewhile_type); Py_VISIT(state->ziplongest_type); @@ -4730,6 +4710,7 @@ itertoolsmodule_clear(PyObject *mod) Py_CLEAR(state->pairwise_type); Py_CLEAR(state->permutations_type); Py_CLEAR(state->product_type); + Py_CLEAR(state->repeat_type); Py_CLEAR(state->starmap_type); Py_CLEAR(state->takewhile_type); Py_CLEAR(state->ziplongest_type); @@ -4770,6 +4751,7 @@ itertoolsmodule_exec(PyObject *mod) ADD_TYPE(mod, state->pairwise_type, &pairwise_spec); ADD_TYPE(mod, state->permutations_type, &permutations_spec); ADD_TYPE(mod, state->product_type, &product_spec); + ADD_TYPE(mod, state->repeat_type, &repeat_spec); ADD_TYPE(mod, state->starmap_type, &starmap_spec); ADD_TYPE(mod, state->takewhile_type, &takewhile_spec); ADD_TYPE(mod, state->ziplongest_type, &ziplongest_spec); @@ -4778,7 +4760,6 @@ itertoolsmodule_exec(PyObject *mod) &batched_type, &islice_type, &chain_type, - &repeat_type, &tee_type, &teedataobject_type }; From a66b888c4d5fe02cbfaea266ae3cb857be47eaaa Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 24 Jan 2023 23:41:06 +0100 Subject: [PATCH 02/22] gh-101277: Add islice type to module state --- Modules/itertoolsmodule.c | 86 ++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 51 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index e6855e0d61ca78..ca17e3be2f8dcd 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -22,6 +22,7 @@ typedef struct { PyTypeObject *filterfalse_type; PyTypeObject *groupby_type; PyTypeObject *_grouper_type; + PyTypeObject *islice_type; PyTypeObject *pairwise_type; PyTypeObject *permutations_type; PyTypeObject *product_type; @@ -1683,8 +1684,6 @@ typedef struct { Py_ssize_t cnt; } isliceobject; -static PyTypeObject islice_type; - static PyObject * islice_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { @@ -1694,9 +1693,11 @@ islice_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_ssize_t numargs; isliceobject *lz; - if ((type == &islice_type || type->tp_init == islice_type.tp_init) && - !_PyArg_NoKeywords("islice", kwds)) + itertools_state *st = find_state_by_type(type); + if ((type == st->islice_type || type->tp_init == st->islice_type->tp_init) + && !_PyArg_NoKeywords("islice", kwds)) { return NULL; + } if (!PyArg_UnpackTuple(args, "islice", 2, 4, &seq, &a1, &a2, &a3)) return NULL; @@ -1773,14 +1774,17 @@ islice_new(PyTypeObject *type, PyObject *args, PyObject *kwds) static void islice_dealloc(isliceobject *lz) { + PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); Py_XDECREF(lz->it); - Py_TYPE(lz)->tp_free(lz); + tp->tp_free(lz); + Py_DECREF(tp); } static int islice_traverse(isliceobject *lz, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(lz)); Py_VISIT(lz->it); return 0; } @@ -1886,48 +1890,25 @@ specified as another value, step determines how many values are\n\ skipped between successive calls. Works like a slice() on a list\n\ but returns an iterator."); -static PyTypeObject islice_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "itertools.islice", /* tp_name */ - sizeof(isliceobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)islice_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - islice_doc, /* tp_doc */ - (traverseproc)islice_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)islice_next, /* tp_iternext */ - islice_methods, /* 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 */ - 0, /* tp_init */ - 0, /* tp_alloc */ - islice_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot islice_slots[] = { + {Py_tp_dealloc, islice_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)islice_doc}, + {Py_tp_traverse, islice_traverse}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, islice_next}, + {Py_tp_methods, islice_methods}, + {Py_tp_new, islice_new}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec islice_spec = { + .name = "itertools.islice", + .basicsize = sizeof(isliceobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = islice_slots, }; @@ -3693,8 +3674,6 @@ accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored)) if (PyType_Ready(&chain_type) < 0) return NULL; - if (PyType_Ready(&islice_type) < 0) - return NULL; it = PyObject_CallFunction((PyObject *)&chain_type, "(O)O", lz->total, lz->it); if (it == NULL) @@ -3703,7 +3682,10 @@ accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored)) it, lz->binop ? lz->binop : Py_None); if (it == NULL) return NULL; - return Py_BuildValue("O(NiO)", &islice_type, it, 1, Py_None); + + PyTypeObject *tp = Py_TYPE(lz); + itertools_state *state = find_state_by_type(tp); + return Py_BuildValue("O(NiO)", state->islice_type, it, 1, Py_None); } return Py_BuildValue("O(OO)O", Py_TYPE(lz), lz->it, lz->binop?lz->binop:Py_None, @@ -4683,6 +4665,7 @@ itertoolsmodule_traverse(PyObject *mod, visitproc visit, void *arg) Py_VISIT(state->filterfalse_type); Py_VISIT(state->groupby_type); Py_VISIT(state->_grouper_type); + Py_VISIT(state->islice_type); Py_VISIT(state->pairwise_type); Py_VISIT(state->permutations_type); Py_VISIT(state->product_type); @@ -4707,6 +4690,7 @@ itertoolsmodule_clear(PyObject *mod) Py_CLEAR(state->filterfalse_type); Py_CLEAR(state->groupby_type); Py_CLEAR(state->_grouper_type); + Py_CLEAR(state->islice_type); Py_CLEAR(state->pairwise_type); Py_CLEAR(state->permutations_type); Py_CLEAR(state->product_type); @@ -4748,6 +4732,7 @@ itertoolsmodule_exec(PyObject *mod) ADD_TYPE(mod, state->filterfalse_type, &filterfalse_spec); ADD_TYPE(mod, state->groupby_type, &groupby_spec); ADD_TYPE(mod, state->_grouper_type, &_grouper_spec); + ADD_TYPE(mod, state->islice_type, &islice_spec); ADD_TYPE(mod, state->pairwise_type, &pairwise_spec); ADD_TYPE(mod, state->permutations_type, &permutations_spec); ADD_TYPE(mod, state->product_type, &product_spec); @@ -4758,7 +4743,6 @@ itertoolsmodule_exec(PyObject *mod) PyTypeObject *typelist[] = { &batched_type, - &islice_type, &chain_type, &tee_type, &teedataobject_type From d18169b4dc20ab224749278285f3c2b266cb2c7a Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 24 Jan 2023 23:45:42 +0100 Subject: [PATCH 03/22] gh-101277: Add chain type to module state --- Modules/itertoolsmodule.c | 96 ++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 58 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index ca17e3be2f8dcd..35bcd2087afeb8 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -13,6 +13,7 @@ typedef struct { PyTypeObject *accumulate_type; + PyTypeObject *chain_type; PyTypeObject *combinations_type; PyTypeObject *compress_type; PyTypeObject *count_type; @@ -69,7 +70,7 @@ class itertools.cycle "cycleobject *" "clinic_state()->cycle_type" class itertools.dropwhile "dropwhileobject *" "clinic_state()->dropwhile_type" class itertools.takewhile "takewhileobject *" "clinic_state()->takewhile_type" class itertools.starmap "starmapobject *" "clinic_state()->starmap_type" -class itertools.chain "chainobject *" "&chain_type" +class itertools.chain "chainobject *" "clinic_state()->chain_type" class itertools.combinations "combinationsobject *" "clinic_state()->combinations_type" class itertools.combinations_with_replacement "cwr_object *" "clinic_state()->cwr_type" class itertools.permutations "permutationsobject *" "clinic_state()->permutations_type" @@ -79,7 +80,7 @@ class itertools.filterfalse "filterfalseobject *" "clinic_state()->filterfalse_t class itertools.count "countobject *" "clinic_state()->count_type" class itertools.pairwise "pairwiseobject *" "clinic_state()->pairwise_type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=28ffff5c0c93eed7]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=102319065d3e090b]*/ static PyTypeObject teedataobject_type; static PyTypeObject tee_type; @@ -2038,8 +2039,6 @@ typedef struct { PyObject *active; /* Currently running input iterator */ } chainobject; -static PyTypeObject chain_type; - static PyObject * chain_new_internal(PyTypeObject *type, PyObject *source) { @@ -2061,9 +2060,12 @@ chain_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *source; - if ((type == &chain_type || type->tp_init == chain_type.tp_init) && - !_PyArg_NoKeywords("chain", kwds)) + itertools_state *st = find_state_by_type(type); + if ((type == st->chain_type || type->tp_init == st->chain_type->tp_init) + && !_PyArg_NoKeywords("chain", kwds)) + { return NULL; + } source = PyObject_GetIter(args); if (source == NULL) @@ -2096,15 +2098,18 @@ itertools_chain_from_iterable(PyTypeObject *type, PyObject *arg) static void chain_dealloc(chainobject *lz) { + PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); Py_XDECREF(lz->active); Py_XDECREF(lz->source); - Py_TYPE(lz)->tp_free(lz); + tp->tp_free(lz); + Py_DECREF(tp); } static int chain_traverse(chainobject *lz, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(lz)); Py_VISIT(lz->source); Py_VISIT(lz->active); return 0; @@ -2209,48 +2214,24 @@ static PyMethodDef chain_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyTypeObject chain_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "itertools.chain", /* tp_name */ - sizeof(chainobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)chain_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - chain_doc, /* tp_doc */ - (traverseproc)chain_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)chain_next, /* tp_iternext */ - chain_methods, /* 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 */ - 0, /* tp_init */ - 0, /* tp_alloc */ - chain_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot chain_slots[] = { + {Py_tp_dealloc, chain_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)chain_doc}, + {Py_tp_traverse, chain_traverse}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, chain_next}, + {Py_tp_methods, chain_methods}, + {Py_tp_new, chain_new}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec chain_spec = { + .name = "itertools.chain", + .basicsize = sizeof(chainobject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + .slots = chain_slots, }; @@ -3656,13 +3637,14 @@ accumulate_next(accumulateobject *lz) static PyObject * accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored)) { + PyTypeObject *tp = Py_TYPE(lz); + itertools_state *state = find_state_by_type(tp); + if (lz->initial != Py_None) { PyObject *it; assert(lz->total == NULL); - if (PyType_Ready(&chain_type) < 0) - return NULL; - it = PyObject_CallFunction((PyObject *)&chain_type, "(O)O", + it = PyObject_CallFunction((PyObject *)(state->chain_type), "(O)O", lz->initial, lz->it); if (it == NULL) return NULL; @@ -3672,9 +3654,7 @@ accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored)) if (lz->total == Py_None) { PyObject *it; - if (PyType_Ready(&chain_type) < 0) - return NULL; - it = PyObject_CallFunction((PyObject *)&chain_type, "(O)O", + it = PyObject_CallFunction((PyObject *)(state->chain_type), "(O)O", lz->total, lz->it); if (it == NULL) return NULL; @@ -3683,8 +3663,6 @@ accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored)) if (it == NULL) return NULL; - PyTypeObject *tp = Py_TYPE(lz); - itertools_state *state = find_state_by_type(tp); return Py_BuildValue("O(NiO)", state->islice_type, it, 1, Py_None); } return Py_BuildValue("O(OO)O", Py_TYPE(lz), @@ -4656,6 +4634,7 @@ itertoolsmodule_traverse(PyObject *mod, visitproc visit, void *arg) { itertools_state *state = get_module_state(mod); Py_VISIT(state->accumulate_type); + Py_VISIT(state->chain_type); Py_VISIT(state->combinations_type); Py_VISIT(state->compress_type); Py_VISIT(state->count_type); @@ -4681,6 +4660,7 @@ itertoolsmodule_clear(PyObject *mod) { itertools_state *state = get_module_state(mod); Py_CLEAR(state->accumulate_type); + Py_CLEAR(state->chain_type); Py_CLEAR(state->combinations_type); Py_CLEAR(state->compress_type); Py_CLEAR(state->count_type); @@ -4723,6 +4703,7 @@ itertoolsmodule_exec(PyObject *mod) { itertools_state *state = get_module_state(mod); ADD_TYPE(mod, state->accumulate_type, &accumulate_spec); + ADD_TYPE(mod, state->chain_type, &chain_spec); ADD_TYPE(mod, state->combinations_type, &combinations_spec); ADD_TYPE(mod, state->compress_type, &compress_spec); ADD_TYPE(mod, state->count_type, &count_spec); @@ -4743,7 +4724,6 @@ itertoolsmodule_exec(PyObject *mod) PyTypeObject *typelist[] = { &batched_type, - &chain_type, &tee_type, &teedataobject_type }; From e574de10a73bc0954581a10ff25fbb07925b398b Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 24 Jan 2023 23:53:38 +0100 Subject: [PATCH 04/22] gh-101277: Add tee type to module state --- Modules/clinic/itertoolsmodule.c.h | 4 +- Modules/itertoolsmodule.c | 99 ++++++++++++++---------------- 2 files changed, 47 insertions(+), 56 deletions(-) diff --git a/Modules/clinic/itertoolsmodule.c.h b/Modules/clinic/itertoolsmodule.c.h index d15d5f0890ca98..801d736cbb9306 100644 --- a/Modules/clinic/itertoolsmodule.c.h +++ b/Modules/clinic/itertoolsmodule.c.h @@ -270,7 +270,7 @@ static PyObject * itertools__tee(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; - PyTypeObject *base_tp = &tee_type; + PyTypeObject *base_tp = clinic_state()->tee_type; PyObject *iterable; if ((type == base_tp || type->tp_init == base_tp->tp_init) && @@ -913,4 +913,4 @@ itertools_count(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=a08b58d7dac825da input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3fa47c27849bd6e7 input=a9049054013a1b77]*/ diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 35bcd2087afeb8..8d9cff676b4dad 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -5,6 +5,7 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_tuple.h" // _PyTuple_ITEMS() +#include "structmember.h" // PyMemberDef #include // offsetof() /* Itertools module written and maintained @@ -30,6 +31,7 @@ typedef struct { PyTypeObject *repeat_type; PyTypeObject *starmap_type; PyTypeObject *takewhile_type; + PyTypeObject *tee_type; PyTypeObject *ziplongest_type; } itertools_state; @@ -64,7 +66,7 @@ module itertools class itertools.groupby "groupbyobject *" "clinic_state()->groupby_type" class itertools._grouper "_grouperobject *" "clinic_state()->_grouper_type" class itertools.teedataobject "teedataobject *" "&teedataobject_type" -class itertools._tee "teeobject *" "&tee_type" +class itertools._tee "teeobject *" "clinic_state()->tee_type" class itertools.batched "batchedobject *" "&batched_type" class itertools.cycle "cycleobject *" "clinic_state()->cycle_type" class itertools.dropwhile "dropwhileobject *" "clinic_state()->dropwhile_type" @@ -80,10 +82,9 @@ class itertools.filterfalse "filterfalseobject *" "clinic_state()->filterfalse_t class itertools.count "countobject *" "clinic_state()->count_type" class itertools.pairwise "pairwiseobject *" "clinic_state()->pairwise_type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=102319065d3e090b]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2de6179a0523a80d]*/ static PyTypeObject teedataobject_type; -static PyTypeObject tee_type; static PyTypeObject batched_type; #define clinic_state() (find_state_by_type(type)) @@ -984,6 +985,7 @@ tee_next(teeobject *to) static int tee_traverse(teeobject *to, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(to)); Py_VISIT((PyObject *)to->dataobj); return 0; } @@ -991,11 +993,10 @@ tee_traverse(teeobject *to, visitproc visit, void *arg) static PyObject * tee_copy(teeobject *to, PyObject *Py_UNUSED(ignored)) { - teeobject *newto; - - newto = PyObject_GC_New(teeobject, &tee_type); - if (newto == NULL) + teeobject *newto = PyObject_GC_New(teeobject, Py_TYPE(to)); + if (newto == NULL) { return NULL; + } newto->dataobj = (teedataobject*)Py_NewRef(to->dataobj); newto->index = to->index; newto->weakreflist = NULL; @@ -1006,7 +1007,7 @@ tee_copy(teeobject *to, PyObject *Py_UNUSED(ignored)) PyDoc_STRVAR(teecopy_doc, "Returns an independent iterator."); static PyObject * -tee_fromiterable(PyObject *iterable) +tee_fromiterable(itertools_state *state, PyObject *iterable) { teeobject *to; PyObject *it; @@ -1014,7 +1015,7 @@ tee_fromiterable(PyObject *iterable) it = PyObject_GetIter(iterable); if (it == NULL) return NULL; - if (PyObject_TypeCheck(it, &tee_type)) { + if (PyObject_TypeCheck(it, state->tee_type)) { to = (teeobject *)tee_copy((teeobject *)it, NULL); goto done; } @@ -1024,7 +1025,7 @@ tee_fromiterable(PyObject *iterable) to = NULL; goto done; } - to = PyObject_GC_New(teeobject, &tee_type); + to = PyObject_GC_New(teeobject, state->tee_type); if (to == NULL) { Py_DECREF(dataobj); goto done; @@ -1050,7 +1051,8 @@ static PyObject * itertools__tee_impl(PyTypeObject *type, PyObject *iterable) /*[clinic end generated code: output=b02d3fd26c810c3f input=adc0779d2afe37a2]*/ { - return tee_fromiterable(iterable); + itertools_state *state = find_state_by_type(type); + return tee_fromiterable(state, iterable); } static int @@ -1065,9 +1067,11 @@ tee_clear(teeobject *to) static void tee_dealloc(teeobject *to) { + PyTypeObject *tp = Py_TYPE(to); PyObject_GC_UnTrack(to); tee_clear(to); PyObject_GC_Del(to); + Py_DECREF(tp); } static PyObject * @@ -1105,47 +1109,31 @@ static PyMethodDef tee_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyTypeObject tee_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "itertools._tee", /* tp_name */ - sizeof(teeobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)tee_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 */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - itertools__tee__doc__, /* tp_doc */ - (traverseproc)tee_traverse, /* tp_traverse */ - (inquiry)tee_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(teeobject, weakreflist), /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)tee_next, /* tp_iternext */ - tee_methods, /* 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 */ - 0, /* tp_init */ - 0, /* tp_alloc */ - itertools__tee, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyMemberDef tee_members[] = { + {"__weaklistoffset__", T_PYSSIZET, offsetof(teeobject, weakreflist), READONLY}, + {NULL}, +}; + +static PyType_Slot tee_slots[] = { + {Py_tp_dealloc, tee_dealloc}, + {Py_tp_doc, (void *)itertools__tee__doc__}, + {Py_tp_traverse, tee_traverse}, + {Py_tp_clear, tee_clear}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, tee_next}, + {Py_tp_methods, tee_methods}, + {Py_tp_members, tee_members}, + {Py_tp_new, itertools__tee}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec tee_spec = { + .name = "itertools._tee", + .basicsize = sizeof(teeobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = tee_slots, }; /*[clinic input] @@ -1187,7 +1175,8 @@ itertools_tee_impl(PyObject *module, PyObject *iterable, Py_ssize_t n) copyable = it; } else { - copyable = tee_fromiterable(it); + itertools_state *state = get_module_state(module); + copyable = tee_fromiterable(state, it); Py_DECREF(it); if (copyable == NULL) { Py_DECREF(result); @@ -4651,6 +4640,7 @@ itertoolsmodule_traverse(PyObject *mod, visitproc visit, void *arg) Py_VISIT(state->repeat_type); Py_VISIT(state->starmap_type); Py_VISIT(state->takewhile_type); + Py_VISIT(state->tee_type); Py_VISIT(state->ziplongest_type); return 0; } @@ -4677,6 +4667,7 @@ itertoolsmodule_clear(PyObject *mod) Py_CLEAR(state->repeat_type); Py_CLEAR(state->starmap_type); Py_CLEAR(state->takewhile_type); + Py_CLEAR(state->tee_type); Py_CLEAR(state->ziplongest_type); return 0; } @@ -4720,11 +4711,11 @@ itertoolsmodule_exec(PyObject *mod) ADD_TYPE(mod, state->repeat_type, &repeat_spec); ADD_TYPE(mod, state->starmap_type, &starmap_spec); ADD_TYPE(mod, state->takewhile_type, &takewhile_spec); + ADD_TYPE(mod, state->tee_type, &tee_spec); ADD_TYPE(mod, state->ziplongest_type, &ziplongest_spec); PyTypeObject *typelist[] = { &batched_type, - &tee_type, &teedataobject_type }; From 053b75902db271c99a90e2c46256d9490d67b799 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 25 Jan 2023 00:02:23 +0100 Subject: [PATCH 05/22] gh-101277: Add tee data object type to module state --- Modules/clinic/itertoolsmodule.c.h | 4 +- Modules/itertoolsmodule.c | 109 +++++++++++++---------------- 2 files changed, 50 insertions(+), 63 deletions(-) diff --git a/Modules/clinic/itertoolsmodule.c.h b/Modules/clinic/itertoolsmodule.c.h index 801d736cbb9306..32278bf715aa98 100644 --- a/Modules/clinic/itertoolsmodule.c.h +++ b/Modules/clinic/itertoolsmodule.c.h @@ -232,7 +232,7 @@ static PyObject * itertools_teedataobject(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; - PyTypeObject *base_tp = &teedataobject_type; + PyTypeObject *base_tp = clinic_state()->teedataobject_type; PyObject *it; PyObject *values; PyObject *next; @@ -913,4 +913,4 @@ itertools_count(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=3fa47c27849bd6e7 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=111cbd102c2a23c9 input=a9049054013a1b77]*/ diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 8d9cff676b4dad..130b4ac68346c0 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -32,6 +32,7 @@ typedef struct { PyTypeObject *starmap_type; PyTypeObject *takewhile_type; PyTypeObject *tee_type; + PyTypeObject *teedataobject_type; PyTypeObject *ziplongest_type; } itertools_state; @@ -65,7 +66,7 @@ find_state_by_type(PyTypeObject *tp) module itertools class itertools.groupby "groupbyobject *" "clinic_state()->groupby_type" class itertools._grouper "_grouperobject *" "clinic_state()->_grouper_type" -class itertools.teedataobject "teedataobject *" "&teedataobject_type" +class itertools.teedataobject "teedataobject *" "clinic_state()->teedataobject_type" class itertools._tee "teeobject *" "clinic_state()->tee_type" class itertools.batched "batchedobject *" "&batched_type" class itertools.cycle "cycleobject *" "clinic_state()->cycle_type" @@ -82,9 +83,8 @@ class itertools.filterfalse "filterfalseobject *" "clinic_state()->filterfalse_t class itertools.count "countobject *" "clinic_state()->count_type" class itertools.pairwise "pairwiseobject *" "clinic_state()->pairwise_type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2de6179a0523a80d]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=419423f2d82cf388]*/ -static PyTypeObject teedataobject_type; static PyTypeObject batched_type; #define clinic_state() (find_state_by_type(type)) @@ -744,13 +744,13 @@ typedef struct { } teeobject; static PyObject * -teedataobject_newinternal(PyObject *it) +teedataobject_newinternal(itertools_state *state, PyObject *it) { - teedataobject *tdo; - - tdo = PyObject_GC_New(teedataobject, &teedataobject_type); - if (tdo == NULL) + teedataobject *tdo = PyObject_GC_New(teedataobject, + state->teedataobject_type); + if (tdo == NULL) { return NULL; + } tdo->running = 0; tdo->numread = 0; @@ -763,8 +763,11 @@ teedataobject_newinternal(PyObject *it) static PyObject * teedataobject_jumplink(teedataobject *tdo) { - if (tdo->nextlink == NULL) - tdo->nextlink = teedataobject_newinternal(tdo->it); + if (tdo->nextlink == NULL) { + PyTypeObject *tp = Py_TYPE(tdo); + itertools_state *state = find_state_by_type(tp); + tdo->nextlink = teedataobject_newinternal(state, tdo->it); + } return Py_XNewRef(tdo->nextlink); } @@ -800,6 +803,7 @@ teedataobject_traverse(teedataobject *tdo, visitproc visit, void * arg) { int i; + Py_VISIT(Py_TYPE(tdo)); Py_VISIT(tdo->it); for (i = 0; i < tdo->numread; i++) Py_VISIT(tdo->values[i]); @@ -808,9 +812,9 @@ teedataobject_traverse(teedataobject *tdo, visitproc visit, void * arg) } static void -teedataobject_safe_decref(PyObject *obj) +teedataobject_safe_decref(PyObject *obj, PyTypeObject *tdo_type) { - while (obj && Py_IS_TYPE(obj, &teedataobject_type) && + while (obj && Py_IS_TYPE(obj, tdo_type) && Py_REFCNT(obj) == 1) { PyObject *nextlink = ((teedataobject *)obj)->nextlink; ((teedataobject *)obj)->nextlink = NULL; @@ -830,16 +834,19 @@ teedataobject_clear(teedataobject *tdo) Py_CLEAR(tdo->values[i]); tmp = tdo->nextlink; tdo->nextlink = NULL; - teedataobject_safe_decref(tmp); + itertools_state *state = find_state_by_type(Py_TYPE(tdo)); + teedataobject_safe_decref(tmp, state->teedataobject_type); return 0; } static void teedataobject_dealloc(teedataobject *tdo) { + PyTypeObject *tp = Py_TYPE(tdo); PyObject_GC_UnTrack(tdo); teedataobject_clear(tdo); PyObject_GC_Del(tdo); + Py_DECREF(tp); } static PyObject * @@ -878,9 +885,10 @@ itertools_teedataobject_impl(PyTypeObject *type, PyObject *it, teedataobject *tdo; Py_ssize_t i, len; - assert(type == &teedataobject_type); + itertools_state *state = find_state_by_type(type); + assert(type == state->teedataobject_type); - tdo = (teedataobject *)teedataobject_newinternal(it); + tdo = (teedataobject *)teedataobject_newinternal(state, it); if (!tdo) return NULL; @@ -896,7 +904,7 @@ itertools_teedataobject_impl(PyTypeObject *type, PyObject *it, if (len == LINKCELLS) { if (next != Py_None) { - if (!Py_IS_TYPE(next, &teedataobject_type)) + if (!Py_IS_TYPE(next, state->teedataobject_type)) goto err; assert(tdo->nextlink == NULL); tdo->nextlink = Py_NewRef(next); @@ -919,47 +927,24 @@ static PyMethodDef teedataobject_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyTypeObject teedataobject_type = { - PyVarObject_HEAD_INIT(0, 0) /* Must fill in type value later */ - "itertools._tee_dataobject", /* tp_name */ - sizeof(teedataobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)teedataobject_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - itertools_teedataobject__doc__, /* tp_doc */ - (traverseproc)teedataobject_traverse, /* tp_traverse */ - (inquiry)teedataobject_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - teedataobject_methods, /* 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 */ - 0, /* tp_init */ - 0, /* tp_alloc */ - itertools_teedataobject, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot teedataobject_slots[] = { + {Py_tp_dealloc, teedataobject_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)itertools_teedataobject__doc__}, + {Py_tp_traverse, teedataobject_traverse}, + {Py_tp_clear, teedataobject_clear}, + {Py_tp_methods, teedataobject_methods}, + {Py_tp_new, itertools_teedataobject}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec teedataobject_spec = { + .name = "itertools._tee_dataobject", + .basicsize = sizeof(teedataobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = teedataobject_slots, }; @@ -1020,7 +1005,7 @@ tee_fromiterable(itertools_state *state, PyObject *iterable) goto done; } - PyObject *dataobj = teedataobject_newinternal(it); + PyObject *dataobj = teedataobject_newinternal(state, it); if (!dataobj) { to = NULL; goto done; @@ -1089,7 +1074,9 @@ tee_setstate(teeobject *to, PyObject *state) PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; } - if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index)) { + itertools_state *m_state = find_state_by_type(Py_TYPE(to)); + PyTypeObject *tdo_type = m_state->teedataobject_type; + if (!PyArg_ParseTuple(state, "O!i", tdo_type, &tdo, &index)) { return NULL; } if (index < 0 || index > LINKCELLS) { @@ -4712,14 +4699,14 @@ itertoolsmodule_exec(PyObject *mod) ADD_TYPE(mod, state->starmap_type, &starmap_spec); ADD_TYPE(mod, state->takewhile_type, &takewhile_spec); ADD_TYPE(mod, state->tee_type, &tee_spec); + ADD_TYPE(mod, state->teedataobject_type, &teedataobject_spec); ADD_TYPE(mod, state->ziplongest_type, &ziplongest_spec); PyTypeObject *typelist[] = { &batched_type, - &teedataobject_type }; - Py_SET_TYPE(&teedataobject_type, &PyType_Type); + Py_SET_TYPE(state->teedataobject_type, &PyType_Type); for (size_t i = 0; i < Py_ARRAY_LENGTH(typelist); i++) { if (PyModule_AddType(mod, typelist[i]) < 0) { From 94972ba5daddeed622354566dd451506fe1d0e99 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 25 Jan 2023 00:14:57 +0100 Subject: [PATCH 06/22] Add NEWS --- .../next/Library/2023-01-25-00-14-52.gh-issue-101277.FceHX7.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-01-25-00-14-52.gh-issue-101277.FceHX7.rst diff --git a/Misc/NEWS.d/next/Library/2023-01-25-00-14-52.gh-issue-101277.FceHX7.rst b/Misc/NEWS.d/next/Library/2023-01-25-00-14-52.gh-issue-101277.FceHX7.rst new file mode 100644 index 00000000000000..e09c0e09fb388f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-01-25-00-14-52.gh-issue-101277.FceHX7.rst @@ -0,0 +1,2 @@ +Remove global state from :mod:`itertools` module (:pep:`687`). Patches by +Erlend E. Aasland. From da57b52bdb80cd039184ba48334602e9dfe4be3b Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 25 Jan 2023 00:16:11 +0100 Subject: [PATCH 07/22] Purge globals-to-fix.tsv --- Tools/c-analyzer/cpython/globals-to-fix.tsv | 22 --------------------- 1 file changed, 22 deletions(-) diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index cf2d5c368f1bda..52ea0b4901d4bb 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -335,28 +335,6 @@ Modules/_testcapi/vectorcall.c - MethodDescriptorBase_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorDerived_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorNopGet_Type - Modules/_testcapi/vectorcall.c - MethodDescriptor2_Type - -Modules/itertoolsmodule.c - _grouper_type - -Modules/itertoolsmodule.c - accumulate_type - -Modules/itertoolsmodule.c - batched_type - -Modules/itertoolsmodule.c - chain_type - -Modules/itertoolsmodule.c - combinations_type - -Modules/itertoolsmodule.c - compress_type - -Modules/itertoolsmodule.c - count_type - -Modules/itertoolsmodule.c - cwr_type - -Modules/itertoolsmodule.c - cycle_type - -Modules/itertoolsmodule.c - dropwhile_type - -Modules/itertoolsmodule.c - filterfalse_type - -Modules/itertoolsmodule.c - groupby_type - -Modules/itertoolsmodule.c - islice_type - -Modules/itertoolsmodule.c - pairwise_type - -Modules/itertoolsmodule.c - permutations_type - -Modules/itertoolsmodule.c - product_type - -Modules/itertoolsmodule.c - repeat_type - -Modules/itertoolsmodule.c - starmap_type - -Modules/itertoolsmodule.c - takewhile_type - -Modules/itertoolsmodule.c - tee_type - -Modules/itertoolsmodule.c - teedataobject_type - -Modules/itertoolsmodule.c - ziplongest_type - ################################## From e9379849b6c921c41d8415b6fe2161d6521bc80a Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 25 Jan 2023 00:34:32 +0100 Subject: [PATCH 08/22] Make chain and repeat immutable --- Modules/itertoolsmodule.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 130b4ac68346c0..28756ad5473594 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2206,7 +2206,8 @@ static PyType_Slot chain_slots[] = { static PyType_Spec chain_spec = { .name = "itertools.chain", .basicsize = sizeof(chainobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_IMMUTABLETYPE), .slots = chain_slots, }; @@ -4316,7 +4317,8 @@ static PyType_Slot repeat_slots[] = { static PyType_Spec repeat_spec = { .name = "itertools.repeat", .basicsize = sizeof(repeatobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_IMMUTABLETYPE), .slots = repeat_slots, }; From 4264f8b58ee41d96b982d07d9a00b61a30561071 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 25 Jan 2023 00:49:32 +0100 Subject: [PATCH 09/22] Add batched type to module state --- Modules/itertoolsmodule.c | 91 +++++++++++++-------------------------- 1 file changed, 30 insertions(+), 61 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 28756ad5473594..8f4a80f001d52e 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -14,6 +14,7 @@ typedef struct { PyTypeObject *accumulate_type; + PyTypeObject *batched_type; PyTypeObject *chain_type; PyTypeObject *combinations_type; PyTypeObject *compress_type; @@ -68,7 +69,7 @@ class itertools.groupby "groupbyobject *" "clinic_state()->groupby_type" class itertools._grouper "_grouperobject *" "clinic_state()->_grouper_type" class itertools.teedataobject "teedataobject *" "clinic_state()->teedataobject_type" class itertools._tee "teeobject *" "clinic_state()->tee_type" -class itertools.batched "batchedobject *" "&batched_type" +class itertools.batched "batchedobject *" "clinic_state()->batched_type" class itertools.cycle "cycleobject *" "clinic_state()->cycle_type" class itertools.dropwhile "dropwhileobject *" "clinic_state()->dropwhile_type" class itertools.takewhile "takewhileobject *" "clinic_state()->takewhile_type" @@ -83,9 +84,7 @@ class itertools.filterfalse "filterfalseobject *" "clinic_state()->filterfalse_t class itertools.count "countobject *" "clinic_state()->count_type" class itertools.pairwise "pairwiseobject *" "clinic_state()->pairwise_type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=419423f2d82cf388]*/ - -static PyTypeObject batched_type; +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=aa48fe4de9d4080f]*/ #define clinic_state() (find_state_by_type(type)) #define clinic_state_by_cls() (get_module_state_by_cls(base_tp)) @@ -166,17 +165,18 @@ batched_new_impl(PyTypeObject *type, PyObject *iterable, Py_ssize_t n) static void batched_dealloc(batchedobject *bo) { + PyTypeObject *tp = Py_TYPE(bo); PyObject_GC_UnTrack(bo); Py_XDECREF(bo->it); - Py_TYPE(bo)->tp_free(bo); + tp->tp_free(bo); + Py_DECREF(tp); } static int batched_traverse(batchedobject *bo, visitproc visit, void *arg) { - if (bo->it != NULL) { - Py_VISIT(bo->it); - } + Py_VISIT(Py_TYPE(bo)); + Py_VISIT(bo->it); return 0; } @@ -226,48 +226,25 @@ batched_next(batchedobject *bo) return result; } -static PyTypeObject batched_type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "itertools.batched", /* tp_name */ - sizeof(batchedobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)batched_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 */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - batched_new__doc__, /* tp_doc */ - (traverseproc)batched_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)batched_next, /* 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 */ - 0, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - batched_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot batched_slots[] = { + {Py_tp_dealloc, batched_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)batched_new__doc__}, + {Py_tp_traverse, batched_traverse}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, batched_next}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, batched_new}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec batched_spec = { + .name = "itertools.batched", + .basicsize = sizeof(batchedobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = batched_slots, }; @@ -4612,6 +4589,7 @@ itertoolsmodule_traverse(PyObject *mod, visitproc visit, void *arg) { itertools_state *state = get_module_state(mod); Py_VISIT(state->accumulate_type); + Py_VISIT(state->batched_type); Py_VISIT(state->chain_type); Py_VISIT(state->combinations_type); Py_VISIT(state->compress_type); @@ -4639,6 +4617,7 @@ itertoolsmodule_clear(PyObject *mod) { itertools_state *state = get_module_state(mod); Py_CLEAR(state->accumulate_type); + Py_CLEAR(state->batched_type); Py_CLEAR(state->chain_type); Py_CLEAR(state->combinations_type); Py_CLEAR(state->compress_type); @@ -4683,6 +4662,7 @@ itertoolsmodule_exec(PyObject *mod) { itertools_state *state = get_module_state(mod); ADD_TYPE(mod, state->accumulate_type, &accumulate_spec); + ADD_TYPE(mod, state->batched_type, &batched_spec); ADD_TYPE(mod, state->chain_type, &chain_spec); ADD_TYPE(mod, state->combinations_type, &combinations_spec); ADD_TYPE(mod, state->compress_type, &compress_spec); @@ -4704,18 +4684,7 @@ itertoolsmodule_exec(PyObject *mod) ADD_TYPE(mod, state->teedataobject_type, &teedataobject_spec); ADD_TYPE(mod, state->ziplongest_type, &ziplongest_spec); - PyTypeObject *typelist[] = { - &batched_type, - }; - Py_SET_TYPE(state->teedataobject_type, &PyType_Type); - - for (size_t i = 0; i < Py_ARRAY_LENGTH(typelist); i++) { - if (PyModule_AddType(mod, typelist[i]) < 0) { - return -1; - } - } - return 0; } From 930fbe130453e11540a66ffdbcf6460e74ecac76 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 3 Feb 2023 16:37:55 +0100 Subject: [PATCH 10/22] Use PyType_GetModuleState for types which cannot be subclassed --- Modules/itertoolsmodule.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 8f4a80f001d52e..9baefdd7875da2 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -741,8 +741,7 @@ static PyObject * teedataobject_jumplink(teedataobject *tdo) { if (tdo->nextlink == NULL) { - PyTypeObject *tp = Py_TYPE(tdo); - itertools_state *state = find_state_by_type(tp); + itertools_state *state = get_module_state_by_cls(Py_TYPE(tdo)); tdo->nextlink = teedataobject_newinternal(state, tdo->it); } return Py_XNewRef(tdo->nextlink); @@ -811,7 +810,7 @@ teedataobject_clear(teedataobject *tdo) Py_CLEAR(tdo->values[i]); tmp = tdo->nextlink; tdo->nextlink = NULL; - itertools_state *state = find_state_by_type(Py_TYPE(tdo)); + itertools_state *state = get_module_state_by_cls(Py_TYPE(tdo)); teedataobject_safe_decref(tmp, state->teedataobject_type); return 0; } @@ -862,7 +861,7 @@ itertools_teedataobject_impl(PyTypeObject *type, PyObject *it, teedataobject *tdo; Py_ssize_t i, len; - itertools_state *state = find_state_by_type(type); + itertools_state *state = get_module_state_by_cls(type); assert(type == state->teedataobject_type); tdo = (teedataobject *)teedataobject_newinternal(state, it); @@ -1013,7 +1012,7 @@ static PyObject * itertools__tee_impl(PyTypeObject *type, PyObject *iterable) /*[clinic end generated code: output=b02d3fd26c810c3f input=adc0779d2afe37a2]*/ { - itertools_state *state = find_state_by_type(type); + itertools_state *state = get_module_state_by_cls(type); return tee_fromiterable(state, iterable); } @@ -1051,8 +1050,8 @@ tee_setstate(teeobject *to, PyObject *state) PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; } - itertools_state *m_state = find_state_by_type(Py_TYPE(to)); - PyTypeObject *tdo_type = m_state->teedataobject_type; + itertools_state *mod_st = get_module_state_by_cls(Py_TYPE(to)); + PyTypeObject *tdo_type = mod_st->teedataobject_type; if (!PyArg_ParseTuple(state, "O!i", tdo_type, &tdo, &index)) { return NULL; } From d45d4386fd2b97a3b6f11e8f5eb7cbb3d4d06a1c Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 8 Feb 2023 21:40:22 +0100 Subject: [PATCH 11/22] Revert unneeded changes that made the code more readable --- Modules/itertoolsmodule.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 9baefdd7875da2..42d8cfe50db306 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -954,10 +954,11 @@ tee_traverse(teeobject *to, visitproc visit, void *arg) static PyObject * tee_copy(teeobject *to, PyObject *Py_UNUSED(ignored)) { - teeobject *newto = PyObject_GC_New(teeobject, Py_TYPE(to)); - if (newto == NULL) { + teeobject *newto; + + newto = PyObject_GC_New(teeobject, Py_TYPE(to)); + if (newto == NULL) return NULL; - } newto->dataobj = (teedataobject*)Py_NewRef(to->dataobj); newto->index = to->index; newto->weakreflist = NULL; From cf3d52818dbea5d0c6e3ab5fdc3ea141f79d5cd9 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 8 Feb 2023 21:46:54 +0100 Subject: [PATCH 12/22] Ditto --- Modules/itertoolsmodule.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 42d8cfe50db306..0a3d1caf23970e 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -1648,10 +1648,10 @@ islice_new(PyTypeObject *type, PyObject *args, PyObject *kwds) isliceobject *lz; itertools_state *st = find_state_by_type(type); - if ((type == st->islice_type || type->tp_init == st->islice_type->tp_init) - && !_PyArg_NoKeywords("islice", kwds)) { + PyTypeObject *islice_type = st->islice_type; + if ((type == islice_type || type->tp_init == islice_type->tp_init) && + !_PyArg_NoKeywords("islice", kwds)) return NULL; - } if (!PyArg_UnpackTuple(args, "islice", 2, 4, &seq, &a1, &a2, &a3)) return NULL; From c4981ff3e588c35003afab495434663b713d6ef1 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 8 Feb 2023 21:50:10 +0100 Subject: [PATCH 13/22] Ditto again --- Modules/itertoolsmodule.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 0a3d1caf23970e..787c45cf07d4a3 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2013,12 +2013,11 @@ chain_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *source; - itertools_state *st = find_state_by_type(type); - if ((type == st->chain_type || type->tp_init == st->chain_type->tp_init) - && !_PyArg_NoKeywords("chain", kwds)) - { + itertools_state *state = find_state_by_type(type); + PyTypeObject *chain_type = state->chain_type; + if ((type == chain_type || type->tp_init == chain_type->tp_init) && + !_PyArg_NoKeywords("chain", kwds)) return NULL; - } source = PyObject_GetIter(args); if (source == NULL) From 1a86a5d5f04244f070012e893d37db0b1bbff7ff Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 8 Feb 2023 22:08:32 +0100 Subject: [PATCH 14/22] Store state in accumulateobject to speed up __reduce__ --- Modules/itertoolsmodule.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 787c45cf07d4a3..d8f32a68277ed1 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -3490,6 +3490,7 @@ typedef struct { PyObject *it; PyObject *binop; PyObject *initial; + itertools_state *state; } accumulateobject; /*[clinic input] @@ -3528,6 +3529,7 @@ itertools_accumulate_impl(PyTypeObject *type, PyObject *iterable, lz->total = NULL; lz->it = it; lz->initial = Py_XNewRef(initial); + lz->state = find_state_by_type(type); return (PyObject *)lz; } @@ -3590,8 +3592,7 @@ accumulate_next(accumulateobject *lz) static PyObject * accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored)) { - PyTypeObject *tp = Py_TYPE(lz); - itertools_state *state = find_state_by_type(tp); + itertools_state *state = lz->state; if (lz->initial != Py_None) { PyObject *it; From b57d177dfcd98ab7b4bf2823b45e3a84565d33c0 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 8 Feb 2023 22:11:23 +0100 Subject: [PATCH 15/22] Store state in teeobject to speed up __setstate__ --- Modules/itertoolsmodule.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index d8f32a68277ed1..f888bd2fb2e3b2 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -718,6 +718,7 @@ typedef struct { teedataobject *dataobj; int index; /* 0 <= index <= LINKCELLS */ PyObject *weakreflist; + itertools_state *state; } teeobject; static PyObject * @@ -995,6 +996,7 @@ tee_fromiterable(itertools_state *state, PyObject *iterable) to->dataobj = (teedataobject *)dataobj; to->index = 0; to->weakreflist = NULL; + to->state = state; PyObject_GC_Track(to); done: Py_DECREF(it); @@ -1051,8 +1053,7 @@ tee_setstate(teeobject *to, PyObject *state) PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; } - itertools_state *mod_st = get_module_state_by_cls(Py_TYPE(to)); - PyTypeObject *tdo_type = mod_st->teedataobject_type; + PyTypeObject *tdo_type = to->state->teedataobject_type; if (!PyArg_ParseTuple(state, "O!i", tdo_type, &tdo, &index)) { return NULL; } From d7bd16aaacd37434f75b54f20bc4ae2f0a2fc00d Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 8 Feb 2023 22:18:00 +0100 Subject: [PATCH 16/22] Remove unneeded change that made the code more readable --- Modules/itertoolsmodule.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index f888bd2fb2e3b2..cb82ece377668e 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -724,11 +724,11 @@ typedef struct { static PyObject * teedataobject_newinternal(itertools_state *state, PyObject *it) { - teedataobject *tdo = PyObject_GC_New(teedataobject, - state->teedataobject_type); - if (tdo == NULL) { + teedataobject *tdo; + + tdo = PyObject_GC_New(teedataobject, state->teedataobject_type); + if (tdo == NULL) return NULL; - } tdo->running = 0; tdo->numread = 0; From d16bed11ec54e388c6b937e49225ea793c6333e9 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 8 Feb 2023 22:20:51 +0100 Subject: [PATCH 17/22] Speed up teedataobject_jumplink() by passing state from teeobject --- Modules/itertoolsmodule.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index cb82ece377668e..4465f18e68fca1 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -739,10 +739,9 @@ teedataobject_newinternal(itertools_state *state, PyObject *it) } static PyObject * -teedataobject_jumplink(teedataobject *tdo) +teedataobject_jumplink(itertools_state *state, teedataobject *tdo) { if (tdo->nextlink == NULL) { - itertools_state *state = get_module_state_by_cls(Py_TYPE(tdo)); tdo->nextlink = teedataobject_newinternal(state, tdo->it); } return Py_XNewRef(tdo->nextlink); @@ -931,7 +930,7 @@ tee_next(teeobject *to) PyObject *value, *link; if (to->index >= LINKCELLS) { - link = teedataobject_jumplink(to->dataobj); + link = teedataobject_jumplink(to->state, to->dataobj); if (link == NULL) return NULL; Py_SETREF(to->dataobj, (teedataobject *)link); From 68e63dd1746b4d16f87993dee8d0443f46ce0042 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 8 Feb 2023 22:22:13 +0100 Subject: [PATCH 18/22] Remove unneeded PEP-7 change --- Modules/itertoolsmodule.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 4465f18e68fca1..11780f3d7bdd76 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -741,9 +741,8 @@ teedataobject_newinternal(itertools_state *state, PyObject *it) static PyObject * teedataobject_jumplink(itertools_state *state, teedataobject *tdo) { - if (tdo->nextlink == NULL) { + if (tdo->nextlink == NULL) tdo->nextlink = teedataobject_newinternal(state, tdo->it); - } return Py_XNewRef(tdo->nextlink); } From 9f68cd16eb20a90d7e688e10b338fc17ce642061 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Thu, 9 Feb 2023 01:09:43 +0100 Subject: [PATCH 19/22] Fix tee_copy --- Modules/itertoolsmodule.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 11780f3d7bdd76..84f873937a8352 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -961,6 +961,7 @@ tee_copy(teeobject *to, PyObject *Py_UNUSED(ignored)) newto->dataobj = (teedataobject*)Py_NewRef(to->dataobj); newto->index = to->index; newto->weakreflist = NULL; + newto->state = to->state; PyObject_GC_Track(newto); return (PyObject *)newto; } From a9c6ce51a0737a08bd1bd8d59398dcd526b80160 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Thu, 9 Feb 2023 09:02:58 +0100 Subject: [PATCH 20/22] Visit and clear teedataobject_type --- Modules/itertoolsmodule.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 84f873937a8352..6986695e47b1ae 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -4608,6 +4608,7 @@ itertoolsmodule_traverse(PyObject *mod, visitproc visit, void *arg) Py_VISIT(state->starmap_type); Py_VISIT(state->takewhile_type); Py_VISIT(state->tee_type); + Py_VISIT(state->teedataobject_type); Py_VISIT(state->ziplongest_type); return 0; } @@ -4636,6 +4637,7 @@ itertoolsmodule_clear(PyObject *mod) Py_CLEAR(state->starmap_type); Py_CLEAR(state->takewhile_type); Py_CLEAR(state->tee_type); + Py_CLEAR(state->teedataobject_type); Py_CLEAR(state->ziplongest_type); return 0; } From 8f554f4e81fe888b81a0fe06eb26feede89108af Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Thu, 9 Feb 2023 10:14:21 +0100 Subject: [PATCH 21/22] Add clear methods to all types --- Modules/itertoolsmodule.c | 270 ++++++++++++++++++++++++++++++-------- 1 file changed, 217 insertions(+), 53 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 6986695e47b1ae..8bfd6309d7bbbf 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -92,6 +92,13 @@ class itertools.pairwise "pairwiseobject *" "clinic_state()->pairwise_type" #undef clinic_state_by_cls #undef clinic_state +#define FREE_AND_CLEAR(ptr) \ +do { \ + void *tmp = (void *)ptr; \ + ptr = NULL; \ + PyMem_Free(tmp); \ +} while (0) + /* batched object ************************************************************/ /* Note: The built-in zip() function includes a "strict" argument @@ -162,12 +169,19 @@ batched_new_impl(PyTypeObject *type, PyObject *iterable, Py_ssize_t n) return (PyObject *)bo; } +static int +batched_clear(batchedobject *bo) +{ + Py_CLEAR(bo->it); + return 0; +} + static void batched_dealloc(batchedobject *bo) { PyTypeObject *tp = Py_TYPE(bo); PyObject_GC_UnTrack(bo); - Py_XDECREF(bo->it); + (void)batched_clear(bo); tp->tp_free(bo); Py_DECREF(tp); } @@ -228,6 +242,7 @@ batched_next(batchedobject *bo) static PyType_Slot batched_slots[] = { {Py_tp_dealloc, batched_dealloc}, + {Py_tp_clear, batched_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)batched_new__doc__}, {Py_tp_traverse, batched_traverse}, @@ -288,13 +303,20 @@ pairwise_new_impl(PyTypeObject *type, PyObject *iterable) return (PyObject *)po; } +static int +pairwise_clear(pairwiseobject *po) +{ + Py_CLEAR(po->it); + Py_CLEAR(po->old); + return 0; +} + static void pairwise_dealloc(pairwiseobject *po) { PyTypeObject *tp = Py_TYPE(po); PyObject_GC_UnTrack(po); - Py_XDECREF(po->it); - Py_XDECREF(po->old); + (void)pairwise_clear(po); tp->tp_free(po); Py_DECREF(tp); } @@ -339,6 +361,7 @@ pairwise_next(pairwiseobject *po) static PyType_Slot pairwise_slots[] = { {Py_tp_dealloc, pairwise_dealloc}, + {Py_tp_clear, pairwise_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)pairwise_new__doc__}, {Py_tp_traverse, pairwise_traverse}, @@ -410,16 +433,23 @@ itertools_groupby_impl(PyTypeObject *type, PyObject *it, PyObject *keyfunc) return (PyObject *)gbo; } +static int +groupby_clear(groupbyobject *gbo) +{ + Py_CLEAR(gbo->it); + Py_CLEAR(gbo->keyfunc); + Py_CLEAR(gbo->tgtkey); + Py_CLEAR(gbo->currkey); + Py_CLEAR(gbo->currvalue); + return 0; +} + static void groupby_dealloc(groupbyobject *gbo) { PyTypeObject *tp = Py_TYPE(gbo); PyObject_GC_UnTrack(gbo); - Py_XDECREF(gbo->it); - Py_XDECREF(gbo->keyfunc); - Py_XDECREF(gbo->tgtkey); - Py_XDECREF(gbo->currkey); - Py_XDECREF(gbo->currvalue); + (void)groupby_clear(gbo); tp->tp_free(gbo); Py_DECREF(tp); } @@ -550,6 +580,7 @@ static PyMethodDef groupby_methods[] = { static PyType_Slot groupby_slots[] = { {Py_tp_dealloc, groupby_dealloc}, + {Py_tp_clear, groupby_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_groupby__doc__}, {Py_tp_traverse, groupby_traverse}, @@ -609,13 +640,20 @@ _grouper_create(groupbyobject *parent, PyObject *tgtkey) return (PyObject *)igo; } +static int +_grouper_clear(_grouperobject *igo) +{ + Py_CLEAR(igo->parent); + Py_CLEAR(igo->tgtkey); + return 0; +} + static void _grouper_dealloc(_grouperobject *igo) { PyTypeObject *tp = Py_TYPE(igo); PyObject_GC_UnTrack(igo); - Py_DECREF(igo->parent); - Py_DECREF(igo->tgtkey); + (void)_grouper_clear(igo); PyObject_GC_Del(igo); Py_DECREF(tp); } @@ -673,6 +711,7 @@ static PyMethodDef _grouper_methods[] = { static PyType_Slot _grouper_slots[] = { {Py_tp_dealloc, _grouper_dealloc}, + {Py_tp_clear, _grouper_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_traverse, _grouper_traverse}, {Py_tp_iter, PyObject_SelfIter}, @@ -819,7 +858,7 @@ teedataobject_dealloc(teedataobject *tdo) { PyTypeObject *tp = Py_TYPE(tdo); PyObject_GC_UnTrack(tdo); - teedataobject_clear(tdo); + (void)teedataobject_clear(tdo); PyObject_GC_Del(tdo); Py_DECREF(tp); } @@ -1032,7 +1071,7 @@ tee_dealloc(teeobject *to) { PyTypeObject *tp = Py_TYPE(to); PyObject_GC_UnTrack(to); - tee_clear(to); + (void)tee_clear(to); PyObject_GC_Del(to); Py_DECREF(tp); } @@ -1221,13 +1260,20 @@ itertools_cycle_impl(PyTypeObject *type, PyObject *iterable) return (PyObject *)lz; } +static int +cycle_clear(cycleobject *lz) +{ + Py_CLEAR(lz->it); + Py_CLEAR(lz->saved); + return 0; +} + static void cycle_dealloc(cycleobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->it); - Py_XDECREF(lz->saved); + (void)cycle_clear(lz); tp->tp_free(lz); Py_DECREF(tp); } @@ -1324,6 +1370,7 @@ static PyMethodDef cycle_methods[] = { static PyType_Slot cycle_slots[] = { {Py_tp_dealloc, cycle_dealloc}, + {Py_tp_clear, cycle_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_cycle__doc__}, {Py_tp_traverse, cycle_traverse}, @@ -1389,13 +1436,20 @@ itertools_dropwhile_impl(PyTypeObject *type, PyObject *func, PyObject *seq) return (PyObject *)lz; } +static int +dropwhile_clear(dropwhileobject *lz) +{ + Py_CLEAR(lz->func); + Py_CLEAR(lz->it); + return 0; +} + static void dropwhile_dealloc(dropwhileobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->func); - Py_XDECREF(lz->it); + (void)dropwhile_clear(lz); tp->tp_free(lz); Py_DECREF(tp); } @@ -1468,6 +1522,7 @@ static PyMethodDef dropwhile_methods[] = { static PyType_Slot dropwhile_slots[] = { {Py_tp_dealloc, dropwhile_dealloc}, + {Py_tp_clear, dropwhile_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_dropwhile__doc__}, {Py_tp_traverse, dropwhile_traverse}, @@ -1531,13 +1586,20 @@ itertools_takewhile_impl(PyTypeObject *type, PyObject *func, PyObject *seq) return (PyObject *)lz; } +static int +takewhile_clear(takewhileobject *lz) +{ + Py_CLEAR(lz->func); + Py_CLEAR(lz->it); + return 0; +} + static void takewhile_dealloc(takewhileobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->func); - Py_XDECREF(lz->it); + (void)takewhile_clear(lz); tp->tp_free(lz); Py_DECREF(tp); } @@ -1607,6 +1669,7 @@ static PyMethodDef takewhile_reduce_methods[] = { static PyType_Slot takewhile_slots[] = { {Py_tp_dealloc, takewhile_dealloc}, + {Py_tp_clear, takewhile_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_takewhile__doc__}, {Py_tp_traverse, takewhile_traverse}, @@ -1725,12 +1788,19 @@ islice_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)lz; } +static int +islice_clear(isliceobject *lz) +{ + Py_CLEAR(lz->it); + return 0; +} + static void islice_dealloc(isliceobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->it); + (void)islice_clear(lz); tp->tp_free(lz); Py_DECREF(tp); } @@ -1846,6 +1916,7 @@ but returns an iterator."); static PyType_Slot islice_slots[] = { {Py_tp_dealloc, islice_dealloc}, + {Py_tp_clear, islice_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)islice_doc}, {Py_tp_traverse, islice_traverse}, @@ -1907,13 +1978,20 @@ itertools_starmap_impl(PyTypeObject *type, PyObject *func, PyObject *seq) return (PyObject *)lz; } +static int +starmap_clear(starmapobject *lz) +{ + Py_CLEAR(lz->func); + Py_CLEAR(lz->it); + return 0; +} + static void starmap_dealloc(starmapobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->func); - Py_XDECREF(lz->it); + (void)starmap_clear(lz); tp->tp_free(lz); Py_DECREF(tp); } @@ -1964,6 +2042,7 @@ static PyMethodDef starmap_methods[] = { static PyType_Slot starmap_slots[] = { {Py_tp_dealloc, starmap_dealloc}, + {Py_tp_clear, starmap_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_starmap__doc__}, {Py_tp_traverse, starmap_traverse}, @@ -2047,13 +2126,20 @@ itertools_chain_from_iterable(PyTypeObject *type, PyObject *arg) return chain_new_internal(type, source); } +static int +chain_clear(chainobject *lz) +{ + Py_CLEAR(lz->source); + Py_CLEAR(lz->active); + return 0; +} + static void chain_dealloc(chainobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->active); - Py_XDECREF(lz->source); + (void)chain_clear(lz); tp->tp_free(lz); Py_DECREF(tp); } @@ -2168,6 +2254,7 @@ static PyMethodDef chain_methods[] = { static PyType_Slot chain_slots[] = { {Py_tp_dealloc, chain_dealloc}, + {Py_tp_clear, chain_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)chain_doc}, {Py_tp_traverse, chain_traverse}, @@ -2281,15 +2368,21 @@ product_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } +static int +product_clear(productobject *lz) +{ + Py_CLEAR(lz->pools); + Py_CLEAR(lz->result); + FREE_AND_CLEAR(lz->indices); + return 0; +} + static void product_dealloc(productobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->pools); - Py_XDECREF(lz->result); - if (lz->indices != NULL) - PyMem_Free(lz->indices); + (void)product_clear(lz); tp->tp_free(lz); Py_DECREF(tp); } @@ -2501,6 +2594,7 @@ product((0,1), (0,1), (0,1)) --> (0,0,0) (0,0,1) (0,1,0) (0,1,1) (1,0,0) ..."); static PyType_Slot product_slots[] = { {Py_tp_dealloc, product_dealloc}, + {Py_tp_clear, product_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)product_doc}, {Py_tp_traverse, product_traverse}, @@ -2592,15 +2686,21 @@ itertools_combinations_impl(PyTypeObject *type, PyObject *iterable, return NULL; } +static int +combinations_clear(combinationsobject *co) +{ + Py_CLEAR(co->pool); + Py_CLEAR(co->result); + FREE_AND_CLEAR(co->indices); + return 0; +} + static void combinations_dealloc(combinationsobject *co) { PyTypeObject *tp = Py_TYPE(co); PyObject_GC_UnTrack(co); - Py_XDECREF(co->pool); - Py_XDECREF(co->result); - if (co->indices != NULL) - PyMem_Free(co->indices); + (void)combinations_clear(co); tp->tp_free(co); Py_DECREF(tp); } @@ -2789,6 +2889,7 @@ static PyMethodDef combinations_methods[] = { static PyType_Slot combinations_slots[] = { {Py_tp_dealloc, combinations_dealloc}, + {Py_tp_clear, combinations_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_combinations__doc__}, {Py_tp_traverse, combinations_traverse}, @@ -2906,15 +3007,21 @@ itertools_combinations_with_replacement_impl(PyTypeObject *type, return NULL; } +static int +cwr_clear(cwrobject *co) +{ + Py_CLEAR(co->pool); + Py_CLEAR(co->result); + FREE_AND_CLEAR(co->indices); + return 0; +} + static void cwr_dealloc(cwrobject *co) { PyTypeObject *tp = Py_TYPE(co); PyObject_GC_UnTrack(co); - Py_XDECREF(co->pool); - Py_XDECREF(co->result); - if (co->indices != NULL) - PyMem_Free(co->indices); + (void)cwr_clear(co); tp->tp_free(co); Py_DECREF(tp); } @@ -3093,6 +3200,7 @@ static PyMethodDef cwr_methods[] = { static PyType_Slot cwr_slots[] = { {Py_tp_dealloc, cwr_dealloc}, + {Py_tp_clear, cwr_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_combinations_with_replacement__doc__}, {Py_tp_traverse, cwr_traverse}, @@ -3229,15 +3337,22 @@ itertools_permutations_impl(PyTypeObject *type, PyObject *iterable, return NULL; } +static int +permutations_clear(permutationsobject *po) +{ + Py_CLEAR(po->pool); + Py_CLEAR(po->result); + FREE_AND_CLEAR(po->indices); + FREE_AND_CLEAR(po->cycles); + return 0; +} + static void permutations_dealloc(permutationsobject *po) { PyTypeObject *tp = Py_TYPE(po); PyObject_GC_UnTrack(po); - Py_XDECREF(po->pool); - Py_XDECREF(po->result); - PyMem_Free(po->indices); - PyMem_Free(po->cycles); + (void)permutations_clear(po); tp->tp_free(po); Py_DECREF(tp); } @@ -3462,6 +3577,7 @@ static PyMethodDef permuations_methods[] = { static PyType_Slot permutations_slots[] = { {Py_tp_dealloc, permutations_dealloc}, + {Py_tp_clear, permutations_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_permutations__doc__}, {Py_tp_traverse, permutations_traverse}, @@ -3533,15 +3649,22 @@ itertools_accumulate_impl(PyTypeObject *type, PyObject *iterable, return (PyObject *)lz; } +static int +accumulate_clear(accumulateobject *lz) +{ + Py_CLEAR(lz->binop); + Py_CLEAR(lz->total); + Py_CLEAR(lz->it); + Py_CLEAR(lz->initial); + return 0; +} + static void accumulate_dealloc(accumulateobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->binop); - Py_XDECREF(lz->total); - Py_XDECREF(lz->it); - Py_XDECREF(lz->initial); + (void)accumulate_clear(lz); tp->tp_free(lz); Py_DECREF(tp); } @@ -3642,6 +3765,7 @@ static PyMethodDef accumulate_methods[] = { static PyType_Slot accumulate_slots[] = { {Py_tp_dealloc, accumulate_dealloc}, + {Py_tp_clear, accumulate_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_accumulate__doc__}, {Py_tp_traverse, accumulate_traverse}, @@ -3716,13 +3840,20 @@ itertools_compress_impl(PyTypeObject *type, PyObject *seq1, PyObject *seq2) return NULL; } +static int +compress_clear(compressobject *lz) +{ + Py_CLEAR(lz->data); + Py_CLEAR(lz->selectors); + return 0; +} + static void compress_dealloc(compressobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->data); - Py_XDECREF(lz->selectors); + (void)compress_clear(lz); tp->tp_free(lz); Py_DECREF(tp); } @@ -3787,6 +3918,7 @@ static PyMethodDef compress_methods[] = { static PyType_Slot compress_slots[] = { {Py_tp_dealloc, compress_dealloc}, + {Py_tp_clear, compress_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_compress__doc__}, {Py_tp_traverse, compress_traverse}, @@ -3850,13 +3982,20 @@ itertools_filterfalse_impl(PyTypeObject *type, PyObject *func, PyObject *seq) return (PyObject *)lz; } +static int +filterfalse_clear(filterfalseobject *lz) +{ + Py_CLEAR(lz->func); + Py_CLEAR(lz->it); + return 0; +} + static void filterfalse_dealloc(filterfalseobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->func); - Py_XDECREF(lz->it); + (void)filterfalse_clear(lz); tp->tp_free(lz); Py_DECREF(tp); } @@ -3918,6 +4057,7 @@ static PyMethodDef filterfalse_methods[] = { static PyType_Slot filterfalse_slots[] = { {Py_tp_dealloc, filterfalse_dealloc}, + {Py_tp_clear, filterfalse_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_filterfalse__doc__}, {Py_tp_traverse, filterfalse_traverse}, @@ -4057,13 +4197,20 @@ itertools_count_impl(PyTypeObject *type, PyObject *long_cnt, return (PyObject *)lz; } +static int +count_clear(countobject *lz) +{ + Py_CLEAR(lz->long_cnt); + Py_CLEAR(lz->long_step); + return 0; +} + static void count_dealloc(countobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->long_cnt); - Py_XDECREF(lz->long_step); + (void)count_clear(lz); tp->tp_free(lz); Py_DECREF(tp); } @@ -4147,6 +4294,7 @@ static PyMethodDef count_methods[] = { static PyType_Slot count_slots[] = { {Py_tp_dealloc, count_dealloc}, + {Py_tp_clear, count_clear}, {Py_tp_repr, count_repr}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_count__doc__}, @@ -4202,12 +4350,19 @@ repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)ro; } +static int +repeat_clear(repeatobject *ro) +{ + Py_CLEAR(ro->element); + return 0; +} + static void repeat_dealloc(repeatobject *ro) { PyTypeObject *tp = Py_TYPE(ro); PyObject_GC_UnTrack(ro); - Py_XDECREF(ro->element); + (void)repeat_clear(ro); tp->tp_free(ro); Py_DECREF(tp); } @@ -4279,6 +4434,7 @@ endlessly."); static PyType_Slot repeat_slots[] = { {Py_tp_dealloc, repeat_dealloc}, + {Py_tp_clear, repeat_clear}, {Py_tp_repr, repeat_repr}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)repeat_doc}, @@ -4379,14 +4535,21 @@ zip_longest_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)lz; } +static int +zip_longest_clear(ziplongestobject *lz) +{ + Py_CLEAR(lz->ittuple); + Py_CLEAR(lz->result); + Py_CLEAR(lz->fillvalue); + return 0; +} + static void zip_longest_dealloc(ziplongestobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->ittuple); - Py_XDECREF(lz->result); - Py_XDECREF(lz->fillvalue); + (void)zip_longest_clear(lz); tp->tp_free(lz); Py_DECREF(tp); } @@ -4530,6 +4693,7 @@ defaults to None or can be specified by a keyword argument.\n\ static PyType_Slot ziplongest_slots[] = { {Py_tp_dealloc, zip_longest_dealloc}, + {Py_tp_clear, zip_longest_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)zip_longest_doc}, {Py_tp_traverse, zip_longest_traverse}, From 5213d1f82945b42d5e40322cc8106ad42e0a2951 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 10 Feb 2023 08:34:04 +0100 Subject: [PATCH 22/22] Revert "Add clear methods to all types" This reverts commit 8f554f4e81fe888b81a0fe06eb26feede89108af. --- Modules/itertoolsmodule.c | 270 ++++++++------------------------------ 1 file changed, 53 insertions(+), 217 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 8bfd6309d7bbbf..6986695e47b1ae 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -92,13 +92,6 @@ class itertools.pairwise "pairwiseobject *" "clinic_state()->pairwise_type" #undef clinic_state_by_cls #undef clinic_state -#define FREE_AND_CLEAR(ptr) \ -do { \ - void *tmp = (void *)ptr; \ - ptr = NULL; \ - PyMem_Free(tmp); \ -} while (0) - /* batched object ************************************************************/ /* Note: The built-in zip() function includes a "strict" argument @@ -169,19 +162,12 @@ batched_new_impl(PyTypeObject *type, PyObject *iterable, Py_ssize_t n) return (PyObject *)bo; } -static int -batched_clear(batchedobject *bo) -{ - Py_CLEAR(bo->it); - return 0; -} - static void batched_dealloc(batchedobject *bo) { PyTypeObject *tp = Py_TYPE(bo); PyObject_GC_UnTrack(bo); - (void)batched_clear(bo); + Py_XDECREF(bo->it); tp->tp_free(bo); Py_DECREF(tp); } @@ -242,7 +228,6 @@ batched_next(batchedobject *bo) static PyType_Slot batched_slots[] = { {Py_tp_dealloc, batched_dealloc}, - {Py_tp_clear, batched_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)batched_new__doc__}, {Py_tp_traverse, batched_traverse}, @@ -303,20 +288,13 @@ pairwise_new_impl(PyTypeObject *type, PyObject *iterable) return (PyObject *)po; } -static int -pairwise_clear(pairwiseobject *po) -{ - Py_CLEAR(po->it); - Py_CLEAR(po->old); - return 0; -} - static void pairwise_dealloc(pairwiseobject *po) { PyTypeObject *tp = Py_TYPE(po); PyObject_GC_UnTrack(po); - (void)pairwise_clear(po); + Py_XDECREF(po->it); + Py_XDECREF(po->old); tp->tp_free(po); Py_DECREF(tp); } @@ -361,7 +339,6 @@ pairwise_next(pairwiseobject *po) static PyType_Slot pairwise_slots[] = { {Py_tp_dealloc, pairwise_dealloc}, - {Py_tp_clear, pairwise_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)pairwise_new__doc__}, {Py_tp_traverse, pairwise_traverse}, @@ -433,23 +410,16 @@ itertools_groupby_impl(PyTypeObject *type, PyObject *it, PyObject *keyfunc) return (PyObject *)gbo; } -static int -groupby_clear(groupbyobject *gbo) -{ - Py_CLEAR(gbo->it); - Py_CLEAR(gbo->keyfunc); - Py_CLEAR(gbo->tgtkey); - Py_CLEAR(gbo->currkey); - Py_CLEAR(gbo->currvalue); - return 0; -} - static void groupby_dealloc(groupbyobject *gbo) { PyTypeObject *tp = Py_TYPE(gbo); PyObject_GC_UnTrack(gbo); - (void)groupby_clear(gbo); + Py_XDECREF(gbo->it); + Py_XDECREF(gbo->keyfunc); + Py_XDECREF(gbo->tgtkey); + Py_XDECREF(gbo->currkey); + Py_XDECREF(gbo->currvalue); tp->tp_free(gbo); Py_DECREF(tp); } @@ -580,7 +550,6 @@ static PyMethodDef groupby_methods[] = { static PyType_Slot groupby_slots[] = { {Py_tp_dealloc, groupby_dealloc}, - {Py_tp_clear, groupby_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_groupby__doc__}, {Py_tp_traverse, groupby_traverse}, @@ -640,20 +609,13 @@ _grouper_create(groupbyobject *parent, PyObject *tgtkey) return (PyObject *)igo; } -static int -_grouper_clear(_grouperobject *igo) -{ - Py_CLEAR(igo->parent); - Py_CLEAR(igo->tgtkey); - return 0; -} - static void _grouper_dealloc(_grouperobject *igo) { PyTypeObject *tp = Py_TYPE(igo); PyObject_GC_UnTrack(igo); - (void)_grouper_clear(igo); + Py_DECREF(igo->parent); + Py_DECREF(igo->tgtkey); PyObject_GC_Del(igo); Py_DECREF(tp); } @@ -711,7 +673,6 @@ static PyMethodDef _grouper_methods[] = { static PyType_Slot _grouper_slots[] = { {Py_tp_dealloc, _grouper_dealloc}, - {Py_tp_clear, _grouper_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_traverse, _grouper_traverse}, {Py_tp_iter, PyObject_SelfIter}, @@ -858,7 +819,7 @@ teedataobject_dealloc(teedataobject *tdo) { PyTypeObject *tp = Py_TYPE(tdo); PyObject_GC_UnTrack(tdo); - (void)teedataobject_clear(tdo); + teedataobject_clear(tdo); PyObject_GC_Del(tdo); Py_DECREF(tp); } @@ -1071,7 +1032,7 @@ tee_dealloc(teeobject *to) { PyTypeObject *tp = Py_TYPE(to); PyObject_GC_UnTrack(to); - (void)tee_clear(to); + tee_clear(to); PyObject_GC_Del(to); Py_DECREF(tp); } @@ -1260,20 +1221,13 @@ itertools_cycle_impl(PyTypeObject *type, PyObject *iterable) return (PyObject *)lz; } -static int -cycle_clear(cycleobject *lz) -{ - Py_CLEAR(lz->it); - Py_CLEAR(lz->saved); - return 0; -} - static void cycle_dealloc(cycleobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - (void)cycle_clear(lz); + Py_XDECREF(lz->it); + Py_XDECREF(lz->saved); tp->tp_free(lz); Py_DECREF(tp); } @@ -1370,7 +1324,6 @@ static PyMethodDef cycle_methods[] = { static PyType_Slot cycle_slots[] = { {Py_tp_dealloc, cycle_dealloc}, - {Py_tp_clear, cycle_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_cycle__doc__}, {Py_tp_traverse, cycle_traverse}, @@ -1436,20 +1389,13 @@ itertools_dropwhile_impl(PyTypeObject *type, PyObject *func, PyObject *seq) return (PyObject *)lz; } -static int -dropwhile_clear(dropwhileobject *lz) -{ - Py_CLEAR(lz->func); - Py_CLEAR(lz->it); - return 0; -} - static void dropwhile_dealloc(dropwhileobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - (void)dropwhile_clear(lz); + Py_XDECREF(lz->func); + Py_XDECREF(lz->it); tp->tp_free(lz); Py_DECREF(tp); } @@ -1522,7 +1468,6 @@ static PyMethodDef dropwhile_methods[] = { static PyType_Slot dropwhile_slots[] = { {Py_tp_dealloc, dropwhile_dealloc}, - {Py_tp_clear, dropwhile_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_dropwhile__doc__}, {Py_tp_traverse, dropwhile_traverse}, @@ -1586,20 +1531,13 @@ itertools_takewhile_impl(PyTypeObject *type, PyObject *func, PyObject *seq) return (PyObject *)lz; } -static int -takewhile_clear(takewhileobject *lz) -{ - Py_CLEAR(lz->func); - Py_CLEAR(lz->it); - return 0; -} - static void takewhile_dealloc(takewhileobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - (void)takewhile_clear(lz); + Py_XDECREF(lz->func); + Py_XDECREF(lz->it); tp->tp_free(lz); Py_DECREF(tp); } @@ -1669,7 +1607,6 @@ static PyMethodDef takewhile_reduce_methods[] = { static PyType_Slot takewhile_slots[] = { {Py_tp_dealloc, takewhile_dealloc}, - {Py_tp_clear, takewhile_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_takewhile__doc__}, {Py_tp_traverse, takewhile_traverse}, @@ -1788,19 +1725,12 @@ islice_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)lz; } -static int -islice_clear(isliceobject *lz) -{ - Py_CLEAR(lz->it); - return 0; -} - static void islice_dealloc(isliceobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - (void)islice_clear(lz); + Py_XDECREF(lz->it); tp->tp_free(lz); Py_DECREF(tp); } @@ -1916,7 +1846,6 @@ but returns an iterator."); static PyType_Slot islice_slots[] = { {Py_tp_dealloc, islice_dealloc}, - {Py_tp_clear, islice_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)islice_doc}, {Py_tp_traverse, islice_traverse}, @@ -1978,20 +1907,13 @@ itertools_starmap_impl(PyTypeObject *type, PyObject *func, PyObject *seq) return (PyObject *)lz; } -static int -starmap_clear(starmapobject *lz) -{ - Py_CLEAR(lz->func); - Py_CLEAR(lz->it); - return 0; -} - static void starmap_dealloc(starmapobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - (void)starmap_clear(lz); + Py_XDECREF(lz->func); + Py_XDECREF(lz->it); tp->tp_free(lz); Py_DECREF(tp); } @@ -2042,7 +1964,6 @@ static PyMethodDef starmap_methods[] = { static PyType_Slot starmap_slots[] = { {Py_tp_dealloc, starmap_dealloc}, - {Py_tp_clear, starmap_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_starmap__doc__}, {Py_tp_traverse, starmap_traverse}, @@ -2126,20 +2047,13 @@ itertools_chain_from_iterable(PyTypeObject *type, PyObject *arg) return chain_new_internal(type, source); } -static int -chain_clear(chainobject *lz) -{ - Py_CLEAR(lz->source); - Py_CLEAR(lz->active); - return 0; -} - static void chain_dealloc(chainobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - (void)chain_clear(lz); + Py_XDECREF(lz->active); + Py_XDECREF(lz->source); tp->tp_free(lz); Py_DECREF(tp); } @@ -2254,7 +2168,6 @@ static PyMethodDef chain_methods[] = { static PyType_Slot chain_slots[] = { {Py_tp_dealloc, chain_dealloc}, - {Py_tp_clear, chain_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)chain_doc}, {Py_tp_traverse, chain_traverse}, @@ -2368,21 +2281,15 @@ product_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } -static int -product_clear(productobject *lz) -{ - Py_CLEAR(lz->pools); - Py_CLEAR(lz->result); - FREE_AND_CLEAR(lz->indices); - return 0; -} - static void product_dealloc(productobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - (void)product_clear(lz); + Py_XDECREF(lz->pools); + Py_XDECREF(lz->result); + if (lz->indices != NULL) + PyMem_Free(lz->indices); tp->tp_free(lz); Py_DECREF(tp); } @@ -2594,7 +2501,6 @@ product((0,1), (0,1), (0,1)) --> (0,0,0) (0,0,1) (0,1,0) (0,1,1) (1,0,0) ..."); static PyType_Slot product_slots[] = { {Py_tp_dealloc, product_dealloc}, - {Py_tp_clear, product_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)product_doc}, {Py_tp_traverse, product_traverse}, @@ -2686,21 +2592,15 @@ itertools_combinations_impl(PyTypeObject *type, PyObject *iterable, return NULL; } -static int -combinations_clear(combinationsobject *co) -{ - Py_CLEAR(co->pool); - Py_CLEAR(co->result); - FREE_AND_CLEAR(co->indices); - return 0; -} - static void combinations_dealloc(combinationsobject *co) { PyTypeObject *tp = Py_TYPE(co); PyObject_GC_UnTrack(co); - (void)combinations_clear(co); + Py_XDECREF(co->pool); + Py_XDECREF(co->result); + if (co->indices != NULL) + PyMem_Free(co->indices); tp->tp_free(co); Py_DECREF(tp); } @@ -2889,7 +2789,6 @@ static PyMethodDef combinations_methods[] = { static PyType_Slot combinations_slots[] = { {Py_tp_dealloc, combinations_dealloc}, - {Py_tp_clear, combinations_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_combinations__doc__}, {Py_tp_traverse, combinations_traverse}, @@ -3007,21 +2906,15 @@ itertools_combinations_with_replacement_impl(PyTypeObject *type, return NULL; } -static int -cwr_clear(cwrobject *co) -{ - Py_CLEAR(co->pool); - Py_CLEAR(co->result); - FREE_AND_CLEAR(co->indices); - return 0; -} - static void cwr_dealloc(cwrobject *co) { PyTypeObject *tp = Py_TYPE(co); PyObject_GC_UnTrack(co); - (void)cwr_clear(co); + Py_XDECREF(co->pool); + Py_XDECREF(co->result); + if (co->indices != NULL) + PyMem_Free(co->indices); tp->tp_free(co); Py_DECREF(tp); } @@ -3200,7 +3093,6 @@ static PyMethodDef cwr_methods[] = { static PyType_Slot cwr_slots[] = { {Py_tp_dealloc, cwr_dealloc}, - {Py_tp_clear, cwr_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_combinations_with_replacement__doc__}, {Py_tp_traverse, cwr_traverse}, @@ -3337,22 +3229,15 @@ itertools_permutations_impl(PyTypeObject *type, PyObject *iterable, return NULL; } -static int -permutations_clear(permutationsobject *po) -{ - Py_CLEAR(po->pool); - Py_CLEAR(po->result); - FREE_AND_CLEAR(po->indices); - FREE_AND_CLEAR(po->cycles); - return 0; -} - static void permutations_dealloc(permutationsobject *po) { PyTypeObject *tp = Py_TYPE(po); PyObject_GC_UnTrack(po); - (void)permutations_clear(po); + Py_XDECREF(po->pool); + Py_XDECREF(po->result); + PyMem_Free(po->indices); + PyMem_Free(po->cycles); tp->tp_free(po); Py_DECREF(tp); } @@ -3577,7 +3462,6 @@ static PyMethodDef permuations_methods[] = { static PyType_Slot permutations_slots[] = { {Py_tp_dealloc, permutations_dealloc}, - {Py_tp_clear, permutations_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_permutations__doc__}, {Py_tp_traverse, permutations_traverse}, @@ -3649,22 +3533,15 @@ itertools_accumulate_impl(PyTypeObject *type, PyObject *iterable, return (PyObject *)lz; } -static int -accumulate_clear(accumulateobject *lz) -{ - Py_CLEAR(lz->binop); - Py_CLEAR(lz->total); - Py_CLEAR(lz->it); - Py_CLEAR(lz->initial); - return 0; -} - static void accumulate_dealloc(accumulateobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - (void)accumulate_clear(lz); + Py_XDECREF(lz->binop); + Py_XDECREF(lz->total); + Py_XDECREF(lz->it); + Py_XDECREF(lz->initial); tp->tp_free(lz); Py_DECREF(tp); } @@ -3765,7 +3642,6 @@ static PyMethodDef accumulate_methods[] = { static PyType_Slot accumulate_slots[] = { {Py_tp_dealloc, accumulate_dealloc}, - {Py_tp_clear, accumulate_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_accumulate__doc__}, {Py_tp_traverse, accumulate_traverse}, @@ -3840,20 +3716,13 @@ itertools_compress_impl(PyTypeObject *type, PyObject *seq1, PyObject *seq2) return NULL; } -static int -compress_clear(compressobject *lz) -{ - Py_CLEAR(lz->data); - Py_CLEAR(lz->selectors); - return 0; -} - static void compress_dealloc(compressobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - (void)compress_clear(lz); + Py_XDECREF(lz->data); + Py_XDECREF(lz->selectors); tp->tp_free(lz); Py_DECREF(tp); } @@ -3918,7 +3787,6 @@ static PyMethodDef compress_methods[] = { static PyType_Slot compress_slots[] = { {Py_tp_dealloc, compress_dealloc}, - {Py_tp_clear, compress_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_compress__doc__}, {Py_tp_traverse, compress_traverse}, @@ -3982,20 +3850,13 @@ itertools_filterfalse_impl(PyTypeObject *type, PyObject *func, PyObject *seq) return (PyObject *)lz; } -static int -filterfalse_clear(filterfalseobject *lz) -{ - Py_CLEAR(lz->func); - Py_CLEAR(lz->it); - return 0; -} - static void filterfalse_dealloc(filterfalseobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - (void)filterfalse_clear(lz); + Py_XDECREF(lz->func); + Py_XDECREF(lz->it); tp->tp_free(lz); Py_DECREF(tp); } @@ -4057,7 +3918,6 @@ static PyMethodDef filterfalse_methods[] = { static PyType_Slot filterfalse_slots[] = { {Py_tp_dealloc, filterfalse_dealloc}, - {Py_tp_clear, filterfalse_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_filterfalse__doc__}, {Py_tp_traverse, filterfalse_traverse}, @@ -4197,20 +4057,13 @@ itertools_count_impl(PyTypeObject *type, PyObject *long_cnt, return (PyObject *)lz; } -static int -count_clear(countobject *lz) -{ - Py_CLEAR(lz->long_cnt); - Py_CLEAR(lz->long_step); - return 0; -} - static void count_dealloc(countobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - (void)count_clear(lz); + Py_XDECREF(lz->long_cnt); + Py_XDECREF(lz->long_step); tp->tp_free(lz); Py_DECREF(tp); } @@ -4294,7 +4147,6 @@ static PyMethodDef count_methods[] = { static PyType_Slot count_slots[] = { {Py_tp_dealloc, count_dealloc}, - {Py_tp_clear, count_clear}, {Py_tp_repr, count_repr}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)itertools_count__doc__}, @@ -4350,19 +4202,12 @@ repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)ro; } -static int -repeat_clear(repeatobject *ro) -{ - Py_CLEAR(ro->element); - return 0; -} - static void repeat_dealloc(repeatobject *ro) { PyTypeObject *tp = Py_TYPE(ro); PyObject_GC_UnTrack(ro); - (void)repeat_clear(ro); + Py_XDECREF(ro->element); tp->tp_free(ro); Py_DECREF(tp); } @@ -4434,7 +4279,6 @@ endlessly."); static PyType_Slot repeat_slots[] = { {Py_tp_dealloc, repeat_dealloc}, - {Py_tp_clear, repeat_clear}, {Py_tp_repr, repeat_repr}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)repeat_doc}, @@ -4535,21 +4379,14 @@ zip_longest_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)lz; } -static int -zip_longest_clear(ziplongestobject *lz) -{ - Py_CLEAR(lz->ittuple); - Py_CLEAR(lz->result); - Py_CLEAR(lz->fillvalue); - return 0; -} - static void zip_longest_dealloc(ziplongestobject *lz) { PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); - (void)zip_longest_clear(lz); + Py_XDECREF(lz->ittuple); + Py_XDECREF(lz->result); + Py_XDECREF(lz->fillvalue); tp->tp_free(lz); Py_DECREF(tp); } @@ -4693,7 +4530,6 @@ defaults to None or can be specified by a keyword argument.\n\ static PyType_Slot ziplongest_slots[] = { {Py_tp_dealloc, zip_longest_dealloc}, - {Py_tp_clear, zip_longest_clear}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_doc, (void *)zip_longest_doc}, {Py_tp_traverse, zip_longest_traverse},