]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-101277: Port more `itertools` static types to heap types (#101303)
authorErlend E. Aasland <erlend.aasland@protonmail.com>
Fri, 3 Feb 2023 09:54:27 +0000 (10:54 +0100)
committerGitHub <noreply@github.com>
Fri, 3 Feb 2023 09:54:27 +0000 (15:24 +0530)
Add dropwhile, takewhile, starmap, combinations*, and permutations types to module state.

Modules/clinic/itertoolsmodule.c.h
Modules/itertoolsmodule.c

index c492c33daea5a261ada8b0f42f3c07da299d4dbd..be44246cc9705a80e47b5e981cd1e098fbd9cec4 100644 (file)
@@ -345,7 +345,7 @@ static PyObject *
 itertools_cycle(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
     PyObject *return_value = NULL;
-    PyTypeObject *base_tp = &cycle_type;
+    PyTypeObject *base_tp = clinic_state()->cycle_type;
     PyObject *iterable;
 
     if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
@@ -377,7 +377,7 @@ static PyObject *
 itertools_dropwhile(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
     PyObject *return_value = NULL;
-    PyTypeObject *base_tp = &dropwhile_type;
+    PyTypeObject *base_tp = clinic_state()->dropwhile_type;
     PyObject *func;
     PyObject *seq;
 
@@ -409,7 +409,7 @@ static PyObject *
 itertools_takewhile(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
     PyObject *return_value = NULL;
-    PyTypeObject *base_tp = &takewhile_type;
+    PyTypeObject *base_tp = clinic_state()->takewhile_type;
     PyObject *func;
     PyObject *seq;
 
@@ -441,7 +441,7 @@ static PyObject *
 itertools_starmap(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
     PyObject *return_value = NULL;
-    PyTypeObject *base_tp = &starmap_type;
+    PyTypeObject *base_tp = clinic_state()->starmap_type;
     PyObject *func;
     PyObject *seq;
 
@@ -913,4 +913,4 @@ skip_optional_pos:
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=c3069caac417e165 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=b86fcd99bd32145e input=a9049054013a1b77]*/
index a2ee48228b5847ac1efa84579f63505b73aa89a4..c9baa47e2c0edd0ae986d84c804f8b7e28ea1eef 100644 (file)
 */
 
 typedef struct {
+    PyTypeObject *combinations_type;
+    PyTypeObject *cwr_type;
+    PyTypeObject *cycle_type;
+    PyTypeObject *dropwhile_type;
     PyTypeObject *groupby_type;
     PyTypeObject *_grouper_type;
+    PyTypeObject *permutations_type;
+    PyTypeObject *starmap_type;
+    PyTypeObject *takewhile_type;
 } itertools_state;
 
 static inline itertools_state *
@@ -50,32 +57,25 @@ class itertools._grouper "_grouperobject *" "clinic_state()->_grouper_type"
 class itertools.teedataobject "teedataobject *" "&teedataobject_type"
 class itertools._tee "teeobject *" "&tee_type"
 class itertools.batched "batchedobject *" "&batched_type"
-class itertools.cycle "cycleobject *" "&cycle_type"
-class itertools.dropwhile "dropwhileobject *" "&dropwhile_type"
-class itertools.takewhile "takewhileobject *" "&takewhile_type"
-class itertools.starmap "starmapobject *" "&starmap_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"
+class itertools.starmap "starmapobject *" "clinic_state()->starmap_type"
 class itertools.chain "chainobject *" "&chain_type"
-class itertools.combinations "combinationsobject *" "&combinations_type"
-class itertools.combinations_with_replacement "cwr_object *" "&cwr_type"
-class itertools.permutations "permutationsobject *" "&permutations_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"
 class itertools.accumulate "accumulateobject *" "&accumulate_type"
 class itertools.compress "compressobject *" "&compress_type"
 class itertools.filterfalse "filterfalseobject *" "&filterfalse_type"
 class itertools.count "countobject *" "&count_type"
 class itertools.pairwise "pairwiseobject *" "&pairwise_type"
 [clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=424108522584b55b]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=1790ac655869a651]*/
 
 static PyTypeObject teedataobject_type;
 static PyTypeObject tee_type;
 static PyTypeObject batched_type;
-static PyTypeObject cycle_type;
-static PyTypeObject dropwhile_type;
-static PyTypeObject takewhile_type;
-static PyTypeObject starmap_type;
-static PyTypeObject combinations_type;
-static PyTypeObject cwr_type;
-static PyTypeObject permutations_type;
 static PyTypeObject accumulate_type;
 static PyTypeObject compress_type;
 static PyTypeObject filterfalse_type;
@@ -1286,15 +1286,18 @@ itertools_cycle_impl(PyTypeObject *type, PyObject *iterable)
 static void
 cycle_dealloc(cycleobject *lz)
 {
+    PyTypeObject *tp = Py_TYPE(lz);
     PyObject_GC_UnTrack(lz);
     Py_XDECREF(lz->it);
     Py_XDECREF(lz->saved);
-    Py_TYPE(lz)->tp_free(lz);
+    tp->tp_free(lz);
+    Py_DECREF(tp);
 }
 
 static int
 cycle_traverse(cycleobject *lz, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(lz));
     Py_VISIT(lz->it);
     Py_VISIT(lz->saved);
     return 0;
@@ -1381,48 +1384,25 @@ static PyMethodDef cycle_methods[] = {
     {NULL,              NULL}   /* sentinel */
 };
 
-static PyTypeObject cycle_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "itertools.cycle",                  /* tp_name */
-    sizeof(cycleobject),                /* tp_basicsize */
-    0,                                  /* tp_itemsize */
-    /* methods */
-    (destructor)cycle_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 */
-    itertools_cycle__doc__,             /* tp_doc */
-    (traverseproc)cycle_traverse,       /* tp_traverse */
-    0,                                  /* tp_clear */
-    0,                                  /* tp_richcompare */
-    0,                                  /* tp_weaklistoffset */
-    PyObject_SelfIter,                  /* tp_iter */
-    (iternextfunc)cycle_next,           /* tp_iternext */
-    cycle_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_cycle,                    /* tp_new */
-    PyObject_GC_Del,                    /* tp_free */
+static PyType_Slot cycle_slots[] = {
+    {Py_tp_dealloc, cycle_dealloc},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_doc, (void *)itertools_cycle__doc__},
+    {Py_tp_traverse, cycle_traverse},
+    {Py_tp_iter, PyObject_SelfIter},
+    {Py_tp_iternext, cycle_next},
+    {Py_tp_methods, cycle_methods},
+    {Py_tp_new, itertools_cycle},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec cycle_spec = {
+    .name = "itertools.cycle",
+    .basicsize = sizeof(cycleobject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = cycle_slots,
 };
 
 
@@ -1474,15 +1454,18 @@ itertools_dropwhile_impl(PyTypeObject *type, PyObject *func, PyObject *seq)
 static void
 dropwhile_dealloc(dropwhileobject *lz)
 {
+    PyTypeObject *tp = Py_TYPE(lz);
     PyObject_GC_UnTrack(lz);
     Py_XDECREF(lz->func);
     Py_XDECREF(lz->it);
-    Py_TYPE(lz)->tp_free(lz);
+    tp->tp_free(lz);
+    Py_DECREF(tp);
 }
 
 static int
 dropwhile_traverse(dropwhileobject *lz, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(lz));
     Py_VISIT(lz->it);
     Py_VISIT(lz->func);
     return 0;
@@ -1545,48 +1528,25 @@ static PyMethodDef dropwhile_methods[] = {
     {NULL,              NULL}   /* sentinel */
 };
 
-static PyTypeObject dropwhile_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "itertools.dropwhile",              /* tp_name */
-    sizeof(dropwhileobject),            /* tp_basicsize */
-    0,                                  /* tp_itemsize */
-    /* methods */
-    (destructor)dropwhile_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 */
-    itertools_dropwhile__doc__,         /* tp_doc */
-    (traverseproc)dropwhile_traverse,   /* tp_traverse */
-    0,                                  /* tp_clear */
-    0,                                  /* tp_richcompare */
-    0,                                  /* tp_weaklistoffset */
-    PyObject_SelfIter,                  /* tp_iter */
-    (iternextfunc)dropwhile_next,       /* tp_iternext */
-    dropwhile_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_dropwhile,                /* tp_new */
-    PyObject_GC_Del,                    /* tp_free */
+static PyType_Slot dropwhile_slots[] = {
+    {Py_tp_dealloc, dropwhile_dealloc},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_doc, (void *)itertools_dropwhile__doc__},
+    {Py_tp_traverse, dropwhile_traverse},
+    {Py_tp_iter, PyObject_SelfIter},
+    {Py_tp_iternext, dropwhile_next},
+    {Py_tp_methods, dropwhile_methods},
+    {Py_tp_new, itertools_dropwhile},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec dropwhile_spec = {
+    .name = "itertools.dropwhile",
+    .basicsize = sizeof(dropwhileobject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = dropwhile_slots,
 };
 
 
@@ -1636,15 +1596,18 @@ itertools_takewhile_impl(PyTypeObject *type, PyObject *func, PyObject *seq)
 static void
 takewhile_dealloc(takewhileobject *lz)
 {
+    PyTypeObject *tp = Py_TYPE(lz);
     PyObject_GC_UnTrack(lz);
     Py_XDECREF(lz->func);
     Py_XDECREF(lz->it);
-    Py_TYPE(lz)->tp_free(lz);
+    tp->tp_free(lz);
+    Py_DECREF(tp);
 }
 
 static int
 takewhile_traverse(takewhileobject *lz, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(lz));
     Py_VISIT(lz->it);
     Py_VISIT(lz->func);
     return 0;
@@ -1704,48 +1667,25 @@ static PyMethodDef takewhile_reduce_methods[] = {
     {NULL,              NULL}   /* sentinel */
 };
 
-static PyTypeObject takewhile_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "itertools.takewhile",              /* tp_name */
-    sizeof(takewhileobject),            /* tp_basicsize */
-    0,                                  /* tp_itemsize */
-    /* methods */
-    (destructor)takewhile_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 */
-    itertools_takewhile__doc__,         /* tp_doc */
-    (traverseproc)takewhile_traverse,   /* tp_traverse */
-    0,                                  /* tp_clear */
-    0,                                  /* tp_richcompare */
-    0,                                  /* tp_weaklistoffset */
-    PyObject_SelfIter,                  /* tp_iter */
-    (iternextfunc)takewhile_next,       /* tp_iternext */
-    takewhile_reduce_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_takewhile,                /* tp_new */
-    PyObject_GC_Del,                    /* tp_free */
+static PyType_Slot takewhile_slots[] = {
+    {Py_tp_dealloc, takewhile_dealloc},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_doc, (void *)itertools_takewhile__doc__},
+    {Py_tp_traverse, takewhile_traverse},
+    {Py_tp_iter, PyObject_SelfIter},
+    {Py_tp_iternext, takewhile_next},
+    {Py_tp_methods, takewhile_reduce_methods},
+    {Py_tp_new, itertools_takewhile},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec takewhile_spec = {
+    .name = "itertools.takewhile",
+    .basicsize = sizeof(takewhileobject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = takewhile_slots,
 };
 
 
@@ -2052,15 +1992,18 @@ itertools_starmap_impl(PyTypeObject *type, PyObject *func, PyObject *seq)
 static void
 starmap_dealloc(starmapobject *lz)
 {
+    PyTypeObject *tp = Py_TYPE(lz);
     PyObject_GC_UnTrack(lz);
     Py_XDECREF(lz->func);
     Py_XDECREF(lz->it);
-    Py_TYPE(lz)->tp_free(lz);
+    tp->tp_free(lz);
+    Py_DECREF(tp);
 }
 
 static int
 starmap_traverse(starmapobject *lz, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(lz));
     Py_VISIT(lz->it);
     Py_VISIT(lz->func);
     return 0;
@@ -2101,48 +2044,25 @@ static PyMethodDef starmap_methods[] = {
     {NULL,              NULL}   /* sentinel */
 };
 
-static PyTypeObject starmap_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "itertools.starmap",                /* tp_name */
-    sizeof(starmapobject),              /* tp_basicsize */
-    0,                                  /* tp_itemsize */
-    /* methods */
-    (destructor)starmap_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 */
-    itertools_starmap__doc__,           /* tp_doc */
-    (traverseproc)starmap_traverse,     /* tp_traverse */
-    0,                                  /* tp_clear */
-    0,                                  /* tp_richcompare */
-    0,                                  /* tp_weaklistoffset */
-    PyObject_SelfIter,                  /* tp_iter */
-    (iternextfunc)starmap_next,         /* tp_iternext */
-    starmap_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_starmap,                  /* tp_new */
-    PyObject_GC_Del,                    /* tp_free */
+static PyType_Slot starmap_slots[] = {
+    {Py_tp_dealloc, starmap_dealloc},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_doc, (void *)itertools_starmap__doc__},
+    {Py_tp_traverse, starmap_traverse},
+    {Py_tp_iter, PyObject_SelfIter},
+    {Py_tp_iternext, starmap_next},
+    {Py_tp_methods, starmap_methods},
+    {Py_tp_new, itertools_starmap},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec starmap_spec = {
+    .name = "itertools.starmap",
+    .basicsize = sizeof(starmapobject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = starmap_slots,
 };
 
 
@@ -2799,12 +2719,14 @@ error:
 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);
-    Py_TYPE(co)->tp_free(co);
+    tp->tp_free(co);
+    Py_DECREF(tp);
 }
 
 static PyObject *
@@ -2818,6 +2740,7 @@ combinations_sizeof(combinationsobject *co, void *unused)
 static int
 combinations_traverse(combinationsobject *co, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(co));
     Py_VISIT(co->pool);
     Py_VISIT(co->result);
     return 0;
@@ -2988,48 +2911,25 @@ static PyMethodDef combinations_methods[] = {
     {NULL,              NULL}   /* sentinel */
 };
 
-static PyTypeObject combinations_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "itertools.combinations",           /* tp_name */
-    sizeof(combinationsobject),         /* tp_basicsize */
-    0,                                  /* tp_itemsize */
-    /* methods */
-    (destructor)combinations_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 */
-    itertools_combinations__doc__,      /* tp_doc */
-    (traverseproc)combinations_traverse,/* tp_traverse */
-    0,                                  /* tp_clear */
-    0,                                  /* tp_richcompare */
-    0,                                  /* tp_weaklistoffset */
-    PyObject_SelfIter,                  /* tp_iter */
-    (iternextfunc)combinations_next,    /* tp_iternext */
-    combinations_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_combinations,             /* tp_new */
-    PyObject_GC_Del,                    /* tp_free */
+static PyType_Slot combinations_slots[] = {
+    {Py_tp_dealloc, combinations_dealloc},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_doc, (void *)itertools_combinations__doc__},
+    {Py_tp_traverse, combinations_traverse},
+    {Py_tp_iter, PyObject_SelfIter},
+    {Py_tp_iternext, combinations_next},
+    {Py_tp_methods, combinations_methods},
+    {Py_tp_new, itertools_combinations},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec combinations_spec = {
+    .name = "itertools.combinations",
+    .basicsize = sizeof(combinationsobject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = combinations_slots,
 };
 
 
@@ -3133,12 +3033,14 @@ error:
 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);
-    Py_TYPE(co)->tp_free(co);
+    tp->tp_free(co);
+    Py_DECREF(tp);
 }
 
 static PyObject *
@@ -3152,6 +3054,7 @@ cwr_sizeof(cwrobject *co, void *unused)
 static int
 cwr_traverse(cwrobject *co, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(co));
     Py_VISIT(co->pool);
     Py_VISIT(co->result);
     return 0;
@@ -3312,48 +3215,25 @@ static PyMethodDef cwr_methods[] = {
     {NULL,              NULL}   /* sentinel */
 };
 
-static PyTypeObject cwr_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "itertools.combinations_with_replacement",          /* tp_name */
-    sizeof(cwrobject),                                  /* tp_basicsize */
-    0,                                                  /* tp_itemsize */
-    /* methods */
-    (destructor)cwr_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 */
-    itertools_combinations_with_replacement__doc__,     /* tp_doc */
-    (traverseproc)cwr_traverse,                         /* tp_traverse */
-    0,                                                  /* tp_clear */
-    0,                                                  /* tp_richcompare */
-    0,                                                  /* tp_weaklistoffset */
-    PyObject_SelfIter,                                  /* tp_iter */
-    (iternextfunc)cwr_next,                             /* tp_iternext */
-    cwr_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_combinations_with_replacement,            /* tp_new */
-    PyObject_GC_Del,                                    /* tp_free */
+static PyType_Slot cwr_slots[] = {
+    {Py_tp_dealloc, cwr_dealloc},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_doc, (void *)itertools_combinations_with_replacement__doc__},
+    {Py_tp_traverse, cwr_traverse},
+    {Py_tp_iter, PyObject_SelfIter},
+    {Py_tp_iternext, cwr_next},
+    {Py_tp_methods, cwr_methods},
+    {Py_tp_new, itertools_combinations_with_replacement},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec cwr_spec = {
+    .name = "itertools.combinations_with_replacement",
+    .basicsize = sizeof(cwrobject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = cwr_slots,
 };
 
 
@@ -3476,12 +3356,14 @@ error:
 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);
-    Py_TYPE(po)->tp_free(po);
+    tp->tp_free(po);
+    Py_DECREF(tp);
 }
 
 static PyObject *
@@ -3496,6 +3378,7 @@ permutations_sizeof(permutationsobject *po, void *unused)
 static int
 permutations_traverse(permutationsobject *po, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(po));
     Py_VISIT(po->pool);
     Py_VISIT(po->result);
     return 0;
@@ -3701,48 +3584,25 @@ static PyMethodDef permuations_methods[] = {
     {NULL,              NULL}   /* sentinel */
 };
 
-static PyTypeObject permutations_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "itertools.permutations",           /* tp_name */
-    sizeof(permutationsobject),         /* tp_basicsize */
-    0,                                  /* tp_itemsize */
-    /* methods */
-    (destructor)permutations_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 */
-    itertools_permutations__doc__,      /* tp_doc */
-    (traverseproc)permutations_traverse,/* tp_traverse */
-    0,                                  /* tp_clear */
-    0,                                  /* tp_richcompare */
-    0,                                  /* tp_weaklistoffset */
-    PyObject_SelfIter,                  /* tp_iter */
-    (iternextfunc)permutations_next,    /* tp_iternext */
-    permuations_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_permutations,             /* tp_new */
-    PyObject_GC_Del,                    /* tp_free */
+static PyType_Slot permutations_slots[] = {
+    {Py_tp_dealloc, permutations_dealloc},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_doc, (void *)itertools_permutations__doc__},
+    {Py_tp_traverse, permutations_traverse},
+    {Py_tp_iter, PyObject_SelfIter},
+    {Py_tp_iternext, permutations_next},
+    {Py_tp_methods, permuations_methods},
+    {Py_tp_new, itertools_permutations},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec permutations_spec = {
+    .name = "itertools.permutations",
+    .basicsize = sizeof(permutationsobject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = permutations_slots,
 };
 
 
@@ -4975,8 +4835,15 @@ static int
 itertoolsmodule_traverse(PyObject *mod, visitproc visit, void *arg)
 {
     itertools_state *state = get_module_state(mod);
+    Py_VISIT(state->combinations_type);
+    Py_VISIT(state->cwr_type);
+    Py_VISIT(state->cycle_type);
+    Py_VISIT(state->dropwhile_type);
     Py_VISIT(state->groupby_type);
     Py_VISIT(state->_grouper_type);
+    Py_VISIT(state->permutations_type);
+    Py_VISIT(state->starmap_type);
+    Py_VISIT(state->takewhile_type);
     return 0;
 }
 
@@ -4984,8 +4851,15 @@ static int
 itertoolsmodule_clear(PyObject *mod)
 {
     itertools_state *state = get_module_state(mod);
+    Py_CLEAR(state->combinations_type);
+    Py_CLEAR(state->cwr_type);
+    Py_CLEAR(state->cycle_type);
+    Py_CLEAR(state->dropwhile_type);
     Py_CLEAR(state->groupby_type);
     Py_CLEAR(state->_grouper_type);
+    Py_CLEAR(state->permutations_type);
+    Py_CLEAR(state->starmap_type);
+    Py_CLEAR(state->takewhile_type);
     return 0;
 }
 
@@ -5010,26 +4884,26 @@ static int
 itertoolsmodule_exec(PyObject *mod)
 {
     itertools_state *state = get_module_state(mod);
+    ADD_TYPE(mod, state->combinations_type, &combinations_spec);
+    ADD_TYPE(mod, state->cwr_type, &cwr_spec);
+    ADD_TYPE(mod, state->cycle_type, &cycle_spec);
+    ADD_TYPE(mod, state->dropwhile_type, &dropwhile_spec);
     ADD_TYPE(mod, state->groupby_type, &groupby_spec);
     ADD_TYPE(mod, state->_grouper_type, &_grouper_spec);
+    ADD_TYPE(mod, state->permutations_type, &permutations_spec);
+    ADD_TYPE(mod, state->starmap_type, &starmap_spec);
+    ADD_TYPE(mod, state->takewhile_type, &takewhile_spec);
 
     PyTypeObject *typelist[] = {
         &accumulate_type,
         &batched_type,
-        &combinations_type,
-        &cwr_type,
-        &cycle_type,
-        &dropwhile_type,
-        &takewhile_type,
         &islice_type,
-        &starmap_type,
         &chain_type,
         &compress_type,
         &filterfalse_type,
         &count_type,
         &ziplongest_type,
         &pairwise_type,
-        &permutations_type,
         &product_type,
         &repeat_type,
         &tee_type,